feat: 添加自定义 DNS 解析器

This commit is contained in:
2025-09-13 02:05:00 +08:00
parent 7af8e540db
commit 9834a55e5d
7 changed files with 175 additions and 17 deletions

132
dnsresolver/resolver.go Normal file
View File

@@ -0,0 +1,132 @@
package dnsresolver
import (
"context"
"fmt"
"net"
"net/http"
"strings"
"time"
)
var (
// DNS服务器列表按优先级排序
DNSServers = []string{
"114.114.114.114:53", // 114DNS中国大陆
"8.8.8.8:53", // Google DNS全球
"8.8.4.4:53", // Google DNS备用全球
"1.1.1.1:53", // Cloudflare DNS全球
"223.5.5.5:53", // 阿里DNS中国大陆
"119.29.29.29:53", // DNSPod中国大陆
}
// CustomDNSServer 自定义DNS服务器可以通过命令行参数设置
CustomDNSServer string
)
// SetCustomDNSServer 设置自定义DNS服务器
func SetCustomDNSServer(dnsServer string) {
if dnsServer != "" {
// 检查是否已包含端口如果没有则添加默认端口53
if !strings.Contains(dnsServer, ":") {
dnsServer = dnsServer + ":53"
}
CustomDNSServer = dnsServer
}
}
// getCurrentDNSServer 获取当前要使用的DNS服务器
func getCurrentDNSServer() string {
if CustomDNSServer != "" {
return CustomDNSServer
}
// 如果没有设置自定义DNS返回默认的第一个
return DNSServers[0]
}
// GetCustomResolver 返回一个使用指定DNS服务器的解析器
func GetCustomResolver() *net.Resolver {
return &net.Resolver{
PreferGo: true,
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
d := net.Dialer{
Timeout: 10 * time.Second,
}
// 尝试自定义DNS或默认DNS
dnsServer := getCurrentDNSServer()
conn, err := d.DialContext(ctx, "udp", dnsServer)
if err == nil {
return conn, nil
}
// 如果连接失败尝试其他DNS服务器
for _, server := range DNSServers {
if server != dnsServer { // 避免重复尝试
conn, err := d.DialContext(ctx, "udp", server)
if err == nil {
return conn, nil
}
}
}
// 所有DNS服务器都失败返回最后一次的错误
return nil, err
},
}
}
// GetHTTPClient 返回一个使用自定义DNS解析器的HTTP客户端
func GetHTTPClient(timeout time.Duration) *http.Client {
if timeout <= 0 {
timeout = 30 * time.Second
}
customResolver := GetCustomResolver()
return &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
host, port, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
}
ips, err := customResolver.LookupHost(ctx, host)
if err != nil {
return nil, err
}
for _, ip := range ips {
dialer := &net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}
conn, err := dialer.DialContext(ctx, network, net.JoinHostPort(ip, port))
if err == nil {
return conn, nil
}
}
return nil, fmt.Errorf("failed to dial to any of the resolved IPs")
},
MaxIdleConns: 10,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
},
Timeout: timeout,
}
}
// GetNetDialer 返回一个使用自定义DNS解析器的网络拨号器
func GetNetDialer(timeout time.Duration) *net.Dialer {
if timeout <= 0 {
timeout = 5 * time.Second
}
return &net.Dialer{
Timeout: timeout,
KeepAlive: 30 * time.Second,
Resolver: GetCustomResolver(),
}
}