github.com/database64128/shadowsocks-go@v1.7.0/zerocopy/packet.go (about) 1 package zerocopy 2 3 import ( 4 "bytes" 5 "crypto/rand" 6 "errors" 7 "net/netip" 8 9 "github.com/database64128/shadowsocks-go/conn" 10 ) 11 12 // Used in packet size calculations. 13 const ( 14 IPv4HeaderLength = 20 15 IPv6HeaderLength = 40 16 UDPHeaderLength = 8 17 18 // Next Header + Hdr Ext Len + Option Type + Opt Data Len + Jumbo Payload Length (u32be) 19 JumboPayloadOptionLength = 8 20 ) 21 22 var ( 23 ErrPacketTooSmall = errors.New("packet too small to unpack") 24 ErrPayloadTooBig = errors.New("payload too big to pack") 25 ) 26 27 // MaxPacketSizeForAddr calculates the maximum packet size for the given address 28 // based on the MTU and the address family. 29 func MaxPacketSizeForAddr(mtu int, addr netip.Addr) int { 30 if addr.Is4() || addr.Is4In6() { 31 return mtu - IPv4HeaderLength - UDPHeaderLength 32 } 33 if mtu > 65575 { 34 return mtu - IPv6HeaderLength - JumboPayloadOptionLength - UDPHeaderLength 35 } 36 return mtu - IPv6HeaderLength - UDPHeaderLength 37 } 38 39 // ClientPackerInfo contains information about a client packer. 40 type ClientPackerInfo struct { 41 Headroom Headroom 42 } 43 44 // ClientPacker processes raw payload into packets ready to be sent to servers. 45 type ClientPacker interface { 46 // ClientPackerInfo returns information about the client packer. 47 ClientPackerInfo() ClientPackerInfo 48 49 // PackInPlace packs the payload in-place into a packet ready for sending and returns 50 // the destination address, packet start offset, packet length, or an error if packing fails. 51 PackInPlace(b []byte, targetAddr conn.Addr, payloadStart, payloadLen int) (destAddrPort netip.AddrPort, packetStart, packetLen int, err error) 52 } 53 54 // ServerPackerInfo contains information about a server packer. 55 type ServerPackerInfo struct { 56 Headroom Headroom 57 } 58 59 // ServerPacker processes raw payload into packets ready to be sent to clients. 60 type ServerPacker interface { 61 // ServerPackerInfo returns information about the server packer. 62 ServerPackerInfo() ServerPackerInfo 63 64 // PackInPlace packs the payload in-place into a packet ready for sending and returns 65 // packet start offset, packet length, or an error if packing fails. 66 PackInPlace(b []byte, sourceAddrPort netip.AddrPort, payloadStart, payloadLen, maxPacketLen int) (packetStart, packetLen int, err error) 67 } 68 69 // ClientUnpackerInfo contains information about a client unpacker. 70 type ClientUnpackerInfo struct { 71 Headroom Headroom 72 } 73 74 // ClientUnpacker processes packets received from the server into raw payload. 75 type ClientUnpacker interface { 76 // ClientUnpackerInfo returns information about the client unpacker. 77 ClientUnpackerInfo() ClientUnpackerInfo 78 79 // UnpackInPlace unpacks the packet in-place and returns packet source address, payload start offset, payload length, or an error if unpacking fails. 80 UnpackInPlace(b []byte, packetSourceAddrPort netip.AddrPort, packetStart, packetLen int) (payloadSourceAddrPort netip.AddrPort, payloadStart, payloadLen int, err error) 81 } 82 83 // ServerUnpackerInfo contains information about a server unpacker. 84 type ServerUnpackerInfo struct { 85 Headroom Headroom 86 } 87 88 // ServerUnpacker processes packets received from the client into raw payload. 89 type ServerUnpacker interface { 90 // ServerUnpackerInfo returns information about the server unpacker. 91 ServerUnpackerInfo() ServerUnpackerInfo 92 93 // UnpackInPlace unpacks the packet in-place and returns target address, payload start offset, payload length, or an error if unpacking fails. 94 UnpackInPlace(b []byte, sourceAddrPort netip.AddrPort, packetStart, packetLen int) (targetAddr conn.Addr, payloadStart, payloadLen int, err error) 95 } 96 97 // SessionServerUnpacker is like ServerUnpacker but also provides a method to create server packers. 98 type SessionServerUnpacker interface { 99 ServerUnpacker 100 101 // NewPacker creates a new server session for the current client session and returns the server session's packer, or an error. 102 NewPacker() (ServerPacker, error) 103 } 104 105 // ClientPackUnpacker implements both ClientPacker and ClientUnpacker interfaces. 106 type ClientPackUnpacker interface { 107 ClientPacker 108 ClientUnpacker 109 } 110 111 // ServerPackUnpacker implements both ServerPacker and ServerUnpacker interfaces. 112 type ServerPackUnpacker interface { 113 ServerPacker 114 ServerUnpacker 115 } 116 117 // ClientServerPackerUnpackerTestFunc tests the client and server following these steps: 118 // 1. Client packer packs. 119 // 2. Server unpacker unpacks. 120 // 3. Server packer packs. 121 // 4. Client unpacker unpacks. 122 func ClientServerPackerUnpackerTestFunc(t tester, clientPacker ClientPacker, clientUnpacker ClientUnpacker, serverPacker ServerPacker, serverUnpacker ServerUnpacker) { 123 const ( 124 packetSize = 1452 125 payloadLen = 1280 126 ) 127 128 headroom := MaxHeadroom(clientPacker.ClientPackerInfo().Headroom, serverPacker.ServerPackerInfo().Headroom) 129 130 b := make([]byte, headroom.Front+payloadLen+headroom.Rear) 131 payload := b[headroom.Front : headroom.Front+payloadLen] 132 targetAddrPort := netip.AddrPortFrom(netip.IPv6Unspecified(), 53) 133 targetAddr := conn.AddrFromIPPort(targetAddrPort) 134 135 // Fill random payload. 136 _, err := rand.Read(payload) 137 if err != nil { 138 t.Fatal(err) 139 } 140 141 // Backup payload. 142 payloadBackup := make([]byte, len(payload)) 143 copy(payloadBackup, payload) 144 145 // Client packs. 146 destAddr, pkts, pktl, err := clientPacker.PackInPlace(b, targetAddr, headroom.Front, payloadLen) 147 if err != nil { 148 t.Fatal(err) 149 } 150 151 // Server unpacks. 152 ta, ps, pl, err := serverUnpacker.UnpackInPlace(b, destAddr, pkts, pktl) 153 if err != nil { 154 t.Fatal(err) 155 } 156 157 // Check target address. 158 if !ta.Equals(targetAddr) { 159 t.Errorf("Target address mismatch: c: %s, s: %s", targetAddr, ta) 160 } 161 162 // Check payload. 163 p := b[ps : ps+pl] 164 if !bytes.Equal(payloadBackup, p) { 165 t.Errorf("Payload mismatch: c: %v, s: %v", payloadBackup, p) 166 } 167 168 // Server packs. 169 pkts, pktl, err = serverPacker.PackInPlace(b, targetAddrPort, ps, pl, packetSize) 170 if err != nil { 171 t.Fatal(err) 172 } 173 174 // Client unpacks. 175 tap, ps, pl, err := clientUnpacker.UnpackInPlace(b, destAddr, pkts, pktl) 176 if err != nil { 177 t.Fatal(err) 178 } 179 180 // Check target address. 181 if tap != targetAddrPort { 182 t.Errorf("Target address mismatch: c: %s, s: %s", targetAddrPort, tap) 183 } 184 185 // Check payload. 186 p = b[ps : ps+pl] 187 if !bytes.Equal(payloadBackup, p) { 188 t.Errorf("Payload mismatch: c: %v, s: %v", payloadBackup, p) 189 } 190 }