github.com/xmplusdev/xmcore@v1.8.11-0.20240412132628-5518b55526af/proxy/dokodemo/fakeudp_linux.go (about) 1 //go:build linux 2 // +build linux 3 4 package dokodemo 5 6 import ( 7 "fmt" 8 "net" 9 "os" 10 "syscall" 11 12 "golang.org/x/sys/unix" 13 ) 14 15 func FakeUDP(addr *net.UDPAddr, mark int) (net.PacketConn, error) { 16 var af int 17 var sockaddr syscall.Sockaddr 18 19 if len(addr.IP) == 4 { 20 af = syscall.AF_INET 21 sockaddr = &syscall.SockaddrInet4{Port: addr.Port} 22 copy(sockaddr.(*syscall.SockaddrInet4).Addr[:], addr.IP) 23 } else { 24 af = syscall.AF_INET6 25 sockaddr = &syscall.SockaddrInet6{Port: addr.Port} 26 copy(sockaddr.(*syscall.SockaddrInet6).Addr[:], addr.IP) 27 } 28 29 var fd int 30 var err error 31 32 if fd, err = syscall.Socket(af, syscall.SOCK_DGRAM, 0); err != nil { 33 return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("socket open: %s", err)} 34 } 35 36 if mark != 0 { 37 if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_MARK, mark); err != nil { 38 syscall.Close(fd) 39 return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("set socket option: SO_MARK: %s", err)} 40 } 41 } 42 43 if err = syscall.SetsockoptInt(fd, syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil { 44 syscall.Close(fd) 45 return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("set socket option: IP_TRANSPARENT: %s", err)} 46 } 47 48 syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) 49 50 syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, unix.SO_REUSEPORT, 1) 51 52 if err = syscall.Bind(fd, sockaddr); err != nil { 53 syscall.Close(fd) 54 return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("socket bind: %s", err)} 55 } 56 57 fdFile := os.NewFile(uintptr(fd), fmt.Sprintf("net-udp-fake-%s", addr.String())) 58 defer fdFile.Close() 59 60 packetConn, err := net.FilePacketConn(fdFile) 61 if err != nil { 62 syscall.Close(fd) 63 return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("convert file descriptor to connection: %s", err)} 64 } 65 66 return packetConn, nil 67 }