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 }