//go:build !windows // +build !windows package transparent import ( "context" "fmt" "net" "os/exec" "runtime" "strings" "syscall" "github.com/sirupsen/logrus" ) type TransparentProxy struct { logger *logrus.Logger proxyPort int transparentPort int dnsPort int originalDNS []string rules []string } type Config struct { ProxyPort int // HTTP代理端口 TransparentPort int // 透明代理端口 DNSPort int // DNS代理端口 BypassIPs []string // 不代理的IP列表 BypassDomains []string // 不代理的域名列表 } func NewTransparentProxy(config Config, logger *logrus.Logger) *TransparentProxy { if config.TransparentPort == 0 { config.TransparentPort = 8888 } if config.DNSPort == 0 { config.DNSPort = 5353 } return &TransparentProxy{ logger: logger, proxyPort: config.ProxyPort, transparentPort: config.TransparentPort, dnsPort: config.DNSPort, rules: make([]string, 0), } } // SetupTransparentProxy 设置透明代理规则 func (tp *TransparentProxy) SetupTransparentProxy(ctx context.Context) error { if runtime.GOOS != "linux" && runtime.GOOS != "darwin" { return fmt.Errorf("transparent proxy only supported on Linux and macOS") } tp.logger.Info("Setting up transparent proxy rules...") // 备份当前DNS设置 if err := tp.backupDNS(); err != nil { tp.logger.WithError(err).Warn("Failed to backup DNS settings") } switch runtime.GOOS { case "linux": return tp.setupLinuxRules() case "darwin": return tp.setupMacOSRules() default: return fmt.Errorf("unsupported operating system: %s", runtime.GOOS) } } // CleanupTransparentProxy 清理透明代理规则 func (tp *TransparentProxy) CleanupTransparentProxy() error { tp.logger.Info("Cleaning up transparent proxy rules...") var errors []string // 恢复DNS设置 if err := tp.restoreDNS(); err != nil { errors = append(errors, fmt.Sprintf("DNS restore: %v", err)) } switch runtime.GOOS { case "linux": if err := tp.cleanupLinuxRules(); err != nil { errors = append(errors, fmt.Sprintf("Linux rules: %v", err)) } case "darwin": if err := tp.cleanupMacOSRules(); err != nil { errors = append(errors, fmt.Sprintf("macOS rules: %v", err)) } } if len(errors) > 0 { return fmt.Errorf("cleanup errors: %s", strings.Join(errors, "; ")) } return nil } // setupLinuxRules 设置Linux iptables规则 func (tp *TransparentProxy) setupLinuxRules() error { rules := []string{ // 创建新的链 "iptables -t nat -N WORMHOLE_OUTPUT", "iptables -t nat -N WORMHOLE_PREROUTING", // 跳过本地流量 fmt.Sprintf("iptables -t nat -A WORMHOLE_OUTPUT -d 127.0.0.0/8 -j RETURN"), fmt.Sprintf("iptables -t nat -A WORMHOLE_OUTPUT -d 10.0.0.0/8 -j RETURN"), fmt.Sprintf("iptables -t nat -A WORMHOLE_OUTPUT -d 172.16.0.0/12 -j RETURN"), fmt.Sprintf("iptables -t nat -A WORMHOLE_OUTPUT -d 192.168.0.0/16 -j RETURN"), // 重定向TCP流量到透明代理 fmt.Sprintf("iptables -t nat -A WORMHOLE_OUTPUT -p tcp -j REDIRECT --to-ports %d", tp.transparentPort), // 应用规则 "iptables -t nat -A OUTPUT -j WORMHOLE_OUTPUT", "iptables -t nat -A PREROUTING -j WORMHOLE_PREROUTING", // DNS重定向 fmt.Sprintf("iptables -t nat -A WORMHOLE_PREROUTING -p udp --dport 53 -j REDIRECT --to-ports %d", tp.dnsPort), fmt.Sprintf("iptables -t nat -A WORMHOLE_OUTPUT -p udp --dport 53 -j REDIRECT --to-ports %d", tp.dnsPort), } return tp.executeRules(rules) } // setupMacOSRules 设置macOS pfctl规则 func (tp *TransparentProxy) setupMacOSRules() error { // macOS需要使用pfctl,配置更复杂 pfRules := fmt.Sprintf(` # Wormhole transparent proxy rules rdr pass on lo0 inet proto tcp from any to any port 1:65535 -> 127.0.0.1 port %d rdr pass on lo0 inet proto udp from any to any port 53 -> 127.0.0.1 port %d pass out quick proto tcp from any to any flags S/SA keep state pass out quick proto udp from any to any keep state `, tp.transparentPort, tp.dnsPort) // 写入pfctl规则文件 if err := tp.writePfRules(pfRules); err != nil { return err } // 加载规则 rules := []string{ "pfctl -f /tmp/wormhole.pf.conf", "pfctl -e", } return tp.executeRules(rules) } // GetOriginalDestination 获取透明代理的原始目标地址 func (tp *TransparentProxy) GetOriginalDestination(conn net.Conn) (string, error) { tcpConn, ok := conn.(*net.TCPConn) if !ok { return "", fmt.Errorf("not a TCP connection") } // 获取socket文件描述符 file, err := tcpConn.File() if err != nil { return "", err } defer file.Close() fd := int(file.Fd()) switch runtime.GOOS { case "linux": return tp.getLinuxOriginalDest(fd) case "darwin": return tp.getMacOSOriginalDest(fd) default: return "", fmt.Errorf("unsupported OS for transparent proxy") } } func (tp *TransparentProxy) executeRules(rules []string) error { for _, rule := range rules { tp.rules = append(tp.rules, rule) parts := strings.Fields(rule) if len(parts) == 0 { continue } cmd := exec.Command(parts[0], parts[1:]...) if output, err := cmd.CombinedOutput(); err != nil { tp.logger.WithFields(logrus.Fields{ "rule": rule, "output": string(output), }).WithError(err).Error("Failed to execute rule") // 继续执行其他规则,不要因为一个失败就停止 } else { tp.logger.WithField("rule", rule).Debug("Rule executed successfully") } } return nil } func (tp *TransparentProxy) cleanupLinuxRules() error { cleanupRules := []string{ "iptables -t nat -D OUTPUT -j WORMHOLE_OUTPUT", "iptables -t nat -D PREROUTING -j WORMHOLE_PREROUTING", "iptables -t nat -F WORMHOLE_OUTPUT", "iptables -t nat -F WORMHOLE_PREROUTING", "iptables -t nat -X WORMHOLE_OUTPUT", "iptables -t nat -X WORMHOLE_PREROUTING", } return tp.executeRules(cleanupRules) } func (tp *TransparentProxy) cleanupMacOSRules() error { rules := []string{ "pfctl -d", "rm -f /tmp/wormhole.pf.conf", } return tp.executeRules(rules) } func (tp *TransparentProxy) backupDNS() error { // 这里简化处理,实际应该备份/etc/resolv.conf tp.originalDNS = []string{"8.8.8.8", "8.8.4.4"} return nil } func (tp *TransparentProxy) restoreDNS() error { // 恢复DNS设置 tp.logger.Info("DNS settings restored") return nil } func (tp *TransparentProxy) writePfRules(rules string) error { return exec.Command("sh", "-c", fmt.Sprintf("echo '%s' > /tmp/wormhole.pf.conf", rules)).Run() } func (tp *TransparentProxy) getLinuxOriginalDest(fd int) (string, error) { // Linux SO_ORIGINAL_DST const SO_ORIGINAL_DST = 80 _, err := syscall.GetsockoptIPv6Mreq(fd, syscall.IPPROTO_IP, SO_ORIGINAL_DST) if err != nil { return "", err } // 解析地址结构(这里简化处理) return "unknown:80", nil } func (tp *TransparentProxy) getMacOSOriginalDest(fd int) (string, error) { // macOS implementation would be more complex return "unknown:80", nil } // IsTransparentSupported 检查系统是否支持透明代理 func IsTransparentSupported() bool { switch runtime.GOOS { case "linux": // 检查是否有iptables if _, err := exec.LookPath("iptables"); err != nil { return false } return true case "darwin": // 检查是否有pfctl if _, err := exec.LookPath("pfctl"); err != nil { return false } return true default: return false } } // RequiresRoot 检查是否需要root权限 func RequiresRoot() bool { return runtime.GOOS == "linux" || runtime.GOOS == "darwin" }