github.com/database64128/shadowsocks-go@v1.10.2-0.20240315062903-143a773533f1/direct/udp.go (about) 1 package direct 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "io" 8 "net/netip" 9 "os" 10 11 "github.com/database64128/shadowsocks-go/conn" 12 "github.com/database64128/shadowsocks-go/socks5" 13 "github.com/database64128/shadowsocks-go/zerocopy" 14 "go.uber.org/zap" 15 ) 16 17 // DirectUDPClient implements the zerocopy UDPClient interface. 18 type DirectUDPClient struct { 19 info zerocopy.UDPClientInfo 20 session zerocopy.UDPClientSession 21 } 22 23 // NewDirectUDPClient creates a new UDP client that sends packets directly. 24 func NewDirectUDPClient(name, network string, mtu int, listenConfig conn.ListenConfig) *DirectUDPClient { 25 return &DirectUDPClient{ 26 info: zerocopy.UDPClientInfo{ 27 Name: name, 28 MTU: mtu, 29 ListenConfig: listenConfig, 30 }, 31 session: zerocopy.UDPClientSession{ 32 MaxPacketSize: zerocopy.MaxPacketSizeForAddr(mtu, netip.IPv4Unspecified()), 33 Packer: NewDirectPacketClientPacker(network, mtu), 34 Unpacker: DirectPacketClientUnpacker{}, 35 Close: zerocopy.NoopClose, 36 }, 37 } 38 } 39 40 // Info implements the zerocopy.UDPClient Info method. 41 func (c *DirectUDPClient) Info() zerocopy.UDPClientInfo { 42 return c.info 43 } 44 45 // NewSession implements the zerocopy.UDPClient NewSession method. 46 func (c *DirectUDPClient) NewSession(ctx context.Context) (zerocopy.UDPClientInfo, zerocopy.UDPClientSession, error) { 47 return c.info, c.session, nil 48 } 49 50 // ShadowsocksNoneUDPClient implements the zerocopy UDPClient interface. 51 type ShadowsocksNoneUDPClient struct { 52 network string 53 addr conn.Addr 54 info zerocopy.UDPClientInfo 55 } 56 57 // NewShadowsocksNoneUDPClient creates a new Shadowsocks none UDP client. 58 func NewShadowsocksNoneUDPClient(name, network string, addr conn.Addr, mtu int, listenConfig conn.ListenConfig) *ShadowsocksNoneUDPClient { 59 return &ShadowsocksNoneUDPClient{ 60 network: network, 61 addr: addr, 62 info: zerocopy.UDPClientInfo{ 63 Name: name, 64 PackerHeadroom: ShadowsocksNonePacketClientMessageHeadroom, 65 MTU: mtu, 66 ListenConfig: listenConfig, 67 }, 68 } 69 } 70 71 // Info implements the zerocopy.UDPClient Info method. 72 func (c *ShadowsocksNoneUDPClient) Info() zerocopy.UDPClientInfo { 73 return c.info 74 } 75 76 // NewSession implements the zerocopy.UDPClient NewSession method. 77 func (c *ShadowsocksNoneUDPClient) NewSession(ctx context.Context) (zerocopy.UDPClientInfo, zerocopy.UDPClientSession, error) { 78 addrPort, err := c.addr.ResolveIPPort(ctx, c.network) 79 if err != nil { 80 return c.info, zerocopy.UDPClientSession{}, fmt.Errorf("failed to resolve endpoint address: %w", err) 81 } 82 maxPacketSize := zerocopy.MaxPacketSizeForAddr(c.info.MTU, addrPort.Addr()) 83 84 return c.info, zerocopy.UDPClientSession{ 85 MaxPacketSize: maxPacketSize, 86 Packer: NewShadowsocksNonePacketClientPacker(addrPort, maxPacketSize), 87 Unpacker: NewShadowsocksNonePacketClientUnpacker(addrPort), 88 Close: zerocopy.NoopClose, 89 }, nil 90 } 91 92 // Socks5UDPClient implements the zerocopy UDPClient interface. 93 type Socks5UDPClient struct { 94 logger *zap.Logger 95 networkTCP string 96 networkIP string 97 address string 98 dialer conn.Dialer 99 info zerocopy.UDPClientInfo 100 } 101 102 // NewSocks5UDPClient creates a new SOCKS5 UDP client. 103 func NewSocks5UDPClient(logger *zap.Logger, name, networkTCP, networkIP, address string, dialer conn.Dialer, mtu int, listenConfig conn.ListenConfig) *Socks5UDPClient { 104 return &Socks5UDPClient{ 105 logger: logger, 106 networkTCP: networkTCP, 107 networkIP: networkIP, 108 address: address, 109 dialer: dialer, 110 info: zerocopy.UDPClientInfo{ 111 Name: name, 112 PackerHeadroom: Socks5PacketClientMessageHeadroom, 113 MTU: mtu, 114 ListenConfig: listenConfig, 115 }, 116 } 117 } 118 119 // Info implements the zerocopy.UDPClient Info method. 120 func (c *Socks5UDPClient) Info() zerocopy.UDPClientInfo { 121 return c.info 122 } 123 124 // NewSession implements the zerocopy.UDPClient NewSession method. 125 func (c *Socks5UDPClient) NewSession(ctx context.Context) (zerocopy.UDPClientInfo, zerocopy.UDPClientSession, error) { 126 tc, err := c.dialer.DialTCP(ctx, c.networkTCP, c.address, nil) 127 if err != nil { 128 return c.info, zerocopy.UDPClientSession{}, err 129 } 130 131 addr, err := socks5.ClientUDPAssociate(tc, conn.Addr{}) 132 if err != nil { 133 tc.Close() 134 return c.info, zerocopy.UDPClientSession{}, fmt.Errorf("failed to request UDP association: %w", err) 135 } 136 137 addrPort, err := addr.ResolveIPPort(ctx, c.networkIP) 138 if err != nil { 139 tc.Close() 140 return c.info, zerocopy.UDPClientSession{}, fmt.Errorf("failed to resolve endpoint address: %w", err) 141 } 142 maxPacketSize := zerocopy.MaxPacketSizeForAddr(c.info.MTU, addrPort.Addr()) 143 144 go func() { 145 b := make([]byte, 1) 146 _, err := tc.Read(b) 147 switch err { 148 case nil, io.EOF: 149 default: 150 if !errors.Is(err, os.ErrDeadlineExceeded) { 151 c.logger.Warn("Failed to keep TCP connection open for UDP association", 152 zap.String("client", c.info.Name), 153 zap.Error(err), 154 ) 155 } 156 } 157 tc.Close() 158 }() 159 160 return c.info, zerocopy.UDPClientSession{ 161 MaxPacketSize: maxPacketSize, 162 Packer: NewSocks5PacketClientPacker(addrPort, maxPacketSize), 163 Unpacker: NewSocks5PacketClientUnpacker(addrPort), 164 Close: func() error { 165 return tc.SetReadDeadline(conn.ALongTimeAgo) 166 }, 167 }, nil 168 } 169 170 // DirectUDPNATServer implements the zerocopy UDPNATServer interface. 171 type DirectUDPNATServer struct { 172 p *DirectPacketServerPackUnpacker 173 } 174 175 func NewDirectUDPNATServer(targetAddr conn.Addr, targetAddrOnly bool) *DirectUDPNATServer { 176 return &DirectUDPNATServer{ 177 p: NewDirectPacketServerPackUnpacker(targetAddr, targetAddrOnly), 178 } 179 } 180 181 // Info implements the zerocopy.UDPNATServer Info method. 182 func (s *DirectUDPNATServer) Info() zerocopy.UDPNATServerInfo { 183 return zerocopy.UDPNATServerInfo{} 184 } 185 186 // NewUnpacker implements the zerocopy.UDPNATServer NewUnpacker method. 187 func (s *DirectUDPNATServer) NewUnpacker() (zerocopy.ServerUnpacker, error) { 188 return s.p, nil 189 } 190 191 // ShadowsocksNoneUDPNATServer implements the zerocopy UDPNATServer interface. 192 type ShadowsocksNoneUDPNATServer struct{} 193 194 // Info implements the zerocopy.UDPNATServer Info method. 195 func (ShadowsocksNoneUDPNATServer) Info() zerocopy.UDPNATServerInfo { 196 return zerocopy.UDPNATServerInfo{ 197 UnpackerHeadroom: ShadowsocksNonePacketClientMessageHeadroom, 198 } 199 } 200 201 // NewUnpacker implements the zerocopy.UDPNATServer NewUnpacker method. 202 func (ShadowsocksNoneUDPNATServer) NewUnpacker() (zerocopy.ServerUnpacker, error) { 203 return &ShadowsocksNonePacketServerUnpacker{}, nil 204 } 205 206 // Socks5UDPNATServer implements the zerocopy UDPNATServer interface. 207 type Socks5UDPNATServer struct{} 208 209 // Info implements the zerocopy.UDPNATServer Info method. 210 func (Socks5UDPNATServer) Info() zerocopy.UDPNATServerInfo { 211 return zerocopy.UDPNATServerInfo{ 212 UnpackerHeadroom: Socks5PacketClientMessageHeadroom, 213 } 214 } 215 216 // NewUnpacker implements the zerocopy.UDPNATServer NewUnpacker method. 217 func (Socks5UDPNATServer) NewUnpacker() (zerocopy.ServerUnpacker, error) { 218 return &Socks5PacketServerUnpacker{}, nil 219 }