Curl-Socks5h-x

[Linux]讓 curl 藉由 socks5 proxy 連線時,不要反解 DNS,造成連線失敗

本文转自Ephrain 并作补充

Proxy Server链接问题

公司的專案程式通常需要支援各種 proxy server,如 HTTP proxy, socks4 和 socks5 proxy。
今天遇到一個問題,我們的程式底層會使用 libcurl 做 HTTP 連線,但連到一台 socks5 proxy 時卻不能成功…

試著用 curl 加上 -x 選項來指定 proxy server,再加 -v 選項看看詳細的錯誤訊息:

1
2
3
4
5
6
7
8
9
10
testuser@localhost ~ curl -v -x socks5://172.22.1.1:8080 https://testdomain.com

* Rebuilt URL to: https://testdomain.com/
* Trying 172.22.1.1...
* TCP_NODELAY set
* SOCKS5 communication to testdomain.com:443
* SOCKS5 connect to IPv6 2600:1417:1b:184::23ac (locally resolved)
* Can't complete SOCKS5 connection to 0.0.0.0:0. (1)
* Closing connection 0
curl: (7) Can't complete SOCKS5 connection to 0.0.0.0:0. (1)

可以看到訊息裡有一行 locally resolved,這行代表的是 curl 自行去查詢了 DNS,將 testdomain.com 的 IP 找出來,但因為 curl 使用的是 Happy Eyeball 的演算法,同時會發出 Type A 和 AAAA 的 DNS request 封包,因此如果 AAAA 的 DNS 回應封包先回來的話,就會拿到 testdomain.com 的對應 IPv6 位址,反之如果是 A 的 DNS 回應封包先回來的話,拿到的則是 IPv4 位址。

下面用 Wireshark 觀察一下 curl 產生出來的 DNS 封包,它送出了 A 和 AAAA 兩種 DNS 封包,以下例來說是 A (IPv4) 的回應先回來,但這個結果會依據網路狀況而有所不同,有時候是 AAAA (IPv6) 的回應先回來:
image

curl 自行查詢 DNS 這件事情有什麼錯誤嗎?
以這個例子來說,curl 幫忙查出 testdomain.com 的 IPv6 位址 2600:1417:1b:184::23ac,然後連線到 socks5 proxy 172.22.1.1,叫它連線到這個 IPv6 位址去。
然而,這台 socks5 proxy 所在的網路只設定了 IPv4 位址,所以 proxy server 本身是無法藉由 IPv6 位址來連線的!
因此它自然無法連線到 curl 指定的 IPv6 位址,導致連線失敗…

要解決這個問題,可以叫 curl 不要雞婆自己去查 DNS,而是讓 proxy server 自己來查 DNS,因為 proxy server 自己知道所處的網路環境,像是它不能連 IPv6 網路時,自然不會去問 Type AAAA (IPv6) 的 DNS 結果。

我們將原本的 socks5://: 改成 socks5h://:,代表要讓 proxy 自己的查詢 DNS,可以看到 curl 直接連到了 proxy server,沒有先做 DNS 查詢,而最終 proxy 也成功完成了連線:

1
2
3
4
5
6
7
8
9
10
11
testuser@localhost ~ curl -v -x socks5h://172.22.1.1:8080 https://testdomain.com

* Rebuilt URL to: https://testdomain.com/
* Trying 172.22.1.1...
* TCP_NODELAY set
* SOCKS5 communication to testdomain.com:443
* SOCKS5 request granted.
* Connected to 172.22.1.1 (172.22.1.1) port 8080 (#0)
...
* Curl_http_done: called premature == 0
* Connection #0 to host testdomain.com left intact

不過這種雷,幾乎是每次整合一個用到 libcurl 的模組,就會再踩到一次啊…

我遇到的场景

首先,我没想到我会被台湾同胞的这篇技术博客教到很有趣的东西,其次,博主的语言和繁体配合起来更有趣了,也基于尊重保留了完整原文
image

公司做安全监控平台收敛内网后,外部主机关联内网服务器的数据,需要监控进程 agent 以走代理的方式进来
自然代理服务器的公网地址和内网地址不在一个网段,然后为了安全性,代理服务器内网地址虽然和监控服务器同一网段,但由于安全组的隔离两者是不能直接访问的……(´◐∀◐`)

代中代(´◐∀◐`)

很自然的 curl 即使走代理都找不到身处内网的监控服务器域名
我只能在代理服务器 host 上配一下域名解析,然后翻了许久找到了 curl 的代理访问方式原理,就是这位博主的文章,让我明白了可以让 Proxy Server 去做 curl 的进一步内网解析
泪目,乙方厂商技术整半天都解决不了的问题,后来和我说我给的命令,其他客户也有这种问题的不能装的也能装了,让我找他们销售要钱草w(“▔□▔)

希望两岸互相少点偏见吧