Files
goproxy/cmd/wildcard_dns_proxy/main.go
2025-03-13 17:53:08 +08:00

191 lines
6.0 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 main
import (
"flag"
"log"
"net/http"
"time"
"github.com/goproxy/internal/config"
"github.com/goproxy/internal/dns"
"github.com/goproxy/internal/proxy"
)
// WildcardDNSDelegate 带有泛解析功能的委托
type WildcardDNSDelegate struct {
proxy.DefaultDelegate
targetHost string
targetPort string
resolver dns.Resolver
}
// ModifyRequest 修改请求头
func (d *WildcardDNSDelegate) ModifyRequest(req *http.Request) {
log.Printf("收到请求: %s %s", req.Method, req.URL.String())
// 设置标准浏览器请求头
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/122.0.0.0 Safari/537.36")
req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
req.Header.Set("Connection", "keep-alive")
// 保留原始Host头便于泛解析匹配
// 只有当明确指定目标主机时才覆盖
if d.targetHost != "" && d.targetHost != "*" {
req.Host = d.targetHost
}
// 设置请求的URL方案为HTTPS
req.URL.Scheme = "https"
log.Printf("修改后的请求: %s %s (Host: %s)", req.Method, req.URL.String(), req.Host)
}
// ModifyResponse 修改响应头
func (d *WildcardDNSDelegate) ModifyResponse(resp *http.Response) error {
log.Printf("收到响应: %d %s", resp.StatusCode, resp.Status)
// 添加CORS头和代理标识
resp.Header.Set("Access-Control-Allow-Origin", "*")
resp.Header.Set("X-Proxied-By", "GoProxy-WildcardDNS")
return nil
}
// ResolveBackend 解析后端服务器
func (d *WildcardDNSDelegate) ResolveBackend(req *http.Request) (string, error) {
// 获取要解析的主机名
hostToResolve := req.Host
if d.targetHost != "" && d.targetHost != "*" {
hostToResolve = d.targetHost
}
// 从泛解析获取目标地址
endpoint, err := d.resolver.ResolveWithPort(hostToResolve, 0)
if err != nil {
log.Printf("解析主机 %s 失败: %v, 使用默认端口: %s", hostToResolve, err, d.targetPort)
return hostToResolve + ":" + d.targetPort, nil
}
// 优先使用解析得到的端口
if endpoint.Port > 0 {
address := endpoint.GetAddressWithDefaultPort(0)
log.Printf("泛解析主机 %s 到目标服务器(自定义端口): %s", hostToResolve, address)
return address, nil
}
// 使用默认端口
address := endpoint.GetAddressWithDefaultPort(443)
log.Printf("泛解析主机 %s 到目标服务器(默认端口): %s", hostToResolve, address)
return address, nil
}
func main() {
// 命令行参数
listenAddr := flag.String("listen", ":8080", "监听地址")
targetHost := flag.String("target", "", "目标站点主机名留空表示使用请求中的Host")
targetPort := flag.String("port", "443", "默认目标端口")
dnsFile := flag.String("dns", "", "DNS配置文件路径 (JSON格式)")
hostsFile := flag.String("hosts", "", "Hosts文件路径")
flag.Parse()
// 创建DNS解析器
var resolver dns.Resolver
var err error
if *dnsFile != "" {
// 从JSON文件加载DNS配置
dnsConfig, err := dns.LoadFromJSON(*dnsFile)
if err != nil {
log.Printf("加载DNS配置文件失败: %v将使用默认DNS解析器", err)
resolver = dns.NewResolver()
} else {
resolver = dns.NewResolverFromConfig(dnsConfig)
log.Printf("已加载DNS配置包含 %d 条记录", len(dnsConfig.Records))
}
} else if *hostsFile != "" {
// 从hosts文件加载DNS配置
dnsConfig, err := dns.LoadFromHostsFile(*hostsFile)
if err != nil {
log.Printf("加载hosts文件失败: %v将使用默认DNS解析器", err)
resolver = dns.NewResolver()
} else {
resolver = dns.NewResolverFromConfig(dnsConfig)
log.Printf("已加载hosts文件包含 %d 条记录", len(dnsConfig.Records))
}
} else {
// 创建默认解析器并添加一些示例泛解析规则
resolver = dns.NewResolver()
// 通配符示例
resolver.AddWildcard("*.example.com", "93.184.216.34")
resolver.AddWildcardWithPort("*.api.example.com", "93.184.216.35", 8443)
resolver.AddWildcard("*.github.com", "140.82.121.3")
// 多级通配符示例
resolver.AddWildcardWithPort("*.dev.local", "127.0.0.1", 3000)
resolver.AddWildcardWithPort("api.*.dev.local", "127.0.0.1", 3001)
resolver.AddWildcardWithPort("db.*.dev.local", "127.0.0.1", 5432)
// 常规精确匹配
resolver.Add("example.com", "93.184.216.34")
resolver.Add("github.com", "140.82.121.4")
log.Printf("已创建默认解析器并添加示例泛解析规则")
}
// 创建自定义DNS拨号器
dnsDialer := dns.NewDialer(resolver)
// 创建配置
cfg := config.DefaultConfig()
cfg.ReverseProxy = true // 启用反向代理模式
cfg.DecryptHTTPS = false // 不解密HTTPS流量避免TLS问题
cfg.IdleTimeout = 30 * time.Second // 连接空闲超时
cfg.AddXForwardedFor = true // 添加X-Forwarded-For头
cfg.AddXRealIP = true // 添加X-Real-IP头
cfg.SupportWebSocketUpgrade = true // 支持WebSocket升级
cfg.EnableCompression = false // 不启用压缩
cfg.EnableCORS = true // 启用CORS
cfg.EnableRetry = false // 关闭重试功能
cfg.EnableConnectionPool = false // 禁用连接池
// 创建自定义委托
delegate := &WildcardDNSDelegate{
targetHost: *targetHost,
targetPort: *targetPort,
resolver: resolver,
}
// 创建代理实例
p := proxy.New(&proxy.Options{
Config: cfg,
Delegate: delegate,
})
// 设置自定义拨号器
p.SetDialContext(dnsDialer.DialContext)
// 创建HTTP服务器
server := &http.Server{
Addr: *listenAddr,
Handler: p,
}
// 启动HTTP服务器
log.Printf("泛解析DNS代理启动监听地址: %s", *listenAddr)
if *targetHost == "" {
log.Printf("透明代理模式请求的Host将直接用于DNS解析")
log.Printf("提示: 尝试访问 http://localhost%s 并设置不同的Host头", *listenAddr)
} else {
log.Printf("目标主机模式:所有请求将被发送到 %s", *targetHost)
log.Printf("提示: 尝试访问 http://localhost%s", *listenAddr)
}
err = server.ListenAndServe()
if err != nil {
log.Fatalf("服务器启动失败: %v", err)
}
}