今天碰到了个需求,我要知道程序对外访问的 http
请求域名的 ip
地址。
直接查看 golang
的 net/http
包,发现 Response
中并没有我想要的 ip
信息。
考虑到在 OSI
七层模型中,ip
是网络层协议,而 http
是应用层协议。去翻了下 net
包,发现了基础用法。
先提一下,域名访问服务器是会通过 dns
服务器去获取服务器的 ip
(这块知识不了解的可以先去了解下),我们日常访问域名的过程:域名 -> dns
服务器 -> 需要访问的服务器的 ip
。 dns
服务器有可能回返回多个 ip
,一般程序都会使用第一个进行数据交互。
源码 net/lookup.go
中有相关的获取方式,测试代码如下:
package main
import (
"fmt"
"log"
"net"
)
func main() {
useNetParse()
}
func useNetParse() {
host := "www.baidu.com"
ips, err := net.LookupIP(host)
if err != nil {
log.Fatal(err)
}
for _, v := range ips {
fmt.Println("DNS 解析:", v.String())
}
ip, err := net.ResolveIPAddr("ip", host)
if err != nil {
log.Fatal(err)
}
fmt.Println("服务器 IP 地址:", ip.String())
}
输出
DNS 解析: 180.101.50.188
DNS 解析: 180.101.50.242
服务器 IP 地址: 180.101.50.188
简单介绍下 httptrace
,它是 go 1.17
后添加的新方法,用于在客户端请求的整个生命周期中收集细粒度信息的工具。
它提供了许多的钩子,如:
DNS
查询获取 DNS
查询使用的是 DNSDone
这个钩子,但是 DNS
解析后可能会解析出多个 IP
地址,而我需要的是访问服务器的 IP
地址,可以使用 GotConn
这个钩子,在连接成功创建后查看其访问的服务器的 IP
地址。
测试代码如下:
package main
import (
"fmt"
"log"
"net/http"
"net/http/httptrace"
)
func main() {
req, _ := http.NewRequest("GET", "https://www.baidu.com", nil)
trace := &httptrace.ClientTrace{
DNSDone: func(dnsInfo httptrace.DNSDoneInfo) {
fmt.Printf("DNS Info: %+v\n", dnsInfo)
},
GotConn: func(connInfo httptrace.GotConnInfo) {
fmt.Printf("Got Conn: %+v\n", connInfo.Conn.RemoteAddr().String())
},
}
req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
_, err := http.DefaultTransport.RoundTrip(req)
if err != nil {
log.Fatal(err)
}
}
输出:
DNS Info: {Addrs:[{IP:180.101.50.188 Zone:} {IP:180.101.50.242 Zone:}] Err: Coalesced:false}
Got Conn: 180.101.50.188:443
可以看到这里访问的实际服务器的 IP
地址是 DNS
解析出的第一个 IP
地址。
ping www.baidu.com
输出
正在 Ping www.a.shifen.com [180.101.50.188] 具有 32 字节的数据:
来自 180.101.50.188 的回复: 字节=32 时间=21ms TTL=50
来自 180.101.50.188 的回复: 字节=32 时间=8ms TTL=50
来自 180.101.50.188 的回复: 字节=32 时间=8ms TTL=50
来自 180.101.50.188 的回复: 字节=32 时间=7ms TTL=50
180.101.50.188 的 Ping 统计信息:
数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
最短 = 7ms,最长 = 21ms,平均 = 11ms
nslookup www.baidu.com
输出
服务器: public1.alidns.com
Address: 223.5.5.5
非权威应答:
名称: www.a.shifen.com
Addresses: 240e:e9:6002:15a:0:ff:b05c:1278
240e:e9:6002:15c:0:ff:b015:146f
180.101.50.242
180.101.50.188
Aliases: www.baidu.com
本篇介绍了在 go
中如何获取访问域名的 ip
地址,通过 go
官方 net
包可获取。
如果有记录 http
请求的域名 ip
这种需求,可以使用 go 1.17
后添加的 httptrace
包来插入钩子获取请求的 ip
地址。当然了,httptrace
的作用不止于此,它可以搜集 http
客户端请求整个生命周期中的信息,本篇未做详细介绍,感兴趣的可自行探索。