Sockopt: Fix some domainStrategy & dialerProxy bugs (#4661)

This commit is contained in:
patterniha 2025-04-29 12:03:36 +03:30 committed by GitHub
parent d9ebb9b2dc
commit 1c4e246788
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -87,7 +87,7 @@ var (
func lookupIP(domain string, strategy DomainStrategy, localAddr net.Address) ([]net.IP, error) { func lookupIP(domain string, strategy DomainStrategy, localAddr net.Address) ([]net.IP, error) {
if dnsClient == nil { if dnsClient == nil {
return nil, nil return nil, errors.New("DNS client not initialized").AtError()
} }
ips, _, err := dnsClient.LookupIP(domain, dns.IPOption{ ips, _, err := dnsClient.LookupIP(domain, dns.IPOption{
@ -103,26 +103,28 @@ func lookupIP(domain string, strategy DomainStrategy, localAddr net.Address) ([]
} }
} }
if err == nil && len(ips) == 0 {
return nil, dns.ErrEmptyResponse
}
return ips, err return ips, err
} }
func canLookupIP(ctx context.Context, dst net.Destination, sockopt *SocketConfig) bool { func canLookupIP(dst net.Destination, sockopt *SocketConfig) bool {
if dst.Address.Family().IsIP() || dnsClient == nil { if dst.Address.Family().IsIP() {
return false return false
} }
return sockopt.DomainStrategy.hasStrategy() return sockopt.DomainStrategy.hasStrategy()
} }
func redirect(ctx context.Context, dst net.Destination, obt string) net.Conn { func redirect(ctx context.Context, dst net.Destination, obt string, h outbound.Handler) net.Conn {
errors.LogInfo(ctx, "redirecting request "+dst.String()+" to "+obt) errors.LogInfo(ctx, "redirecting request "+dst.String()+" to "+obt)
h := obm.GetHandler(obt)
outbounds := session.OutboundsFromContext(ctx) outbounds := session.OutboundsFromContext(ctx)
ctx = session.ContextWithOutbounds(ctx, append(outbounds, &session.Outbound{ ctx = session.ContextWithOutbounds(ctx, append(outbounds, &session.Outbound{
Target: dst, Target: dst,
Gateway: nil, Gateway: nil,
Tag: obt, Tag: obt,
})) // add another outbound in session ctx })) // add another outbound in session ctx
if h != nil {
ur, uw := pipe.New(pipe.OptionsFromContext(ctx)...) ur, uw := pipe.New(pipe.OptionsFromContext(ctx)...)
dr, dw := pipe.New(pipe.OptionsFromContext(ctx)...) dr, dw := pipe.New(pipe.OptionsFromContext(ctx)...)
@ -139,8 +141,7 @@ func redirect(ctx context.Context, dst net.Destination, obt string) net.Conn {
cnc.ConnectionOnClose(common.ChainedClosable{uw, dw}), cnc.ConnectionOnClose(common.ChainedClosable{uw, dw}),
) )
return nc return nc
}
return nil
} }
func checkAddressPortStrategy(ctx context.Context, dest net.Destination, sockopt *SocketConfig) (*net.Destination, error) { func checkAddressPortStrategy(ctx context.Context, dest net.Destination, sockopt *SocketConfig) (*net.Destination, error) {
@ -247,21 +248,28 @@ func DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig
dest = *newDest dest = *newDest
} }
if canLookupIP(ctx, dest, sockopt) { if canLookupIP(dest, sockopt) {
ips, err := lookupIP(dest.Address.String(), sockopt.DomainStrategy, src) ips, err := lookupIP(dest.Address.String(), sockopt.DomainStrategy, src)
if err == nil && len(ips) > 0 { if err != nil {
errors.LogErrorInner(ctx, err, "failed to resolve ip")
if sockopt.DomainStrategy.forceIP() {
return nil, err
}
} else {
dest.Address = net.IPAddress(ips[dice.Roll(len(ips))]) dest.Address = net.IPAddress(ips[dice.Roll(len(ips))])
errors.LogInfo(ctx, "replace destination with "+dest.String()) errors.LogInfo(ctx, "replace destination with "+dest.String())
} else if err != nil {
errors.LogWarningInner(ctx, err, "failed to resolve ip")
} }
} }
if obm != nil && len(sockopt.DialerProxy) > 0 { if len(sockopt.DialerProxy) > 0 {
nc := redirect(ctx, dest, sockopt.DialerProxy) if obm == nil {
if nc != nil { return nil, errors.New("there is no outbound manager for dialerProxy").AtError()
return nc, nil
} }
h := obm.GetHandler(sockopt.DialerProxy)
if h == nil {
return nil, errors.New("there is no outbound handler for dialerProxy").AtError()
}
return redirect(ctx, dest, sockopt.DialerProxy, h), nil
} }
return effectiveSystemDialer.Dial(ctx, src, dest, sockopt) return effectiveSystemDialer.Dial(ctx, src, dest, sockopt)