Files
komari-agent/dnsresolver/resolver.go

133 lines
3.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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(),
}
}