package main import ( "flag" "fmt" "log" "os" "github.com/azoic/wormhole-client/internal/client" ) var ( version = "v1.0.0" buildTime = "unknown" ) func main() { configPath := flag.String("config", "configs/client.yaml", "Configuration file path") mode := flag.String("mode", "http", "Client mode: http, global, transparent") showVersion := flag.Bool("version", false, "Show version information") flag.Parse() if *showVersion { fmt.Printf("Wormhole SOCKS5 Client %s\n", version) fmt.Printf("Build time: %s\n", buildTime) os.Exit(0) } fmt.Printf("🚀 Starting Wormhole SOCKS5 Client %s\n", version) fmt.Printf("📄 Config: %s\n", *configPath) fmt.Printf("🔧 Mode: %s\n", *mode) // TODO: 实现完整的客户端逻辑 cli := client.NewClient(*mode) if err := cli.Start(*configPath); err != nil { log.Fatalf("Client failed: %v", err) } }
package client import ( "fmt" "os" "os/signal" "syscall" "github.com/azoic/wormhole-client/internal/config" "github.com/azoic/wormhole-client/internal/proxy" "github.com/azoic/wormhole-client/internal/system" "github.com/azoic/wormhole-client/pkg/dns" "github.com/azoic/wormhole-client/pkg/logger" ) type Client struct { mode string config *config.Config socks5Proxy *proxy.SOCKS5Proxy dnsProxy *dns.DNSProxy systemProxyMgr *system.SystemProxyManager } func NewClient(mode string) *Client { return &Client{ mode: mode, systemProxyMgr: system.NewSystemProxyManager(), } } func (c *Client) Start(configPath string) error { // 加载配置 cfg, err := config.LoadConfig(configPath) if err != nil { return fmt.Errorf("failed to load config: %v", err) } if err := cfg.Validate(); err != nil { return fmt.Errorf("invalid config: %v", err) } c.config = cfg // 设置日志级别 logger.SetLevel(cfg.LogLevel) logger.Info("🚀 Starting Wormhole SOCKS5 Client") logger.Info("📄 Config loaded from: %s", configPath) logger.Info("🔧 Mode: %s", c.mode) logger.Info("🎯 SOCKS5 Server: %s", cfg.GetServerAddr()) // 创建SOCKS5代理客户端 c.socks5Proxy = proxy.NewSOCKS5Proxy( cfg.GetServerAddr(), cfg.Server.Username, cfg.Server.Password, cfg.Timeout, ) // 设置信号处理 c.setupSignalHandler() switch c.mode { case "http": return c.startHTTPProxy() case "global": return c.startGlobalProxy() case "transparent": return c.startTransparentProxy() default: return fmt.Errorf("unsupported mode: %s", c.mode) } } func (c *Client) startHTTPProxy() error { logger.Info("🌐 Starting HTTP proxy mode...") logger.Info("💡 Setting up HTTP proxy on port %d", c.config.Proxy.LocalPort) server := c.socks5Proxy.CreateHTTPProxy(c.config.Proxy.LocalPort) logger.Info("✅ HTTP proxy started on :%d", c.config.Proxy.LocalPort) logger.Info("💡 Configure your browser to use HTTP proxy: 127.0.0.1:%d", c.config.Proxy.LocalPort) return server.ListenAndServe() } func (c *Client) startGlobalProxy() error { logger.Info("🌍 Starting global proxy mode...") logger.Info("💡 This will configure system-wide proxy settings") logger.Info("⚠️ Requires administrator privileges") // 启动HTTP代理服务器 server := c.socks5Proxy.CreateHTTPProxy(c.config.Proxy.LocalPort) go func() { if err := server.ListenAndServe(); err != nil { logger.Error("HTTP proxy server failed: %v", err) } }() // 设置系统代理 httpProxy := fmt.Sprintf("127.0.0.1:%d", c.config.Proxy.LocalPort) httpsProxy := httpProxy if err := c.systemProxyMgr.SetGlobalProxy(httpProxy, httpsProxy, ""); err != nil { logger.Error("Failed to set system proxy: %v", err) logger.Warn("You may need to run with administrator privileges") logger.Info("Manual setup: Set HTTP/HTTPS proxy to %s", httpProxy) } else { logger.Info("✅ System proxy configured successfully") } // 启动DNS代理(如果启用) if c.config.GlobalProxy.DNSProxy { logger.Info("🔍 Starting DNS proxy on port %d", c.config.GlobalProxy.DNSPort) c.dnsProxy = dns.NewDNSProxy("8.8.8.8:53", c.config.GlobalProxy.DNSPort) if err := c.dnsProxy.Start(); err != nil { logger.Warn("Failed to start DNS proxy: %v", err) } else { logger.Info("✅ DNS proxy started") } } logger.Info("🎉 Global proxy mode started successfully") logger.Info("📍 HTTP/HTTPS Proxy: %s", httpProxy) if c.dnsProxy != nil { logger.Info("📍 DNS Proxy: 127.0.0.1:%d", c.config.GlobalProxy.DNSPort) } // 保持运行 select {} } func (c *Client) startTransparentProxy() error { logger.Info("🔍 Starting transparent proxy mode...") logger.Info("💡 This will intercept network traffic transparently") logger.Info("⚠️ Requires root privileges and iptables support") logger.Error("❌ Transparent proxy mode is not yet implemented") return fmt.Errorf("transparent proxy mode not implemented") } func (c *Client) setupSignalHandler() { sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM) go func() { <-sigChan logger.Info("🛑 Shutting down...") c.cleanup() os.Exit(0) }() } func (c *Client) cleanup() { // 恢复系统代理设置 if c.systemProxyMgr != nil { if err := c.systemProxyMgr.RestoreProxy(); err != nil { logger.Error("Failed to restore system proxy: %v", err) } } // 停止DNS代理 if c.dnsProxy != nil { if err := c.dnsProxy.Stop(); err != nil { logger.Error("Failed to stop DNS proxy: %v", err) } } logger.Info("✅ Cleanup completed") }
package config import ( "fmt" "io/ioutil" "time" "gopkg.in/yaml.v3" ) // Config 客户端配置结构 type Config struct { ServiceType string `yaml:"serviceType"` Server Server `yaml:"server"` Proxy Proxy `yaml:"proxy"` GlobalProxy GlobalProxy `yaml:"globalProxy"` TransparentProxy TransparentProxy `yaml:"transparentProxy"` LogLevel string `yaml:"logLevel"` Timeout time.Duration `yaml:"timeout"` } // Server SOCKS5服务器配置 type Server struct { Address string `yaml:"address"` Port int `yaml:"port"` Username string `yaml:"username"` Password string `yaml:"password"` } // Proxy 代理模式配置 type Proxy struct { Mode string `yaml:"mode"` LocalPort int `yaml:"localPort"` } // GlobalProxy 全局代理配置 type GlobalProxy struct { Enabled bool `yaml:"enabled"` DNSProxy bool `yaml:"dnsProxy"` DNSPort int `yaml:"dnsPort"` Routing Routing `yaml:"routing"` } // TransparentProxy 透明代理配置 type TransparentProxy struct { Enabled bool `yaml:"enabled"` Port int `yaml:"port"` DNSPort int `yaml:"dnsPort"` ModifyDNS bool `yaml:"modifyDNS"` ModifyRoute bool `yaml:"modifyRoute"` } // Routing 路由规则配置 type Routing struct { BypassLocal bool `yaml:"bypassLocal"` BypassPrivate bool `yaml:"bypassPrivate"` BypassDomains []string `yaml:"bypassDomains"` ForceDomains []string `yaml:"forceDomains"` } // LoadConfig 从文件加载配置 func LoadConfig(configPath string) (*Config, error) { data, err := ioutil.ReadFile(configPath) if err != nil { return nil, fmt.Errorf("failed to read config file: %v", err) } var config Config if err := yaml.Unmarshal(data, &config); err != nil { return nil, fmt.Errorf("failed to parse config file: %v", err) } // 设置默认值 if config.LogLevel == "" { config.LogLevel = "info" } if config.Timeout == 0 { config.Timeout = 30 * time.Second } if config.Proxy.LocalPort == 0 { config.Proxy.LocalPort = 8080 } return &config, nil } // GetServerAddr 获取服务器地址 func (c *Config) GetServerAddr() string { return fmt.Sprintf("%s:%d", c.Server.Address, c.Server.Port) } // Validate 验证配置 func (c *Config) Validate() error { if c.Server.Address == "" { return fmt.Errorf("server address is required") } if c.Server.Port <= 0 || c.Server.Port > 65535 { return fmt.Errorf("invalid server port: %d", c.Server.Port) } validModes := map[string]bool{"http": true, "global": true, "transparent": true} if !validModes[c.Proxy.Mode] { return fmt.Errorf("invalid proxy mode: %s", c.Proxy.Mode) } return nil }
package proxy import ( "context" "encoding/json" "fmt" "io" "net" "net/http" "strconv" "sync" "time" "github.com/azoic/wormhole-client/pkg/logger" ) // SOCKS5Proxy SOCKS5代理客户端 type SOCKS5Proxy struct { serverAddr string username string password string timeout time.Duration connPool *connectionPool stats *ProxyStats } // connectionPool 连接池 type connectionPool struct { connections chan net.Conn maxSize int mutex sync.Mutex } // NewSOCKS5Proxy 创建SOCKS5代理客户端 func NewSOCKS5Proxy(serverAddr, username, password string, timeout time.Duration) *SOCKS5Proxy { return &SOCKS5Proxy{ serverAddr: serverAddr, username: username, password: password, timeout: timeout, connPool: &connectionPool{ connections: make(chan net.Conn, 10), maxSize: 10, }, stats: NewProxyStats(), } } // CreateHTTPProxy 创建HTTP代理服务器 func (p *SOCKS5Proxy) CreateHTTPProxy(localPort int) *http.Server { proxyHandler := &httpProxyHandler{ socks5Proxy: p, } // 创建ServeMux来处理不同的路径 mux := http.NewServeMux() mux.Handle("/", proxyHandler) mux.HandleFunc("/stats", p.handleStats) mux.HandleFunc("/health", p.handleHealth) server := &http.Server{ Addr: fmt.Sprintf(":%d", localPort), Handler: mux, ReadTimeout: 30 * time.Second, WriteTimeout: 30 * time.Second, IdleTimeout: 120 * time.Second, MaxHeaderBytes: 1 << 20, // 1MB } return server } // httpProxyHandler HTTP代理处理器 type httpProxyHandler struct { socks5Proxy *SOCKS5Proxy } func (h *httpProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // 统计连接 h.socks5Proxy.stats.IncrementConnections() defer h.socks5Proxy.stats.DecrementActiveConnections() logger.Debug("Processing request: %s %s from %s", r.Method, r.URL.String(), r.RemoteAddr) if r.Method == http.MethodConnect { h.handleHTTPSProxy(w, r) } else { h.handleHTTPProxy(w, r) } } // handleHTTPSProxy 处理HTTPS代理请求 (CONNECT方法) func (h *httpProxyHandler) handleHTTPSProxy(w http.ResponseWriter, r *http.Request) { ctx, cancel := context.WithTimeout(r.Context(), h.socks5Proxy.timeout) defer cancel() destConn, err := h.socks5Proxy.DialTCPWithContext(ctx, r.Host) if err != nil { h.socks5Proxy.stats.IncrementFailedRequests() h.socks5Proxy.stats.IncrementSOCKS5Error("connection_failed") logger.Error("Failed to connect via SOCKS5 to %s: %v", r.Host, err) http.Error(w, "Bad Gateway", http.StatusBadGateway) return } defer destConn.Close() // 发送200 Connection established响应 w.WriteHeader(http.StatusOK) hijacker, ok := w.(http.Hijacker) if !ok { h.socks5Proxy.stats.IncrementFailedRequests() logger.Error("Hijacking not supported") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } clientConn, _, err := hijacker.Hijack() if err != nil { h.socks5Proxy.stats.IncrementFailedRequests() logger.Error("Failed to hijack connection: %v", err) return } defer clientConn.Close() h.socks5Proxy.stats.IncrementSuccessfulRequests() logger.Debug("Established HTTPS tunnel to %s", r.Host) // 双向数据转发 var wg sync.WaitGroup wg.Add(2) go func() { defer wg.Done() written := h.copyData(clientConn, destConn, "client->server") h.socks5Proxy.stats.AddBytesTransferred(written, 0) }() go func() { defer wg.Done() written := h.copyData(destConn, clientConn, "server->client") h.socks5Proxy.stats.AddBytesTransferred(0, written) }() wg.Wait() logger.Debug("HTTPS tunnel to %s closed", r.Host) } // handleHTTPProxy 处理HTTP代理请求 func (h *httpProxyHandler) handleHTTPProxy(w http.ResponseWriter, r *http.Request) { ctx, cancel := context.WithTimeout(r.Context(), h.socks5Proxy.timeout) defer cancel() // 确保URL包含Host if r.URL.Host == "" { r.URL.Host = r.Host } if r.URL.Scheme == "" { r.URL.Scheme = "http" } // 通过SOCKS5连接到目标服务器 destConn, err := h.socks5Proxy.DialTCPWithContext(ctx, r.Host) if err != nil { h.socks5Proxy.stats.IncrementFailedRequests() h.socks5Proxy.stats.IncrementSOCKS5Error("connection_failed") logger.Error("Failed to connect via SOCKS5 to %s: %v", r.Host, err) http.Error(w, "Bad Gateway", http.StatusBadGateway) return } defer destConn.Close() // 发送HTTP请求 if err := r.Write(destConn); err != nil { h.socks5Proxy.stats.IncrementFailedRequests() logger.Error("Failed to write request to %s: %v", r.Host, err) http.Error(w, "Bad Gateway", http.StatusBadGateway) return } // 设置响应头 w.Header().Set("Via", "1.1 wormhole-proxy") // 使用自定义ResponseWriter来统计字节数 statsWriter := &statsResponseWriter{ ResponseWriter: w, stats: h.socks5Proxy.stats, } // 读取响应并返回给客户端 written, err := io.Copy(statsWriter, destConn) if err != nil { h.socks5Proxy.stats.IncrementFailedRequests() logger.Error("Failed to copy response from %s: %v", r.Host, err) return } h.socks5Proxy.stats.IncrementSuccessfulRequests() h.socks5Proxy.stats.AddBytesTransferred(0, written) logger.Debug("HTTP request to %s completed, %d bytes", r.Host, written) } // statsResponseWriter 带统计功能的ResponseWriter type statsResponseWriter struct { http.ResponseWriter stats *ProxyStats } func (w *statsResponseWriter) Write(data []byte) (int, error) { n, err := w.ResponseWriter.Write(data) if n > 0 { w.stats.AddBytesTransferred(int64(n), 0) } return n, err } // copyData 数据复制,带方向标识和字节统计 func (h *httpProxyHandler) copyData(dst, src net.Conn, direction string) int64 { defer dst.Close() defer src.Close() written, err := io.Copy(dst, src) if err != nil { logger.Debug("Copy %s finished with error: %v, bytes: %d", direction, err, written) } else { logger.Debug("Copy %s finished successfully, bytes: %d", direction, written) } return written } // handleStats 处理统计信息请求 func (p *SOCKS5Proxy) handleStats(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } stats := p.stats.GetStats() w.Header().Set("Content-Type", "application/json") w.Header().Set("Access-Control-Allow-Origin", "*") if err := json.NewEncoder(w).Encode(stats); err != nil { logger.Error("Failed to encode stats: %v", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } } // handleHealth 处理健康检查请求 func (p *SOCKS5Proxy) handleHealth(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } stats := p.stats.GetStats() health := map[string]interface{}{ "status": "healthy", "uptime": stats.Uptime.String(), "active_connections": stats.ActiveConnections, "success_rate": stats.GetSuccessRate(), } w.Header().Set("Content-Type", "application/json") if err := json.NewEncoder(w).Encode(health); err != nil { logger.Error("Failed to encode health: %v", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } } // GetStats 获取代理统计信息 func (p *SOCKS5Proxy) GetStats() ProxyStatsSnapshot { return p.stats.GetStats() } // DialTCP 通过SOCKS5连接到目标地址 func (p *SOCKS5Proxy) DialTCP(address string) (net.Conn, error) { return p.DialTCPWithContext(context.Background(), address) } // DialTCPWithContext 通过SOCKS5连接到目标地址(带上下文) func (p *SOCKS5Proxy) DialTCPWithContext(ctx context.Context, address string) (net.Conn, error) { // 连接到SOCKS5代理服务器 dialer := &net.Dialer{ Timeout: p.timeout, } conn, err := dialer.DialContext(ctx, "tcp", p.serverAddr) if err != nil { return nil, fmt.Errorf("failed to connect to SOCKS5 server: %v", err) } // 设置连接超时 deadline, ok := ctx.Deadline() if ok { conn.SetDeadline(deadline) } // 执行SOCKS5握手 if err := p.performSOCKS5Handshake(conn, address); err != nil { conn.Close() return nil, fmt.Errorf("SOCKS5 handshake failed: %v", err) } // 清除deadline,让连接正常使用 conn.SetDeadline(time.Time{}) logger.Debug("Successfully connected to %s via SOCKS5 proxy", address) return conn, nil } // performSOCKS5Handshake 执行SOCKS5握手协议 func (p *SOCKS5Proxy) performSOCKS5Handshake(conn net.Conn, targetAddr string) error { // 设置握手超时 deadline := time.Now().Add(p.timeout) conn.SetDeadline(deadline) // 第一步:发送认证方法选择 authMethods := []byte{0x05, 0x02, 0x00, 0x02} // 版本5,2个方法,无认证+用户名密码认证 if _, err := conn.Write(authMethods); err != nil { return fmt.Errorf("failed to send auth methods: %v", err) } // 读取服务器响应 response := make([]byte, 2) if _, err := io.ReadFull(conn, response); err != nil { return fmt.Errorf("failed to read auth response: %v", err) } if response[0] != 0x05 { return fmt.Errorf("invalid SOCKS version: %d", response[0]) } // 第二步:处理认证 switch response[1] { case 0x00: // 无认证 logger.Debug("SOCKS5 server requires no authentication") case 0x02: // 用户名密码认证 if err := p.performUserPassAuth(conn); err != nil { return fmt.Errorf("user/pass authentication failed: %v", err) } case 0xFF: // 无可接受的认证方法 return fmt.Errorf("no acceptable authentication methods") default: return fmt.Errorf("unsupported authentication method: %d", response[1]) } // 第三步:发送连接请求 connectReq, err := p.buildConnectRequest(targetAddr) if err != nil { return fmt.Errorf("failed to build connect request: %v", err) } if _, err := conn.Write(connectReq); err != nil { return fmt.Errorf("failed to send connect request: %v", err) } // 第四步:读取连接响应 return p.readConnectResponse(conn) } // buildConnectRequest 构建连接请求 func (p *SOCKS5Proxy) buildConnectRequest(targetAddr string) ([]byte, error) { host, portStr, err := net.SplitHostPort(targetAddr) if err != nil { return nil, fmt.Errorf("invalid target address: %v", err) } // 解析端口号 portNum, err := parsePort(portStr) if err != nil { return nil, fmt.Errorf("invalid port: %v", err) } var connectReq []byte // 检测地址类型并构建请求 if ip := net.ParseIP(host); ip != nil { if ip4 := ip.To4(); ip4 != nil { // IPv4地址 connectReq = []byte{0x05, 0x01, 0x00, 0x01} connectReq = append(connectReq, ip4...) } else if ip6 := ip.To16(); ip6 != nil { // IPv6地址 connectReq = []byte{0x05, 0x01, 0x00, 0x04} connectReq = append(connectReq, ip6...) } } else { // 域名 if len(host) > 255 { return nil, fmt.Errorf("domain name too long: %d", len(host)) } connectReq = []byte{0x05, 0x01, 0x00, 0x03} connectReq = append(connectReq, byte(len(host))) connectReq = append(connectReq, []byte(host)...) } // 添加端口 connectReq = append(connectReq, byte(portNum>>8), byte(portNum&0xFF)) return connectReq, nil } // readConnectResponse 读取连接响应 func (p *SOCKS5Proxy) readConnectResponse(conn net.Conn) error { // 读取响应头部 header := make([]byte, 4) if _, err := io.ReadFull(conn, header); err != nil { return fmt.Errorf("failed to read connect response header: %v", err) } if header[0] != 0x05 { return fmt.Errorf("invalid SOCKS version in response: %d", header[0]) } if header[1] != 0x00 { return fmt.Errorf("connection failed, status: %d (%s)", header[1], getSOCKS5ErrorMessage(header[1])) } // 读取绑定地址和端口 addrType := header[3] switch addrType { case 0x01: // IPv4 skipBytes := make([]byte, 6) // 4字节IP + 2字节端口 _, err := io.ReadFull(conn, skipBytes) return err case 0x03: // 域名 lenByte := make([]byte, 1) if _, err := io.ReadFull(conn, lenByte); err != nil { return err } skipBytes := make([]byte, int(lenByte[0])+2) // 域名长度 + 2字节端口 _, err := io.ReadFull(conn, skipBytes) return err case 0x04: // IPv6 skipBytes := make([]byte, 18) // 16字节IP + 2字节端口 _, err := io.ReadFull(conn, skipBytes) return err default: return fmt.Errorf("unsupported address type: %d", addrType) } } // performUserPassAuth 执行用户名密码认证 func (p *SOCKS5Proxy) performUserPassAuth(conn net.Conn) error { // 发送用户名密码 authData := []byte{0x01} // 子协议版本 authData = append(authData, byte(len(p.username))) authData = append(authData, []byte(p.username)...) authData = append(authData, byte(len(p.password))) authData = append(authData, []byte(p.password)...) if _, err := conn.Write(authData); err != nil { return fmt.Errorf("failed to send credentials: %v", err) } // 读取认证结果 authResult := make([]byte, 2) if _, err := io.ReadFull(conn, authResult); err != nil { return fmt.Errorf("failed to read auth result: %v", err) } if authResult[0] != 0x01 { return fmt.Errorf("invalid auth response version: %d", authResult[0]) } if authResult[1] != 0x00 { return fmt.Errorf("authentication failed") } logger.Debug("SOCKS5 authentication successful") return nil } // getSOCKS5ErrorMessage 获取SOCKS5错误消息 func getSOCKS5ErrorMessage(code byte) string { switch code { case 0x01: return "general SOCKS server failure" case 0x02: return "connection not allowed by ruleset" case 0x03: return "network unreachable" case 0x04: return "host unreachable" case 0x05: return "connection refused" case 0x06: return "TTL expired" case 0x07: return "command not supported" case 0x08: return "address type not supported" default: return "unknown error" } } // parsePort 解析端口号 func parsePort(portStr string) (int, error) { if portStr == "" { return 80, nil // 默认HTTP端口 } port, err := strconv.Atoi(portStr) if err != nil { return 0, fmt.Errorf("invalid port format: %s", portStr) } if port < 1 || port > 65535 { return 0, fmt.Errorf("port out of range: %d", port) } return port, nil }
package proxy import ( "sync" "sync/atomic" "time" ) // ProxyStats 代理统计信息 type ProxyStats struct { StartTime time.Time TotalConnections int64 ActiveConnections int64 SuccessfulRequests int64 FailedRequests int64 BytesSent int64 BytesReceived int64 SOCKS5Errors map[string]int64 mutex sync.RWMutex } // NewProxyStats 创建新的统计实例 func NewProxyStats() *ProxyStats { return &ProxyStats{ StartTime: time.Now(), SOCKS5Errors: make(map[string]int64), } } // IncrementConnections 增加连接计数 func (s *ProxyStats) IncrementConnections() { atomic.AddInt64(&s.TotalConnections, 1) atomic.AddInt64(&s.ActiveConnections, 1) } // DecrementActiveConnections 减少活跃连接计数 func (s *ProxyStats) DecrementActiveConnections() { atomic.AddInt64(&s.ActiveConnections, -1) } // IncrementSuccessfulRequests 增加成功请求计数 func (s *ProxyStats) IncrementSuccessfulRequests() { atomic.AddInt64(&s.SuccessfulRequests, 1) } // IncrementFailedRequests 增加失败请求计数 func (s *ProxyStats) IncrementFailedRequests() { atomic.AddInt64(&s.FailedRequests, 1) } // AddBytesTransferred 添加传输字节数 func (s *ProxyStats) AddBytesTransferred(sent, received int64) { atomic.AddInt64(&s.BytesSent, sent) atomic.AddInt64(&s.BytesReceived, received) } // IncrementSOCKS5Error 增加SOCKS5错误计数 func (s *ProxyStats) IncrementSOCKS5Error(errorType string) { s.mutex.Lock() defer s.mutex.Unlock() s.SOCKS5Errors[errorType]++ } // GetStats 获取统计快照 func (s *ProxyStats) GetStats() ProxyStatsSnapshot { s.mutex.RLock() defer s.mutex.RUnlock() errors := make(map[string]int64) for k, v := range s.SOCKS5Errors { errors[k] = v } return ProxyStatsSnapshot{ StartTime: s.StartTime, Uptime: time.Since(s.StartTime), TotalConnections: atomic.LoadInt64(&s.TotalConnections), ActiveConnections: atomic.LoadInt64(&s.ActiveConnections), SuccessfulRequests: atomic.LoadInt64(&s.SuccessfulRequests), FailedRequests: atomic.LoadInt64(&s.FailedRequests), BytesSent: atomic.LoadInt64(&s.BytesSent), BytesReceived: atomic.LoadInt64(&s.BytesReceived), SOCKS5Errors: errors, } } // ProxyStatsSnapshot 统计快照 type ProxyStatsSnapshot struct { StartTime time.Time `json:"start_time"` Uptime time.Duration `json:"uptime"` TotalConnections int64 `json:"total_connections"` ActiveConnections int64 `json:"active_connections"` SuccessfulRequests int64 `json:"successful_requests"` FailedRequests int64 `json:"failed_requests"` BytesSent int64 `json:"bytes_sent"` BytesReceived int64 `json:"bytes_received"` SOCKS5Errors map[string]int64 `json:"socks5_errors"` } // GetSuccessRate 获取成功率 func (s *ProxyStatsSnapshot) GetSuccessRate() float64 { total := s.SuccessfulRequests + s.FailedRequests if total == 0 { return 0 } return float64(s.SuccessfulRequests) / float64(total) * 100 } // GetTotalBytes 获取总传输字节数 func (s *ProxyStatsSnapshot) GetTotalBytes() int64 { return s.BytesSent + s.BytesReceived } // GetAverageConnectionsPerHour 获取每小时平均连接数 func (s *ProxyStatsSnapshot) GetAverageConnectionsPerHour() float64 { hours := s.Uptime.Hours() if hours == 0 { return 0 } return float64(s.TotalConnections) / hours }
package system import ( "fmt" "os/exec" "runtime" "strings" "github.com/azoic/wormhole-client/pkg/logger" ) // SystemProxyManager 系统代理管理器 type SystemProxyManager struct { originalSettings map[string]string } // NewSystemProxyManager 创建系统代理管理器 func NewSystemProxyManager() *SystemProxyManager { return &SystemProxyManager{ originalSettings: make(map[string]string), } } // SetGlobalProxy 设置全局代理 func (s *SystemProxyManager) SetGlobalProxy(httpProxy, httpsProxy, socksProxy string) error { switch runtime.GOOS { case "darwin": return s.setMacOSProxy(httpProxy, httpsProxy, socksProxy) case "windows": return s.setWindowsProxy(httpProxy, httpsProxy, socksProxy) case "linux": return s.setLinuxProxy(httpProxy, httpsProxy, socksProxy) default: return fmt.Errorf("unsupported operating system: %s", runtime.GOOS) } } // RestoreProxy 恢复原始代理设置 func (s *SystemProxyManager) RestoreProxy() error { switch runtime.GOOS { case "darwin": return s.restoreMacOSProxy() case "windows": return s.restoreWindowsProxy() case "linux": return s.restoreLinuxProxy() default: return fmt.Errorf("unsupported operating system: %s", runtime.GOOS) } } // macOS 代理设置 func (s *SystemProxyManager) setMacOSProxy(httpProxy, httpsProxy, socksProxy string) error { logger.Info("Setting macOS system proxy...") // 获取网络服务名称 networkService, err := s.getMacOSNetworkService() if err != nil { return fmt.Errorf("failed to get network service: %v", err) } // 保存原始设置 if err := s.saveMacOSOriginalSettings(networkService); err != nil { logger.Warn("Failed to save original proxy settings: %v", err) } // 设置HTTP代理 if httpProxy != "" { if err := s.runCommand("networksetup", "-setwebproxy", networkService, s.parseProxyHost(httpProxy), s.parseProxyPort(httpProxy)); err != nil { return fmt.Errorf("failed to set HTTP proxy: %v", err) } if err := s.runCommand("networksetup", "-setwebproxystate", networkService, "on"); err != nil { return fmt.Errorf("failed to enable HTTP proxy: %v", err) } } // 设置HTTPS代理 if httpsProxy != "" { if err := s.runCommand("networksetup", "-setsecurewebproxy", networkService, s.parseProxyHost(httpsProxy), s.parseProxyPort(httpsProxy)); err != nil { return fmt.Errorf("failed to set HTTPS proxy: %v", err) } if err := s.runCommand("networksetup", "-setsecurewebproxystate", networkService, "on"); err != nil { return fmt.Errorf("failed to enable HTTPS proxy: %v", err) } } // 设置SOCKS代理 if socksProxy != "" { if err := s.runCommand("networksetup", "-setsocksfirewallproxy", networkService, s.parseProxyHost(socksProxy), s.parseProxyPort(socksProxy)); err != nil { return fmt.Errorf("failed to set SOCKS proxy: %v", err) } if err := s.runCommand("networksetup", "-setsocksfirewallproxystate", networkService, "on"); err != nil { return fmt.Errorf("failed to enable SOCKS proxy: %v", err) } } logger.Info("macOS system proxy configured successfully") return nil } // 获取macOS网络服务名称 func (s *SystemProxyManager) getMacOSNetworkService() (string, error) { output, err := exec.Command("networksetup", "-listallnetworkservices").Output() if err != nil { return "", err } lines := strings.Split(string(output), "\n") for _, line := range lines { line = strings.TrimSpace(line) if line != "" && !strings.HasPrefix(line, "*") && !strings.Contains(line, "An asterisk") { // 优先选择Wi-Fi,否则选择第一个可用的服务 if strings.Contains(strings.ToLower(line), "wi-fi") || strings.Contains(strings.ToLower(line), "wifi") { return line, nil } } } // 如果没找到Wi-Fi,返回第一个可用的服务 for _, line := range lines { line = strings.TrimSpace(line) if line != "" && !strings.HasPrefix(line, "*") && !strings.Contains(line, "An asterisk") { return line, nil } } return "", fmt.Errorf("no network service found") } // 保存macOS原始代理设置 func (s *SystemProxyManager) saveMacOSOriginalSettings(networkService string) error { // 保存HTTP代理状态 if output, err := exec.Command("networksetup", "-getwebproxy", networkService).Output(); err == nil { s.originalSettings["http_proxy"] = string(output) } // 保存HTTPS代理状态 if output, err := exec.Command("networksetup", "-getsecurewebproxy", networkService).Output(); err == nil { s.originalSettings["https_proxy"] = string(output) } // 保存SOCKS代理状态 if output, err := exec.Command("networksetup", "-getsocksfirewallproxy", networkService).Output(); err == nil { s.originalSettings["socks_proxy"] = string(output) } s.originalSettings["network_service"] = networkService return nil } // 恢复macOS代理设置 func (s *SystemProxyManager) restoreMacOSProxy() error { networkService, exists := s.originalSettings["network_service"] if !exists { return fmt.Errorf("no network service information saved") } logger.Info("Restoring macOS system proxy...") // 关闭所有代理 s.runCommand("networksetup", "-setwebproxystate", networkService, "off") s.runCommand("networksetup", "-setsecurewebproxystate", networkService, "off") s.runCommand("networksetup", "-setsocksfirewallproxystate", networkService, "off") logger.Info("macOS system proxy restored") return nil } // Windows 代理设置(简化实现) func (s *SystemProxyManager) setWindowsProxy(httpProxy, httpsProxy, socksProxy string) error { logger.Warn("Windows proxy setting not fully implemented") return fmt.Errorf("Windows proxy setting not implemented yet") } func (s *SystemProxyManager) restoreWindowsProxy() error { logger.Warn("Windows proxy restoration not fully implemented") return nil } // Linux 代理设置(简化实现) func (s *SystemProxyManager) setLinuxProxy(httpProxy, httpsProxy, socksProxy string) error { logger.Warn("Linux proxy setting not fully implemented") return fmt.Errorf("Linux proxy setting not implemented yet") } func (s *SystemProxyManager) restoreLinuxProxy() error { logger.Warn("Linux proxy restoration not fully implemented") return nil } // 辅助函数 func (s *SystemProxyManager) runCommand(name string, args ...string) error { cmd := exec.Command(name, args...) output, err := cmd.CombinedOutput() if err != nil { logger.Error("Command failed: %s %v, output: %s", name, args, string(output)) return err } return nil } func (s *SystemProxyManager) parseProxyHost(proxy string) string { // 简单解析,格式: host:port parts := strings.Split(proxy, ":") if len(parts) >= 1 { return parts[0] } return proxy } func (s *SystemProxyManager) parseProxyPort(proxy string) string { // 简单解析,格式: host:port parts := strings.Split(proxy, ":") if len(parts) >= 2 { return parts[1] } return "8080" // 默认端口 }
package dns import ( "fmt" "net" "strings" "sync" "time" "github.com/azoic/wormhole-client/pkg/logger" ) // DNSProxy DNS代理服务器 type DNSProxy struct { upstreamDNS string localPort int server *net.UDPConn cache *dnsCache running bool mutex sync.RWMutex } // dnsCache DNS缓存 type dnsCache struct { entries map[string]*cacheEntry mutex sync.RWMutex } type cacheEntry struct { response []byte expiry time.Time } // NewDNSProxy 创建DNS代理 func NewDNSProxy(upstreamDNS string, localPort int) *DNSProxy { return &DNSProxy{ upstreamDNS: upstreamDNS, localPort: localPort, cache: &dnsCache{ entries: make(map[string]*cacheEntry), }, } } // Start 启动DNS代理服务器 func (d *DNSProxy) Start() error { d.mutex.Lock() defer d.mutex.Unlock() if d.running { return fmt.Errorf("DNS proxy is already running") } addr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", d.localPort)) if err != nil { return fmt.Errorf("failed to resolve UDP address: %v", err) } d.server, err = net.ListenUDP("udp", addr) if err != nil { return fmt.Errorf("failed to start DNS proxy server: %v", err) } d.running = true logger.Info("DNS proxy started on port %d", d.localPort) // 启动清理缓存的goroutine go d.cleanupCache() // 处理DNS请求 go d.handleRequests() return nil } // Stop 停止DNS代理服务器 func (d *DNSProxy) Stop() error { d.mutex.Lock() defer d.mutex.Unlock() if !d.running { return nil } d.running = false if d.server != nil { d.server.Close() } logger.Info("DNS proxy stopped") return nil } // handleRequests 处理DNS请求 func (d *DNSProxy) handleRequests() { buffer := make([]byte, 512) // DNS消息最大512字节(UDP) for d.isRunning() { n, clientAddr, err := d.server.ReadFromUDP(buffer) if err != nil { if d.isRunning() { logger.Error("Failed to read DNS request: %v", err) } continue } go d.processRequest(buffer[:n], clientAddr) } } // processRequest 处理单个DNS请求 func (d *DNSProxy) processRequest(request []byte, clientAddr *net.UDPAddr) { // 简单的DNS请求解析 domain := d.extractDomain(request) logger.Debug("DNS request for domain: %s", domain) // 检查缓存 if cachedResponse := d.getFromCache(domain); cachedResponse != nil { logger.Debug("Serving %s from cache", domain) d.server.WriteToUDP(cachedResponse, clientAddr) return } // 转发到上游DNS服务器 response, err := d.forwardToUpstream(request) if err != nil { logger.Error("Failed to forward DNS request: %v", err) return } // 缓存响应 d.addToCache(domain, response) // 返回响应给客户端 d.server.WriteToUDP(response, clientAddr) } // extractDomain 从DNS请求中提取域名(简化实现) func (d *DNSProxy) extractDomain(request []byte) string { if len(request) < 12 { return "" } // 跳过DNS头部(12字节) offset := 12 var domain strings.Builder for offset < len(request) { length := int(request[offset]) if length == 0 { break } offset++ if offset+length > len(request) { break } if domain.Len() > 0 { domain.WriteByte('.') } domain.Write(request[offset : offset+length]) offset += length } return domain.String() } // forwardToUpstream 转发DNS请求到上游服务器 func (d *DNSProxy) forwardToUpstream(request []byte) ([]byte, error) { conn, err := net.Dial("udp", d.upstreamDNS) if err != nil { return nil, fmt.Errorf("failed to connect to upstream DNS: %v", err) } defer conn.Close() // 设置超时 conn.SetDeadline(time.Now().Add(5 * time.Second)) // 发送请求 if _, err := conn.Write(request); err != nil { return nil, fmt.Errorf("failed to send DNS request: %v", err) } // 读取响应 response := make([]byte, 512) n, err := conn.Read(response) if err != nil { return nil, fmt.Errorf("failed to read DNS response: %v", err) } return response[:n], nil } // getFromCache 从缓存获取DNS响应 func (d *DNSProxy) getFromCache(domain string) []byte { d.cache.mutex.RLock() defer d.cache.mutex.RUnlock() entry, exists := d.cache.entries[domain] if !exists || time.Now().After(entry.expiry) { return nil } return entry.response } // addToCache 添加DNS响应到缓存 func (d *DNSProxy) addToCache(domain string, response []byte) { d.cache.mutex.Lock() defer d.cache.mutex.Unlock() // 设置缓存过期时间(5分钟) expiry := time.Now().Add(5 * time.Minute) d.cache.entries[domain] = &cacheEntry{ response: make([]byte, len(response)), expiry: expiry, } copy(d.cache.entries[domain].response, response) } // cleanupCache 清理过期的缓存条目 func (d *DNSProxy) cleanupCache() { ticker := time.NewTicker(1 * time.Minute) defer ticker.Stop() for { select { case <-ticker.C: if !d.isRunning() { return } d.cache.mutex.Lock() now := time.Now() for domain, entry := range d.cache.entries { if now.After(entry.expiry) { delete(d.cache.entries, domain) } } d.cache.mutex.Unlock() } } } // isRunning 检查DNS代理是否在运行 func (d *DNSProxy) isRunning() bool { d.mutex.RLock() defer d.mutex.RUnlock() return d.running }
package logger import ( "fmt" "log" "os" "strings" "time" ) type LogLevel int const ( DEBUG LogLevel = iota INFO WARN ERROR ) type Logger struct { level LogLevel logger *log.Logger } var defaultLogger *Logger func init() { defaultLogger = New("INFO") } // New 创建新的日志记录器 func New(levelStr string) *Logger { level := parseLogLevel(levelStr) logger := log.New(os.Stdout, "", 0) return &Logger{ level: level, logger: logger, } } // SetLevel 设置日志级别 func SetLevel(levelStr string) { defaultLogger.level = parseLogLevel(levelStr) } func parseLogLevel(levelStr string) LogLevel { switch strings.ToUpper(levelStr) { case "DEBUG": return DEBUG case "INFO": return INFO case "WARN", "WARNING": return WARN case "ERROR": return ERROR default: return INFO } } func (l *Logger) log(level LogLevel, format string, args ...interface{}) { if level < l.level { return } levelStr := "" switch level { case DEBUG: levelStr = "DEBUG" case INFO: levelStr = "INFO" case WARN: levelStr = "WARN" case ERROR: levelStr = "ERROR" } timestamp := time.Now().Format("2006-01-02 15:04:05") message := fmt.Sprintf(format, args...) logLine := fmt.Sprintf("[%s] [%s] %s", timestamp, levelStr, message) l.logger.Println(logLine) } // Debug 调试日志 func (l *Logger) Debug(format string, args ...interface{}) { l.log(DEBUG, format, args...) } // Info 信息日志 func (l *Logger) Info(format string, args ...interface{}) { l.log(INFO, format, args...) } // Warn 警告日志 func (l *Logger) Warn(format string, args ...interface{}) { l.log(WARN, format, args...) } // Error 错误日志 func (l *Logger) Error(format string, args ...interface{}) { l.log(ERROR, format, args...) } // 全局日志函数 func Debug(format string, args ...interface{}) { defaultLogger.Debug(format, args...) } func Info(format string, args ...interface{}) { defaultLogger.Info(format, args...) } func Warn(format string, args ...interface{}) { defaultLogger.Warn(format, args...) } func Error(format string, args ...interface{}) { defaultLogger.Error(format, args...) }