Golang net / http客户端 - 捕获提供响应的服务器的IP地址

时间:2018-03-20 12:54:44

标签: http go ip

使用Golang(default HTTP client),我无法直接确定处理请求的服务器的IP地址。例如,在请求example.com时,example.com在请求时解析的IP地址是多少?

import "net/http"

resp, err := http.Get("http://example.com/")

resp对象包含resp.RemoteAddr属性,但在客户端操作期间未使用如下所述。

 // RemoteAddr allows HTTP servers and other software to record
 // the network address that sent the request, usually for
 // logging. This field is not filled in by ReadRequest and
 // has no defined format. The HTTP server in this package
 // sets RemoteAddr to an "IP:port" address before invoking a
 // handler.
 // This field is ignored by the HTTP client.
 RemoteAddr string

有没有直接的方法来实现这一目标?我最初的想法是:

  1. 启动对远程域的DNS查找
  2. 使用返回的A / AAAA记录创建新的http传输
  3. 提出请求
  4. 在响应对象上设置RemoteAddr属性
  5. 有更好的方法吗?

    谢谢。

    更新 - 使用@flimzy的建议。此方法将远程IP:PORT存储到request.RemoteAddr属性中。我还添加了对多个重定向的支持,以便每个后续请求都填充了RemoteAddr。

    request, _ := http.NewRequest("GET", "http://www.google.com", nil)
    client := &http.Client{
        Transport:&http.Transport{
            DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
                conn, err := net.Dial(network, addr)
                request.RemoteAddr = conn.RemoteAddr().String()
                return conn, err
            },
        },
        CheckRedirect: func(req *http.Request, via []*http.Request) error {
            request = req
            return nil
        },
    }
    resp, _ := client.Do(request)
    

3 个答案:

答案 0 :(得分:5)

据我所知,使用标准库实现此目的的唯一方法是使用自定义http.Transport来记录远程IP地址,例如在DialContext函数中。

client := &http.Client{
    Transport: &http.Transport{
        DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
            conn, err := net.Dial(network, addr)
            fmt.Printf("Remote IP: %s\n", conn.RemoteAddr())
            return conn, err
        },
    },
}
resp, _ := client.Get("http://www.google.com")

将连接IP与响应联系起来留给读者练习。

答案 1 :(得分:1)

您还可以使用跟踪建立请求:

request = request.WithContext(httptrace.WithClientTrace(request.Context(), &httptrace.ClientTrace{
        GotConn: func(connInfo httptrace.GotConnInfo) {
            fmt.Printf("target ip:%+v\n", connInfo.Conn.RemoteAddr().String())
        },
    }))
response, _:= client.Do(request)

答案 2 :(得分:0)

httptrace形式https://golang.org/pkg/net/http/httptrace/

req, err := http.NewRequest(method, url, strings.NewReader(body))
    trace := &httptrace.ClientTrace{
        GotConn: func(connInfo httptrace.GotConnInfo) {
            fmt.Printf("Got Conn: %+v\n", connInfo)
        },
        DNSDone: func(dnsInfo httptrace.DNSDoneInfo) {
            fmt.Printf("DNS Info: %+v\n", dnsInfo)
        },
    }
req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))