1---2title: "简单的 TProxy 代理 (Golang)"3date: 2023-04-16T10:04:19+08:004---56> 代码参考了 https://github.com/KatelynHaworth/go-tproxy78实际很简单,只是在普通的 TCPListener 上,使用 `setsockopt` 系统调用,在 IP 层设置 `IP_TRANSPARENT` 属性。910示例代码如下:11```12import (13 "fmt"14 "io"15 "net"16 "syscall"17)1819func main() {20 listener, err := net.ListenTCP("tcp", &net.TCPAddr{IP: net.ParseIP("0.0.0.0"), Port: 8080})21 if err != nil {22 panic(err)23 }24 defer listener.Close()2526 if err := initTCPTProxy(listener); err != nil {27 panic(err)28 }2930 for {31 conn, err := listener.Accept()32 if err != nil {33 panic(err)34 }35 defer conn.Close()3637 localAddr := conn.LocalAddr()38 remoteAddr := conn.RemoteAddr()3940 fmt.Printf("Local address: %v\n", localAddr)41 fmt.Printf("Remote address: %v\n", remoteAddr)42 r_conn, err := net.Dial("tcp", localAddr.String())43 if err != nil {44 panic(err)45 }4647 go func() {48 defer r_conn.Close()49 defer conn.Close()50 io.Copy(r_conn, conn)51 }()52 go func() {53 defer r_conn.Close()54 defer conn.Close()55 io.Copy(conn, r_conn)56 }()5758 }59}6061func initTCPTProxy(l *net.TCPListener) error {62 fileDescriptorSource, err := l.File()63 if err != nil {64 return &net.OpError{Op: "listen", Net: l.Addr().Network(), Source: nil, Addr: l.Addr(), Err: fmt.Errorf("get file descriptor: %s", err)}65 }66 defer fileDescriptorSource.Close()6768 if err = syscall.SetsockoptInt(int(fileDescriptorSource.Fd()), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil {69 return &net.OpError{Op: "listen", Net: l.Addr().Network(), Source: nil, Addr: l.Addr(), Err: fmt.Errorf("set socket option: IP_TRANSPARENT: %s", err)}70 }71 return nil72}73```7475UDP 的非常类似,只是从 net.UDPConn 对象里获取 socket fd , 而不是 listener 。76