github.com/database64128/shadowsocks-go@v1.10.2-0.20240315062903-143a773533f1/ss2022/udp.go (about)

     1  package ss2022
     2  
     3  import (
     4  	"context"
     5  	"crypto/cipher"
     6  	"crypto/rand"
     7  	"crypto/subtle"
     8  	"encoding/binary"
     9  	"fmt"
    10  
    11  	"github.com/database64128/shadowsocks-go/conn"
    12  	"github.com/database64128/shadowsocks-go/zerocopy"
    13  )
    14  
    15  // UDPClient implements the zerocopy UDPClient interface.
    16  type UDPClient struct {
    17  	network          string
    18  	addr             conn.Addr
    19  	info             zerocopy.UDPClientInfo
    20  	nonAEADHeaderLen int
    21  	filterSize       uint64
    22  	cipherConfig     *ClientCipherConfig
    23  	shouldPad        PaddingPolicy
    24  }
    25  
    26  func NewUDPClient(name, network string, addr conn.Addr, mtu int, listenConfig conn.ListenConfig, filterSize uint64, cipherConfig *ClientCipherConfig, shouldPad PaddingPolicy) *UDPClient {
    27  	identityHeadersLen := IdentityHeaderLength * len(cipherConfig.iPSKs)
    28  	return &UDPClient{
    29  		network: network,
    30  		addr:    addr,
    31  		info: zerocopy.UDPClientInfo{
    32  			Name:           name,
    33  			PackerHeadroom: ShadowPacketClientMessageHeadroom(identityHeadersLen),
    34  			MTU:            mtu,
    35  			ListenConfig:   listenConfig,
    36  		},
    37  		nonAEADHeaderLen: UDPSeparateHeaderLength + identityHeadersLen,
    38  		filterSize:       filterSize,
    39  		cipherConfig:     cipherConfig,
    40  		shouldPad:        shouldPad,
    41  	}
    42  }
    43  
    44  // Info implements the zerocopy.UDPClient Info method.
    45  func (c *UDPClient) Info() zerocopy.UDPClientInfo {
    46  	return c.info
    47  }
    48  
    49  // NewSession implements the zerocopy.UDPClient NewSession method.
    50  func (c *UDPClient) NewSession(ctx context.Context) (zerocopy.UDPClientInfo, zerocopy.UDPClientSession, error) {
    51  	addrPort, err := c.addr.ResolveIPPort(ctx, c.network)
    52  	if err != nil {
    53  		return c.info, zerocopy.UDPClientSession{}, fmt.Errorf("failed to resolve endpoint address: %w", err)
    54  	}
    55  	maxPacketSize := zerocopy.MaxPacketSizeForAddr(c.info.MTU, addrPort.Addr())
    56  
    57  	salt := make([]byte, 8)
    58  	if _, err = rand.Read(salt); err != nil {
    59  		return c.info, zerocopy.UDPClientSession{}, err
    60  	}
    61  	csid := binary.BigEndian.Uint64(salt)
    62  	aead, err := c.cipherConfig.AEAD(salt)
    63  	if err != nil {
    64  		return c.info, zerocopy.UDPClientSession{}, err
    65  	}
    66  
    67  	return c.info, zerocopy.UDPClientSession{
    68  		MaxPacketSize: maxPacketSize,
    69  		Packer: &ShadowPacketClientPacker{
    70  			csid:             csid,
    71  			aead:             aead,
    72  			block:            c.cipherConfig.UDPSeparateHeaderPackerCipher(),
    73  			shouldPad:        c.shouldPad,
    74  			eihCiphers:       c.cipherConfig.UDPIdentityHeaderCiphers(),
    75  			eihPSKHashes:     c.cipherConfig.EIHPSKHashes(),
    76  			maxPacketSize:    maxPacketSize,
    77  			nonAEADHeaderLen: c.nonAEADHeaderLen,
    78  			info: zerocopy.ClientPackerInfo{
    79  				Headroom: c.info.PackerHeadroom,
    80  			},
    81  			serverAddrPort: addrPort,
    82  		},
    83  		Unpacker: &ShadowPacketClientUnpacker{
    84  			csid:         csid,
    85  			filterSize:   c.filterSize,
    86  			cipherConfig: c.cipherConfig,
    87  		},
    88  		Close: zerocopy.NoopClose,
    89  	}, nil
    90  }
    91  
    92  // UDPServer implements the zerocopy UDPSessionServer interface.
    93  type UDPServer struct {
    94  	CredStore
    95  	info                 zerocopy.UDPSessionServerInfo
    96  	filterSize           uint64
    97  	identityHeaderLen    int
    98  	block                cipher.Block
    99  	identityCipherConfig ServerIdentityCipherConfig
   100  	shouldPad            PaddingPolicy
   101  	userCipherConfig     UserCipherConfig
   102  }
   103  
   104  func NewUDPServer(filterSize uint64, userCipherConfig UserCipherConfig, identityCipherConfig ServerIdentityCipherConfig, shouldPad PaddingPolicy) *UDPServer {
   105  	var identityHeaderLen int
   106  	block := userCipherConfig.Block()
   107  	if block == nil {
   108  		identityHeaderLen = IdentityHeaderLength
   109  		block = identityCipherConfig.UDP()
   110  	}
   111  
   112  	return &UDPServer{
   113  		info: zerocopy.UDPSessionServerInfo{
   114  			UnpackerHeadroom: ShadowPacketClientMessageHeadroom(identityHeaderLen),
   115  			MinNATTimeout:    ReplayWindowDuration,
   116  		},
   117  		filterSize:           filterSize,
   118  		identityHeaderLen:    identityHeaderLen,
   119  		block:                block,
   120  		identityCipherConfig: identityCipherConfig,
   121  		shouldPad:            shouldPad,
   122  		userCipherConfig:     userCipherConfig,
   123  	}
   124  }
   125  
   126  // Info implements the zerocopy.UDPSessionServer Info method.
   127  func (s *UDPServer) Info() zerocopy.UDPSessionServerInfo {
   128  	return s.info
   129  }
   130  
   131  // SessionInfo implements the zerocopy.UDPSessionServer SessionInfo method.
   132  func (s *UDPServer) SessionInfo(b []byte) (csid uint64, err error) {
   133  	if len(b) < UDPSeparateHeaderLength {
   134  		err = fmt.Errorf("%w: %d", zerocopy.ErrPacketTooSmall, len(b))
   135  		return
   136  	}
   137  
   138  	s.block.Decrypt(b, b)
   139  
   140  	csid = binary.BigEndian.Uint64(b)
   141  	return
   142  }
   143  
   144  // NewUnpacker implements the zerocopy.UDPSessionServer NewUnpacker method.
   145  func (s *UDPServer) NewUnpacker(b []byte, csid uint64) (zerocopy.ServerUnpacker, string, error) {
   146  	nonAEADHeaderLen := UDPSeparateHeaderLength + s.identityHeaderLen
   147  
   148  	if len(b) < nonAEADHeaderLen {
   149  		return nil, "", fmt.Errorf("%w: %d", zerocopy.ErrPacketTooSmall, len(b))
   150  	}
   151  
   152  	userCipherConfig := s.userCipherConfig
   153  	var username string
   154  
   155  	// Process identity header.
   156  	if s.identityHeaderLen != 0 {
   157  		separateHeader := b[:UDPSeparateHeaderLength]
   158  		identityHeader := b[UDPSeparateHeaderLength:nonAEADHeaderLen]
   159  		s.block.Decrypt(identityHeader, identityHeader)
   160  		subtle.XORBytes(identityHeader, identityHeader, separateHeader)
   161  		uPSKHash := *(*[IdentityHeaderLength]byte)(identityHeader)
   162  		serverUserCipherConfig := s.ulm[uPSKHash]
   163  		if serverUserCipherConfig == nil {
   164  			return nil, "", ErrIdentityHeaderUserPSKNotFound
   165  		}
   166  		userCipherConfig = serverUserCipherConfig.UserCipherConfig
   167  		username = serverUserCipherConfig.Name
   168  	}
   169  
   170  	aead, err := userCipherConfig.AEAD(b[:8])
   171  	if err != nil {
   172  		return nil, "", err
   173  	}
   174  
   175  	return &ShadowPacketServerUnpacker{
   176  		csid:             csid,
   177  		aead:             aead,
   178  		filterSize:       s.filterSize,
   179  		nonAEADHeaderLen: nonAEADHeaderLen,
   180  		info: zerocopy.ServerUnpackerInfo{
   181  			Headroom: s.info.UnpackerHeadroom,
   182  		},
   183  		userCipherConfig: userCipherConfig,
   184  		packerShouldPad:  s.shouldPad,
   185  	}, username, nil
   186  }