初始化提交
This commit is contained in:
commit
666db25b3f
13
go.mod
Normal file
13
go.mod
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
module zhuabao
|
||||||
|
|
||||||
|
go 1.22
|
||||||
|
|
||||||
|
require github.com/miekg/dns v1.1.62
|
||||||
|
|
||||||
|
require (
|
||||||
|
golang.org/x/mod v0.18.0 // indirect
|
||||||
|
golang.org/x/net v0.27.0 // indirect
|
||||||
|
golang.org/x/sync v0.7.0 // indirect
|
||||||
|
golang.org/x/sys v0.22.0 // indirect
|
||||||
|
golang.org/x/tools v0.22.0 // indirect
|
||||||
|
)
|
12
go.sum
Normal file
12
go.sum
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
|
||||||
|
github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
|
||||||
|
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
|
||||||
|
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
|
||||||
|
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
||||||
|
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||||
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||||
|
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
|
||||||
|
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
|
404
main.go
Normal file
404
main.go
Normal file
@ -0,0 +1,404 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"crypto/x509/pkix"
|
||||||
|
"encoding/pem"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"math/big"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 添加全局变量
|
||||||
|
var (
|
||||||
|
proxyAddress string // 默认值,可以通过命令行参数修改
|
||||||
|
listenAddress string // 新增的地址代理参数
|
||||||
|
dnsPort string // 新增DNS服务器端口
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// 解析命令行参数
|
||||||
|
flag.StringVar(&listenAddress, "address", "127.0.0.1", "HTTP和HTTPS监听地址")
|
||||||
|
flag.StringVar(&proxyAddress, "address-proxy", "127.0.0.1:7897", "代理服务器地址")
|
||||||
|
flag.StringVar(&dnsPort, "dns-port", "53", "DNS服务器端口")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
// 检查CA证书是否存在
|
||||||
|
sslDir := "SSL"
|
||||||
|
caFile := filepath.Join(sslDir, "ca.pem")
|
||||||
|
keyFile := filepath.Join(sslDir, "ca-key.pem")
|
||||||
|
if !fileExists(caFile) || !fileExists(keyFile) {
|
||||||
|
generateCACert(caFile, keyFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载CA证书和私钥
|
||||||
|
caCert, caKey, err := loadCA(caFile, keyFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("加载CA证书和私钥失败:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置HTTP服务器
|
||||||
|
go func() {
|
||||||
|
httpServer := &http.Server{
|
||||||
|
Addr: listenAddress + ":80",
|
||||||
|
Handler: http.HandlerFunc(httpHandler),
|
||||||
|
}
|
||||||
|
log.Printf("启动HTTP服务器,监听地址: %s:80\n", listenAddress)
|
||||||
|
if err := httpServer.ListenAndServe(); err != nil {
|
||||||
|
log.Fatal("HTTP服务器错误:", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 设置HTTPS服务器
|
||||||
|
httpsServer := &http.Server{
|
||||||
|
Addr: listenAddress + ":443",
|
||||||
|
TLSConfig: &tls.Config{
|
||||||
|
GetCertificate: func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||||
|
sni := hello.ServerName
|
||||||
|
fmt.Printf("接收到HTTPS请求,SNI: %s\n", sni)
|
||||||
|
return generateCert(caCert, caKey, sni)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Handler: http.HandlerFunc(httpsHandler),
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("启动HTTPS服务器,监听地址: %s:443, 代理地址: %s...\n", listenAddress, proxyAddress)
|
||||||
|
if err := httpsServer.ListenAndServeTLS("", ""); err != nil {
|
||||||
|
log.Fatal("HTTPS服务器错误:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启动DNS服务器
|
||||||
|
go startDNSServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
func httpHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// 实现HTTP代理逻辑
|
||||||
|
if r.Method == http.MethodConnect {
|
||||||
|
handleHTTPS(w, r)
|
||||||
|
} else {
|
||||||
|
handleHTTP(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// 用全局变量创建代理URL
|
||||||
|
proxyURL, err := url.Parse("http://" + proxyAddress)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "解析代理URL失败", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个使用HTTP代理的客户端
|
||||||
|
proxyClient := &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
Proxy: http.ProxyURL(proxyURL),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个新的请求
|
||||||
|
proxyReq, err := http.NewRequest(r.Method, r.URL.String(), r.Body)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "创建代理请求失败", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 复制原始请求的头部
|
||||||
|
for name, values := range r.Header {
|
||||||
|
for _, value := range values {
|
||||||
|
proxyReq.Header.Add(name, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送代理请求
|
||||||
|
resp, err := proxyClient.Do(proxyReq)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "代理请求失败", http.StatusBadGateway)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
// 复制响应头部
|
||||||
|
for name, values := range resp.Header {
|
||||||
|
for _, value := range values {
|
||||||
|
w.Header().Add(name, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置状态码
|
||||||
|
w.WriteHeader(resp.StatusCode)
|
||||||
|
|
||||||
|
// 复制响应体
|
||||||
|
io.Copy(w, resp.Body)
|
||||||
|
|
||||||
|
// 设置Connection头为close,确保客户端知道连接将被关闭
|
||||||
|
w.Header().Set("Connection", "close")
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleHTTPS(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// 建立到目标服务器的连接
|
||||||
|
destConn, err := net.Dial("tcp", r.Host)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusServiceUnavailable)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer destConn.Close()
|
||||||
|
|
||||||
|
// 向客户端发送200 OK响应
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
|
// 获取底层的TCP连接
|
||||||
|
hijacker, ok := w.(http.Hijacker)
|
||||||
|
if !ok {
|
||||||
|
http.Error(w, "Hijacking not supported", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
clientConn, _, err := hijacker.Hijack()
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusServiceUnavailable)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer clientConn.Close()
|
||||||
|
|
||||||
|
// 在客户端和目标服务器之间转发数据
|
||||||
|
go io.Copy(destConn, clientConn)
|
||||||
|
io.Copy(clientConn, destConn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fileExists(filename string) bool {
|
||||||
|
_, err := os.Stat(filename)
|
||||||
|
return !os.IsNotExist(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateCACert(caFile, keyFile string) {
|
||||||
|
// 生成CA私钥
|
||||||
|
caKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("生成CA私钥失败:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建CA证书模板
|
||||||
|
caTemplate := x509.Certificate{
|
||||||
|
SerialNumber: big.NewInt(1),
|
||||||
|
Subject: pkix.Name{
|
||||||
|
CommonName: "自签名CA",
|
||||||
|
},
|
||||||
|
NotBefore: time.Now(),
|
||||||
|
NotAfter: time.Now().AddDate(10, 0, 0),
|
||||||
|
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature,
|
||||||
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||||
|
BasicConstraintsValid: true,
|
||||||
|
IsCA: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建CA证书
|
||||||
|
caCertDER, err := x509.CreateCertificate(rand.Reader, &caTemplate, &caTemplate, &caKey.PublicKey, caKey)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("创建CA证书失败:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保SSL目录存在
|
||||||
|
sslDir := filepath.Dir(caFile)
|
||||||
|
if err := os.MkdirAll(sslDir, 0755); err != nil {
|
||||||
|
log.Fatal("创建SSL目录失败:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将CA证书写入文件
|
||||||
|
caCertPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: caCertDER})
|
||||||
|
if err := ioutil.WriteFile(caFile, caCertPEM, 0644); err != nil {
|
||||||
|
log.Fatal("写入CA证书失败:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将CA私钥写入文件
|
||||||
|
caKeyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(caKey)})
|
||||||
|
if err := ioutil.WriteFile(keyFile, caKeyPEM, 0600); err != nil {
|
||||||
|
log.Fatal("写入CA私钥失败:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("生成了新的CA证书")
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadCA(caFile, keyFile string) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||||
|
// 读取CA证书
|
||||||
|
caCertPEM, err := ioutil.ReadFile(caFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("读取CA证书失败: %v", err)
|
||||||
|
}
|
||||||
|
caCertBlock, _ := pem.Decode(caCertPEM)
|
||||||
|
if caCertBlock == nil {
|
||||||
|
return nil, nil, fmt.Errorf("解码CA证书失败")
|
||||||
|
}
|
||||||
|
caCert, err := x509.ParseCertificate(caCertBlock.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("解析CA证书失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取CA私钥
|
||||||
|
caKeyPEM, err := ioutil.ReadFile(keyFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("读取CA私钥失败: %v", err)
|
||||||
|
}
|
||||||
|
caKeyBlock, _ := pem.Decode(caKeyPEM)
|
||||||
|
if caKeyBlock == nil {
|
||||||
|
return nil, nil, fmt.Errorf("解码CA私钥失败")
|
||||||
|
}
|
||||||
|
caKey, err := x509.ParsePKCS1PrivateKey(caKeyBlock.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("解析CA私钥失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return caCert, caKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateCert(caCert *x509.Certificate, caKey *rsa.PrivateKey, serverName string) (*tls.Certificate, error) {
|
||||||
|
// 生成服务器私钥
|
||||||
|
serverKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("生成服务器私钥失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建服务器证书模板
|
||||||
|
serverTemplate := x509.Certificate{
|
||||||
|
SerialNumber: big.NewInt(2),
|
||||||
|
Subject: pkix.Name{
|
||||||
|
CommonName: serverName,
|
||||||
|
},
|
||||||
|
NotBefore: time.Now(),
|
||||||
|
NotAfter: time.Now().AddDate(1, 0, 0),
|
||||||
|
KeyUsage: x509.KeyUsageDigitalSignature,
|
||||||
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||||
|
DNSNames: []string{serverName},
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用CA签发服务器证书
|
||||||
|
serverCertDER, err := x509.CreateCertificate(rand.Reader, &serverTemplate, caCert, &serverKey.PublicKey, caKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("创建服务器证书失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将证书和私钥转换为PEM格式
|
||||||
|
serverCertPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: serverCertDER})
|
||||||
|
serverKeyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(serverKey)})
|
||||||
|
|
||||||
|
// 创建SSL文件夹和SNI子文件夹
|
||||||
|
sslDir := "SSL"
|
||||||
|
sniDir := filepath.Join(sslDir, serverName)
|
||||||
|
if err := os.MkdirAll(sniDir, 0755); err != nil {
|
||||||
|
return nil, fmt.Errorf("创建目录失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存证书和私钥到SNI子文件夹
|
||||||
|
certFile := filepath.Join(sniDir, serverName+".pem")
|
||||||
|
keyFile := filepath.Join(sniDir, serverName+"-key.pem")
|
||||||
|
if err := ioutil.WriteFile(certFile, serverCertPEM, 0644); err != nil {
|
||||||
|
return nil, fmt.Errorf("写入服务器证书失败: %v", err)
|
||||||
|
}
|
||||||
|
if err := ioutil.WriteFile(keyFile, serverKeyPEM, 0600); err != nil {
|
||||||
|
return nil, fmt.Errorf("写入服务器私钥失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创tls.Certificate对象
|
||||||
|
cert, err := tls.X509KeyPair(serverCertPEM, serverKeyPEM)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("创建X509密钥对失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cert, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func httpsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// 确保URL使用HTTPS协议并包含正确的Host
|
||||||
|
r.URL.Scheme = "https"
|
||||||
|
if r.URL.Host == "" {
|
||||||
|
r.URL.Host = r.Host
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建正向代理客户端
|
||||||
|
proxyClient := &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
Proxy: http.ProxyURL(&url.URL{
|
||||||
|
Scheme: "http",
|
||||||
|
Host: proxyAddress,
|
||||||
|
}),
|
||||||
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||||
|
DisableKeepAlives: true, // 禁用Keep-Alive
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个新的请求
|
||||||
|
proxyReq, err := http.NewRequest(r.Method, r.URL.String(), r.Body)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "创建代理请求失败", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 复制原始请求的头部
|
||||||
|
proxyReq.Header = r.Header.Clone()
|
||||||
|
|
||||||
|
// 确保请求体被关闭
|
||||||
|
if r.Body != nil {
|
||||||
|
defer r.Body.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送代理请求
|
||||||
|
resp, err := proxyClient.Do(proxyReq)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "代理请求失败: "+err.Error(), http.StatusBadGateway)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
// 复制响应头部和状态码
|
||||||
|
for name, values := range resp.Header {
|
||||||
|
w.Header()[name] = values
|
||||||
|
}
|
||||||
|
w.WriteHeader(resp.StatusCode)
|
||||||
|
|
||||||
|
// 复制响应体
|
||||||
|
_, err = io.Copy(w, resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("复制响应体时发生错误: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置Connection头为close,确保客户端知道连接将被关闭
|
||||||
|
w.Header().Set("Connection", "close")
|
||||||
|
}
|
||||||
|
|
||||||
|
func startDNSServer() {
|
||||||
|
dns.HandleFunc(".", handleDNSRequest)
|
||||||
|
server := &dns.Server{Addr: ":" + dnsPort, Net: "udp"}
|
||||||
|
log.Printf("启动DNS服务器,监听端口: %s\n", dnsPort)
|
||||||
|
err := server.ListenAndServe()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("启动DNS服务器失败: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
|
||||||
|
m := new(dns.Msg)
|
||||||
|
m.SetReply(r)
|
||||||
|
m.Authoritative = true
|
||||||
|
|
||||||
|
for _, q := range m.Question {
|
||||||
|
switch q.Qtype {
|
||||||
|
case dns.TypeA:
|
||||||
|
rr, err := dns.NewRR(fmt.Sprintf("%s A %s", q.Name, listenAddress))
|
||||||
|
if err == nil {
|
||||||
|
m.Answer = append(m.Answer, rr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
w.WriteMsg(m)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user