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