github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/proxy/shadowsocks2022/client.go (about) 1 package shadowsocks2022 2 3 import ( 4 "context" 5 gonet "net" 6 "sync" 7 "time" 8 9 "github.com/v2fly/v2ray-core/v5/common" 10 "github.com/v2fly/v2ray-core/v5/common/buf" 11 "github.com/v2fly/v2ray-core/v5/common/environment" 12 "github.com/v2fly/v2ray-core/v5/common/environment/envctx" 13 "github.com/v2fly/v2ray-core/v5/common/net" 14 "github.com/v2fly/v2ray-core/v5/common/net/packetaddr" 15 "github.com/v2fly/v2ray-core/v5/common/retry" 16 "github.com/v2fly/v2ray-core/v5/common/session" 17 "github.com/v2fly/v2ray-core/v5/common/signal" 18 "github.com/v2fly/v2ray-core/v5/common/task" 19 "github.com/v2fly/v2ray-core/v5/transport" 20 "github.com/v2fly/v2ray-core/v5/transport/internet" 21 "github.com/v2fly/v2ray-core/v5/transport/internet/udp" 22 ) 23 24 type Client struct { 25 config *ClientConfig 26 ctx context.Context 27 } 28 29 const UDPConnectionState = "UDPConnectionState" 30 31 type ClientUDPConnState struct { 32 session *ClientUDPSession 33 initOnce *sync.Once 34 } 35 36 func (c *ClientUDPConnState) GetOrCreateSession(create func() (*ClientUDPSession, error)) (*ClientUDPSession, error) { 37 var errOuter error 38 c.initOnce.Do(func() { 39 sessionState, err := create() 40 if err != nil { 41 errOuter = newError("failed to create UDP session").Base(err) 42 return 43 } 44 c.session = sessionState 45 }) 46 if errOuter != nil { 47 return nil, newError("failed to initialize UDP State").Base(errOuter) 48 } 49 return c.session, nil 50 } 51 52 func NewClientUDPConnState() (*ClientUDPConnState, error) { 53 return &ClientUDPConnState{initOnce: &sync.Once{}}, nil 54 } 55 56 func (c *Client) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error { 57 outbound := session.OutboundFromContext(ctx) 58 if outbound == nil || !outbound.Target.IsValid() { 59 return newError("target not specified") 60 } 61 destination := outbound.Target 62 network := destination.Network 63 64 keyDerivation := newBLAKE3KeyDerivation() 65 var method Method 66 switch c.config.Method { 67 case "2022-blake3-aes-128-gcm": 68 method = newAES128GCMMethod() 69 case "2022-blake3-aes-256-gcm": 70 method = newAES256GCMMethod() 71 default: 72 return newError("unknown method: ", c.config.Method) 73 } 74 75 effectivePsk := c.config.Psk 76 77 ctx, cancel := context.WithCancel(ctx) 78 timer := signal.CancelAfterInactivity(ctx, cancel, time.Minute) 79 80 if packetConn, err := packetaddr.ToPacketAddrConn(link, destination); err == nil { 81 udpSession, err := c.getUDPSession(c.ctx, network, dialer, method, keyDerivation) 82 if err != nil { 83 return newError("failed to get UDP udpSession").Base(err) 84 } 85 requestDone := func() error { 86 return udp.CopyPacketConn(udpSession, packetConn, udp.UpdateActivity(timer)) 87 } 88 responseDone := func() error { 89 return udp.CopyPacketConn(packetConn, udpSession, udp.UpdateActivity(timer)) 90 } 91 responseDoneAndCloseWriter := task.OnSuccess(responseDone, task.Close(link.Writer)) 92 if err := task.Run(ctx, requestDone, responseDoneAndCloseWriter); err != nil { 93 return newError("connection ends").Base(err) 94 } 95 return nil 96 } 97 98 if network == net.Network_TCP { 99 var conn internet.Connection 100 err := retry.ExponentialBackoff(5, 100).On(func() error { 101 dest := net.TCPDestination(c.config.Address.AsAddress(), net.Port(c.config.Port)) 102 dest.Network = network 103 rawConn, err := dialer.Dial(ctx, dest) 104 if err != nil { 105 return err 106 } 107 conn = rawConn 108 109 return nil 110 }) 111 if err != nil { 112 return newError("failed to find an available destination").AtWarning().Base(err) 113 } 114 newError("tunneling request to ", destination, " via ", network, ":", net.TCPDestination(c.config.Address.AsAddress(), net.Port(c.config.Port)).NetAddr()).WriteToLog(session.ExportIDToError(ctx)) 115 defer conn.Close() 116 117 request := &TCPRequest{ 118 keyDerivation: keyDerivation, 119 method: method, 120 } 121 TCPRequestBuffer := buf.New() 122 defer TCPRequestBuffer.Release() 123 err = request.EncodeTCPRequestHeader(effectivePsk, c.config.Ipsk, destination.Address, 124 int(destination.Port), nil, TCPRequestBuffer) 125 if err != nil { 126 return newError("failed to encode TCP request header").Base(err) 127 } 128 _, err = conn.Write(TCPRequestBuffer.Bytes()) 129 if err != nil { 130 return newError("failed to write TCP request header").Base(err) 131 } 132 requestDone := func() error { 133 encodedWriter := request.CreateClientC2SWriter(conn) 134 return buf.Copy(link.Reader, encodedWriter, buf.UpdateActivity(timer)) 135 } 136 responseDone := func() error { 137 err = request.DecodeTCPResponseHeader(effectivePsk, conn) 138 if err != nil { 139 return newError("failed to decode TCP response header").Base(err) 140 } 141 if err = request.CheckC2SConnectionConstraint(); err != nil { 142 return newError("C2S connection constraint violation").Base(err) 143 } 144 initialPayload := buf.NewWithSize(65535) 145 encodedReader, err := request.CreateClientS2CReader(conn, initialPayload) 146 if err != nil { 147 return newError("failed to create client S2C reader").Base(err) 148 } 149 err = link.Writer.WriteMultiBuffer(buf.MultiBuffer{initialPayload}) 150 if err != nil { 151 return newError("failed to write initial payload").Base(err) 152 } 153 return buf.Copy(encodedReader, link.Writer, buf.UpdateActivity(timer)) 154 } 155 responseDoneAndCloseWriter := task.OnSuccess(responseDone, task.Close(link.Writer)) 156 if err := task.Run(ctx, requestDone, responseDoneAndCloseWriter); err != nil { 157 return newError("connection ends").Base(err) 158 } 159 return nil 160 } else { 161 udpSession, err := c.getUDPSession(c.ctx, network, dialer, method, keyDerivation) 162 if err != nil { 163 return newError("failed to get UDP udpSession").Base(err) 164 } 165 monoDestUDPConn := udp.NewMonoDestUDPConn(udpSession, &gonet.UDPAddr{IP: destination.Address.IP(), Port: int(destination.Port)}) 166 requestDone := func() error { 167 return buf.Copy(link.Reader, monoDestUDPConn, buf.UpdateActivity(timer)) 168 } 169 responseDone := func() error { 170 return buf.Copy(monoDestUDPConn, link.Writer, buf.UpdateActivity(timer)) 171 } 172 responseDoneAndCloseWriter := task.OnSuccess(responseDone, task.Close(link.Writer)) 173 if err := task.Run(ctx, requestDone, responseDoneAndCloseWriter); err != nil { 174 return newError("connection ends").Base(err) 175 } 176 return nil 177 } 178 } 179 180 func (c *Client) getUDPSession(ctx context.Context, network net.Network, dialer internet.Dialer, method Method, keyDerivation *BLAKE3KeyDerivation) (internet.AbstractPacketConn, error) { 181 storage := envctx.EnvironmentFromContext(ctx).(environment.ProxyEnvironment).TransientStorage() 182 clientUDPStateIfce, err := storage.Get(ctx, UDPConnectionState) 183 if err != nil { 184 return nil, newError("failed to get UDP connection state").Base(err) 185 } 186 clientUDPState, ok := clientUDPStateIfce.(*ClientUDPConnState) 187 if !ok { 188 return nil, newError("failed to cast UDP connection state") 189 } 190 191 sessionState, err := clientUDPState.GetOrCreateSession(func() (*ClientUDPSession, error) { 192 var conn internet.Connection 193 err := retry.ExponentialBackoff(5, 100).On(func() error { 194 dest := net.TCPDestination(c.config.Address.AsAddress(), net.Port(c.config.Port)) 195 dest.Network = network 196 rawConn, err := dialer.Dial(ctx, dest) 197 if err != nil { 198 return err 199 } 200 conn = rawConn 201 202 return nil 203 }) 204 if err != nil { 205 return nil, newError("failed to find an available destination").AtWarning().Base(err) 206 } 207 newError("creating udp session to ", network, ":", c.config.Address).WriteToLog(session.ExportIDToError(ctx)) 208 packetProcessor, err := method.GetUDPClientProcessor(c.config.Ipsk, c.config.Psk, keyDerivation) 209 if err != nil { 210 return nil, newError("failed to create UDP client packet processor").Base(err) 211 } 212 return NewClientUDPSession(ctx, conn, packetProcessor), nil 213 }) 214 if err != nil { 215 return nil, newError("failed to create UDP session").Base(err) 216 } 217 sessionConn, err := sessionState.NewSessionConn() 218 if err != nil { 219 return nil, newError("failed to create UDP session connection").Base(err) 220 } 221 return sessionConn, nil 222 } 223 224 func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) { 225 storage := envctx.EnvironmentFromContext(ctx).(environment.ProxyEnvironment).TransientStorage() 226 227 udpState, err := NewClientUDPConnState() 228 if err != nil { 229 return nil, newError("failed to create UDP connection state").Base(err) 230 } 231 storage.Put(ctx, UDPConnectionState, udpState) 232 233 return &Client{ 234 config: config, 235 ctx: ctx, 236 }, nil 237 } 238 239 func init() { 240 common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { 241 clientConfig, ok := config.(*ClientConfig) 242 if !ok { 243 return nil, newError("not a ClientConfig") 244 } 245 return NewClient(ctx, clientConfig) 246 })) 247 }