github.com/database64128/shadowsocks-go@v1.10.2-0.20240315062903-143a773533f1/conn/conn_linux.go (about) 1 package conn 2 3 import ( 4 "fmt" 5 "net/netip" 6 "unsafe" 7 8 "golang.org/x/sys/unix" 9 ) 10 11 // TransparentSocketControlMessageBufferSize specifies the buffer size for receiving IPV6_RECVORIGDSTADDR socket control messages. 12 const TransparentSocketControlMessageBufferSize = unix.SizeofCmsghdr + (unix.SizeofSockaddrInet6+unix.SizeofPtr-1) & ^(unix.SizeofPtr-1) 13 14 func setFwmark(fd, fwmark int) error { 15 if err := unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_MARK, fwmark); err != nil { 16 return fmt.Errorf("failed to set socket option SO_MARK: %w", err) 17 } 18 return nil 19 } 20 21 func setTrafficClass(fd int, network string, trafficClass int) error { 22 // Set IP_TOS for both v4 and v6. 23 if err := unix.SetsockoptInt(fd, unix.IPPROTO_IP, unix.IP_TOS, trafficClass); err != nil { 24 return fmt.Errorf("failed to set socket option IP_TOS: %w", err) 25 } 26 27 switch network { 28 case "tcp4", "udp4": 29 case "tcp6", "udp6": 30 if err := unix.SetsockoptInt(fd, unix.IPPROTO_IPV6, unix.IPV6_TCLASS, trafficClass); err != nil { 31 return fmt.Errorf("failed to set socket option IPV6_TCLASS: %w", err) 32 } 33 default: 34 return fmt.Errorf("unsupported network: %s", network) 35 } 36 37 return nil 38 } 39 40 func setTransparent(fd int, network string) error { 41 switch network { 42 case "tcp4", "udp4": 43 if err := unix.SetsockoptInt(fd, unix.IPPROTO_IP, unix.IP_TRANSPARENT, 1); err != nil { 44 return fmt.Errorf("failed to set socket option IP_TRANSPARENT: %w", err) 45 } 46 case "tcp6", "udp6": 47 if err := unix.SetsockoptInt(fd, unix.IPPROTO_IPV6, unix.IPV6_TRANSPARENT, 1); err != nil { 48 return fmt.Errorf("failed to set socket option IPV6_TRANSPARENT: %w", err) 49 } 50 default: 51 return fmt.Errorf("unsupported network: %s", network) 52 } 53 return nil 54 } 55 56 func setPMTUD(fd int, network string) error { 57 // Set IP_MTU_DISCOVER for both v4 and v6. 58 if err := unix.SetsockoptInt(fd, unix.IPPROTO_IP, unix.IP_MTU_DISCOVER, unix.IP_PMTUDISC_DO); err != nil { 59 return fmt.Errorf("failed to set socket option IP_MTU_DISCOVER: %w", err) 60 } 61 62 switch network { 63 case "tcp4", "udp4": 64 case "tcp6", "udp6": 65 if err := unix.SetsockoptInt(fd, unix.IPPROTO_IPV6, unix.IPV6_MTU_DISCOVER, unix.IP_PMTUDISC_DO); err != nil { 66 return fmt.Errorf("failed to set socket option IPV6_MTU_DISCOVER: %w", err) 67 } 68 default: 69 return fmt.Errorf("unsupported network: %s", network) 70 } 71 72 return nil 73 } 74 75 func setRecvPktinfo(fd int, network string) error { 76 switch network { 77 case "udp4": 78 if err := unix.SetsockoptInt(fd, unix.IPPROTO_IP, unix.IP_PKTINFO, 1); err != nil { 79 return fmt.Errorf("failed to set socket option IP_PKTINFO: %w", err) 80 } 81 case "udp6": 82 if err := unix.SetsockoptInt(fd, unix.IPPROTO_IPV6, unix.IPV6_RECVPKTINFO, 1); err != nil { 83 return fmt.Errorf("failed to set socket option IPV6_RECVPKTINFO: %w", err) 84 } 85 default: 86 return fmt.Errorf("unsupported network: %s", network) 87 } 88 return nil 89 } 90 91 func setRecvOrigDstAddr(fd int, network string) error { 92 // Set IP_RECVORIGDSTADDR for both v4 and v6. 93 if err := unix.SetsockoptInt(fd, unix.IPPROTO_IP, unix.IP_RECVORIGDSTADDR, 1); err != nil { 94 return fmt.Errorf("failed to set socket option IP_RECVORIGDSTADDR: %w", err) 95 } 96 97 switch network { 98 case "udp4": 99 case "udp6": 100 if err := unix.SetsockoptInt(fd, unix.IPPROTO_IPV6, unix.IPV6_RECVORIGDSTADDR, 1); err != nil { 101 return fmt.Errorf("failed to set socket option IPV6_RECVORIGDSTADDR: %w", err) 102 } 103 default: 104 return fmt.Errorf("unsupported network: %s", network) 105 } 106 107 return nil 108 } 109 110 func (fns setFuncSlice) appendSetTransparentFunc(transparent bool) setFuncSlice { 111 if transparent { 112 return append(fns, setTransparent) 113 } 114 return fns 115 } 116 117 func (fns setFuncSlice) appendSetRecvOrigDstAddrFunc(recvOrigDstAddr bool) setFuncSlice { 118 if recvOrigDstAddr { 119 return append(fns, setRecvOrigDstAddr) 120 } 121 return fns 122 } 123 124 func (lso ListenerSocketOptions) buildSetFns() setFuncSlice { 125 return setFuncSlice{}. 126 appendSetFwmarkFunc(lso.Fwmark). 127 appendSetTrafficClassFunc(lso.TrafficClass). 128 appendSetReusePortFunc(lso.ReusePort). 129 appendSetTransparentFunc(lso.Transparent). 130 appendSetPMTUDFunc(lso.PathMTUDiscovery). 131 appendSetRecvPktinfoFunc(lso.ReceivePacketInfo). 132 appendSetRecvOrigDstAddrFunc(lso.ReceiveOriginalDestAddr) 133 } 134 135 func ParseOrigDstAddrCmsg(cmsg []byte) (netip.AddrPort, error) { 136 if len(cmsg) < unix.SizeofCmsghdr { 137 return netip.AddrPort{}, fmt.Errorf("control message length %d is shorter than cmsghdr length", len(cmsg)) 138 } 139 140 cmsghdr := (*unix.Cmsghdr)(unsafe.Pointer(&cmsg[0])) 141 142 switch { 143 case cmsghdr.Level == unix.IPPROTO_IP && cmsghdr.Type == unix.IP_ORIGDSTADDR && len(cmsg) >= unix.SizeofCmsghdr+unix.SizeofSockaddrInet4: 144 sa := (*unix.RawSockaddrInet4)(unsafe.Pointer(&cmsg[unix.SizeofCmsghdr])) 145 return SockaddrInet4ToAddrPort(sa), nil 146 147 case cmsghdr.Level == unix.IPPROTO_IPV6 && cmsghdr.Type == unix.IPV6_ORIGDSTADDR && len(cmsg) >= unix.SizeofCmsghdr+unix.SizeofSockaddrInet6: 148 sa := (*unix.RawSockaddrInet6)(unsafe.Pointer(&cmsg[unix.SizeofCmsghdr])) 149 return SockaddrInet6ToAddrPort(sa), nil 150 151 default: 152 return netip.AddrPort{}, fmt.Errorf("unknown control message level %d type %d", cmsghdr.Level, cmsghdr.Type) 153 } 154 }