diff --git a/firewall.go b/firewall.go index 2d8cf49e..58dea318 100644 --- a/firewall.go +++ b/firewall.go @@ -215,7 +215,6 @@ func NewFirewall(l *logrus.Logger, tcpTimeout, UDPTimeout, defaultTimeout time.D routableNetworks: routableNetworks, assignedNetworks: assignedNetworks, hasUnsafeNetworks: hasUnsafeNetworks, - snatAddr: snatAddr, l: l, 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) if certificate == nil { 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") } - 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) @@ -347,6 +353,12 @@ func (f *Firewall) GetRuleHashes() string { 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 { // f.snatAddr is only valid if we're a snat-capable router return f.snatAddr.IsValid() && fp.RemoteAddr == f.snatAddr diff --git a/interface.go b/interface.go index 1377bc1b..83d313b5 100644 --- a/interface.go +++ b/interface.go @@ -249,6 +249,7 @@ func (f *Interface) activate() { f.inside.Close() f.l.Fatal(err) } + f.firewall.SetSNATAddressFromInterface(f) } func (f *Interface) run() { @@ -340,11 +341,12 @@ func (f *Interface) reloadFirewall(c *config.C) { 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 { f.l.WithError(err).Error("Error while creating firewall during reload") return } + fw.SetSNATAddressFromInterface(f) oldFw := f.firewall conntrack := oldFw.Conntrack diff --git a/main.go b/main.go index e924ce8a..975bdebf 100644 --- a/main.go +++ b/main.go @@ -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) } - snatAddr := netip.MustParseAddr("169.254.55.96") //todo get this from tun! - fw, err := NewFirewallFromConfig(l, pki.getCertState(), c, snatAddr) + fw, err := NewFirewallFromConfig(l, pki.getCertState(), c) if err != nil { return nil, util.ContextualizeIfNeeded("Error while loading firewall rules", err) } diff --git a/overlay/device.go b/overlay/device.go index b6077aba..bb14a76c 100644 --- a/overlay/device.go +++ b/overlay/device.go @@ -11,6 +11,8 @@ type Device interface { io.ReadWriteCloser Activate() error Networks() []netip.Prefix + UnsafeNetworks() []netip.Prefix + SNATAddress() netip.Prefix Name() string RoutesFor(netip.Addr) routing.Gateways SupportsMultiqueue() bool diff --git a/overlay/tun.go b/overlay/tun.go index 56c7fccf..8bac6502 100644 --- a/overlay/tun.go +++ b/overlay/tun.go @@ -1,6 +1,7 @@ package overlay import ( + "crypto/rand" "fmt" "net" "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) } + +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) +} diff --git a/overlay/tun_android.go b/overlay/tun_android.go index f091772a..3ab3f8a7 100644 --- a/overlay/tun_android.go +++ b/overlay/tun_android.go @@ -19,14 +19,15 @@ import ( type tun struct { io.ReadWriteCloser - fd int - vpnNetworks []netip.Prefix - Routes atomic.Pointer[[]Route] - routeTree atomic.Pointer[bart.Table[routing.Gateways]] - l *logrus.Logger + fd int + vpnNetworks []netip.Prefix + unsafeNetworks []netip.Prefix + Routes atomic.Pointer[[]Route] + 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. // Be sure not to call file.Fd() as it will set the fd to blocking mode. 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, fd: deviceFd, vpnNetworks: vpnNetworks, + unsafeNetworks: unsafeNetworks, l: l, } @@ -91,6 +93,10 @@ func (t *tun) Networks() []netip.Prefix { return t.vpnNetworks } +func (t *tun) UnsafeNetworks() []netip.Prefix { + return t.UnsafeNetworks() +} + func (t *tun) Name() string { return "android" } diff --git a/overlay/tun_darwin.go b/overlay/tun_darwin.go index c9c3927e..23be219f 100644 --- a/overlay/tun_darwin.go +++ b/overlay/tun_darwin.go @@ -24,13 +24,15 @@ import ( type tun struct { io.ReadWriteCloser - Device string - vpnNetworks []netip.Prefix - DefaultMTU int - Routes atomic.Pointer[[]Route] - routeTree atomic.Pointer[bart.Table[routing.Gateways]] - linkAddr *netroute.LinkAddr - l *logrus.Logger + Device string + vpnNetworks []netip.Prefix + unsafeNetworks []netip.Prefix + snatAddr netip.Prefix + DefaultMTU int + Routes atomic.Pointer[[]Route] + 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 out []byte @@ -127,6 +129,7 @@ func newTun(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, unsafeNet ReadWriteCloser: os.NewFile(uintptr(fd), ""), Device: name, vpnNetworks: vpnNetworks, + unsafeNetworks: unsafeNetworks, DefaultMTU: c.GetInt("tun.mtu", DefaultMTU), l: l, } @@ -545,6 +548,14 @@ func (t *tun) Networks() []netip.Prefix { 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 { return t.Device } diff --git a/overlay/tun_disabled.go b/overlay/tun_disabled.go index aa3dddaf..db976d10 100644 --- a/overlay/tun_disabled.go +++ b/overlay/tun_disabled.go @@ -22,6 +22,13 @@ type disabledTun struct { 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 { tun := &disabledTun{ vpnNetworks: vpnNetworks, diff --git a/overlay/tun_freebsd.go b/overlay/tun_freebsd.go index c66e45f1..bae53235 100644 --- a/overlay/tun_freebsd.go +++ b/overlay/tun_freebsd.go @@ -86,14 +86,16 @@ type ifreqAlias6 struct { } type tun struct { - Device string - vpnNetworks []netip.Prefix - MTU int - Routes atomic.Pointer[[]Route] - routeTree atomic.Pointer[bart.Table[routing.Gateways]] - linkAddr *netroute.LinkAddr - l *logrus.Logger - devFd int + Device string + vpnNetworks []netip.Prefix + unsafeNetworks []netip.Prefix + snatAddr netip.Prefix + MTU int + Routes atomic.Pointer[[]Route] + routeTree atomic.Pointer[bart.Table[routing.Gateways]] + linkAddr *netroute.LinkAddr + l *logrus.Logger + devFd int } 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{ - Device: deviceName, - vpnNetworks: vpnNetworks, - MTU: c.GetInt("tun.mtu", DefaultMTU), - l: l, - devFd: fd, + Device: deviceName, + vpnNetworks: vpnNetworks, + unsafeNetworks: unsafeNetworks, + MTU: c.GetInt("tun.mtu", DefaultMTU), + l: l, + devFd: fd, } err = t.reload(c, true) @@ -446,6 +449,14 @@ func (t *tun) Networks() []netip.Prefix { 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 { return t.Device } diff --git a/overlay/tun_ios.go b/overlay/tun_ios.go index 85466d1e..963e49c2 100644 --- a/overlay/tun_ios.go +++ b/overlay/tun_ios.go @@ -22,20 +22,22 @@ import ( type tun struct { io.ReadWriteCloser - vpnNetworks []netip.Prefix - Routes atomic.Pointer[[]Route] - routeTree atomic.Pointer[bart.Table[routing.Gateways]] - l *logrus.Logger + vpnNetworks []netip.Prefix + unsafeNetworks []netip.Prefix + Routes atomic.Pointer[[]Route] + routeTree atomic.Pointer[bart.Table[routing.Gateways]] + l *logrus.Logger } func newTun(_ *config.C, _ *logrus.Logger, _ []netip.Prefix, _ []netip.Prefix, _ bool) (*tun, error) { 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") t := &tun{ vpnNetworks: vpnNetworks, + unsafeNetworks: unsafeNetworks, ReadWriteCloser: &tunReadCloser{f: file}, l: l, } @@ -147,6 +149,14 @@ func (t *tun) Networks() []netip.Prefix { 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 { return "iOS" } diff --git a/overlay/tun_linux.go b/overlay/tun_linux.go index 4ba815e9..1b604c2a 100644 --- a/overlay/tun_linux.go +++ b/overlay/tun_linux.go @@ -4,7 +4,6 @@ package overlay import ( - "crypto/rand" "fmt" "io" "net" @@ -57,6 +56,14 @@ func (t *tun) Networks() []netip.Prefix { return t.vpnNetworks } +func (t *tun) UnsafeNetworks() []netip.Prefix { + return t.unsafeNetworks +} + +func (t *tun) SNATAddress() netip.Prefix { + return t.snatAddr +} + type ifReq struct { Name [16]byte Flags uint16 @@ -165,59 +172,6 @@ func newTunGeneric(c *config.C, l *logrus.Logger, file *os.File, vpnNetworks []n 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 { routeChange, routes, err := getAllRoutesFromConfig(c, t.vpnNetworks, initial) if err != nil { @@ -228,7 +182,9 @@ func (t *tun) reload(c *config.C, initial bool) error { 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) if err != nil { diff --git a/overlay/tun_netbsd.go b/overlay/tun_netbsd.go index 39336108..5174adb3 100644 --- a/overlay/tun_netbsd.go +++ b/overlay/tun_netbsd.go @@ -58,14 +58,16 @@ type addrLifetime struct { } type tun struct { - Device string - vpnNetworks []netip.Prefix - MTU int - Routes atomic.Pointer[[]Route] - routeTree atomic.Pointer[bart.Table[routing.Gateways]] - l *logrus.Logger - f *os.File - fd int + Device string + vpnNetworks []netip.Prefix + unsafeNetworks []netip.Prefix + snatAddr netip.Prefix + MTU int + Routes atomic.Pointer[[]Route] + routeTree atomic.Pointer[bart.Table[routing.Gateways]] + l *logrus.Logger + f *os.File + fd int } var deviceNameRE = regexp.MustCompile(`^tun[0-9]+$`) @@ -386,6 +388,14 @@ func (t *tun) Networks() []netip.Prefix { 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 { return t.Device } diff --git a/overlay/tun_openbsd.go b/overlay/tun_openbsd.go index 701d97dd..9f0d6567 100644 --- a/overlay/tun_openbsd.go +++ b/overlay/tun_openbsd.go @@ -49,14 +49,16 @@ type ifreq struct { } type tun struct { - Device string - vpnNetworks []netip.Prefix - MTU int - Routes atomic.Pointer[[]Route] - routeTree atomic.Pointer[bart.Table[routing.Gateways]] - l *logrus.Logger - f *os.File - fd int + Device string + vpnNetworks []netip.Prefix + unsafeNetworks []netip.Prefix + snatAddr netip.Prefix + MTU int + Routes atomic.Pointer[[]Route] + routeTree atomic.Pointer[bart.Table[routing.Gateways]] + l *logrus.Logger + f *os.File + fd int // cache out buffer since we need to prepend 4 bytes for tun metadata out []byte } @@ -89,12 +91,13 @@ func newTun(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, unsafeNet } t := &tun{ - f: os.NewFile(uintptr(fd), ""), - fd: fd, - Device: deviceName, - vpnNetworks: vpnNetworks, - MTU: c.GetInt("tun.mtu", DefaultMTU), - l: l, + f: os.NewFile(uintptr(fd), ""), + fd: fd, + Device: deviceName, + vpnNetworks: vpnNetworks, + unsafeNetworks: unsafeNetworks, + MTU: c.GetInt("tun.mtu", DefaultMTU), + l: l, } err = t.reload(c, true) @@ -306,6 +309,14 @@ func (t *tun) Networks() []netip.Prefix { 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 { return t.Device } diff --git a/overlay/tun_tester.go b/overlay/tun_tester.go index 145eccb9..3e876cb5 100644 --- a/overlay/tun_tester.go +++ b/overlay/tun_tester.go @@ -17,11 +17,12 @@ import ( ) type TestTun struct { - Device string - vpnNetworks []netip.Prefix - Routes []Route - routeTree *bart.Table[routing.Gateways] - l *logrus.Logger + Device string + vpnNetworks []netip.Prefix + unsafeNetworks []netip.Prefix + Routes []Route + routeTree *bart.Table[routing.Gateways] + l *logrus.Logger closed atomic.Bool 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{ - Device: c.GetString("tun.dev", ""), - vpnNetworks: vpnNetworks, - Routes: routes, - routeTree: routeTree, - l: l, - rxPackets: make(chan []byte, 10), - TxPackets: make(chan []byte, 10), + Device: c.GetString("tun.dev", ""), + vpnNetworks: vpnNetworks, + unsafeNetworks: unsafeNetworks, + Routes: routes, + routeTree: routeTree, + l: l, + rxPackets: make(chan []byte, 10), + TxPackets: make(chan []byte, 10), }, nil } @@ -139,3 +141,11 @@ func (t *TestTun) SupportsMultiqueue() bool { func (t *TestTun) NewMultiQueueReader() (io.ReadWriteCloser, error) { 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{} +} diff --git a/overlay/tun_windows.go b/overlay/tun_windows.go index d434d66d..cab52d99 100644 --- a/overlay/tun_windows.go +++ b/overlay/tun_windows.go @@ -28,12 +28,14 @@ import ( const tunGUIDLabel = "Fixed Nebula Windows GUID v1" type winTun struct { - Device string - vpnNetworks []netip.Prefix - MTU int - Routes atomic.Pointer[[]Route] - routeTree atomic.Pointer[bart.Table[routing.Gateways]] - l *logrus.Logger + Device string + vpnNetworks []netip.Prefix + unsafeNetworks []netip.Prefix + snatAddr netip.Prefix + MTU int + Routes atomic.Pointer[[]Route] + routeTree atomic.Pointer[bart.Table[routing.Gateways]] + l *logrus.Logger tun *wintun.NativeTun } @@ -55,10 +57,11 @@ func newTun(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, unsafeNet } t := &winTun{ - Device: deviceName, - vpnNetworks: vpnNetworks, - MTU: c.GetInt("tun.mtu", DefaultMTU), - l: l, + Device: deviceName, + vpnNetworks: vpnNetworks, + unsafeNetworks: unsafeNetworks, + MTU: c.GetInt("tun.mtu", DefaultMTU), + l: l, } err = t.reload(c, true) @@ -102,6 +105,10 @@ func (t *winTun) reload(c *config.C, initial bool) error { return nil } + if !initial { + t.snatAddr = prepareSnatAddr(t, t.l, c, routes) + } + routeTree, err := makeRouteTree(t.l, routes, false) if err != nil { return err @@ -225,6 +232,14 @@ func (t *winTun) Networks() []netip.Prefix { 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 { return t.Device } diff --git a/overlay/user.go b/overlay/user.go index 52fa0df7..1c01dd1c 100644 --- a/overlay/user.go +++ b/overlay/user.go @@ -36,6 +36,14 @@ type UserDevice struct { 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 { return nil } diff --git a/test/tun.go b/test/tun.go index fb32782f..182ee88d 100644 --- a/test/tun.go +++ b/test/tun.go @@ -10,6 +10,16 @@ import ( 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 { return routing.Gateways{} }