bolt more stuff onto tun to help auto-assign snat addresses

This commit is contained in:
JackDoan
2026-02-17 13:09:31 -06:00
parent 83744a106d
commit 1cc257f997
17 changed files with 267 additions and 136 deletions

View File

@@ -215,7 +215,6 @@ func NewFirewall(l *logrus.Logger, tcpTimeout, UDPTimeout, defaultTimeout time.D
routableNetworks: routableNetworks, routableNetworks: routableNetworks,
assignedNetworks: assignedNetworks, assignedNetworks: assignedNetworks,
hasUnsafeNetworks: hasUnsafeNetworks, hasUnsafeNetworks: hasUnsafeNetworks,
snatAddr: snatAddr,
l: l, l: l,
incomingMetrics: firewallMetrics{ incomingMetrics: firewallMetrics{
@@ -231,7 +230,7 @@ func NewFirewall(l *logrus.Logger, tcpTimeout, UDPTimeout, defaultTimeout time.D
} }
} }
func NewFirewallFromConfig(l *logrus.Logger, cs *CertState, c *config.C, snatAddr netip.Addr) (*Firewall, error) { func NewFirewallFromConfig(l *logrus.Logger, cs *CertState, c *config.C) (*Firewall, error) {
certificate := cs.getCertificate(cert.Version2) certificate := cs.getCertificate(cert.Version2)
if certificate == nil { if certificate == nil {
certificate = cs.getCertificate(cert.Version1) certificate = cs.getCertificate(cert.Version1)
@@ -241,7 +240,14 @@ func NewFirewallFromConfig(l *logrus.Logger, cs *CertState, c *config.C, snatAdd
panic("No certificate available to reconfigure the firewall") panic("No certificate available to reconfigure the firewall")
} }
fw := NewFirewall(l, c.GetDuration("firewall.conntrack.tcp_timeout", time.Minute*12), c.GetDuration("firewall.conntrack.udp_timeout", time.Minute*3), c.GetDuration("firewall.conntrack.default_timeout", time.Minute*10), certificate, snatAddr) fw := NewFirewall(
l,
c.GetDuration("firewall.conntrack.tcp_timeout", time.Minute*12),
c.GetDuration("firewall.conntrack.udp_timeout", time.Minute*3),
c.GetDuration("firewall.conntrack.default_timeout", time.Minute*10),
certificate,
netip.Addr{},
)
fw.defaultLocalCIDRAny = c.GetBool("firewall.default_local_cidr_any", false) fw.defaultLocalCIDRAny = c.GetBool("firewall.default_local_cidr_any", false)
@@ -347,6 +353,12 @@ func (f *Firewall) GetRuleHashes() string {
return "SHA:" + f.GetRuleHash() + ",FNV:" + strconv.FormatUint(uint64(f.GetRuleHashFNV()), 10) return "SHA:" + f.GetRuleHash() + ",FNV:" + strconv.FormatUint(uint64(f.GetRuleHashFNV()), 10)
} }
func (f *Firewall) SetSNATAddressFromInterface(i *Interface) {
//address-mutation-avoidance is done inside Interface, the firewall doesn't need to care
//todo should snatted conntracks get expired out? Probably not needed until if/when we allow reload
f.snatAddr = i.inside.SNATAddress().Addr()
}
func (f *Firewall) ShouldUnSNAT(fp *firewall.Packet) bool { func (f *Firewall) ShouldUnSNAT(fp *firewall.Packet) bool {
// f.snatAddr is only valid if we're a snat-capable router // f.snatAddr is only valid if we're a snat-capable router
return f.snatAddr.IsValid() && fp.RemoteAddr == f.snatAddr return f.snatAddr.IsValid() && fp.RemoteAddr == f.snatAddr

View File

@@ -249,6 +249,7 @@ func (f *Interface) activate() {
f.inside.Close() f.inside.Close()
f.l.Fatal(err) f.l.Fatal(err)
} }
f.firewall.SetSNATAddressFromInterface(f)
} }
func (f *Interface) run() { func (f *Interface) run() {
@@ -340,11 +341,12 @@ func (f *Interface) reloadFirewall(c *config.C) {
return return
} }
fw, err := NewFirewallFromConfig(f.l, f.pki.getCertState(), c, f.firewall.snatAddr) fw, err := NewFirewallFromConfig(f.l, f.pki.getCertState(), c)
if err != nil { if err != nil {
f.l.WithError(err).Error("Error while creating firewall during reload") f.l.WithError(err).Error("Error while creating firewall during reload")
return return
} }
fw.SetSNATAddressFromInterface(f)
oldFw := f.firewall oldFw := f.firewall
conntrack := oldFw.Conntrack conntrack := oldFw.Conntrack

View File

@@ -66,8 +66,7 @@ func Main(c *config.C, configTest bool, buildVersion string, logger *logrus.Logg
return nil, util.ContextualizeIfNeeded("Failed to load PKI from config", err) return nil, util.ContextualizeIfNeeded("Failed to load PKI from config", err)
} }
snatAddr := netip.MustParseAddr("169.254.55.96") //todo get this from tun! fw, err := NewFirewallFromConfig(l, pki.getCertState(), c)
fw, err := NewFirewallFromConfig(l, pki.getCertState(), c, snatAddr)
if err != nil { if err != nil {
return nil, util.ContextualizeIfNeeded("Error while loading firewall rules", err) return nil, util.ContextualizeIfNeeded("Error while loading firewall rules", err)
} }

View File

@@ -11,6 +11,8 @@ type Device interface {
io.ReadWriteCloser io.ReadWriteCloser
Activate() error Activate() error
Networks() []netip.Prefix Networks() []netip.Prefix
UnsafeNetworks() []netip.Prefix
SNATAddress() netip.Prefix
Name() string Name() string
RoutesFor(netip.Addr) routing.Gateways RoutesFor(netip.Addr) routing.Gateways
SupportsMultiqueue() bool SupportsMultiqueue() bool

View File

@@ -1,6 +1,7 @@
package overlay package overlay
import ( import (
"crypto/rand"
"fmt" "fmt"
"net" "net"
"net/netip" "net/netip"
@@ -129,3 +130,53 @@ func selectGateway(dest netip.Prefix, gateways []netip.Prefix) (netip.Prefix, er
return netip.Prefix{}, fmt.Errorf("no gateway found for %v in the list of vpn networks", dest) return netip.Prefix{}, fmt.Errorf("no gateway found for %v in the list of vpn networks", dest)
} }
func prepareSnatAddr(d Device, l *logrus.Logger, c *config.C, routes []Route) netip.Prefix {
if !d.Networks()[0].Addr().Is6() {
return netip.Prefix{} //if we have an IPv4 assignment within the overlay, we don't need a snat address
}
addSnatAddr := false
for _, un := range d.UnsafeNetworks() { //if we are an unsafe router for an IPv4 range
if un.Addr().Is4() {
addSnatAddr = true
break
}
}
for _, route := range routes { //or if we have a route defined into an IPv4 range
if route.Cidr.Addr().Is4() {
addSnatAddr = true //todo should this only apply to unsafe routes?
break
}
}
if !addSnatAddr {
return netip.Prefix{}
}
var err error
out := netip.Addr{}
if a := c.GetString("tun.snat_address_for_4over6", ""); a != "" {
out, err = netip.ParseAddr(a)
if err != nil {
l.WithField("value", a).WithError(err).Warn("failed to parse tun.snat_address_for_4over6, will use a random value")
} else if !out.Is4() || !out.IsLinkLocalUnicast() {
l.WithField("value", out).Warn("tun.snat_address_for_4over6 must be an IPv4 address")
}
}
if !out.IsValid() {
octets := []byte{169, 254, 0, 0}
_, _ = rand.Read(octets[2:4])
if octets[3] == 0 {
octets[3] = 1 //please no .0 addresses
} else if octets[2] == 255 && octets[3] == 255 {
octets[3] = 254 //please no broadcast addresses
}
ok := false
out, ok = netip.AddrFromSlice(octets)
if !ok {
l.Error("failed to produce a valid IPv4 address for tun.snat_address_for_4over6")
return netip.Prefix{}
}
}
return netip.PrefixFrom(out, 32)
}

View File

@@ -19,14 +19,15 @@ import (
type tun struct { type tun struct {
io.ReadWriteCloser io.ReadWriteCloser
fd int fd int
vpnNetworks []netip.Prefix vpnNetworks []netip.Prefix
Routes atomic.Pointer[[]Route] unsafeNetworks []netip.Prefix
routeTree atomic.Pointer[bart.Table[routing.Gateways]] Routes atomic.Pointer[[]Route]
l *logrus.Logger routeTree atomic.Pointer[bart.Table[routing.Gateways]]
l *logrus.Logger
} }
func newTunFromFd(c *config.C, l *logrus.Logger, deviceFd int, vpnNetworks []netip.Prefix, _ []netip.Prefix) (*tun, error) { func newTunFromFd(c *config.C, l *logrus.Logger, deviceFd int, vpnNetworks []netip.Prefix, unsafeNetworks []netip.Prefix) (*tun, error) {
// XXX Android returns an fd in non-blocking mode which is necessary for shutdown to work properly. // XXX Android returns an fd in non-blocking mode which is necessary for shutdown to work properly.
// Be sure not to call file.Fd() as it will set the fd to blocking mode. // Be sure not to call file.Fd() as it will set the fd to blocking mode.
file := os.NewFile(uintptr(deviceFd), "/dev/net/tun") file := os.NewFile(uintptr(deviceFd), "/dev/net/tun")
@@ -35,6 +36,7 @@ func newTunFromFd(c *config.C, l *logrus.Logger, deviceFd int, vpnNetworks []net
ReadWriteCloser: file, ReadWriteCloser: file,
fd: deviceFd, fd: deviceFd,
vpnNetworks: vpnNetworks, vpnNetworks: vpnNetworks,
unsafeNetworks: unsafeNetworks,
l: l, l: l,
} }
@@ -91,6 +93,10 @@ func (t *tun) Networks() []netip.Prefix {
return t.vpnNetworks return t.vpnNetworks
} }
func (t *tun) UnsafeNetworks() []netip.Prefix {
return t.UnsafeNetworks()
}
func (t *tun) Name() string { func (t *tun) Name() string {
return "android" return "android"
} }

View File

@@ -24,13 +24,15 @@ import (
type tun struct { type tun struct {
io.ReadWriteCloser io.ReadWriteCloser
Device string Device string
vpnNetworks []netip.Prefix vpnNetworks []netip.Prefix
DefaultMTU int unsafeNetworks []netip.Prefix
Routes atomic.Pointer[[]Route] snatAddr netip.Prefix
routeTree atomic.Pointer[bart.Table[routing.Gateways]] DefaultMTU int
linkAddr *netroute.LinkAddr Routes atomic.Pointer[[]Route]
l *logrus.Logger routeTree atomic.Pointer[bart.Table[routing.Gateways]]
linkAddr *netroute.LinkAddr
l *logrus.Logger
// cache out buffer since we need to prepend 4 bytes for tun metadata // cache out buffer since we need to prepend 4 bytes for tun metadata
out []byte out []byte
@@ -127,6 +129,7 @@ func newTun(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, unsafeNet
ReadWriteCloser: os.NewFile(uintptr(fd), ""), ReadWriteCloser: os.NewFile(uintptr(fd), ""),
Device: name, Device: name,
vpnNetworks: vpnNetworks, vpnNetworks: vpnNetworks,
unsafeNetworks: unsafeNetworks,
DefaultMTU: c.GetInt("tun.mtu", DefaultMTU), DefaultMTU: c.GetInt("tun.mtu", DefaultMTU),
l: l, l: l,
} }
@@ -545,6 +548,14 @@ func (t *tun) Networks() []netip.Prefix {
return t.vpnNetworks return t.vpnNetworks
} }
func (t *tun) UnsafeNetworks() []netip.Prefix {
return t.unsafeNetworks
}
func (t *tun) SNATAddress() netip.Prefix {
return t.snatAddr
}
func (t *tun) Name() string { func (t *tun) Name() string {
return t.Device return t.Device
} }

View File

@@ -22,6 +22,13 @@ type disabledTun struct {
l *logrus.Logger l *logrus.Logger
} }
func (*disabledTun) UnsafeNetworks() []netip.Prefix {
return nil
}
func (*disabledTun) SNATAddress() netip.Prefix {
return netip.Prefix{}
}
func newDisabledTun(vpnNetworks []netip.Prefix, queueLen int, metricsEnabled bool, l *logrus.Logger) *disabledTun { func newDisabledTun(vpnNetworks []netip.Prefix, queueLen int, metricsEnabled bool, l *logrus.Logger) *disabledTun {
tun := &disabledTun{ tun := &disabledTun{
vpnNetworks: vpnNetworks, vpnNetworks: vpnNetworks,

View File

@@ -86,14 +86,16 @@ type ifreqAlias6 struct {
} }
type tun struct { type tun struct {
Device string Device string
vpnNetworks []netip.Prefix vpnNetworks []netip.Prefix
MTU int unsafeNetworks []netip.Prefix
Routes atomic.Pointer[[]Route] snatAddr netip.Prefix
routeTree atomic.Pointer[bart.Table[routing.Gateways]] MTU int
linkAddr *netroute.LinkAddr Routes atomic.Pointer[[]Route]
l *logrus.Logger routeTree atomic.Pointer[bart.Table[routing.Gateways]]
devFd int linkAddr *netroute.LinkAddr
l *logrus.Logger
devFd int
} }
func (t *tun) Read(to []byte) (int, error) { func (t *tun) Read(to []byte) (int, error) {
@@ -270,11 +272,12 @@ func newTun(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, unsafeNet
} }
t := &tun{ t := &tun{
Device: deviceName, Device: deviceName,
vpnNetworks: vpnNetworks, vpnNetworks: vpnNetworks,
MTU: c.GetInt("tun.mtu", DefaultMTU), unsafeNetworks: unsafeNetworks,
l: l, MTU: c.GetInt("tun.mtu", DefaultMTU),
devFd: fd, l: l,
devFd: fd,
} }
err = t.reload(c, true) err = t.reload(c, true)
@@ -446,6 +449,14 @@ func (t *tun) Networks() []netip.Prefix {
return t.vpnNetworks return t.vpnNetworks
} }
func (t *tun) UnsafeNetworks() []netip.Prefix {
return t.unsafeNetworks
}
func (t *tun) SNATAddress() netip.Prefix {
return t.snatAddr
}
func (t *tun) Name() string { func (t *tun) Name() string {
return t.Device return t.Device
} }

View File

@@ -22,20 +22,22 @@ import (
type tun struct { type tun struct {
io.ReadWriteCloser io.ReadWriteCloser
vpnNetworks []netip.Prefix vpnNetworks []netip.Prefix
Routes atomic.Pointer[[]Route] unsafeNetworks []netip.Prefix
routeTree atomic.Pointer[bart.Table[routing.Gateways]] Routes atomic.Pointer[[]Route]
l *logrus.Logger routeTree atomic.Pointer[bart.Table[routing.Gateways]]
l *logrus.Logger
} }
func newTun(_ *config.C, _ *logrus.Logger, _ []netip.Prefix, _ []netip.Prefix, _ bool) (*tun, error) { func newTun(_ *config.C, _ *logrus.Logger, _ []netip.Prefix, _ []netip.Prefix, _ bool) (*tun, error) {
return nil, fmt.Errorf("newTun not supported in iOS") return nil, fmt.Errorf("newTun not supported in iOS")
} }
func newTunFromFd(c *config.C, l *logrus.Logger, deviceFd int, vpnNetworks []netip.Prefix, _ []netip.Prefix) (*tun, error) { func newTunFromFd(c *config.C, l *logrus.Logger, deviceFd int, vpnNetworks []netip.Prefix, unsafeNetworks []netip.Prefix) (*tun, error) {
file := os.NewFile(uintptr(deviceFd), "/dev/tun") file := os.NewFile(uintptr(deviceFd), "/dev/tun")
t := &tun{ t := &tun{
vpnNetworks: vpnNetworks, vpnNetworks: vpnNetworks,
unsafeNetworks: unsafeNetworks,
ReadWriteCloser: &tunReadCloser{f: file}, ReadWriteCloser: &tunReadCloser{f: file},
l: l, l: l,
} }
@@ -147,6 +149,14 @@ func (t *tun) Networks() []netip.Prefix {
return t.vpnNetworks return t.vpnNetworks
} }
func (t *tun) UnsafeNetworks() []netip.Prefix {
return t.unsafeNetworks
}
func (t *tun) SNATAddress() netip.Prefix {
return t.snatAddr
}
func (t *tun) Name() string { func (t *tun) Name() string {
return "iOS" return "iOS"
} }

View File

@@ -4,7 +4,6 @@
package overlay package overlay
import ( import (
"crypto/rand"
"fmt" "fmt"
"io" "io"
"net" "net"
@@ -57,6 +56,14 @@ func (t *tun) Networks() []netip.Prefix {
return t.vpnNetworks return t.vpnNetworks
} }
func (t *tun) UnsafeNetworks() []netip.Prefix {
return t.unsafeNetworks
}
func (t *tun) SNATAddress() netip.Prefix {
return t.snatAddr
}
type ifReq struct { type ifReq struct {
Name [16]byte Name [16]byte
Flags uint16 Flags uint16
@@ -165,59 +172,6 @@ func newTunGeneric(c *config.C, l *logrus.Logger, file *os.File, vpnNetworks []n
return t, nil return t, nil
} }
func (t *tun) prepareSnatAddr(c *config.C, initial bool, routes []Route) netip.Prefix {
if !initial {
return netip.Prefix{} //I don't wanna think about reloading this yet
}
if !t.vpnNetworks[0].Addr().Is6() {
return netip.Prefix{} //if we have an IPv4 assignment within the overlay, we don't need a snat address
}
addSnatAddr := false
for _, un := range t.unsafeNetworks { //if we are an unsafe router for an IPv4 range
if un.Addr().Is4() {
addSnatAddr = true
break
}
}
for _, route := range routes { //or if we have a route defined into an IPv4 range
if route.Cidr.Addr().Is4() {
addSnatAddr = true //todo should this only apply to unsafe routes?
break
}
}
if !addSnatAddr {
return netip.Prefix{}
}
var err error
out := netip.Addr{}
if a := c.GetString("tun.snat_address_for_4over6", ""); a != "" {
out, err = netip.ParseAddr(a)
if err != nil {
t.l.WithField("value", a).WithError(err).Warn("failed to parse tun.snat_address_for_4over6, will use a random value")
} else if !out.Is4() || !out.IsLinkLocalUnicast() {
t.l.WithField("value", t.snatAddr).Warn("tun.snat_address_for_4over6 must be an IPv4 address")
}
}
if !out.IsValid() {
octets := []byte{169, 254, 0, 0}
_, _ = rand.Read(octets[2:4])
if octets[3] == 0 {
octets[3] = 1 //please no .0 addresses
} else if octets[2] == 255 && octets[3] == 255 {
octets[3] = 254 //please no broadcast addresses
}
ok := false
out, ok = netip.AddrFromSlice(octets)
if !ok {
t.l.Error("failed to produce a valid IPv4 address for tun.snat_address_for_4over6")
return netip.Prefix{}
}
}
return netip.PrefixFrom(out, 32)
}
func (t *tun) reload(c *config.C, initial bool) error { func (t *tun) reload(c *config.C, initial bool) error {
routeChange, routes, err := getAllRoutesFromConfig(c, t.vpnNetworks, initial) routeChange, routes, err := getAllRoutesFromConfig(c, t.vpnNetworks, initial)
if err != nil { if err != nil {
@@ -228,7 +182,9 @@ func (t *tun) reload(c *config.C, initial bool) error {
return nil return nil
} }
t.snatAddr = t.prepareSnatAddr(c, initial, routes) if !initial {
t.snatAddr = prepareSnatAddr(t, t.l, c, routes)
}
routeTree, err := makeRouteTree(t.l, routes, true) routeTree, err := makeRouteTree(t.l, routes, true)
if err != nil { if err != nil {

View File

@@ -58,14 +58,16 @@ type addrLifetime struct {
} }
type tun struct { type tun struct {
Device string Device string
vpnNetworks []netip.Prefix vpnNetworks []netip.Prefix
MTU int unsafeNetworks []netip.Prefix
Routes atomic.Pointer[[]Route] snatAddr netip.Prefix
routeTree atomic.Pointer[bart.Table[routing.Gateways]] MTU int
l *logrus.Logger Routes atomic.Pointer[[]Route]
f *os.File routeTree atomic.Pointer[bart.Table[routing.Gateways]]
fd int l *logrus.Logger
f *os.File
fd int
} }
var deviceNameRE = regexp.MustCompile(`^tun[0-9]+$`) var deviceNameRE = regexp.MustCompile(`^tun[0-9]+$`)
@@ -386,6 +388,14 @@ func (t *tun) Networks() []netip.Prefix {
return t.vpnNetworks return t.vpnNetworks
} }
func (t *tun) UnsafeNetworks() []netip.Prefix {
return t.unsafeNetworks
}
func (t *tun) SNATAddress() netip.Prefix {
return t.snatAddr
}
func (t *tun) Name() string { func (t *tun) Name() string {
return t.Device return t.Device
} }

View File

@@ -49,14 +49,16 @@ type ifreq struct {
} }
type tun struct { type tun struct {
Device string Device string
vpnNetworks []netip.Prefix vpnNetworks []netip.Prefix
MTU int unsafeNetworks []netip.Prefix
Routes atomic.Pointer[[]Route] snatAddr netip.Prefix
routeTree atomic.Pointer[bart.Table[routing.Gateways]] MTU int
l *logrus.Logger Routes atomic.Pointer[[]Route]
f *os.File routeTree atomic.Pointer[bart.Table[routing.Gateways]]
fd int l *logrus.Logger
f *os.File
fd int
// cache out buffer since we need to prepend 4 bytes for tun metadata // cache out buffer since we need to prepend 4 bytes for tun metadata
out []byte out []byte
} }
@@ -89,12 +91,13 @@ func newTun(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, unsafeNet
} }
t := &tun{ t := &tun{
f: os.NewFile(uintptr(fd), ""), f: os.NewFile(uintptr(fd), ""),
fd: fd, fd: fd,
Device: deviceName, Device: deviceName,
vpnNetworks: vpnNetworks, vpnNetworks: vpnNetworks,
MTU: c.GetInt("tun.mtu", DefaultMTU), unsafeNetworks: unsafeNetworks,
l: l, MTU: c.GetInt("tun.mtu", DefaultMTU),
l: l,
} }
err = t.reload(c, true) err = t.reload(c, true)
@@ -306,6 +309,14 @@ func (t *tun) Networks() []netip.Prefix {
return t.vpnNetworks return t.vpnNetworks
} }
func (t *tun) UnsafeNetworks() []netip.Prefix {
return t.unsafeNetworks
}
func (t *tun) SNATAddress() netip.Prefix {
return t.snatAddr
}
func (t *tun) Name() string { func (t *tun) Name() string {
return t.Device return t.Device
} }

View File

@@ -17,11 +17,12 @@ import (
) )
type TestTun struct { type TestTun struct {
Device string Device string
vpnNetworks []netip.Prefix vpnNetworks []netip.Prefix
Routes []Route unsafeNetworks []netip.Prefix
routeTree *bart.Table[routing.Gateways] Routes []Route
l *logrus.Logger routeTree *bart.Table[routing.Gateways]
l *logrus.Logger
closed atomic.Bool closed atomic.Bool
rxPackets chan []byte // Packets to receive into nebula rxPackets chan []byte // Packets to receive into nebula
@@ -39,13 +40,14 @@ func newTun(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, unsafeNet
} }
return &TestTun{ return &TestTun{
Device: c.GetString("tun.dev", ""), Device: c.GetString("tun.dev", ""),
vpnNetworks: vpnNetworks, vpnNetworks: vpnNetworks,
Routes: routes, unsafeNetworks: unsafeNetworks,
routeTree: routeTree, Routes: routes,
l: l, routeTree: routeTree,
rxPackets: make(chan []byte, 10), l: l,
TxPackets: make(chan []byte, 10), rxPackets: make(chan []byte, 10),
TxPackets: make(chan []byte, 10),
}, nil }, nil
} }
@@ -139,3 +141,11 @@ func (t *TestTun) SupportsMultiqueue() bool {
func (t *TestTun) NewMultiQueueReader() (io.ReadWriteCloser, error) { func (t *TestTun) NewMultiQueueReader() (io.ReadWriteCloser, error) {
return nil, fmt.Errorf("TODO: multiqueue not implemented") return nil, fmt.Errorf("TODO: multiqueue not implemented")
} }
func (t *tun) UnsafeNetworks() []netip.Prefix {
return t.UnsafeNetworks()
}
func (t *tun) SNATAddress() netip.Prefix {
return netip.Prefix{}
}

View File

@@ -28,12 +28,14 @@ import (
const tunGUIDLabel = "Fixed Nebula Windows GUID v1" const tunGUIDLabel = "Fixed Nebula Windows GUID v1"
type winTun struct { type winTun struct {
Device string Device string
vpnNetworks []netip.Prefix vpnNetworks []netip.Prefix
MTU int unsafeNetworks []netip.Prefix
Routes atomic.Pointer[[]Route] snatAddr netip.Prefix
routeTree atomic.Pointer[bart.Table[routing.Gateways]] MTU int
l *logrus.Logger Routes atomic.Pointer[[]Route]
routeTree atomic.Pointer[bart.Table[routing.Gateways]]
l *logrus.Logger
tun *wintun.NativeTun tun *wintun.NativeTun
} }
@@ -55,10 +57,11 @@ func newTun(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, unsafeNet
} }
t := &winTun{ t := &winTun{
Device: deviceName, Device: deviceName,
vpnNetworks: vpnNetworks, vpnNetworks: vpnNetworks,
MTU: c.GetInt("tun.mtu", DefaultMTU), unsafeNetworks: unsafeNetworks,
l: l, MTU: c.GetInt("tun.mtu", DefaultMTU),
l: l,
} }
err = t.reload(c, true) err = t.reload(c, true)
@@ -102,6 +105,10 @@ func (t *winTun) reload(c *config.C, initial bool) error {
return nil return nil
} }
if !initial {
t.snatAddr = prepareSnatAddr(t, t.l, c, routes)
}
routeTree, err := makeRouteTree(t.l, routes, false) routeTree, err := makeRouteTree(t.l, routes, false)
if err != nil { if err != nil {
return err return err
@@ -225,6 +232,14 @@ func (t *winTun) Networks() []netip.Prefix {
return t.vpnNetworks return t.vpnNetworks
} }
func (t *winTun) UnsafeNetworks() []netip.Prefix {
return t.unsafeNetworks
}
func (t *winTun) SNATAddress() netip.Prefix {
return t.snatAddr
}
func (t *winTun) Name() string { func (t *winTun) Name() string {
return t.Device return t.Device
} }

View File

@@ -36,6 +36,14 @@ type UserDevice struct {
inboundWriter *io.PipeWriter inboundWriter *io.PipeWriter
} }
func (d *UserDevice) UnsafeNetworks() []netip.Prefix {
return nil
}
func (d *UserDevice) SNATAddress() netip.Prefix {
return netip.Prefix{}
}
func (d *UserDevice) Activate() error { func (d *UserDevice) Activate() error {
return nil return nil
} }

View File

@@ -10,6 +10,16 @@ import (
type NoopTun struct{} type NoopTun struct{}
func (NoopTun) Routes() []Route {
//TODO implement me
panic("implement me")
}
func (NoopTun) UnsafeNetworks() []netip.Prefix {
//TODO implement me
panic("implement me")
}
func (NoopTun) RoutesFor(addr netip.Addr) routing.Gateways { func (NoopTun) RoutesFor(addr netip.Addr) routing.Gateways {
return routing.Gateways{} return routing.Gateways{}
} }