github.com/eagleql/xray-core@v1.4.4/transport/internet/system_dialer.go (about) 1 package internet 2 3 import ( 4 "context" 5 "syscall" 6 "time" 7 8 "github.com/eagleql/xray-core/common" 9 "github.com/eagleql/xray-core/common/dice" 10 "github.com/eagleql/xray-core/common/net" 11 "github.com/eagleql/xray-core/common/net/cnc" 12 "github.com/eagleql/xray-core/common/session" 13 "github.com/eagleql/xray-core/features/dns" 14 "github.com/eagleql/xray-core/features/outbound" 15 "github.com/eagleql/xray-core/transport" 16 "github.com/eagleql/xray-core/transport/pipe" 17 ) 18 19 var ( 20 effectiveSystemDialer SystemDialer = &DefaultSystemDialer{} 21 ) 22 23 // InitSystemDialer: It's private method and you are NOT supposed to use this function. 24 func InitSystemDialer(dc dns.Client, om outbound.Manager) { 25 effectiveSystemDialer.Init(dc, om) 26 } 27 28 type SystemDialer interface { 29 Dial(ctx context.Context, source net.Address, destination net.Destination, sockopt *SocketConfig) (net.Conn, error) 30 Init(dc dns.Client, om outbound.Manager) 31 } 32 33 type DefaultSystemDialer struct { 34 controllers []controller 35 dns dns.Client 36 obm outbound.Manager 37 } 38 39 func resolveSrcAddr(network net.Network, src net.Address) net.Addr { 40 if src == nil || src == net.AnyIP { 41 return nil 42 } 43 44 if network == net.Network_TCP { 45 return &net.TCPAddr{ 46 IP: src.IP(), 47 Port: 0, 48 } 49 } 50 51 return &net.UDPAddr{ 52 IP: src.IP(), 53 Port: 0, 54 } 55 } 56 57 func hasBindAddr(sockopt *SocketConfig) bool { 58 return sockopt != nil && len(sockopt.BindAddress) > 0 && sockopt.BindPort > 0 59 } 60 61 func (d *DefaultSystemDialer) lookupIP(domain string, strategy DomainStrategy, localAddr net.Address) ([]net.IP, error) { 62 if d.dns == nil { 63 return nil, nil 64 } 65 66 var option = dns.IPOption{ 67 IPv4Enable: true, 68 IPv6Enable: true, 69 FakeEnable: false, 70 } 71 72 switch { 73 case strategy == DomainStrategy_USE_IP4 || (localAddr != nil && localAddr.Family().IsIPv4()): 74 option = dns.IPOption{ 75 IPv4Enable: true, 76 IPv6Enable: false, 77 FakeEnable: false, 78 } 79 case strategy == DomainStrategy_USE_IP6 || (localAddr != nil && localAddr.Family().IsIPv6()): 80 option = dns.IPOption{ 81 IPv4Enable: false, 82 IPv6Enable: true, 83 FakeEnable: false, 84 } 85 case strategy == DomainStrategy_AS_IS: 86 return nil, nil 87 } 88 89 return d.dns.LookupIP(domain, option) 90 } 91 92 func (d *DefaultSystemDialer) canLookupIP(ctx context.Context, dst net.Destination, sockopt *SocketConfig) bool { 93 if sockopt == nil || dst.Address.Family().IsIP() || d.dns == nil { 94 return false 95 } 96 if dst.Address.Domain() == LookupDomainFromContext(ctx) { 97 newError("infinite loop detected").AtError().WriteToLog(session.ExportIDToError(ctx)) 98 return false 99 } 100 return sockopt.DomainStrategy != DomainStrategy_AS_IS 101 } 102 103 func (d *DefaultSystemDialer) redirect(ctx context.Context, dst net.Destination, obt string) net.Conn { 104 newError("redirecting request " + dst.String() + " to " + obt).WriteToLog(session.ExportIDToError(ctx)) 105 h := d.obm.GetHandler(obt) 106 ctx = session.ContextWithOutbound(ctx, &session.Outbound{dst, nil}) 107 if h != nil { 108 ur, uw := pipe.New(pipe.OptionsFromContext(ctx)...) 109 dr, dw := pipe.New(pipe.OptionsFromContext(ctx)...) 110 111 go h.Dispatch(ctx, &transport.Link{ur, dw}) 112 nc := cnc.NewConnection( 113 cnc.ConnectionInputMulti(uw), 114 cnc.ConnectionOutputMulti(dr), 115 cnc.ConnectionOnClose(common.ChainedClosable{uw, dw}), 116 ) 117 return nc 118 } 119 return nil 120 } 121 122 func (d *DefaultSystemDialer) Dial(ctx context.Context, src net.Address, dest net.Destination, sockopt *SocketConfig) (net.Conn, error) { 123 newError("dialing to " + dest.String()).AtDebug().WriteToLog() 124 if d.obm != nil && sockopt != nil && len(sockopt.DialerProxy) > 0 { 125 nc := d.redirect(ctx, dest, sockopt.DialerProxy) 126 if nc != nil { 127 return nc, nil 128 } 129 } 130 131 if d.canLookupIP(ctx, dest, sockopt) { 132 ips, err := d.lookupIP(dest.Address.String(), sockopt.DomainStrategy, src) 133 if err == nil && len(ips) > 0 { 134 dest.Address = net.IPAddress(ips[dice.Roll(len(ips))]) 135 newError("replace destination with " + dest.String()).AtInfo().WriteToLog() 136 } else if err != nil { 137 newError("failed to resolve ip").Base(err).AtWarning().WriteToLog() 138 } 139 } 140 141 if dest.Network == net.Network_UDP && !hasBindAddr(sockopt) { 142 srcAddr := resolveSrcAddr(net.Network_UDP, src) 143 if srcAddr == nil { 144 srcAddr = &net.UDPAddr{ 145 IP: []byte{0, 0, 0, 0}, 146 Port: 0, 147 } 148 } 149 packetConn, err := ListenSystemPacket(ctx, srcAddr, sockopt) 150 if err != nil { 151 return nil, err 152 } 153 destAddr, err := net.ResolveUDPAddr("udp", dest.NetAddr()) 154 if err != nil { 155 return nil, err 156 } 157 return &PacketConnWrapper{ 158 conn: packetConn, 159 dest: destAddr, 160 }, nil 161 } 162 163 dialer := &net.Dialer{ 164 Timeout: time.Second * 16, 165 DualStack: true, 166 LocalAddr: resolveSrcAddr(dest.Network, src), 167 } 168 169 if sockopt != nil || len(d.controllers) > 0 { 170 dialer.Control = func(network, address string, c syscall.RawConn) error { 171 return c.Control(func(fd uintptr) { 172 if sockopt != nil { 173 if err := applyOutboundSocketOptions(network, address, fd, sockopt); err != nil { 174 newError("failed to apply socket options").Base(err).WriteToLog(session.ExportIDToError(ctx)) 175 } 176 if dest.Network == net.Network_UDP && hasBindAddr(sockopt) { 177 if err := bindAddr(fd, sockopt.BindAddress, sockopt.BindPort); err != nil { 178 newError("failed to bind source address to ", sockopt.BindAddress).Base(err).WriteToLog(session.ExportIDToError(ctx)) 179 } 180 } 181 } 182 183 for _, ctl := range d.controllers { 184 if err := ctl(network, address, fd); err != nil { 185 newError("failed to apply external controller").Base(err).WriteToLog(session.ExportIDToError(ctx)) 186 } 187 } 188 }) 189 } 190 } 191 192 return dialer.DialContext(ctx, dest.Network.SystemString(), dest.NetAddr()) 193 } 194 195 func (d *DefaultSystemDialer) Init(dc dns.Client, om outbound.Manager) { 196 d.dns = dc 197 d.obm = om 198 } 199 200 type PacketConnWrapper struct { 201 conn net.PacketConn 202 dest net.Addr 203 } 204 205 func (c *PacketConnWrapper) Close() error { 206 return c.conn.Close() 207 } 208 209 func (c *PacketConnWrapper) LocalAddr() net.Addr { 210 return c.conn.LocalAddr() 211 } 212 213 func (c *PacketConnWrapper) RemoteAddr() net.Addr { 214 return c.dest 215 } 216 217 func (c *PacketConnWrapper) Write(p []byte) (int, error) { 218 return c.conn.WriteTo(p, c.dest) 219 } 220 221 func (c *PacketConnWrapper) Read(p []byte) (int, error) { 222 n, _, err := c.conn.ReadFrom(p) 223 return n, err 224 } 225 226 func (c *PacketConnWrapper) WriteTo(p []byte, d net.Addr) (int, error) { 227 return c.conn.WriteTo(p, d) 228 } 229 230 func (c *PacketConnWrapper) ReadFrom(p []byte) (int, net.Addr, error) { 231 return c.conn.ReadFrom(p) 232 } 233 234 func (c *PacketConnWrapper) SetDeadline(t time.Time) error { 235 return c.conn.SetDeadline(t) 236 } 237 238 func (c *PacketConnWrapper) SetReadDeadline(t time.Time) error { 239 return c.conn.SetReadDeadline(t) 240 } 241 242 func (c *PacketConnWrapper) SetWriteDeadline(t time.Time) error { 243 return c.conn.SetWriteDeadline(t) 244 } 245 246 type SystemDialerAdapter interface { 247 Dial(network string, address string) (net.Conn, error) 248 } 249 250 type SimpleSystemDialer struct { 251 adapter SystemDialerAdapter 252 } 253 254 func WithAdapter(dialer SystemDialerAdapter) SystemDialer { 255 return &SimpleSystemDialer{ 256 adapter: dialer, 257 } 258 } 259 260 func (v *SimpleSystemDialer) Init(_ dns.Client, _ outbound.Manager) {} 261 262 func (v *SimpleSystemDialer) Dial(ctx context.Context, src net.Address, dest net.Destination, sockopt *SocketConfig) (net.Conn, error) { 263 return v.adapter.Dial(dest.Network.SystemString(), dest.NetAddr()) 264 } 265 266 // UseAlternativeSystemDialer replaces the current system dialer with a given one. 267 // Caller must ensure there is no race condition. 268 // 269 // xray:api:stable 270 func UseAlternativeSystemDialer(dialer SystemDialer) { 271 if dialer == nil { 272 effectiveSystemDialer = &DefaultSystemDialer{} 273 } 274 effectiveSystemDialer = dialer 275 } 276 277 // RegisterDialerController adds a controller to the effective system dialer. 278 // The controller can be used to operate on file descriptors before they are put into use. 279 // It only works when effective dialer is the default dialer. 280 // 281 // xray:api:beta 282 func RegisterDialerController(ctl func(network, address string, fd uintptr) error) error { 283 if ctl == nil { 284 return newError("nil listener controller") 285 } 286 287 dialer, ok := effectiveSystemDialer.(*DefaultSystemDialer) 288 if !ok { 289 return newError("RegisterListenerController not supported in custom dialer") 290 } 291 292 dialer.controllers = append(dialer.controllers, ctl) 293 return nil 294 }