golang net/http库在发送http请求时会通过调用net下的Dialer建立TCP连接, net.Dialer 会在发起连接前执行通过ControlContext字段传入的一个函数, 我们可以通过这个函数获取ip、端口和网络名等信息。

示例代码:

package main

import (
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"syscall"
)

func customControl(network string, address string, conn syscall.RawConn) error {
	fmt.Printf("%s,%s\n", network, address)
	return nil
}

func main() {
	dialer := &net.Dialer{
		Control: customControl,
	}
	t := http.DefaultTransport.(*http.Transport).Clone()
	t.DialContext = dialer.DialContext

	c := &http.Client{
		Transport: t,
	}
	resp, _ := c.Get("https://www.baidu.com")
	body, _ := ioutil.ReadAll(resp.Body)
	fmt.Printf("%s\n", body)
}

我们可以再这个函数里记录每个http请求的实际ip地址,也可以在这里对请求IP做一些策略和检查,比如防范SSRF等等。