github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/transport/internet/dialer.go (about) 1 package internet 2 3 import ( 4 "context" 5 6 "github.com/v2fly/v2ray-core/v5/common/net" 7 "github.com/v2fly/v2ray-core/v5/common/session" 8 "github.com/v2fly/v2ray-core/v5/transport/internet/tagged" 9 ) 10 11 // Dialer is the interface for dialing outbound connections. 12 type Dialer interface { 13 // Dial dials a system connection to the given destination. 14 Dial(ctx context.Context, destination net.Destination) (Connection, error) 15 16 // Address returns the address used by this Dialer. Maybe nil if not known. 17 Address() net.Address 18 } 19 20 // dialFunc is an interface to dial network connection to a specific destination. 21 type dialFunc func(ctx context.Context, dest net.Destination, streamSettings *MemoryStreamConfig) (Connection, error) 22 23 var transportDialerCache = make(map[string]dialFunc) 24 25 // RegisterTransportDialer registers a Dialer with given name. 26 func RegisterTransportDialer(protocol string, dialer dialFunc) error { 27 if _, found := transportDialerCache[protocol]; found { 28 return newError(protocol, " dialer already registered").AtError() 29 } 30 transportDialerCache[protocol] = dialer 31 return nil 32 } 33 34 // Dial dials a internet connection towards the given destination. 35 func Dial(ctx context.Context, dest net.Destination, streamSettings *MemoryStreamConfig) (Connection, error) { 36 if dest.Network == net.Network_TCP { 37 if streamSettings == nil { 38 s, err := ToMemoryStreamConfig(nil) 39 if err != nil { 40 return nil, newError("failed to create default stream settings").Base(err) 41 } 42 streamSettings = s 43 } 44 45 protocol := streamSettings.ProtocolName 46 47 if originalProtocolName := getOriginalMessageName(streamSettings); originalProtocolName != "" { 48 protocol = originalProtocolName 49 } 50 51 dialer := transportDialerCache[protocol] 52 if dialer == nil { 53 return nil, newError(protocol, " dialer not registered").AtError() 54 } 55 return dialer(ctx, dest, streamSettings) 56 } 57 58 if dest.Network == net.Network_UDP { 59 udpDialer := transportDialerCache["udp"] 60 if udpDialer == nil { 61 return nil, newError("UDP dialer not registered").AtError() 62 } 63 return udpDialer(ctx, dest, streamSettings) 64 } 65 66 return nil, newError("unknown network ", dest.Network) 67 } 68 69 // DialSystem calls system dialer to create a network connection. 70 func DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig) (net.Conn, error) { 71 outbound := session.OutboundFromContext(ctx) 72 73 var src net.Address 74 if outbound != nil { 75 src = outbound.Gateway 76 } 77 78 if transportLayerOutgoingTag := session.GetTransportLayerProxyTagFromContext(ctx); transportLayerOutgoingTag != "" { 79 return DialTaggedOutbound(ctx, dest, transportLayerOutgoingTag) 80 } 81 82 originalAddr := dest.Address 83 if outbound != nil && outbound.Resolver != nil && dest.Address.Family().IsDomain() { 84 if addr := outbound.Resolver(ctx, dest.Address.Domain()); addr != nil { 85 dest.Address = addr 86 } 87 } 88 89 switch { 90 case src != nil && dest.Address != originalAddr: 91 newError("dialing to ", dest, " resolved from ", originalAddr, " via ", src).WriteToLog(session.ExportIDToError(ctx)) 92 case src != nil: 93 newError("dialing to ", dest, " via ", src).WriteToLog(session.ExportIDToError(ctx)) 94 case dest.Address != originalAddr: 95 newError("dialing to ", dest, " resolved from ", originalAddr).WriteToLog(session.ExportIDToError(ctx)) 96 } 97 98 return effectiveSystemDialer.Dial(ctx, src, dest, sockopt) 99 } 100 101 func DialTaggedOutbound(ctx context.Context, dest net.Destination, tag string) (net.Conn, error) { 102 if tagged.Dialer == nil { 103 return nil, newError("tagged dial not enabled") 104 } 105 return tagged.Dialer(ctx, dest, tag) 106 }