github.com/database64128/shadowsocks-go@v1.7.0/conn/conn.go (about) 1 package conn 2 3 import ( 4 "context" 5 "net" 6 "syscall" 7 8 "github.com/database64128/tfo-go/v2" 9 ) 10 11 type setFunc = func(fd int, network string) error 12 13 type setFuncSlice []setFunc 14 15 func (fns setFuncSlice) controlContextFunc() func(ctx context.Context, network, address string, c syscall.RawConn) error { 16 if len(fns) == 0 { 17 return nil 18 } 19 return func(ctx context.Context, network, address string, c syscall.RawConn) (err error) { 20 if cerr := c.Control(func(fd uintptr) { 21 for _, fn := range fns { 22 if err = fn(int(fd), network); err != nil { 23 return 24 } 25 } 26 }); cerr != nil { 27 return cerr 28 } 29 return 30 } 31 } 32 33 func (fns setFuncSlice) controlFunc() func(network, address string, c syscall.RawConn) error { 34 if len(fns) == 0 { 35 return nil 36 } 37 return func(network, address string, c syscall.RawConn) (err error) { 38 if cerr := c.Control(func(fd uintptr) { 39 for _, fn := range fns { 40 if err = fn(int(fd), network); err != nil { 41 return 42 } 43 } 44 }); cerr != nil { 45 return cerr 46 } 47 return 48 } 49 } 50 51 // ListenerSocketOptions contains listener-specific socket options. 52 type ListenerSocketOptions struct { 53 // Fwmark sets the listener's fwmark on Linux, or user cookie on FreeBSD. 54 // 55 // Available on Linux and FreeBSD. 56 Fwmark int 57 58 // TrafficClass sets the traffic class of the listener. 59 // 60 // Available on most platforms except Windows. 61 TrafficClass int 62 63 // ReusePort enables SO_REUSEPORT on the listener. 64 // 65 // Available on Linux and the BSDs. 66 ReusePort bool 67 68 // Transparent enables transparent proxy on the listener. 69 // 70 // Only available on Linux. 71 Transparent bool 72 73 // PathMTUDiscovery enables Path MTU Discovery on the listener. 74 // 75 // Available on Linux, macOS, FreeBSD, and Windows. 76 PathMTUDiscovery bool 77 78 // TCPFastOpen enables TCP Fast Open on the listener. 79 // 80 // Available on Linux, macOS, FreeBSD, and Windows. 81 TCPFastOpen bool 82 83 // ReceivePacketInfo enables the reception of packet information control messages on the listener. 84 // 85 // Available on Linux, macOS, and Windows. 86 ReceivePacketInfo bool 87 88 // ReceiveOriginalDestAddr enables the reception of original destination address control messages on the listener. 89 // 90 // Only available on Linux. 91 ReceiveOriginalDestAddr bool 92 } 93 94 // ListenConfig returns a [tfo.ListenConfig] with a control function that sets the socket options. 95 func (lso ListenerSocketOptions) ListenConfig() tfo.ListenConfig { 96 return tfo.ListenConfig{ 97 ListenConfig: net.ListenConfig{ 98 Control: lso.buildSetFns().controlFunc(), 99 }, 100 DisableTFO: !lso.TCPFastOpen, 101 } 102 } 103 104 var ( 105 // DefaultTCPListenerSocketOptions is the default [ListenerSocketOptions] for TCP servers. 106 DefaultTCPListenerSocketOptions = ListenerSocketOptions{ 107 TCPFastOpen: true, 108 } 109 110 // DefaultTCPListenConfig is the default [tfo.ListenConfig] for TCP listeners. 111 DefaultTCPListenConfig = DefaultTCPListenerSocketOptions.ListenConfig() 112 113 // DefaultUDPServerSocketOptions is the default [ListenerSocketOptions] for UDP servers. 114 DefaultUDPServerSocketOptions = ListenerSocketOptions{ 115 PathMTUDiscovery: true, 116 ReceivePacketInfo: true, 117 } 118 119 // DefaultUDPServerListenConfig is the default [tfo.ListenConfig] for UDP servers. 120 DefaultUDPServerListenConfig = DefaultUDPServerSocketOptions.ListenConfig() 121 122 // DefaultUDPClientSocketOptions is the default [ListenerSocketOptions] for UDP clients. 123 DefaultUDPClientSocketOptions = ListenerSocketOptions{ 124 PathMTUDiscovery: true, 125 } 126 127 // DefaultUDPClientListenConfig is the default [tfo.ListenConfig] for UDP clients. 128 DefaultUDPClientListenConfig = DefaultUDPClientSocketOptions.ListenConfig() 129 ) 130 131 // DialerSocketOptions contains dialer-specific socket options. 132 type DialerSocketOptions struct { 133 // Fwmark sets the dialer's fwmark on Linux, or user cookie on FreeBSD. 134 // 135 // Available on Linux and FreeBSD. 136 Fwmark int 137 138 // TrafficClass sets the traffic class of the dialer. 139 // 140 // Available on most platforms except Windows. 141 TrafficClass int 142 143 // TCPFastOpen enables TCP Fast Open on the dialer. 144 // 145 // Available on Linux, macOS, FreeBSD, and Windows. 146 TCPFastOpen bool 147 } 148 149 // Dialer returns a [tfo.Dialer] with a control function that sets the socket options. 150 func (dso DialerSocketOptions) Dialer() tfo.Dialer { 151 return tfo.Dialer{ 152 Dialer: net.Dialer{ 153 ControlContext: dso.buildSetFns().controlContextFunc(), 154 }, 155 DisableTFO: !dso.TCPFastOpen, 156 } 157 } 158 159 var ( 160 // DefaultTCPDialerSocketOptions is the default [DialerSocketOptions] for TCP clients. 161 DefaultTCPDialerSocketOptions = DialerSocketOptions{ 162 TCPFastOpen: true, 163 } 164 165 // DefaultTCPDialer is the default [tfo.Dialer] for TCP clients. 166 DefaultTCPDialer = DefaultTCPDialerSocketOptions.Dialer() 167 ) 168 169 // ListenConfigCache is a map of [ListenerSocketOptions] to [tfo.ListenConfig]. 170 type ListenConfigCache map[ListenerSocketOptions]tfo.ListenConfig 171 172 // NewListenConfigCache creates a new cache for [tfo.ListenConfig] with a few default entries. 173 func NewListenConfigCache() ListenConfigCache { 174 cache := make(ListenConfigCache) 175 cache[DefaultTCPListenerSocketOptions] = DefaultTCPListenConfig 176 cache[DefaultUDPServerSocketOptions] = DefaultUDPServerListenConfig 177 cache[DefaultUDPClientSocketOptions] = DefaultUDPClientListenConfig 178 return cache 179 } 180 181 // Get returns a [tfo.ListenConfig] for the given [ListenerSocketOptions]. 182 func (cache ListenConfigCache) Get(lso ListenerSocketOptions) (lc tfo.ListenConfig) { 183 lc, ok := cache[lso] 184 if ok { 185 return 186 } 187 lc = lso.ListenConfig() 188 cache[lso] = lc 189 return 190 } 191 192 // DialerCache is a map of [DialerSocketOptions] to [tfo.Dialer]. 193 type DialerCache map[DialerSocketOptions]tfo.Dialer 194 195 // NewDialerCache creates a new cache for [tfo.Dialer] with a few default entries. 196 func NewDialerCache() DialerCache { 197 cache := make(DialerCache) 198 cache[DefaultTCPDialerSocketOptions] = DefaultTCPDialer 199 return cache 200 } 201 202 // Get returns a [tfo.Dialer] for the given [DialerSocketOptions]. 203 func (cache DialerCache) Get(dso DialerSocketOptions) (d tfo.Dialer) { 204 d, ok := cache[dso] 205 if ok { 206 return 207 } 208 d = dso.Dialer() 209 cache[dso] = d 210 return 211 } 212 213 // ListenUDP creates a [*net.UDPConn] from the given [tfo.ListenConfig]. 214 func ListenUDP(listenConfig tfo.ListenConfig, network, address string) (*net.UDPConn, error) { 215 packetConn, err := listenConfig.ListenPacket(context.Background(), network, address) 216 if err != nil { 217 return nil, err 218 } 219 return packetConn.(*net.UDPConn), nil 220 }