mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-10-29 22:46:58 +00:00
"dns" in autoSystemWfpBlockLeak only blocked port 53 outside the TUN, plus the DNS Client service on Windows 11 and Server 2022 and later, so other programs' DNS over TLS (TCP 853) and DNS over QUIC (UDP 853) could still leave outside the TUN. autoSystemWfpBlockLeak now takes: - "tcp/<port>", "udp/<port>": connections to that port may only go through the TUN (or come from Xray itself). - "windnsclient": Windows' DNS Client service may only connect through the TUN, except for mDNS and LLMNR. As before, this only applies from Windows 11 and Server 2022 on, where the service may use DoH or DoT to any port; earlier versions only query port 53. - "dns": stands for "udp/53", "tcp/53", "windnsclient", "tcp/853" and "udp/853". - "misconfigtun": unchanged. Values are case-insensitive, deduplicated, and anything else, such as "tcp/0" or "icmp/1", is rejected. Keeping the system's DNS inside the TUN, with "udp/53", "tcp/53" or "windnsclient", needs dns to be set, as "dns" did; ports like 853 alone do not. Each port gets its own permit-through-TUN and block filters with a protocol condition, where port 53 used to have one for both protocols, and the log lists what is blocked, e.g. "[tun] blocked outside the TUN: udp/53, tcp/53, tcp/853, udp/853, windnsclient". Tested on Windows 11 with a Wintun adapter as the outside interface: with "tcp/853", "udp/853", "tcp/7215" and "udp/7216", those are blocked outside the TUN over IPv4 and IPv6, while tcp/7216, udp/7215 and 443 are not, port 853 works through the TUN, Xray's own connections to port 853 still leave outside it, and nothing is blocked after Xray stops. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
80 lines
2.2 KiB
Go
80 lines
2.2 KiB
Go
package tun
|
|
|
|
import (
|
|
"slices"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/xtls/xray-core/common/errors"
|
|
)
|
|
|
|
// dnsLeaks is what "dns" in autoSystemWfpBlockLeak stands for: DNS over UDP and
|
|
// TCP, Windows' DNS Client service, which may also use other protocols and
|
|
// ports, DNS over TLS, and DNS over QUIC.
|
|
var dnsLeaks = []string{"udp/53", "tcp/53", "windnsclient", "tcp/853", "udp/853"}
|
|
|
|
// leakPort is a "tcp/<port>" or "udp/<port>" value of autoSystemWfpBlockLeak:
|
|
// connections to that port may only go through the TUN.
|
|
type leakPort struct {
|
|
tcp bool
|
|
port uint16
|
|
}
|
|
|
|
func (p leakPort) String() string {
|
|
if p.tcp {
|
|
return "tcp/" + strconv.Itoa(int(p.port))
|
|
}
|
|
return "udp/" + strconv.Itoa(int(p.port))
|
|
}
|
|
|
|
// parseLeakPort parses a lower case "tcp/<port>" or "udp/<port>" value.
|
|
func parseLeakPort(value string) (leakPort, bool) {
|
|
protocol, port, ok := strings.Cut(value, "/")
|
|
if !ok || protocol != "tcp" && protocol != "udp" {
|
|
return leakPort{}, false
|
|
}
|
|
n, err := strconv.ParseUint(port, 10, 16)
|
|
if err != nil || n == 0 {
|
|
return leakPort{}, false
|
|
}
|
|
return leakPort{tcp: protocol == "tcp", port: uint16(n)}, true
|
|
}
|
|
|
|
// ExpandWfpBlockLeak checks the values of autoSystemWfpBlockLeak and returns
|
|
// them in lower case, in order and without duplicates, with "dns" replaced by
|
|
// what it stands for.
|
|
func ExpandWfpBlockLeak(values []string) ([]string, error) {
|
|
var leaks []string
|
|
add := func(leak string) {
|
|
if !slices.Contains(leaks, leak) {
|
|
leaks = append(leaks, leak)
|
|
}
|
|
}
|
|
for _, value := range values {
|
|
switch value = strings.ToLower(value); value {
|
|
case "dns":
|
|
for _, leak := range dnsLeaks {
|
|
add(leak)
|
|
}
|
|
case "windnsclient", "misconfigtun":
|
|
add(value)
|
|
default:
|
|
port, ok := parseLeakPort(value)
|
|
if !ok {
|
|
return nil, errors.New("unknown autoSystemWfpBlockLeak value: ", value)
|
|
}
|
|
add(port.String())
|
|
}
|
|
}
|
|
return leaks, nil
|
|
}
|
|
|
|
// BlocksSystemDNS tells whether expanded autoSystemWfpBlockLeak values keep the
|
|
// system's DNS (port 53, or Windows' DNS Client service) inside the TUN, which
|
|
// then needs DNS servers of its own.
|
|
func BlocksSystemDNS(leaks []string) bool {
|
|
return slices.ContainsFunc(leaks, func(leak string) bool {
|
|
return leak == "udp/53" || leak == "tcp/53" || leak == "windnsclient"
|
|
})
|
|
}
|