TUN inbound: Refine gateway and autoSystemRoutingTable on Linux (#6398)

https://github.com/XTLS/Xray-core/pull/6398#issuecomment-4880261591
This commit is contained in:
yiguodev
2026-07-04 10:25:15 +08:00
committed by GitHub
parent 3263ae9255
commit 65f6f0a43b
2 changed files with 48 additions and 8 deletions
+5 -5
View File
@@ -14,11 +14,11 @@ Plainly enabling it in the config probably will result nothing, or lock your rou
## DETAILS
Current implementation does not contain options to configure network level addresses, routing or rules.
Enabling the feature will result only tun interface up, and that's it. \
This is explicit decision, significantly simplifying implementation, and allowing any number of custom configurations, consumers could come up with. Network interface is OS level entity, and OS is what should manage it. \
Working configuration, is tun enabled in Xray config with specific name (e.g. xray0), and OS level configuration to manage "xray0" interface, applying routing and rules on interface up.
This way consistency of system level routing and rules is ensured from single place of responsibility - the OS itself. \
By default, enabling the feature will only bring the tun interface up. \
When configured explicitly, Windows and Linux can also apply interface addresses from `gateway` and on-link routes from `autoSystemRoutingTable`.
Linux does not configure system DNS from the `dns` field; system DNS remains managed by the OS or distribution-specific network services. \
For more advanced routing policies or rules, OS level configuration can still manage the named interface (e.g. xray0) when it appears.
This keeps complex system level routing and rules in a single place of responsibility - the OS itself. \
Examples of how to achieve this on a simple Linux system (Ubuntu with systemd-networkd) can be found at the end of this README.
Due to this inbound not actually being a proxy, the configuration ignore required listen and port options, and never listen on any port. \
+43 -3
View File
@@ -26,9 +26,10 @@ type LinuxTun struct {
options *Config
ownsTun bool
systemRoutes []netlink.Route
routeMonitorStop chan struct{}
routeMonitorOnce sync.Once
interfaceAddresses []netlink.Addr
systemRoutes []netlink.Route
routeMonitorStop chan struct{}
routeMonitorOnce sync.Once
}
// LinuxTun implements Tun
@@ -172,7 +173,14 @@ func (t *LinuxTun) Start() error {
return err
}
if err := t.setInterfaceAddresses(); err != nil {
_ = netlink.LinkSetDown(t.tunLink)
return err
}
if err := t.setSystemRoutes(); err != nil {
_ = t.unsetInterfaceAddresses()
_ = netlink.LinkSetDown(t.tunLink)
return err
}
@@ -193,6 +201,7 @@ func (t *LinuxTun) Close() error {
})
_ = t.unsetSystemRoutes()
_ = t.unsetInterfaceAddresses()
if t.ownsTun {
_ = netlink.LinkSetDown(t.tunLink)
@@ -223,6 +232,37 @@ func setinterface(network, address string, fd uintptr, iface *net.Interface) err
return unix.BindToDevice(int(fd), iface.Name)
}
func (t *LinuxTun) setInterfaceAddresses() error {
if len(t.options.Gateway) == 0 {
return nil
}
for _, address := range t.options.Gateway {
addr, err := netlink.ParseAddr(address)
if err != nil {
_ = t.unsetInterfaceAddresses()
return errors.New("invalid interface address ", address).Base(err)
}
if err := netlink.AddrAdd(t.tunLink, addr); err != nil {
_ = t.unsetInterfaceAddresses()
return errors.New("failed to add interface address ", address).Base(err)
}
t.interfaceAddresses = append(t.interfaceAddresses, *addr)
}
return nil
}
func (t *LinuxTun) unsetInterfaceAddresses() error {
var errs []error
for i := len(t.interfaceAddresses) - 1; i >= 0; i-- {
address := t.interfaceAddresses[i]
if err := netlink.AddrDel(t.tunLink, &address); err != nil {
errs = append(errs, errors.New("failed to delete interface address ", address.String()).Base(err))
}
}
t.interfaceAddresses = nil
return errors.Combine(errs...)
}
func (t *LinuxTun) setSystemRoutes() error {
if len(t.options.AutoSystemRoutingTable) == 0 {
return nil