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  }