mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-10-05 15:23:33 +00:00
Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
14f4bcaf29 | ||
|
|
30a78f1563 | ||
|
|
46d49adc5c | ||
|
|
b71975abed | ||
|
|
6b0f06fb2b |
@@ -213,6 +213,8 @@ If the filters cannot be added, Xray does not start. They are removed when Xray
|
||||
|
||||
`autoSystemWfpBlockLeak` (Windows only) is empty by default, as the filters break some setups: with `"dns"`, a local DNS resolver other programs use (e.g. on `127.0.0.1:53`), the DNS of another VPN on its own interface, virtual machines whose NAT resolves names on the host, or signing in to a captive portal; with `"misconfigtun"`, IPv4 or IPv6 on the local network while no route of that version leads to the TUN. Without the filters, DNS may leak as described above. To keep an IP version out of the TUN on purpose while still blocking DNS leaks, use only `["dns"]`.
|
||||
|
||||
`autoOutboundsInterface` (the default with `autoSystemRoutingTable`) keeps Xray's own connections out of the TUN by binding them to another interface, which Windows only honors while that interface has weak host send and forwarding off for the IP versions routed to the TUN. Otherwise, Windows sends them into the TUN, from that interface's address, and they stall. While the TUN runs, Xray therefore turns weak host send off on that interface, and on again when it stops or another interface takes over. Forwarding cannot be turned off this way, as Mobile Hotspot and Internet Connection Sharing need it, so a warning is logged while it is on. Having the hotspot share the TUN instead of that interface (Settings, Mobile hotspot, Share my internet connection from) moves forwarding to the TUN, where it does no harm, and sends the hotspot's devices through Xray as well.
|
||||
|
||||
You can give the adapter ip address manually, you can live Windows to give it autogenerated ip address (which take few seconds), it doesn't matter, the traffic going _through_ the interface will be forwarded into the app for proxying. \
|
||||
Minimal configuration that will work for local machine is routing passing the traffic on-link through the interface.
|
||||
You will need the interface id for that, unfortunately it is going to change with every Xray start due to implementation ambiguity between Xray and wintun driver.
|
||||
|
||||
@@ -46,6 +46,7 @@ type WindowsTun struct {
|
||||
luid winipcfg.LUID
|
||||
cbr winipcfg.ChangeCallback
|
||||
cbi winipcfg.ChangeCallback
|
||||
guard outboundGuard
|
||||
wfp windows.Handle
|
||||
resolver *savedResolver
|
||||
skipStop chan struct{}
|
||||
@@ -297,10 +298,21 @@ startOver:
|
||||
}
|
||||
|
||||
if updater != nil {
|
||||
// Xray's own connections have to stay out of the IP versions routed
|
||||
// to the TUN, which needs Windows to honor the binding to updater's
|
||||
// interface.
|
||||
if route4 {
|
||||
t.guard.families = append(t.guard.families, windows.AF_INET)
|
||||
}
|
||||
if route6 {
|
||||
t.guard.families = append(t.guard.families, windows.AF_INET6)
|
||||
}
|
||||
t.guard.check()
|
||||
// Only a registered callback goes into the fields: a nil pointer in
|
||||
// them would not compare equal to nil in Close.
|
||||
cbr, err := winipcfg.RegisterRouteChangeCallback(func(notificationType winipcfg.MibNotificationType, route *winipcfg.MibIPforwardRow2) {
|
||||
updater.Update()
|
||||
t.guard.check()
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -308,6 +320,7 @@ startOver:
|
||||
t.cbr = cbr
|
||||
cbi, err := winipcfg.RegisterInterfaceChangeCallback(func(notificationType winipcfg.MibNotificationType, iface *winipcfg.MibIPInterfaceRow) {
|
||||
updater.Update()
|
||||
t.guard.check()
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -331,6 +344,7 @@ func (t *WindowsTun) Close() error {
|
||||
if t.cbi != nil {
|
||||
t.cbi.Unregister()
|
||||
}
|
||||
t.guard.restore()
|
||||
if t.luid != 0 {
|
||||
t.luid.FlushRoutes(windows.AF_INET)
|
||||
t.luid.FlushIPAddresses(windows.AF_INET)
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
//go:build windows
|
||||
|
||||
package tun
|
||||
|
||||
import (
|
||||
"context"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
||||
)
|
||||
|
||||
// outboundGuard keeps Windows to the binding of autoOutboundsInterface, which
|
||||
// keeps Xray's own connections out of the TUN. With weak host send or
|
||||
// forwarding on for an IP version on the bound interface, Windows sends them
|
||||
// where the routes lead, into the TUN, from that interface's address, and
|
||||
// drops what comes back to that address through the TUN, so they stall.
|
||||
//
|
||||
// For the IP versions routed to the TUN, weak host send is turned off on the
|
||||
// bound interface while the TUN runs, and turned on again when the TUN stops
|
||||
// or another interface takes over. Forwarding is what Mobile Hotspot and
|
||||
// Internet Connection Sharing need, so it is only reported.
|
||||
type outboundGuard struct {
|
||||
sync.Mutex
|
||||
families []winipcfg.AddressFamily
|
||||
luid winipcfg.LUID // of the interface last checked
|
||||
name string // of that interface
|
||||
turnedOff []winipcfg.AddressFamily // where weak host send was turned off on it
|
||||
forwarding bool // whether forwarding was on there
|
||||
stopped bool
|
||||
}
|
||||
|
||||
// check turns weak host send off on the bound interface, and warns when
|
||||
// forwarding comes on there, but not again while it stays on.
|
||||
func (g *outboundGuard) check() {
|
||||
g.Lock()
|
||||
defer g.Unlock()
|
||||
if g.stopped {
|
||||
return
|
||||
}
|
||||
var luid winipcfg.LUID
|
||||
var name string
|
||||
if iface := updater.Get(); iface != nil {
|
||||
luid, _ = winipcfg.LUIDFromIndex(uint32(iface.Index))
|
||||
name = iface.Name
|
||||
}
|
||||
if luid != g.luid {
|
||||
g.restoreLocked()
|
||||
g.luid, g.name = luid, name
|
||||
g.forwarding = false // to warn about the new interface as well
|
||||
}
|
||||
if luid == 0 {
|
||||
return
|
||||
}
|
||||
var forwarding []string
|
||||
for _, family := range g.families {
|
||||
row, err := luid.IPInterface(family)
|
||||
if err != nil {
|
||||
continue // the interface lacks that IP version
|
||||
}
|
||||
if row.ForwardingEnabled {
|
||||
forwarding = append(forwarding, familyName(family))
|
||||
}
|
||||
if !row.WeakHostSend {
|
||||
continue
|
||||
}
|
||||
if err := setWeakHostSend(row, false); err != nil {
|
||||
errors.LogWarningInner(context.Background(), err, "[tun] unable to turn weak host send off for ", familyName(family), " on ", name)
|
||||
continue
|
||||
}
|
||||
if !slices.Contains(g.turnedOff, family) {
|
||||
g.turnedOff = append(g.turnedOff, family)
|
||||
errors.LogInfo(context.Background(), "[tun] weak host send turned off for ", familyName(family), " on ", name, " while the TUN runs, as Windows would ignore autoOutboundsInterface")
|
||||
}
|
||||
}
|
||||
wasOn := g.forwarding
|
||||
g.forwarding = len(forwarding) > 0
|
||||
if g.forwarding && !wasOn {
|
||||
errors.LogWarning(context.Background(), "[tun] forwarding is on for ", strings.Join(forwarding, " and "), " on ", name, " (Mobile Hotspot and Internet Connection Sharing turn it on), so Windows ignores autoOutboundsInterface there, and Xray's own connections go into the TUN and stall: turn the hotspot off, or have it share the TUN instead of ", name)
|
||||
}
|
||||
}
|
||||
|
||||
// restore turns weak host send on again where check turned it off, for good.
|
||||
func (g *outboundGuard) restore() {
|
||||
g.Lock()
|
||||
defer g.Unlock()
|
||||
g.restoreLocked()
|
||||
g.stopped = true
|
||||
}
|
||||
|
||||
func (g *outboundGuard) restoreLocked() {
|
||||
for _, family := range g.turnedOff {
|
||||
row, err := g.luid.IPInterface(family)
|
||||
if err == nil {
|
||||
err = setWeakHostSend(row, true)
|
||||
}
|
||||
if err != nil {
|
||||
errors.LogWarningInner(context.Background(), err, "[tun] unable to turn weak host send on again for ", familyName(family), " on ", g.name)
|
||||
}
|
||||
}
|
||||
g.turnedOff = nil
|
||||
}
|
||||
|
||||
func setWeakHostSend(row *winipcfg.MibIPInterfaceRow, on bool) error {
|
||||
row.WeakHostSend = on
|
||||
if row.Family == windows.AF_INET {
|
||||
row.SitePrefixLength = 0 // as SetIpInterfaceEntry requires for IPv4
|
||||
}
|
||||
return row.Set()
|
||||
}
|
||||
|
||||
func familyName(family winipcfg.AddressFamily) string {
|
||||
if family == windows.AF_INET {
|
||||
return "IPv4"
|
||||
}
|
||||
return "IPv6"
|
||||
}
|
||||
Reference in New Issue
Block a user