优化DNS解析逻辑
This commit is contained in:
228
README_DNS.md
228
README_DNS.md
@@ -5,6 +5,7 @@
|
|||||||
- 自定义域名解析
|
- 自定义域名解析
|
||||||
- 动态变更后端服务器IP
|
- 动态变更后端服务器IP
|
||||||
- 自定义后端服务器端口
|
- 自定义后端服务器端口
|
||||||
|
- 泛解析(通配符域名)支持
|
||||||
- 负载均衡和故障转移
|
- 负载均衡和故障转移
|
||||||
- 绕过DNS污染
|
- 绕过DNS污染
|
||||||
- 高效的DNS缓存
|
- 高效的DNS缓存
|
||||||
@@ -13,6 +14,8 @@
|
|||||||
|
|
||||||
- **自定义记录**:直接设置域名到IP的映射
|
- **自定义记录**:直接设置域名到IP的映射
|
||||||
- **自定义端口**:为每个域名指定自定义端口,无需在URL中指定
|
- **自定义端口**:为每个域名指定自定义端口,无需在URL中指定
|
||||||
|
- **泛解析**:支持通配符域名(如`*.example.com`)自动匹配多个子域名
|
||||||
|
- **多级泛解析**:支持复杂的通配符模式(如`api.*.example.com`)
|
||||||
- **备用解析**:在自定义记录未找到时可选择使用系统DNS
|
- **备用解析**:在自定义记录未找到时可选择使用系统DNS
|
||||||
- **DNS缓存**:缓存解析结果以提高性能
|
- **DNS缓存**:缓存解析结果以提高性能
|
||||||
- **自动重试**:解析失败时可配置重试策略
|
- **自动重试**:解析失败时可配置重试策略
|
||||||
@@ -39,37 +42,37 @@ go build ./...
|
|||||||
go run cmd/custom_dns_proxy/main.go
|
go run cmd/custom_dns_proxy/main.go
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 参数说明
|
### 2. 自定义端口代理
|
||||||
|
|
||||||
- `-listen`: 监听地址,默认 `:8080`
|
支持为不同域名指定不同端口的代理:
|
||||||
- `-target`: 目标主机名,默认 `www.github.com`
|
|
||||||
- `-port`: 目标端口,默认 `443`
|
|
||||||
- `-dns`: DNS配置文件(JSON格式)
|
|
||||||
- `-hosts`: hosts格式配置文件
|
|
||||||
|
|
||||||
### 2. HTTPS代理(自定义DNS)
|
|
||||||
|
|
||||||
以下命令会启动一个HTTPS代理(监听端口8443),它使用自定义DNS解析:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 首先生成自签名证书
|
go run cmd/custom_port_proxy/main.go
|
||||||
# Linux/MacOS
|
```
|
||||||
./scripts/generate_cert.sh
|
|
||||||
|
|
||||||
# Windows
|
### 3. 泛解析DNS代理
|
||||||
powershell -ExecutionPolicy Bypass -File .\scripts\generate_cert.ps1
|
|
||||||
|
|
||||||
# 然后启动HTTPS代理
|
支持通配符域名解析的代理:
|
||||||
go run cmd/custom_dns_https_proxy/main.go
|
|
||||||
|
```bash
|
||||||
|
# 使用默认的示例泛解析规则
|
||||||
|
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`: 监听地址,默认 `:8443`
|
- `-listen`: 监听地址,默认 `:8080`
|
||||||
- `-target`: 目标主机名,默认 `www.github.com`
|
- `-target`: 目标主机名,空字符串表示使用请求中的Host头
|
||||||
- `-port`: 目标端口,默认 `443`
|
- `-port`: 默认目标端口,默认 `443`
|
||||||
- `-cert`: 证书文件,默认 `server.crt`
|
|
||||||
- `-key`: 私钥文件,默认 `server.key`
|
|
||||||
- `-dns`: DNS配置文件(JSON格式)
|
- `-dns`: DNS配置文件(JSON格式)
|
||||||
- `-hosts`: hosts格式配置文件
|
- `-hosts`: hosts格式配置文件
|
||||||
|
|
||||||
@@ -80,12 +83,14 @@ go run cmd/custom_dns_https_proxy/main.go
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"records": {
|
"records": {
|
||||||
"www.github.com": "140.82.121.3",
|
"example.com": "93.184.216.34",
|
||||||
"github.com": "140.82.121.4",
|
"api.example.com": "93.184.216.35:8443",
|
||||||
"api.github.com": "140.82.121.5",
|
|
||||||
|
|
||||||
"custom-port-example.com": "192.168.1.10:8080",
|
"*.github.com": "140.82.121.3",
|
||||||
"api.dev.example.com": "127.0.0.1:3001"
|
"github.com": "140.82.121.4",
|
||||||
|
|
||||||
|
"*.dev.local": "127.0.0.1:3000",
|
||||||
|
"api.*.dev.local": "127.0.0.1:3001"
|
||||||
},
|
},
|
||||||
"use_fallback": true,
|
"use_fallback": true,
|
||||||
"ttl": 300
|
"ttl": 300
|
||||||
@@ -95,13 +100,14 @@ go run cmd/custom_dns_https_proxy/main.go
|
|||||||
### Hosts格式
|
### Hosts格式
|
||||||
|
|
||||||
```
|
```
|
||||||
# 标准格式:IP 域名
|
# 精确匹配
|
||||||
140.82.121.3 www.github.com
|
93.184.216.34 example.com
|
||||||
140.82.121.4 github.com
|
93.184.216.35:8443 api.example.com
|
||||||
|
|
||||||
# 带端口格式:IP:端口 域名
|
# 泛解析(通配符域名)
|
||||||
192.168.1.10:8080 custom-port-example.com
|
140.82.121.3 *.github.com
|
||||||
127.0.0.1:3001 api.dev.example.com
|
127.0.0.1:3000 *.dev.local
|
||||||
|
127.0.0.1:3001 api.*.dev.local
|
||||||
```
|
```
|
||||||
|
|
||||||
## 编程接口
|
## 编程接口
|
||||||
@@ -120,6 +126,12 @@ resolver.Add("example.com", "93.184.216.34")
|
|||||||
// 添加带端口的记录
|
// 添加带端口的记录
|
||||||
resolver.AddWithPort("api.example.com", "93.184.216.35", 8443)
|
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)
|
||||||
ip, err := resolver.Resolve("example.com")
|
ip, err := resolver.Resolve("example.com")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -127,12 +139,19 @@ if err != nil {
|
|||||||
}
|
}
|
||||||
fmt.Printf("解析结果IP: %s\n", ip)
|
fmt.Printf("解析结果IP: %s\n", ip)
|
||||||
|
|
||||||
// 解析域名(获取IP和端口)
|
// 测试泛解析功能
|
||||||
endpoint, err := resolver.ResolveWithPort("api.example.com", 443) // 443为默认端口
|
ip, err = resolver.Resolve("sub.example.com")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("解析失败: %v", err)
|
log.Fatalf("解析失败: %v", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("解析结果: IP=%s, 端口=%d\n", endpoint.IP, endpoint.Port)
|
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拨号器
|
### 使用DNS拨号器
|
||||||
@@ -143,17 +162,16 @@ import "github.com/goproxy/internal/dns"
|
|||||||
// 创建解析器
|
// 创建解析器
|
||||||
resolver := dns.NewResolver()
|
resolver := dns.NewResolver()
|
||||||
resolver.Add("example.com", "93.184.216.34")
|
resolver.Add("example.com", "93.184.216.34")
|
||||||
resolver.AddWithPort("example-api.com", "93.184.216.35", 8443)
|
resolver.AddWildcard("*.example.com", "93.184.216.36")
|
||||||
|
|
||||||
// 创建拨号器
|
// 创建拨号器
|
||||||
dialer := dns.NewDialer(resolver)
|
dialer := dns.NewDialer(resolver)
|
||||||
|
|
||||||
// 使用拨号器连接(会自动应用自定义端口)
|
// 使用拨号器连接(会自动应用泛解析)
|
||||||
conn, err := dialer.Dial("tcp", "example-api.com:443")
|
conn, err := dialer.Dial("tcp", "sub.example.com:443")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("连接失败: %v", err)
|
log.Fatalf("连接失败: %v", err)
|
||||||
}
|
}
|
||||||
// 注意:即使这里指定了443端口,实际会连接到8443端口
|
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
// 或者获取用于http.Transport的拨号上下文函数
|
// 或者获取用于http.Transport的拨号上下文函数
|
||||||
@@ -165,29 +183,35 @@ client := &http.Client{Transport: transport}
|
|||||||
|
|
||||||
## 高级用法
|
## 高级用法
|
||||||
|
|
||||||
### 负载均衡
|
### 泛解析模式
|
||||||
|
|
||||||
可以通过多次添加同一域名的不同IP地址来实现简单的负载均衡:
|
泛解析支持以下模式:
|
||||||
|
|
||||||
```go
|
1. **单级通配符**:`*.example.com` 匹配 `a.example.com`、`b.example.com` 等
|
||||||
resolver := dns.NewResolver()
|
|
||||||
resolver.Add("api.example.com", "10.0.0.1")
|
2. **多级通配符**:`*.*.example.com` 匹配 `a.b.example.com`、`c.d.example.com` 等
|
||||||
resolver.Add("api.example.com", "10.0.0.2")
|
|
||||||
resolver.Add("api.example.com", "10.0.0.3")
|
3. **中间通配符**:`api.*.example.com` 匹配 `api.v1.example.com`、`api.beta.example.com` 等
|
||||||
|
|
||||||
|
4. **前缀通配符**:`api-*.example.com` 匹配 `api-v1.example.com`、`api-beta.example.com` 等
|
||||||
|
|
||||||
|
### 域名匹配优先级
|
||||||
|
|
||||||
|
当有多条规则可以匹配同一个域名时,解析器会按照以下优先级选择:
|
||||||
|
|
||||||
|
1. 精确匹配(如 `example.com`)
|
||||||
|
2. 最具体的通配符匹配(如 `*.test.example.com` 比 `*.example.com` 更优先)
|
||||||
|
3. 后添加的通配符规则优先于先添加的规则
|
||||||
|
|
||||||
|
### 透明代理模式
|
||||||
|
|
||||||
|
泛解析代理支持透明模式,这种模式下代理会使用请求中的Host头来进行DNS解析,而不是固定的目标主机:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go run cmd/wildcard_dns_proxy/main.go -target ""
|
||||||
```
|
```
|
||||||
|
|
||||||
解析器将按轮询方式返回这些IP地址。
|
这样,通过修改请求的Host头或使用不同的域名访问代理,可以自动路由到不同的后端服务器。
|
||||||
|
|
||||||
### 带端口的负载均衡
|
|
||||||
|
|
||||||
可以为不同的后端服务器指定不同的端口:
|
|
||||||
|
|
||||||
```go
|
|
||||||
resolver := dns.NewResolver()
|
|
||||||
resolver.AddWithPort("api.example.com", "10.0.0.1", 8080)
|
|
||||||
resolver.AddWithPort("api.example.com", "10.0.0.2", 8081)
|
|
||||||
resolver.AddWithPort("api.example.com", "10.0.0.3", 8082)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 自定义DNS后端
|
### 自定义DNS后端
|
||||||
|
|
||||||
@@ -198,7 +222,7 @@ type MyResolver struct {
|
|||||||
// 你的字段
|
// 你的字段
|
||||||
}
|
}
|
||||||
|
|
||||||
// 实现Resolver接口
|
// 实现Resolver接口的所有方法
|
||||||
func (r *MyResolver) Resolve(hostname string) (string, error) {
|
func (r *MyResolver) Resolve(hostname string) (string, error) {
|
||||||
// 自定义逻辑
|
// 自定义逻辑
|
||||||
}
|
}
|
||||||
@@ -215,6 +239,14 @@ 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) Remove(hostname string) error {
|
||||||
// 自定义逻辑
|
// 自定义逻辑
|
||||||
}
|
}
|
||||||
@@ -226,44 +258,56 @@ func (r *MyResolver) Clear() {
|
|||||||
|
|
||||||
## 应用场景
|
## 应用场景
|
||||||
|
|
||||||
### 开发环境映射
|
|
||||||
|
|
||||||
在本地开发时,可以将多个服务映射到不同的端口:
|
|
||||||
|
|
||||||
```
|
|
||||||
127.0.0.1:3000 web.local
|
|
||||||
127.0.0.1:3001 api.local
|
|
||||||
127.0.0.1:5432 db.local
|
|
||||||
```
|
|
||||||
|
|
||||||
### 微服务路由
|
|
||||||
|
|
||||||
可以将不同的微服务映射到不同的IP和端口:
|
|
||||||
|
|
||||||
```
|
|
||||||
192.168.1.10:8001 auth-service.internal
|
|
||||||
192.168.1.11:8002 user-service.internal
|
|
||||||
192.168.1.12:8003 payment-service.internal
|
|
||||||
```
|
|
||||||
|
|
||||||
### 多环境测试
|
### 多环境测试
|
||||||
|
|
||||||
可以创建多个配置文件,针对不同的环境:
|
使用泛解析可以为不同环境的所有服务配置不同的后端:
|
||||||
|
|
||||||
```
|
```
|
||||||
# 测试环境
|
# 测试环境的所有服务
|
||||||
10.0.0.1:8080 api.example.com
|
192.168.1.100 *.test.example.com
|
||||||
10.0.0.2:8080 web.example.com
|
|
||||||
|
|
||||||
# 生产环境
|
# 预发布环境的所有服务
|
||||||
20.0.0.1:443 api.example.com
|
192.168.1.101 *.staging.example.com
|
||||||
20.0.0.2:443 web.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
|
||||||
```
|
```
|
||||||
|
|
||||||
## 注意事项
|
## 注意事项
|
||||||
|
|
||||||
1. 自签名证书会导致浏览器警告,仅用于测试目的
|
1. 通配符域名只在我们的自定义DNS解析器中有效,不会影响系统DNS
|
||||||
2. 某些网站可能拒绝代理连接
|
2. 泛解析规则的顺序会影响匹配结果,后添加的规则优先级更高
|
||||||
3. 此功能主要用于控制后端连接的IP解析和端口,不影响客户端DNS解析
|
3. 过多的泛解析规则可能会影响性能,建议合理组织规则
|
||||||
4. 在生产环境中使用时,建议使用更强大的DNS解析系统
|
4. 当域名同时匹配多个规则时,精确匹配优先于通配符匹配
|
||||||
5. 端口信息会覆盖请求中的端口,即使请求URL中指定了端口也会被替换为自定义端口
|
5. 自签名证书会导致浏览器警告,仅用于测试目的
|
190
cmd/wildcard_dns_proxy/main.go
Normal file
190
cmd/wildcard_dns_proxy/main.go
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
23
examples/wildcard_dns_config.json
Normal file
23
examples/wildcard_dns_config.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"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",
|
||||||
|
"api.github.com": "140.82.121.5",
|
||||||
|
|
||||||
|
"*.s3.amazonaws.com": "52.216.162.69",
|
||||||
|
"cdn-*.example.org": "203.0.113.10",
|
||||||
|
|
||||||
|
"*.dev.local": "127.0.0.1:3000",
|
||||||
|
"api.*.dev.local": "127.0.0.1:3001",
|
||||||
|
"db.*.dev.local": "127.0.0.1:5432",
|
||||||
|
|
||||||
|
"*.test.example.com": "192.168.1.100",
|
||||||
|
"*.staging.example.com": "192.168.1.101",
|
||||||
|
"*.production.example.com": "192.168.1.102"
|
||||||
|
},
|
||||||
|
"use_fallback": true,
|
||||||
|
"ttl": 300
|
||||||
|
}
|
27
examples/wildcard_hosts.txt
Normal file
27
examples/wildcard_hosts.txt
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# 精确匹配记录
|
||||||
|
93.184.216.34 example.com
|
||||||
|
93.184.216.35:8443 api.example.com
|
||||||
|
|
||||||
|
# GitHub相关泛解析
|
||||||
|
140.82.121.3 *.github.com
|
||||||
|
140.82.121.4 github.com
|
||||||
|
140.82.121.5 api.github.com
|
||||||
|
|
||||||
|
# AWS服务泛解析
|
||||||
|
52.216.162.69 *.s3.amazonaws.com
|
||||||
|
203.0.113.10 cdn-*.example.org
|
||||||
|
|
||||||
|
# 本地开发环境泛解析
|
||||||
|
127.0.0.1:3000 *.dev.local
|
||||||
|
127.0.0.1:3001 api.*.dev.local
|
||||||
|
127.0.0.1:5432 db.*.dev.local
|
||||||
|
|
||||||
|
# 多环境测试泛解析
|
||||||
|
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 *.api.service.com
|
||||||
|
10.0.0.2 *.auth.service.com
|
||||||
|
10.0.0.3 *.cdn.service.com
|
@@ -12,8 +12,8 @@ import (
|
|||||||
|
|
||||||
// DNSConfig DNS配置文件结构
|
// DNSConfig DNS配置文件结构
|
||||||
type DNSConfig struct {
|
type DNSConfig struct {
|
||||||
Records map[string]string `json:"records"`
|
Records map[string]string `json:"records"` // 普通记录和泛解析记录
|
||||||
Fallback bool `json:"fallback"`
|
Fallback bool `json:"fallback"` // 是否回退到系统DNS
|
||||||
TTL int `json:"ttl"` // 缓存TTL,单位为秒
|
TTL int `json:"ttl"` // 缓存TTL,单位为秒
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,6 +59,11 @@ func (c *DNSConfig) SaveToJSON(filePath string) error {
|
|||||||
// 用于解析hosts文件中的IP:端口格式
|
// 用于解析hosts文件中的IP:端口格式
|
||||||
var ipPortRegex = regexp.MustCompile(`^([0-9.]+)(?::(\d+))?$`)
|
var ipPortRegex = regexp.MustCompile(`^([0-9.]+)(?::(\d+))?$`)
|
||||||
|
|
||||||
|
// 检查是否为通配符域名
|
||||||
|
func isWildcardDomain(domain string) bool {
|
||||||
|
return strings.Contains(domain, "*")
|
||||||
|
}
|
||||||
|
|
||||||
// LoadFromHostsFile 从hosts文件格式加载DNS配置
|
// LoadFromHostsFile 从hosts文件格式加载DNS配置
|
||||||
func LoadFromHostsFile(filePath string) (*DNSConfig, error) {
|
func LoadFromHostsFile(filePath string) (*DNSConfig, error) {
|
||||||
file, err := os.Open(filePath)
|
file, err := os.Open(filePath)
|
||||||
@@ -112,6 +117,8 @@ func LoadFromHostsFile(filePath string) (*DNSConfig, error) {
|
|||||||
if strings.HasPrefix(domain, "#") {
|
if strings.HasPrefix(domain, "#") {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 支持通配符和普通域名
|
||||||
config.Records[domain] = value
|
config.Records[domain] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,8 @@ package dns
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -21,6 +23,12 @@ type Resolver interface {
|
|||||||
// AddWithPort 添加带端口的域名解析规则
|
// AddWithPort 添加带端口的域名解析规则
|
||||||
AddWithPort(host, ip string, port int) error
|
AddWithPort(host, ip string, port int) error
|
||||||
|
|
||||||
|
// AddWildcard 添加泛解析规则(通配符域名)
|
||||||
|
AddWildcard(wildcardDomain, ip string) error
|
||||||
|
|
||||||
|
// AddWildcardWithPort 添加带端口的泛解析规则
|
||||||
|
AddWildcardWithPort(wildcardDomain, ip string, port int) error
|
||||||
|
|
||||||
// Remove 删除域名解析规则
|
// Remove 删除域名解析规则
|
||||||
Remove(host string) error
|
Remove(host string) error
|
||||||
|
|
||||||
@@ -31,12 +39,20 @@ type Resolver interface {
|
|||||||
// CustomResolver 自定义DNS解析器
|
// CustomResolver 自定义DNS解析器
|
||||||
type CustomResolver struct {
|
type CustomResolver struct {
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
records map[string]*Endpoint // 域名到端点的映射
|
records map[string]*Endpoint // 精确域名到端点的映射
|
||||||
|
wildcardRules []wildcardRule // 通配符规则列表
|
||||||
cache map[string]cacheEntry // 外部域名解析缓存
|
cache map[string]cacheEntry // 外部域名解析缓存
|
||||||
fallback bool // 是否在本地记录找不到时回退到系统DNS
|
fallback bool // 是否在本地记录找不到时回退到系统DNS
|
||||||
ttl time.Duration // 缓存TTL
|
ttl time.Duration // 缓存TTL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wildcardRule 通配符规则
|
||||||
|
type wildcardRule struct {
|
||||||
|
pattern string // 原始通配符模式,如 *.example.com
|
||||||
|
parts []string // 分解后的模式部分,如 ["*", "example", "com"]
|
||||||
|
endpoint *Endpoint // 对应的端点
|
||||||
|
}
|
||||||
|
|
||||||
// cacheEntry 缓存条目
|
// cacheEntry 缓存条目
|
||||||
type cacheEntry struct {
|
type cacheEntry struct {
|
||||||
endpoint *Endpoint
|
endpoint *Endpoint
|
||||||
@@ -47,6 +63,7 @@ type cacheEntry struct {
|
|||||||
func NewResolver(options ...Option) *CustomResolver {
|
func NewResolver(options ...Option) *CustomResolver {
|
||||||
r := &CustomResolver{
|
r := &CustomResolver{
|
||||||
records: make(map[string]*Endpoint),
|
records: make(map[string]*Endpoint),
|
||||||
|
wildcardRules: make([]wildcardRule, 0),
|
||||||
cache: make(map[string]cacheEntry),
|
cache: make(map[string]cacheEntry),
|
||||||
fallback: true,
|
fallback: true,
|
||||||
ttl: 5 * time.Minute,
|
ttl: 5 * time.Minute,
|
||||||
@@ -73,11 +90,19 @@ func (r *CustomResolver) Resolve(host string) (string, error) {
|
|||||||
func (r *CustomResolver) ResolveWithPort(host string, defaultPort int) (*Endpoint, error) {
|
func (r *CustomResolver) ResolveWithPort(host string, defaultPort int) (*Endpoint, error) {
|
||||||
// 首先检查自定义记录
|
// 首先检查自定义记录
|
||||||
r.mu.RLock()
|
r.mu.RLock()
|
||||||
|
|
||||||
|
// 精确匹配
|
||||||
if endpoint, ok := r.records[host]; ok {
|
if endpoint, ok := r.records[host]; ok {
|
||||||
r.mu.RUnlock()
|
r.mu.RUnlock()
|
||||||
return endpoint, nil
|
return endpoint, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 尝试通配符匹配
|
||||||
|
if endpoint := r.matchWildcard(host); endpoint != nil {
|
||||||
|
r.mu.RUnlock()
|
||||||
|
return endpoint, nil
|
||||||
|
}
|
||||||
|
|
||||||
// 检查缓存
|
// 检查缓存
|
||||||
if entry, ok := r.cache[host]; ok {
|
if entry, ok := r.cache[host]; ok {
|
||||||
if time.Now().Before(entry.expiresAt) {
|
if time.Now().Before(entry.expiresAt) {
|
||||||
@@ -127,6 +152,44 @@ func (r *CustomResolver) ResolveWithPort(host string, defaultPort int) (*Endpoin
|
|||||||
return nil, errors.New("未找到域名记录且系统DNS回退被禁用")
|
return nil, errors.New("未找到域名记录且系统DNS回退被禁用")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// matchWildcard 尝试匹配通配符规则
|
||||||
|
func (r *CustomResolver) matchWildcard(host string) *Endpoint {
|
||||||
|
hostParts := strings.Split(host, ".")
|
||||||
|
|
||||||
|
// 按照通配符规则列表的顺序尝试匹配
|
||||||
|
// 规则顺序应该保证更具体的规则先匹配
|
||||||
|
for _, rule := range r.wildcardRules {
|
||||||
|
if matchDomainPattern(hostParts, rule.parts) {
|
||||||
|
return rule.endpoint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// matchDomainPattern 判断域名部分是否匹配通配符模式
|
||||||
|
func matchDomainPattern(hostParts, patternParts []string) bool {
|
||||||
|
// 如果长度不匹配,则不匹配
|
||||||
|
if len(hostParts) != len(patternParts) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 逐部分匹配
|
||||||
|
for i := 0; i < len(hostParts); i++ {
|
||||||
|
// 如果模式部分是星号,则匹配任何内容
|
||||||
|
if patternParts[i] == "*" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 否则必须精确匹配
|
||||||
|
if hostParts[i] != patternParts[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// Add 添加域名解析规则
|
// Add 添加域名解析规则
|
||||||
func (r *CustomResolver) Add(host, ip string) error {
|
func (r *CustomResolver) Add(host, ip string) error {
|
||||||
return r.AddWithPort(host, ip, 0)
|
return r.AddWithPort(host, ip, 0)
|
||||||
@@ -145,17 +208,62 @@ func (r *CustomResolver) AddWithPort(host, ip string, port int) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddWildcard 添加泛解析规则
|
||||||
|
func (r *CustomResolver) AddWildcard(wildcardDomain, ip string) error {
|
||||||
|
return r.AddWildcardWithPort(wildcardDomain, ip, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddWildcardWithPort 添加带端口的泛解析规则
|
||||||
|
func (r *CustomResolver) AddWildcardWithPort(wildcardDomain, ip string, port int) error {
|
||||||
|
if net.ParseIP(ip) == nil {
|
||||||
|
return errors.New("无效的IP地址")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查通配符格式
|
||||||
|
if !strings.Contains(wildcardDomain, "*") {
|
||||||
|
return errors.New("泛解析域名必须包含通配符'*'")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分解通配符域名
|
||||||
|
parts := strings.Split(wildcardDomain, ".")
|
||||||
|
|
||||||
|
r.mu.Lock()
|
||||||
|
defer r.mu.Unlock()
|
||||||
|
|
||||||
|
// 创建新的通配符规则
|
||||||
|
rule := wildcardRule{
|
||||||
|
pattern: wildcardDomain,
|
||||||
|
parts: parts,
|
||||||
|
endpoint: NewEndpointWithPort(ip, port),
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将新规则添加到规则列表头部,确保更新的规则优先匹配
|
||||||
|
r.wildcardRules = append([]wildcardRule{rule}, r.wildcardRules...)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Remove 删除域名解析规则
|
// Remove 删除域名解析规则
|
||||||
func (r *CustomResolver) Remove(host string) error {
|
func (r *CustomResolver) Remove(host string) error {
|
||||||
r.mu.Lock()
|
r.mu.Lock()
|
||||||
defer r.mu.Unlock()
|
defer r.mu.Unlock()
|
||||||
|
|
||||||
if _, ok := r.records[host]; !ok {
|
// 先尝试删除精确匹配记录
|
||||||
return errors.New("域名记录不存在")
|
if _, ok := r.records[host]; ok {
|
||||||
}
|
|
||||||
|
|
||||||
delete(r.records, host)
|
delete(r.records, host)
|
||||||
return nil
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 然后尝试删除通配符记录
|
||||||
|
for i, rule := range r.wildcardRules {
|
||||||
|
if rule.pattern == host {
|
||||||
|
// 删除这条规则
|
||||||
|
r.wildcardRules = append(r.wildcardRules[:i], r.wildcardRules[i+1:]...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.New("域名记录不存在")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear 清除所有解析规则
|
// Clear 清除所有解析规则
|
||||||
@@ -164,6 +272,7 @@ func (r *CustomResolver) Clear() {
|
|||||||
defer r.mu.Unlock()
|
defer r.mu.Unlock()
|
||||||
|
|
||||||
r.records = make(map[string]*Endpoint)
|
r.records = make(map[string]*Endpoint)
|
||||||
|
r.wildcardRules = make([]wildcardRule, 0)
|
||||||
r.cache = make(map[string]cacheEntry)
|
r.cache = make(map[string]cacheEntry)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,6 +299,27 @@ func (r *CustomResolver) LoadFromMap(records map[string]string) error {
|
|||||||
defer r.mu.Unlock()
|
defer r.mu.Unlock()
|
||||||
|
|
||||||
for host, value := range records {
|
for host, value := range records {
|
||||||
|
// 判断是否为通配符域名
|
||||||
|
if strings.Contains(host, "*") {
|
||||||
|
endpoint, err := ParseEndpoint(value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if net.ParseIP(endpoint.IP) == nil {
|
||||||
|
return errors.New("无效的IP地址: " + endpoint.IP + " (域名: " + host + ")")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加通配符规则
|
||||||
|
rule := wildcardRule{
|
||||||
|
pattern: host,
|
||||||
|
parts: strings.Split(host, "."),
|
||||||
|
endpoint: endpoint,
|
||||||
|
}
|
||||||
|
r.wildcardRules = append(r.wildcardRules, rule)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// 常规记录
|
||||||
endpoint, err := ParseEndpoint(value)
|
endpoint, err := ParseEndpoint(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -201,6 +331,42 @@ func (r *CustomResolver) LoadFromMap(records map[string]string) error {
|
|||||||
|
|
||||||
r.records[host] = endpoint
|
r.records[host] = endpoint
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对通配符规则进行排序,确保更具体的规则先匹配
|
||||||
|
sortWildcardRules(r.wildcardRules)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sortWildcardRules 对通配符规则进行排序,使更具体的规则优先匹配
|
||||||
|
func sortWildcardRules(rules []wildcardRule) {
|
||||||
|
// 使用稳定排序,保证相同优先级的规则保持原有顺序(后添加的规则在前面)
|
||||||
|
sort.SliceStable(rules, func(i, j int) bool {
|
||||||
|
ruleI := rules[i]
|
||||||
|
ruleJ := rules[j]
|
||||||
|
|
||||||
|
// 计算每个规则中通配符的数量
|
||||||
|
wildcardCountI := countWildcards(ruleI.parts)
|
||||||
|
wildcardCountJ := countWildcards(ruleJ.parts)
|
||||||
|
|
||||||
|
// 通配符数量少的规则更具体,优先级更高
|
||||||
|
if wildcardCountI != wildcardCountJ {
|
||||||
|
return wildcardCountI < wildcardCountJ
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果通配符数量相同,域名部分数量多的更具体
|
||||||
|
return len(ruleI.parts) > len(ruleJ.parts)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// countWildcards 计算域名部分中通配符的数量
|
||||||
|
func countWildcards(parts []string) int {
|
||||||
|
count := 0
|
||||||
|
for _, part := range parts {
|
||||||
|
if part == "*" {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
@@ -1,16 +1,12 @@
|
|||||||
# PowerShell 脚本:生成自签名证书
|
# PowerShell 脚本:生成自签名证书
|
||||||
|
|
||||||
# 默认值
|
|
||||||
$Days = 365
|
|
||||||
$Subject = "CN=localhost,OU=Test,O=GoProxy,L=Shanghai,S=Shanghai,C=CN"
|
|
||||||
|
|
||||||
# 处理命令行参数
|
# 处理命令行参数
|
||||||
param(
|
param(
|
||||||
[Parameter(HelpMessage="证书有效期(天数)")]
|
[Parameter(HelpMessage="证书有效期(天数)")]
|
||||||
[int]$days = 365,
|
[int]$days = 365,
|
||||||
|
|
||||||
[Parameter(HelpMessage="证书主题")]
|
[Parameter(HelpMessage="证书主题")]
|
||||||
[string]$subject = $Subject,
|
[string]$subject = "CN=localhost,OU=Test,O=GoProxy,L=Shanghai,S=Shanghai,C=CN",
|
||||||
|
|
||||||
[Parameter(HelpMessage="公用名(CN)")]
|
[Parameter(HelpMessage="公用名(CN)")]
|
||||||
[string]$cn = "",
|
[string]$cn = "",
|
||||||
@@ -28,7 +24,7 @@ function Show-Help {
|
|||||||
Write-Host "选项:"
|
Write-Host "选项:"
|
||||||
Write-Host " -help 显示此帮助信息"
|
Write-Host " -help 显示此帮助信息"
|
||||||
Write-Host " -days DAYS 证书有效期(天数),默认: 365"
|
Write-Host " -days DAYS 证书有效期(天数),默认: 365"
|
||||||
Write-Host " -subject SUB 证书主题,默认: $Subject"
|
Write-Host " -subject SUB 证书主题,默认: $subject"
|
||||||
Write-Host " -cn CN 公用名(CN),将替换主题中的CN,默认: localhost"
|
Write-Host " -cn CN 公用名(CN),将替换主题中的CN,默认: localhost"
|
||||||
Write-Host
|
Write-Host
|
||||||
Write-Host "示例:"
|
Write-Host "示例:"
|
||||||
@@ -44,12 +40,12 @@ if ($help) {
|
|||||||
|
|
||||||
# 如果指定了CN,替换主题中的CN部分
|
# 如果指定了CN,替换主题中的CN部分
|
||||||
if ($cn -ne "") {
|
if ($cn -ne "") {
|
||||||
$Subject = $Subject -replace "CN=[^,]*", "CN=$cn"
|
$subject = $subject -replace "CN=[^,]*", "CN=$cn"
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Host "生成自签名证书..."
|
Write-Host "生成自签名证书..."
|
||||||
Write-Host "有效期: $days 天"
|
Write-Host "有效期: $days 天"
|
||||||
Write-Host "主题: $Subject"
|
Write-Host "主题: $subject"
|
||||||
|
|
||||||
# 检查OpenSSL是否可用
|
# 检查OpenSSL是否可用
|
||||||
$openssl = Get-Command "openssl" -ErrorAction SilentlyContinue
|
$openssl = Get-Command "openssl" -ErrorAction SilentlyContinue
|
||||||
@@ -66,7 +62,7 @@ try {
|
|||||||
|
|
||||||
# 生成证书请求
|
# 生成证书请求
|
||||||
Write-Host "正在生成证书请求..." -ForegroundColor Cyan
|
Write-Host "正在生成证书请求..." -ForegroundColor Cyan
|
||||||
& openssl req -new -key server.key -out server.csr -subj $Subject.Replace(",", "/")
|
& openssl req -new -key server.key -out server.csr -subj $subject.Replace(",", "/")
|
||||||
|
|
||||||
# 生成自签名证书
|
# 生成自签名证书
|
||||||
Write-Host "正在生成自签名证书..." -ForegroundColor Cyan
|
Write-Host "正在生成自签名证书..." -ForegroundColor Cyan
|
||||||
|
Reference in New Issue
Block a user