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