Files
https-socks5-http/pkg/proxy/upstream.go
2025-01-10 14:07:07 +08:00

200 lines
7.2 KiB
Go

// Package proxy 实现代理服务器功能
package proxy
import (
"bufio"
"crypto/tls"
"encoding/base64"
"fmt"
"io"
"net"
"net/http"
"strings"
"time"
"s5/pkg/config"
"s5/pkg/logger"
)
// UpstreamDialer 上游代理拨号器
// 负责与上游HTTPS代理建立连接
type UpstreamDialer struct {
config config.UpstreamConfig // 上游代理配置
}
// NewUpstreamDialer 创建新的上游代理拨号器
func NewUpstreamDialer(config config.UpstreamConfig) *UpstreamDialer {
return &UpstreamDialer{config: config}
}
// Dial 通过上游代理连接目标地址
func (d *UpstreamDialer) Dial(network, addr string) (net.Conn, error) {
log := logger.Get()
log.Debugf("[UPSTREAM] 开始新的代理连接: %s -> %s", d.config.Server, addr)
switch d.config.Type {
case "https":
return d.dialHTTPS(addr)
default:
return nil, fmt.Errorf("不支持的上游代理类型: %s", d.config.Type)
}
}
// dialHTTPS 通过 HTTPS 代理连接
func (d *UpstreamDialer) dialHTTPS(addr string) (net.Conn, error) {
log := logger.Get()
log.Debugf("[UPSTREAM] =====================================================")
log.Debugf("[UPSTREAM] 开始建立HTTPS代理连接")
log.Debugf("[UPSTREAM] 连接信息:")
log.Debugf("[UPSTREAM] - 目标地址: %s", addr)
log.Debugf("[UPSTREAM] - 代理服务器: %s", d.config.Server)
log.Debugf("[UPSTREAM] - 代理类型: %s", d.config.Type)
log.Debugf("[UPSTREAM] - 认证用户名: %s", d.config.Username)
log.Debugf("[UPSTREAM] - 认证密码: %s", d.config.Password)
// 解析服务器地址
host := d.config.Server
if !strings.Contains(host, ":") {
host = host + ":443"
}
log.Debugf("[UPSTREAM] 解析代理服务器地址: %s -> %s", d.config.Server, host)
// 创建 TLS 配置
tlsConfig := &tls.Config{
InsecureSkipVerify: false,
ServerName: strings.Split(host, ":")[0],
MinVersion: tls.VersionTLS12,
MaxVersion: tls.VersionTLS13,
NextProtos: []string{"http/1.1"},
}
log.Debugf("[UPSTREAM] TLS配置:")
log.Debugf("[UPSTREAM] - SNI: %s", tlsConfig.ServerName)
log.Debugf("[UPSTREAM] - 最低TLS版本: %s", tlsVersionToString(tlsConfig.MinVersion))
log.Debugf("[UPSTREAM] - 最高TLS版本: %s", tlsVersionToString(tlsConfig.MaxVersion))
log.Debugf("[UPSTREAM] - ALPN: %v", tlsConfig.NextProtos)
// 建立TCP连接
log.Debugf("[UPSTREAM] 开始建立TCP连接...")
tcpConn, err := net.Dial("tcp", host)
if err != nil {
log.Errorf("[UPSTREAM] TCP连接失败: %v", err)
return nil, fmt.Errorf("TCP连接失败: %v", err)
}
log.Debugf("[UPSTREAM] TCP连接成功:")
log.Debugf("[UPSTREAM] - 本地地址: %s", tcpConn.LocalAddr())
log.Debugf("[UPSTREAM] - 远程地址: %s", tcpConn.RemoteAddr())
// 设置 TCP 参数
if tc, ok := tcpConn.(*net.TCPConn); ok {
tc.SetKeepAlive(true)
tc.SetKeepAlivePeriod(30 * time.Second)
tc.SetNoDelay(true)
log.Debugf("[UPSTREAM] TCP参数设置完成")
}
// TLS握手
log.Debugf("[UPSTREAM] 开始TLS握手...")
tlsConn := tls.Client(tcpConn, tlsConfig)
if err := tlsConn.Handshake(); err != nil {
tcpConn.Close()
log.Errorf("[UPSTREAM] TLS握手失败: %v", err)
return nil, fmt.Errorf("TLS握手失败: %v", err)
}
// 输出TLS连接信息
state := tlsConn.ConnectionState()
log.Debugf("[UPSTREAM] TLS握手成功:")
log.Debugf("[UPSTREAM] - TLS版本: %s", tlsVersionToString(state.Version))
log.Debugf("[UPSTREAM] - 加密套件: %s", tls.CipherSuiteName(state.CipherSuite))
log.Debugf("[UPSTREAM] - 协商协议: %s", state.NegotiatedProtocol)
// 构建详细的CONNECT请求
auth := base64.StdEncoding.EncodeToString([]byte(d.config.Username + ":" + d.config.Password))
connectReq := fmt.Sprintf(
"CONNECT %s HTTP/1.1\r\n"+
"Host: %s\r\n"+
"Proxy-Authorization: Basic %s\r\n"+
"User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36\r\n"+
"Proxy-Connection: Keep-Alive\r\n"+
"Connection: Keep-Alive\r\n"+
"X-Forwarded-For: %s\r\n"+
"X-Proxy-ID: Go-Proxy\r\n\r\n",
addr, addr, auth, "unknown",
)
log.Debugf("[UPSTREAM] 发送CONNECT请求:")
for _, line := range strings.Split(connectReq, "\r\n") {
if line != "" {
log.Debugf("[UPSTREAM] %s", line)
if strings.HasPrefix(line, "Proxy-Authorization: Basic ") {
if decoded, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(line, "Proxy-Authorization: Basic ")); err == nil {
log.Debugf("[UPSTREAM] Proxy-Authorization (decoded): %s", string(decoded))
}
}
}
}
if _, err = tlsConn.Write([]byte(connectReq)); err != nil {
tlsConn.Close()
log.Errorf("[UPSTREAM] 发送CONNECT请求失败: %v", err)
return nil, fmt.Errorf("发送CONNECT请求失败: %v", err)
}
// 读取并解析响应
log.Debugf("[UPSTREAM] 等待代理响应...")
resp, err := http.ReadResponse(bufio.NewReader(tlsConn), &http.Request{Method: "CONNECT"})
if err != nil {
tlsConn.Close()
log.Errorf("[UPSTREAM] 读取代理响应失败: %v", err)
return nil, fmt.Errorf("读取代理响应失败: %v", err)
}
defer resp.Body.Close()
log.Debugf("[UPSTREAM] 收到代理响应:")
log.Debugf("[UPSTREAM] - 协议版本: %s", resp.Proto)
log.Debugf("[UPSTREAM] - 状态码: %d", resp.StatusCode)
log.Debugf("[UPSTREAM] - 状态描述: %s", resp.Status)
log.Debugf("[UPSTREAM] - Content-Length: %d", resp.ContentLength)
log.Debugf("[UPSTREAM] - Transfer-Encoding: %v", resp.TransferEncoding)
log.Debugf("[UPSTREAM] - Close: %v", resp.Close)
log.Debugf("[UPSTREAM] 响应头:")
for k, vs := range resp.Header {
for _, v := range vs {
log.Debugf("[UPSTREAM] %s: %s", k, v)
}
}
// 读取响应体
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
log.Debugf("[UPSTREAM] 响应体: %s", string(body))
tlsConn.Close()
return nil, fmt.Errorf("代理连接失败: %s", resp.Status)
}
log.Debugf("[UPSTREAM] 代理隧道建立成功")
log.Debugf("[UPSTREAM] - 本地地址: %s", tlsConn.LocalAddr())
log.Debugf("[UPSTREAM] - 远程地址: %s", tlsConn.RemoteAddr())
log.Debugf("[UPSTREAM] =====================================================")
return tlsConn, nil
}
// tlsVersionToString 将TLS版本转换为字符串
func tlsVersionToString(version uint16) string {
switch version {
case tls.VersionTLS10:
return "TLS 1.0"
case tls.VersionTLS11:
return "TLS 1.1"
case tls.VersionTLS12:
return "TLS 1.2"
case tls.VersionTLS13:
return "TLS 1.3"
default:
return fmt.Sprintf("Unknown(0x%04x)", version)
}
}