mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-04-30 09:18:34 +00:00
Sockopt: Add addressPortStrategy
(query SRV or TXT) (#4416)
Co-authored-by: 风扇滑翔翼 <Fangliding.fshxy@outlook.com>
This commit is contained in:
parent
8d46f7e14c
commit
b9cb93d3c2
4 changed files with 280 additions and 64 deletions
|
@ -2,6 +2,9 @@ package internet
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
gonet "net"
|
||||
"strings"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/dice"
|
||||
|
@ -140,6 +143,93 @@ func redirect(ctx context.Context, dst net.Destination, obt string) net.Conn {
|
|||
return nil
|
||||
}
|
||||
|
||||
func checkAddressPortStrategy(ctx context.Context, dest net.Destination, sockopt *SocketConfig) (*net.Destination, error) {
|
||||
if sockopt.AddressPortStrategy == AddressPortStrategy_None {
|
||||
return nil, nil
|
||||
}
|
||||
newDest := dest
|
||||
var OverridePort, OverrideAddress bool
|
||||
var OverrideBy string
|
||||
switch sockopt.AddressPortStrategy {
|
||||
case AddressPortStrategy_SrvPortOnly:
|
||||
OverridePort = true
|
||||
OverrideAddress = false
|
||||
OverrideBy = "srv"
|
||||
case AddressPortStrategy_SrvAddressOnly:
|
||||
OverridePort = false
|
||||
OverrideAddress = true
|
||||
OverrideBy = "srv"
|
||||
case AddressPortStrategy_SrvPortAndAddress:
|
||||
OverridePort = true
|
||||
OverrideAddress = true
|
||||
OverrideBy = "srv"
|
||||
case AddressPortStrategy_TxtPortOnly:
|
||||
OverridePort = true
|
||||
OverrideAddress = false
|
||||
OverrideBy = "txt"
|
||||
case AddressPortStrategy_TxtAddressOnly:
|
||||
OverridePort = false
|
||||
OverrideAddress = true
|
||||
OverrideBy = "txt"
|
||||
case AddressPortStrategy_TxtPortAndAddress:
|
||||
OverridePort = true
|
||||
OverrideAddress = true
|
||||
OverrideBy = "txt"
|
||||
default:
|
||||
return nil, errors.New("unknown AddressPortStrategy")
|
||||
}
|
||||
|
||||
if !dest.Address.Family().IsDomain() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if OverrideBy == "srv" {
|
||||
errors.LogDebug(ctx, "query SRV record for "+dest.Address.String())
|
||||
parts := strings.SplitN(dest.Address.String(), ".", 3)
|
||||
if len(parts) != 3 {
|
||||
return nil, errors.New("invalid address format", dest.Address.String())
|
||||
}
|
||||
_, srvRecords, err := gonet.DefaultResolver.LookupSRV(context.Background(), parts[0][1:], parts[1][1:], parts[2])
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to lookup SRV record").Base(err)
|
||||
}
|
||||
errors.LogDebug(ctx, "SRV record: "+fmt.Sprintf("addr=%s, port=%d, priority=%d, weight=%d", srvRecords[0].Target, srvRecords[0].Port, srvRecords[0].Priority, srvRecords[0].Weight))
|
||||
if OverridePort {
|
||||
newDest.Port = net.Port(srvRecords[0].Port)
|
||||
}
|
||||
if OverrideAddress {
|
||||
newDest.Address = net.ParseAddress(srvRecords[0].Target)
|
||||
}
|
||||
return &newDest, nil
|
||||
}
|
||||
if OverrideBy == "txt" {
|
||||
errors.LogDebug(ctx, "query TXT record for "+dest.Address.String())
|
||||
txtRecords, err := gonet.DefaultResolver.LookupTXT(ctx, dest.Address.String())
|
||||
if err != nil {
|
||||
errors.LogError(ctx, "failed to lookup SRV record: "+err.Error())
|
||||
return nil, errors.New("failed to lookup SRV record").Base(err)
|
||||
}
|
||||
for _, txtRecord := range txtRecords {
|
||||
errors.LogDebug(ctx, "TXT record: "+txtRecord)
|
||||
addr_s, port_s, _ := net.SplitHostPort(string(txtRecord))
|
||||
addr := net.ParseAddress(addr_s)
|
||||
port, err := net.PortFromString(port_s)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if OverridePort {
|
||||
newDest.Port = port
|
||||
}
|
||||
if OverrideAddress {
|
||||
newDest.Address = addr
|
||||
}
|
||||
return &newDest, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// DialSystem calls system dialer to create a network connection.
|
||||
func DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig) (net.Conn, error) {
|
||||
var src net.Address
|
||||
|
@ -152,6 +242,11 @@ func DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig
|
|||
return effectiveSystemDialer.Dial(ctx, src, dest, sockopt)
|
||||
}
|
||||
|
||||
if newDest, err := checkAddressPortStrategy(ctx, dest, sockopt); err == nil && newDest != nil {
|
||||
errors.LogInfo(ctx, "replace destination with "+newDest.String())
|
||||
dest = *newDest
|
||||
}
|
||||
|
||||
if canLookupIP(ctx, dest, sockopt) {
|
||||
ips, err := lookupIP(dest.Address.String(), sockopt.DomainStrategy, src)
|
||||
if err == nil && len(ips) > 0 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue