【问题标题】:How to capture IP address of server providing HTTP response如何捕获提供 HTTP 响应的服务器的 IP 地址
【发布时间】:2018-08-29 07:13:36
【问题描述】:

使用 Go 的 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 属性

有没有更好的办法?


已更新 - 使用 @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)

【问题讨论】:

  • 您最多可以在途中的某个时间获取处理响应的a 服务器的 IP 地址。这可能是代理、负载均衡器、WAF、反向代理……您实际上想完成 什么?为什么需要 IP?
  • @Adrian 响应链中的最后一个服务器很好。使用 WARC 标准创建档案具有 IP 地址的元数据字段。虽然有 Golang 的 warc 编写器,但它们(当前)都不支持将响应处理为 WARC 格式。

标签: http go ip


【解决方案1】:

据我所知,使用标准库完成此操作的唯一方法是使用记录远程 IP 地址的自定义 http.Transport,例如在 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 绑定到响应留给读者作为练习。

【讨论】:

  • 在响应对象中持久保存它的好方法是什么?
【解决方案2】:

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

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)

【讨论】:

    【解决方案3】:

    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))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多