Sockopt: Handle single-family interface binding on Windows, including TUN inbound's autoOutboundsInterface (#7214)

And https://github.com/XTLS/Xray-core/pull/7214#issuecomment-6329118637

https://github.com/XTLS/Xray-core/pull/7201#issuecomment-6314453444

Fixes https://github.com/XTLS/Xray-core/issues/7160#issuecomment-6246944012

---------

Co-authored-by: patterniha <71074308+patterniha@users.noreply.github.com>
This commit is contained in:
Eliot the Cougar
2026-10-28 10:15:58 +00:00
committed by GitHub
co-authored by patterniha
parent 1576e79563
commit 3071fbfa25
4 changed files with 110 additions and 1 deletions
+25 -1
View File
@@ -401,6 +401,15 @@ func resolveOnOwn() *savedResolver {
if internet.IsSkippedDNSServer(address) {
return nil, errors.New("skipped DNS server ", address)
}
// A socket of the server's IP version only needs that version bound
// to the interface, which a dual-stack one would need both of.
if ap, err := netip.ParseAddrPort(address); err == nil && (network == "udp" || network == "tcp") {
if ap.Addr().Unmap().Is4() {
network += "4"
} else {
network += "6"
}
}
return dialer.DialContext(ctx, network, address)
}
net.DefaultResolver.PreferGo = true
@@ -558,10 +567,22 @@ func setinterface(network, address string, fd uintptr, iface *net.Interface) err
switch network {
case "tcp6", "udp6", "ip6":
dualStack := false
if network == "udp6" {
ipv6Only, err := windows.GetsockoptInt(windows.Handle(fd), windows.IPPROTO_IPV6, windows.IPV6_V6ONLY)
if err != nil {
return internet.NewBindError(err)
}
dualStack = ipv6Only == 0
}
err1 = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IPV6, IPV6_UNICAST_IF, iface.Index)
if network == "udp6" {
err2 = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IPV6, windows.IPV6_MULTICAST_IF, iface.Index)
}
// Only dual-stack UDP can send to both IPv4 and IPv6 destinations.
if !dualStack {
break
}
fallthrough
case "tcp4", "udp4", "ip4":
err3 = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IP, IP_UNICAST_IF, *(*int)(unsafe.Pointer(&index[0])))
@@ -572,7 +593,10 @@ func setinterface(network, address string, fd uintptr, iface *net.Interface) err
panic(network + " " + address)
}
return errors.Combine(err1, err2, err3, err4)
if err := errors.Combine(err1, err2, err3, err4); err != nil {
return internet.NewBindError(err)
}
return nil
}
func findOutboundInterface(tunIndex int, fixedName string) (*net.Interface, error) {