7.7 KiB
7.7 KiB
GoProxy自定义DNS解析功能
该功能允许GoProxy使用自定义DNS解析器,实现以下功能:
- 自定义域名解析
- 动态变更后端服务器IP
- 自定义后端服务器端口
- 泛解析(通配符域名)支持
- 负载均衡和故障转移
- 绕过DNS污染
- 高效的DNS缓存
特性
- 自定义记录:直接设置域名到IP的映射
- 自定义端口:为每个域名指定自定义端口,无需在URL中指定
- 泛解析:支持通配符域名(如
*.example.com)自动匹配多个子域名 - 多级泛解析:支持复杂的通配符模式(如
api.*.example.com) - 备用解析:在自定义记录未找到时可选择使用系统DNS
- DNS缓存:缓存解析结果以提高性能
- 自动重试:解析失败时可配置重试策略
- 加载配置:从JSON文件或hosts格式文件加载配置
- 自定义拨号器:与net标准库兼容的拨号器
安装
确保已安装Go(建议1.22或更高版本):
git clone https://github.com/ouqiang/goproxy
cd goproxy
go build ./...
使用方法
1. HTTP代理(自定义DNS)
以下命令会启动一个HTTP代理(监听端口8080),它使用自定义DNS解析:
go run cmd/custom_dns_proxy/main.go
2. 自定义端口代理
支持为不同域名指定不同端口的代理:
go run cmd/custom_port_proxy/main.go
3. 泛解析DNS代理
支持通配符域名解析的代理:
# 使用默认的示例泛解析规则
go run cmd/wildcard_dns_proxy/main.go
# 透明代理模式(使用请求中的Host进行匹配)
go run cmd/wildcard_dns_proxy/main.go -target ""
# 使用自定义配置文件
go run cmd/wildcard_dns_proxy/main.go -dns examples/wildcard_dns_config.json
# 使用hosts格式配置文件
go run cmd/wildcard_dns_proxy/main.go -hosts examples/wildcard_hosts.txt
参数说明
-listen: 监听地址,默认:8080-target: 目标主机名,空字符串表示使用请求中的Host头-port: 默认目标端口,默认443-dns: DNS配置文件(JSON格式)-hosts: hosts格式配置文件
DNS配置格式
JSON格式
{
"records": {
"example.com": "93.184.216.34",
"api.example.com": "93.184.216.35:8443",
"*.github.com": "140.82.121.3",
"github.com": "140.82.121.4",
"*.dev.local": "127.0.0.1:3000",
"api.*.dev.local": "127.0.0.1:3001"
},
"use_fallback": true,
"ttl": 300
}
Hosts格式
# 精确匹配
93.184.216.34 example.com
93.184.216.35:8443 api.example.com
# 泛解析(通配符域名)
140.82.121.3 *.github.com
127.0.0.1:3000 *.dev.local
127.0.0.1:3001 api.*.dev.local
编程接口
使用DNS解析器
import "github.com/goproxy/internal/dns"
// 创建解析器
resolver := dns.NewResolver()
// 添加标准记录(使用默认端口)
resolver.Add("example.com", "93.184.216.34")
// 添加带端口的记录
resolver.AddWithPort("api.example.com", "93.184.216.35", 8443)
// 添加泛解析记录(使用默认端口)
resolver.AddWildcard("*.example.com", "93.184.216.36")
// 添加带端口的泛解析记录
resolver.AddWildcardWithPort("*.api.example.com", "93.184.216.37", 8444)
// 解析域名(只获取IP)
ip, err := resolver.Resolve("example.com")
if err != nil {
log.Fatalf("解析失败: %v", err)
}
fmt.Printf("解析结果IP: %s\n", ip)
// 测试泛解析功能
ip, err = resolver.Resolve("sub.example.com")
if err != nil {
log.Fatalf("解析失败: %v", err)
}
fmt.Printf("泛解析结果IP: %s\n", ip)
// 测试多级泛解析功能
endpoint, err := resolver.ResolveWithPort("test.api.example.com", 443)
if err != nil {
log.Fatalf("解析失败: %v", err)
}
fmt.Printf("多级泛解析结果: IP=%s, 端口=%d\n", endpoint.IP, endpoint.Port)
使用DNS拨号器
import "github.com/goproxy/internal/dns"
// 创建解析器
resolver := dns.NewResolver()
resolver.Add("example.com", "93.184.216.34")
resolver.AddWildcard("*.example.com", "93.184.216.36")
// 创建拨号器
dialer := dns.NewDialer(resolver)
// 使用拨号器连接(会自动应用泛解析)
conn, err := dialer.Dial("tcp", "sub.example.com:443")
if err != nil {
log.Fatalf("连接失败: %v", err)
}
defer conn.Close()
// 或者获取用于http.Transport的拨号上下文函数
transport := &http.Transport{
DialContext: dialer.DialContext,
}
client := &http.Client{Transport: transport}
高级用法
泛解析模式
泛解析支持以下模式:
-
单级通配符:
*.example.com匹配a.example.com、b.example.com等 -
多级通配符:
*.*.example.com匹配a.b.example.com、c.d.example.com等 -
中间通配符:
api.*.example.com匹配api.v1.example.com、api.beta.example.com等 -
前缀通配符:
api-*.example.com匹配api-v1.example.com、api-beta.example.com等
域名匹配优先级
当有多条规则可以匹配同一个域名时,解析器会按照以下优先级选择:
- 精确匹配(如
example.com) - 最具体的通配符匹配(如
*.test.example.com比*.example.com更优先) - 后添加的通配符规则优先于先添加的规则
透明代理模式
泛解析代理支持透明模式,这种模式下代理会使用请求中的Host头来进行DNS解析,而不是固定的目标主机:
go run cmd/wildcard_dns_proxy/main.go -target ""
这样,通过修改请求的Host头或使用不同的域名访问代理,可以自动路由到不同的后端服务器。
自定义DNS后端
可以实现自己的dns.Resolver接口来创建更复杂的DNS解析策略:
type MyResolver struct {
// 你的字段
}
// 实现Resolver接口的所有方法
func (r *MyResolver) Resolve(hostname string) (string, error) {
// 自定义逻辑
}
func (r *MyResolver) ResolveWithPort(hostname string, defaultPort int) (*dns.Endpoint, error) {
// 自定义逻辑
}
func (r *MyResolver) Add(hostname, ip string) error {
// 自定义逻辑
}
func (r *MyResolver) AddWithPort(hostname, ip string, port int) error {
// 自定义逻辑
}
func (r *MyResolver) AddWildcard(wildcardDomain, ip string) error {
// 自定义逻辑
}
func (r *MyResolver) AddWildcardWithPort(wildcardDomain, ip string, port int) error {
// 自定义逻辑
}
func (r *MyResolver) Remove(hostname string) error {
// 自定义逻辑
}
func (r *MyResolver) Clear() {
// 自定义逻辑
}
应用场景
多环境测试
使用泛解析可以为不同环境的所有服务配置不同的后端:
# 测试环境的所有服务
192.168.1.100 *.test.example.com
# 预发布环境的所有服务
192.168.1.101 *.staging.example.com
# 生产环境的所有服务
192.168.1.102 *.production.example.com
微服务架构
为不同类型的微服务提供统一的路由模式:
10.0.0.1:8001 *.auth.internal
10.0.0.2:8002 *.user.internal
10.0.0.3:8003 *.payment.internal
多租户系统
在多租户系统中为每个租户路由到不同后端:
# 每个租户的子域名指向专用服务器
192.168.1.10 tenant1.*.example.com
192.168.1.11 tenant2.*.example.com
192.168.1.12 tenant3.*.example.com
本地开发环境
在本地开发中快速模拟复杂的服务架构:
127.0.0.1:3000 *.local
127.0.0.1:3001 api.*.local
127.0.0.1:5432 db.*.local
注意事项
- 通配符域名只在我们的自定义DNS解析器中有效,不会影响系统DNS
- 泛解析规则的顺序会影响匹配结果,后添加的规则优先级更高
- 过多的泛解析规则可能会影响性能,建议合理组织规则
- 当域名同时匹配多个规则时,精确匹配优先于通配符匹配
- 自签名证书会导致浏览器警告,仅用于测试目的