编译getaddrinfo钩子 LD_PRELOAD加载 钩Python程序 钩Go程序 GODEBUG=netdns=cgo
这样的钩子技术可以应用在很多其它情况下.
并不会因为钩子的源代码是C, 就只能钩C写的程序 (curl 是 C写的).
编译钩子请参考上一篇, 略.
钩子文件是 /root/hook_getaddrinfo.so
钩 Python 程序
感谢 Debian中文群的群友的 python 代码 https://t.me/c/1039975886/766756
python3 -c 'import sys, socket; [print(res) for res in socket.getaddrinfo(sys.argv[1], int(sys.argv[2] if len(sys.argv) > 2 else 80))]' api.myip.la
上面的代码是python调用系统 getaddrinfo. 我们在开头加上钩子, 得到
LD_PRELOAD=/root/hook_getaddrinfo.so python3 -c 'import sys, socket; [print(res) for res in socket.getaddrinfo(sys.argv[1], int(sys.argv[2] if len(sys.argv) > 2 else 80))]' api.myip.la日志如下
钩 Go 程序
让GPT写一个Go程序, 实现简单的功能:
访问一个域名, 打印HTTP结果. 看起来就像curl
代码如下, gurl.go
package main
import ( "fmt" "io/ioutil" "log" "net/http" "os" "strings" // 导入 strings 包用于字符串操作 "time" )
func main() { // --- 1. 处理命令行参数 --- if len(os.Args) < 2 { log.Fatalf("❌ 缺少参数。用法: gurl <URL/Domain>") } url := os.Args[1]
// --- 2. 检查并补全协议头(核心修改部分) --- // 检查 URL 是否以 "http://" 或 "https://" 开头 if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") { // 如果没有协议头,默认加上 "http://" // 注意:如果访问的网站强制使用 HTTPS,这里可能需要手动改为 "https://" url = "http://" + url }
// 3. 创建 HTTP 客户端 client := http.Client{ Timeout: time.Second * 10, // 设置 10 秒的请求超时 }
// 4. 发送 GET 请求 resp, err := client.Get(url) if err != nil { // 如果请求失败(例如网络错误、DNS 解析失败等) log.Fatalf("❌ 发送请求失败: %v", err) }
// 5. 确保在函数结束时关闭响应体 defer resp.Body.Close()
// 6. 检查 HTTP 状态码 if resp.StatusCode != http.StatusOK { log.Fatalf("⚠️ 访问失败,状态码: %d %s", resp.StatusCode, resp.Status) }
// 7. 读取响应体内容 body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatalf("❌ 读取响应体失败: %v", err) }
// 8. 打印结果 fmt.Println(string(body)) }
在vps上编译一下
go build gurl.go得到可执行文件 gurl
简单测试一下, 功能正常
加上钩子测试
LD_PRELOAD=/root/hook_getaddrinfo.so ./gurl api.myip.la
奇怪, 结果中没有钩子的打印.
一开始我还以为是钩子的 .so 文件名写错了还是目录搞错了还是用户没权限,... 各种查了半天
最后去问GPT, 原来 Go 的函数底层不一定使用系统的 getaddrinfo 接口. 默认是调用Go自己的DNS解析实现.
如果要指定使用系统的 getaddrinfo, 需要设置环境变量 GODEBUG=netdns=cgo
也就是这样
GODEBUG=netdns=cgo LD_PRELOAD=/root/hook_getaddrinfo.so ./gurl api.myip.la
* 上面这是1整行.
结果有钩子的打印了, 而且 gai.conf 也确实能控制 IPv4 / IPv6
========




