502 Bad Gateway: net/http GET failed with IPSec Tunnel

huangapple go评论94阅读模式
英文:

502 Bad Gateway: net/http GET failed with IPSec Tunnel

问题

在Windows上使用net/http包通过IPSec隧道(VPN)进行远程GET请求时,GET请求失败,响应代码为502 Bad Gateway。然而,使用相同的headers、uri和method通过curl发送的请求却能正常工作。以下是Go源代码的样子:

	var req *http.Request
	req, err = http.NewRequest('GET', *uri, reader)
	if nil != err {
		level.Warn(log).Log('msg', '无法创建请求', 'err', err, 'uri', uri)
		return nil, err
	}
	if nil != req.Body {
		defer req.Body.Close()
	}
	for h, v := range opts.Headers {
		req.Header.Add(h, *v)
	}

	client := http.Client{}
	if nil != err {
		return nil, err
	}
	res, err := client.Do(req)
	if nil != err {
		level.Warn(log).Log('msg', '无法发送请求', 'err', err, 'uri', uri)
		return nil, err
	}
	defer res.Body.Close()

	buf, err := io.ReadAll(res.Body)
	if nil != err {
		level.Warn(log).Log('msg', '无法读取响应', 'err', err, 'uri', uri, 'status', res.Status, 'status_code', res.StatusCode)
		return nil, err
	}

在捕获和分析流量后,我发现通过curl发送的请求可以在VPN接口上正常捕获,但通过go(net/http)发送的GET请求却丢失了。

然后我猜测可能是框架选择了错误的接口来发送数据包。

因此,我尝试找到适当的本地网络接口,并指定其LocalAddr来发送我的GET请求,代码如下:

func Client(u string) (*http.Client, error) {
	uri, err := url.Parse(u)
	if nil != err {
		return nil, err
	}
    host := uri.Host
	port := uri.Port()
	if Empty == port {
		if uri.Scheme == 'http' {
			host = host + ':80'
		} else if uri.Scheme == 'https' {
			host = host + ':443'
		}
	}
	conn, err := net.Dial('tcp', host)
	if nil != err {
		return nil, err
	}
	addr := conn.LocalAddr().(*net.TCPAddr)
    // **确保使用随机端口作为本地端口**
	addr.Port = 0

	dialer := &net.Dialer{LocalAddr: addr}
	dialContext := func(ctx context.Context, network, addr string) (net.Conn, error) {
		conn, err := dialer.Dial(network, addr)
		return conn, err
	}

	transport := &http.Transport{DialContext: dialContext}
	client := &http.Client{
		Transport: transport,
	}
	return client, nil
}

client := &http.Client{}替换为client, err := Client(uri)后,GET请求最终可以正常工作。

然后,我的问题是为什么Golang不会自动选择适当的本地网络接口来发送请求?

英文:

When making remote GET requests with net/http package through IPSec Tunnel(VPN) on windows, GET request failed with response code 502 Bad Gateway. However request with same headers, uri, method sent by curl works greatly. The go source code looks like:

	var req *http.Request
	req, err = http.NewRequest('GET', *uri, reader)
	if nil != err {
		level.Warn(log).Log("msg", "Unable to create request", "err", err, "uri", uri)
		return nil, err
	}
	if nil != req.Body {
		defer req.Body.Close()
	}
	for h, v := range opts.Headers {
		req.Header.Add(h, *v)
	}

	client := http.Client{}
	if nil != err {
		return nil, err
	}
	res, err := client.Do(req)
	if nil != err {
		level.Warn(log).Log("msg", "Unable to send request", "err", err, "uri", uri)
		return nil, err
	}
	defer res.Body.Close()

	buf, err := io.ReadAll(res.Body)
	if nil != err {
		level.Warn(log).Log("msg", "Unable to read response", "err", err, "uri", uri, "status", res.Status, "status_code", res.StatusCode)
		return nil, err
	}

After capturing and analysising the traffic, I found the request sent by curl can be captured normally on VPN Interface but GET request sent from go(net/http) lost.

Then I guess it probably because the framework seleted wrong interface to send the packet.

So I tried to find out proper local network interface and specify its LocalAddr to send my GET request as following:

func Client(u string) (*http.Client, error) {
	uri, err := url.Parse(u)
	if nil != err {
		return nil, err
	}
    host := uri.Host
	port := uri.Port()
	if Empty == port {
		if uri.Scheme == "http" {
			host = host + ":80"
		} else if uri.Scheme == "https" {
			host = host + ":443"
		}
	}
	conn, err := net.Dial("tcp", host)
	if nil != err {
		return nil, err
	}
	addr := conn.LocalAddr().(*net.TCPAddr)
    // **make sure using random port as local port**
	addr.Port = 0

	dialer := &net.Dialer{LocalAddr: addr}
	dialContext := func(ctx context.Context, network, addr string) (net.Conn, error) {
		conn, err := dialer.Dial(network, addr)
		return conn, err
	}

	transport := &http.Transport{DialContext: dialContext}
	client := &http.Client{
		Transport: transport,
	}
	return client, nil
}

And after repacing client with Client function, GET request final works.

client := &http.Client{} => client, err := Client(uri)

Then my question is why golang doesn't select proper local network interface to send request automatically?

答案1

得分: 0

在调试net.dial#DialContext之后,我发现在Visual Studio Code的设置中,地址已经被更改为我的代理地址。而我的代理服务器将无法处理我的应用程序请求。

当我移除代理设置时,net.dial按预期工作。

问题所在

我正在使用vscode与TypeScript/Java/Golang...一起工作,这是我在vscode IDE中首次遇到代理问题。换句话说,我从未想过IDE代理会对其构建的工作产生影响。因为扩展或IDE本身使用这个代理设置是合理的,但我的golang项目调试也使用了它,这真的让我很困惑。

502 Bad Gateway: net/http GET failed with IPSec Tunnel

502 Bad Gateway: net/http GET failed with IPSec Tunnel

英文:

After debugging the net.dial#DialContext, I found the address has been changed to my proxy address in Visual Studio Code settings. And my proxy server won't be able to handle my application requests.

502 Bad Gateway: net/http GET failed with IPSec Tunnel

502 Bad Gateway: net/http GET failed with IPSec Tunnel

When I removed the proxy setting, net.dial works as expected.

What matters

I'm using vscode to work with TypeScript/Java/Golang... and this is the first time I encounter a proxy issue on Developing Application in vscode IDE. In other words, I never thought the IDE proxy will work on the work it builds. Since extensions or IDE itself use this proxy settings is reasonable but my golang project debugging use it too that really confused me a lot.

huangapple
  • 本文由 发表于 2023年3月30日 17:31:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/75886458.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定