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  }