github.com/database64128/shadowsocks-go@v1.7.0/direct/packet.go (about) 1 package direct 2 3 import ( 4 "fmt" 5 "net/netip" 6 7 "github.com/database64128/shadowsocks-go/conn" 8 "github.com/database64128/shadowsocks-go/socks5" 9 "github.com/database64128/shadowsocks-go/zerocopy" 10 ) 11 12 // DirectPacketClientPackUnpacker packs and unpacks packets for direct connection. 13 // 14 // DirectPacketClientPackUnpacker implements the zerocopy ClientPacker and Unpacker interfaces. 15 type DirectPacketClientPackUnpacker struct { 16 // cachedDomain caches the last used domain target to avoid excessive DNS lookups. 17 cachedDomain string 18 19 // cachedDomainIP is the last used domain target's resolved IP address. 20 cachedDomainIP netip.Addr 21 22 // mtu is used in the PackInPlace method to determine whether the payload is too big. 23 mtu int 24 } 25 26 // NewDirectPacketClientPackUnpacker creates a zerocopy.ClientPackUnpacker for direct connection. 27 func NewDirectPacketClientPackUnpacker(mtu int) *DirectPacketClientPackUnpacker { 28 return &DirectPacketClientPackUnpacker{ 29 mtu: mtu, 30 } 31 } 32 33 // ClientPackerInfo implements the zerocopy.ClientPacker ClientPackerInfo method. 34 func (p *DirectPacketClientPackUnpacker) ClientPackerInfo() zerocopy.ClientPackerInfo { 35 return zerocopy.ClientPackerInfo{} 36 } 37 38 func (p *DirectPacketClientPackUnpacker) updateDomainIPCache(targetAddr conn.Addr) error { 39 if p.cachedDomain != targetAddr.Domain() { 40 ip, err := targetAddr.ResolveIP() 41 if err != nil { 42 return err 43 } 44 p.cachedDomain = targetAddr.Domain() 45 p.cachedDomainIP = ip 46 } 47 return nil 48 } 49 50 // PackInPlace implements the zerocopy.ClientPacker PackInPlace method. 51 func (p *DirectPacketClientPackUnpacker) PackInPlace(b []byte, targetAddr conn.Addr, payloadStart, payloadLen int) (destAddrPort netip.AddrPort, packetStart, packetLen int, err error) { 52 if targetAddr.IsIP() { 53 destAddrPort = targetAddr.IPPort() 54 } else { 55 err = p.updateDomainIPCache(targetAddr) 56 if err != nil { 57 return 58 } 59 destAddrPort = netip.AddrPortFrom(p.cachedDomainIP, targetAddr.Port()) 60 } 61 packetStart = payloadStart 62 packetLen = payloadLen 63 maxPacketLen := zerocopy.MaxPacketSizeForAddr(p.mtu, destAddrPort.Addr()) 64 if packetLen > maxPacketLen { 65 err = zerocopy.ErrPayloadTooBig 66 } 67 return 68 } 69 70 // ClientUnpackerInfo implements the zerocopy.ClientUnpacker ClientUnpackerInfo method. 71 func (p *DirectPacketClientPackUnpacker) ClientUnpackerInfo() zerocopy.ClientUnpackerInfo { 72 return zerocopy.ClientUnpackerInfo{} 73 } 74 75 // UnpackInPlace implements the zerocopy.ClientUnpacker UnpackInPlace method. 76 func (p *DirectPacketClientPackUnpacker) UnpackInPlace(b []byte, packetSourceAddrPort netip.AddrPort, packetStart, packetLen int) (payloadSourceAddr netip.AddrPort, payloadStart, payloadLen int, err error) { 77 payloadSourceAddr = packetSourceAddrPort 78 payloadStart = packetStart 79 payloadLen = packetLen 80 return 81 } 82 83 type DirectPacketServerPackUnpacker struct { 84 // targetAddr is the address to which packets are forwarded by the direct server. 85 targetAddr conn.Addr 86 87 // targetAddrOnly controls whether to discard packets from non-target sources. 88 targetAddrOnly bool 89 } 90 91 // NewDirectPacketServerPackUnpacker creates a zerocopy.ServerPackUnpacker that forwards packets to the specified target address. 92 func NewDirectPacketServerPackUnpacker(targetAddr conn.Addr, targetAddrOnly bool) *DirectPacketServerPackUnpacker { 93 return &DirectPacketServerPackUnpacker{ 94 targetAddr: targetAddr, 95 targetAddrOnly: targetAddrOnly, 96 } 97 } 98 99 // ServerPackerInfo implements the zerocopy.ServerPacker ServerPackerInfo method. 100 func (p *DirectPacketServerPackUnpacker) ServerPackerInfo() zerocopy.ServerPackerInfo { 101 return zerocopy.ServerPackerInfo{} 102 } 103 104 // PackInPlace implements the zerocopy.ServerPacker PackInPlace method. 105 func (p *DirectPacketServerPackUnpacker) PackInPlace(b []byte, sourceAddrPort netip.AddrPort, payloadStart, payloadLen, maxPacketLen int) (packetStart, packetLen int, err error) { 106 packetStart = payloadStart 107 packetLen = payloadLen 108 if packetLen > maxPacketLen { 109 err = zerocopy.ErrPayloadTooBig 110 } 111 if p.targetAddrOnly && !conn.AddrPortMappedEqual(sourceAddrPort, p.targetAddr.IPPort()) { 112 err = fmt.Errorf("dropped packet from non-target source %s", sourceAddrPort) 113 } 114 return 115 } 116 117 // ServerUnpackerInfo implements the zerocopy.ServerUnpacker ServerUnpackerInfo method. 118 func (p *DirectPacketServerPackUnpacker) ServerUnpackerInfo() zerocopy.ServerUnpackerInfo { 119 return zerocopy.ServerUnpackerInfo{} 120 } 121 122 // UnpackInPlace implements the zerocopy.ServerUnpacker UnpackInPlace method. 123 func (p *DirectPacketServerPackUnpacker) UnpackInPlace(b []byte, sourceAddrPort netip.AddrPort, packetStart, packetLen int) (targetAddr conn.Addr, payloadStart, payloadLen int, err error) { 124 targetAddr = p.targetAddr 125 payloadStart = packetStart 126 payloadLen = packetLen 127 return 128 } 129 130 // ShadowsocksNonePacketClientMessageHeadroom is the headroom required by a Shadowsocks none client message. 131 var ShadowsocksNonePacketClientMessageHeadroom = zerocopy.Headroom{ 132 Front: socks5.MaxAddrLen, 133 Rear: 0, 134 } 135 136 // ShadowsocksNonePacketServerMessageHeadroom is the headroom required by a Shadowsocks none server message. 137 var ShadowsocksNonePacketServerMessageHeadroom = zerocopy.Headroom{ 138 Front: socks5.IPv6AddrLen, 139 Rear: 0, 140 } 141 142 // ShadowsocksNonePacketClientPacker implements the zerocopy ClientPacker interface. 143 type ShadowsocksNonePacketClientPacker struct { 144 // serverAddrPort is the Shadowsocks none server's IP and port. 145 serverAddrPort netip.AddrPort 146 147 // maxPacketSize is the maximum allowed size of a packed packet. 148 // The value is calculated from MTU and server address family. 149 maxPacketSize int 150 } 151 152 // NewShadowsocksNonePacketClientPacker creates a Shadowsocks none packet client packer. 153 func NewShadowsocksNonePacketClientPacker(serverAddrPort netip.AddrPort, maxPacketSize int) *ShadowsocksNonePacketClientPacker { 154 return &ShadowsocksNonePacketClientPacker{ 155 serverAddrPort: serverAddrPort, 156 maxPacketSize: maxPacketSize, 157 } 158 } 159 160 // ClientPackerInfo implements the zerocopy.ClientPacker ClientPackerInfo method. 161 func (p *ShadowsocksNonePacketClientPacker) ClientPackerInfo() zerocopy.ClientPackerInfo { 162 return zerocopy.ClientPackerInfo{ 163 Headroom: ShadowsocksNonePacketClientMessageHeadroom, 164 } 165 } 166 167 // PackInPlace implements the zerocopy.ClientPacker PackInPlace method. 168 func (p *ShadowsocksNonePacketClientPacker) PackInPlace(b []byte, targetAddr conn.Addr, payloadStart, payloadLen int) (destAddrPort netip.AddrPort, packetStart, packetLen int, err error) { 169 targetAddrLen := socks5.LengthOfAddrFromConnAddr(targetAddr) 170 destAddrPort = p.serverAddrPort 171 packetStart = payloadStart - targetAddrLen 172 packetLen = payloadLen + targetAddrLen 173 if packetLen > p.maxPacketSize { 174 err = zerocopy.ErrPayloadTooBig 175 } 176 socks5.WriteAddrFromConnAddr(b[packetStart:], targetAddr) 177 return 178 } 179 180 // ShadowsocksNonePacketClientUnpacker implements the zerocopy ClientUnpacker interface. 181 type ShadowsocksNonePacketClientUnpacker struct { 182 // serverAddrPort is the Shadowsocks none server's IP and port. 183 serverAddrPort netip.AddrPort 184 } 185 186 // NewShadowsocksNonePacketClientUnpacker creates a Shadowsocks none packet client unpacker. 187 func NewShadowsocksNonePacketClientUnpacker(serverAddrPort netip.AddrPort) *ShadowsocksNonePacketClientUnpacker { 188 return &ShadowsocksNonePacketClientUnpacker{ 189 serverAddrPort: serverAddrPort, 190 } 191 } 192 193 // ClientUnpackerInfo implements the zerocopy.ClientUnpacker ClientUnpackerInfo method. 194 func (p *ShadowsocksNonePacketClientUnpacker) ClientUnpackerInfo() zerocopy.ClientUnpackerInfo { 195 return zerocopy.ClientUnpackerInfo{ 196 Headroom: ShadowsocksNonePacketServerMessageHeadroom, 197 } 198 } 199 200 // UnpackInPlace implements the zerocopy.ClientUnpacker UnpackInPlace method. 201 func (p *ShadowsocksNonePacketClientUnpacker) UnpackInPlace(b []byte, packetSourceAddrPort netip.AddrPort, packetStart, packetLen int) (payloadSourceAddrPort netip.AddrPort, payloadStart, payloadLen int, err error) { 202 if !conn.AddrPortMappedEqual(packetSourceAddrPort, p.serverAddrPort) { 203 err = fmt.Errorf("dropped packet from non-server source %s", packetSourceAddrPort) 204 return 205 } 206 var payloadSourceAddrLen int 207 payloadSourceAddrPort, payloadSourceAddrLen, err = socks5.AddrPortFromSlice(b[packetStart : packetStart+packetLen]) 208 payloadStart = packetStart + payloadSourceAddrLen 209 payloadLen = packetLen - payloadSourceAddrLen 210 return 211 } 212 213 // ShadowsocksNonePacketServerPacker implements the zerocopy ServerPacker interface. 214 type ShadowsocksNonePacketServerPacker struct{} 215 216 // ServerPackerInfo implements the zerocopy.ServerPacker ServerPackerInfo method. 217 func (ShadowsocksNonePacketServerPacker) ServerPackerInfo() zerocopy.ServerPackerInfo { 218 return zerocopy.ServerPackerInfo{ 219 Headroom: ShadowsocksNonePacketServerMessageHeadroom, 220 } 221 } 222 223 // PackInPlace implements the zerocopy.ServerPacker PackInPlace method. 224 func (ShadowsocksNonePacketServerPacker) PackInPlace(b []byte, sourceAddrPort netip.AddrPort, payloadStart, payloadLen, maxPacketLen int) (packetStart, packetLen int, err error) { 225 targetAddrLen := socks5.LengthOfAddrFromAddrPort(sourceAddrPort) 226 packetStart = payloadStart - targetAddrLen 227 packetLen = payloadLen + targetAddrLen 228 if packetLen > maxPacketLen { 229 err = zerocopy.ErrPayloadTooBig 230 } 231 socks5.WriteAddrFromAddrPort(b[packetStart:], sourceAddrPort) 232 return 233 } 234 235 // ShadowsocksNonePacketServerUnpacker implements the zerocopy Unpacker interface. 236 type ShadowsocksNonePacketServerUnpacker struct { 237 // cachedDomain caches the last used domain target to avoid allocating new strings. 238 cachedDomain string 239 } 240 241 // ServerUnpackerInfo implements the zerocopy.ServerUnpacker ServerUnpackerInfo method. 242 func (ShadowsocksNonePacketServerUnpacker) ServerUnpackerInfo() zerocopy.ServerUnpackerInfo { 243 return zerocopy.ServerUnpackerInfo{ 244 Headroom: ShadowsocksNonePacketClientMessageHeadroom, 245 } 246 } 247 248 // UnpackInPlace implements the zerocopy.ServerUnpacker UnpackInPlace method. 249 func (p *ShadowsocksNonePacketServerUnpacker) UnpackInPlace(b []byte, sourceAddrPort netip.AddrPort, packetStart, packetLen int) (targetAddr conn.Addr, payloadStart, payloadLen int, err error) { 250 var targetAddrLen int 251 targetAddr, targetAddrLen, p.cachedDomain, err = socks5.ConnAddrFromSliceWithDomainCache(b[packetStart:packetStart+packetLen], p.cachedDomain) 252 payloadStart = packetStart + targetAddrLen 253 payloadLen = packetLen - targetAddrLen 254 return 255 } 256 257 // Socks5PacketClientMessageHeadroom is the headroom required by a SOCKS5 client message. 258 var Socks5PacketClientMessageHeadroom = zerocopy.Headroom{ 259 Front: 3 + socks5.MaxAddrLen, 260 Rear: 0, 261 } 262 263 // Socks5PacketServerMessageHeadroom is the headroom required by a SOCKS5 server message. 264 var Socks5PacketServerMessageHeadroom = zerocopy.Headroom{ 265 Front: 3 + socks5.IPv6AddrLen, 266 Rear: 0, 267 } 268 269 // Socks5PacketClientPacker implements the zerocopy ClientPacker interface. 270 type Socks5PacketClientPacker struct { 271 // serverAddrPort is the SOCKS5 server's IP and port. 272 serverAddrPort netip.AddrPort 273 274 // maxPacketSize is the maximum allowed size of a packed packet. 275 // The value is calculated from MTU and server address family. 276 maxPacketSize int 277 } 278 279 // NewSocks5PacketClientPacker creates a SOCKS5 packet client packer. 280 func NewSocks5PacketClientPacker(serverAddrPort netip.AddrPort, maxPacketSize int) *Socks5PacketClientPacker { 281 return &Socks5PacketClientPacker{ 282 serverAddrPort: serverAddrPort, 283 maxPacketSize: maxPacketSize, 284 } 285 } 286 287 // ClientPackerInfo implements the zerocopy.ClientPacker ClientPackerInfo method. 288 func (p *Socks5PacketClientPacker) ClientPackerInfo() zerocopy.ClientPackerInfo { 289 return zerocopy.ClientPackerInfo{ 290 Headroom: Socks5PacketClientMessageHeadroom, 291 } 292 } 293 294 // PackInPlace implements the zerocopy.ClientPacker PackInPlace method. 295 func (p *Socks5PacketClientPacker) PackInPlace(b []byte, targetAddr conn.Addr, payloadStart, payloadLen int) (destAddrPort netip.AddrPort, packetStart, packetLen int, err error) { 296 targetAddrLen := socks5.LengthOfAddrFromConnAddr(targetAddr) 297 destAddrPort = p.serverAddrPort 298 packetStart = payloadStart - targetAddrLen - 3 299 packetLen = payloadLen + targetAddrLen + 3 300 if packetLen > p.maxPacketSize { 301 err = zerocopy.ErrPayloadTooBig 302 } 303 socks5.WritePacketHeader(b[packetStart:]) 304 socks5.WriteAddrFromConnAddr(b[packetStart+3:], targetAddr) 305 return 306 } 307 308 // Socks5PacketClientUnpacker implements the zerocopy Unpacker interface. 309 type Socks5PacketClientUnpacker struct { 310 // serverAddrPort is the SOCKS5 server's IP and port. 311 serverAddrPort netip.AddrPort 312 } 313 314 // NewSocks5PacketClientUnpacker creates a SOCKS5 packet client unpacker. 315 func NewSocks5PacketClientUnpacker(serverAddrPort netip.AddrPort) *Socks5PacketClientUnpacker { 316 return &Socks5PacketClientUnpacker{ 317 serverAddrPort: serverAddrPort, 318 } 319 } 320 321 // ClientUnpackerInfo implements the zerocopy.ClientUnpacker ClientUnpackerInfo method. 322 func (p *Socks5PacketClientUnpacker) ClientUnpackerInfo() zerocopy.ClientUnpackerInfo { 323 return zerocopy.ClientUnpackerInfo{ 324 Headroom: Socks5PacketServerMessageHeadroom, 325 } 326 } 327 328 // UnpackInPlace implements the zerocopy.ClientUnpacker UnpackInPlace method. 329 func (p *Socks5PacketClientUnpacker) UnpackInPlace(b []byte, packetSourceAddrPort netip.AddrPort, packetStart, packetLen int) (payloadSourceAddrPort netip.AddrPort, payloadStart, payloadLen int, err error) { 330 if !conn.AddrPortMappedEqual(packetSourceAddrPort, p.serverAddrPort) { 331 err = fmt.Errorf("dropped packet from non-server source %s", packetSourceAddrPort) 332 return 333 } 334 335 if packetLen < 3 { 336 err = fmt.Errorf("%w: %d", zerocopy.ErrPacketTooSmall, packetLen) 337 return 338 } 339 340 pkt := b[packetStart : packetStart+packetLen] 341 err = socks5.ValidatePacketHeader(pkt) 342 if err != nil { 343 return 344 } 345 346 var payloadSourceAddrLen int 347 payloadSourceAddrPort, payloadSourceAddrLen, err = socks5.AddrPortFromSlice(pkt[3:]) 348 payloadStart = packetStart + payloadSourceAddrLen + 3 349 payloadLen = packetLen - payloadSourceAddrLen - 3 350 return 351 } 352 353 // Socks5PacketServerPacker implements the zerocopy ServerPacker interface. 354 type Socks5PacketServerPacker struct{} 355 356 // ServerPackerInfo implements the zerocopy.ServerPacker ServerPackerInfo method. 357 func (Socks5PacketServerPacker) ServerPackerInfo() zerocopy.ServerPackerInfo { 358 return zerocopy.ServerPackerInfo{ 359 Headroom: Socks5PacketServerMessageHeadroom, 360 } 361 } 362 363 // PackInPlace implements the zerocopy.ServerPacker PackInPlace method. 364 func (Socks5PacketServerPacker) PackInPlace(b []byte, sourceAddrPort netip.AddrPort, payloadStart, payloadLen, maxPacketLen int) (packetStart, packetLen int, err error) { 365 targetAddrLen := socks5.LengthOfAddrFromAddrPort(sourceAddrPort) 366 packetStart = payloadStart - targetAddrLen - 3 367 packetLen = payloadLen + targetAddrLen + 3 368 if packetLen > maxPacketLen { 369 err = zerocopy.ErrPayloadTooBig 370 } 371 socks5.WritePacketHeader(b[packetStart:]) 372 socks5.WriteAddrFromAddrPort(b[packetStart+3:], sourceAddrPort) 373 return 374 } 375 376 // Socks5PacketServerUnpacker implements the zerocopy Unpacker interface. 377 type Socks5PacketServerUnpacker struct { 378 // cachedDomain caches the last used domain target to avoid allocating new strings. 379 cachedDomain string 380 } 381 382 // ServerUnpackerInfo implements the zerocopy.ServerUnpacker ServerUnpackerInfo method. 383 func (Socks5PacketServerUnpacker) ServerUnpackerInfo() zerocopy.ServerUnpackerInfo { 384 return zerocopy.ServerUnpackerInfo{ 385 Headroom: Socks5PacketClientMessageHeadroom, 386 } 387 } 388 389 // UnpackInPlace implements the zerocopy.ServerUnpacker UnpackInPlace method. 390 func (p *Socks5PacketServerUnpacker) UnpackInPlace(b []byte, sourceAddrPort netip.AddrPort, packetStart, packetLen int) (targetAddr conn.Addr, payloadStart, payloadLen int, err error) { 391 if packetLen < 3 { 392 err = fmt.Errorf("%w: %d", zerocopy.ErrPacketTooSmall, packetLen) 393 return 394 } 395 396 pkt := b[packetStart : packetStart+packetLen] 397 err = socks5.ValidatePacketHeader(pkt) 398 if err != nil { 399 return 400 } 401 402 var targetAddrLen int 403 targetAddr, targetAddrLen, p.cachedDomain, err = socks5.ConnAddrFromSliceWithDomainCache(pkt[3:], p.cachedDomain) 404 payloadStart = packetStart + targetAddrLen + 3 405 payloadLen = packetLen - targetAddrLen - 3 406 return 407 }