mirror of
https://github.com/slackhq/nebula.git
synced 2026-04-03 12:45:17 +02:00
split the client-snat-addr and the router-snat-addr to decrease confusion hopefully
This commit is contained in:
@@ -12,6 +12,7 @@ type Device interface {
|
||||
Activate() error
|
||||
Networks() []netip.Prefix
|
||||
UnsafeNetworks() []netip.Prefix
|
||||
UnsafeIPv4OriginAddress() netip.Prefix
|
||||
SNATAddress() netip.Prefix
|
||||
Name() string
|
||||
RoutesFor(netip.Addr) routing.Gateways
|
||||
|
||||
@@ -131,52 +131,75 @@ 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 {
|
||||
func genLinkLocal() netip.Prefix {
|
||||
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
|
||||
}
|
||||
out, _ := netip.AddrFromSlice(octets)
|
||||
return netip.PrefixFrom(out, 32)
|
||||
}
|
||||
|
||||
// prepareUnsafeOriginAddr provides the IPv4 address used on IPv6-only clients that need to access IPv4 unsafe routes
|
||||
func prepareUnsafeOriginAddr(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 an unsafe origin address
|
||||
}
|
||||
|
||||
needed := false
|
||||
for _, route := range routes { //or if we have a route defined into an IPv4 range
|
||||
if route.Cidr.Addr().Is4() {
|
||||
needed = true //todo should this only apply to unsafe routes? almost certainly
|
||||
break
|
||||
}
|
||||
}
|
||||
if !needed {
|
||||
return netip.Prefix{}
|
||||
}
|
||||
|
||||
//todo better config name for sure
|
||||
if a := c.GetString("tun.unsafe_origin_address_for_4over6", ""); a != "" {
|
||||
out, err := netip.ParseAddr(a)
|
||||
if err != nil {
|
||||
l.WithField("value", a).WithError(err).Warn("failed to parse tun.unsafe_origin_address_for_4over6, will use a random value")
|
||||
} else if !out.Is4() || !out.IsLinkLocalUnicast() {
|
||||
l.WithField("value", out).Warn("tun.unsafe_origin_address_for_4over6 must be an IPv4 address")
|
||||
} else if out.IsValid() {
|
||||
return netip.PrefixFrom(out, 32)
|
||||
}
|
||||
}
|
||||
return genLinkLocal()
|
||||
}
|
||||
|
||||
// prepareSnatAddr provides the address that an IPv6-only unsafe router should use to SNAT traffic before handing it to the operating system
|
||||
func prepareSnatAddr(d Device, l *logrus.Logger, c *config.C) 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
|
||||
needed := false
|
||||
for _, un := range d.UnsafeNetworks() { //if we are an unsafe router for an IPv4 range
|
||||
if un.Addr().Is4() {
|
||||
addSnatAddr = true
|
||||
needed = 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 {
|
||||
if !needed {
|
||||
return netip.Prefix{}
|
||||
}
|
||||
|
||||
var err error
|
||||
out := netip.Addr{}
|
||||
if a := c.GetString("tun.snat_address_for_4over6", ""); a != "" {
|
||||
out, err = netip.ParseAddr(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")
|
||||
} else if out.IsValid() {
|
||||
return netip.PrefixFrom(out, 32)
|
||||
}
|
||||
}
|
||||
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)
|
||||
return genLinkLocal()
|
||||
}
|
||||
|
||||
@@ -19,12 +19,13 @@ import (
|
||||
|
||||
type tun struct {
|
||||
io.ReadWriteCloser
|
||||
fd int
|
||||
vpnNetworks []netip.Prefix
|
||||
unsafeNetworks []netip.Prefix
|
||||
Routes atomic.Pointer[[]Route]
|
||||
routeTree atomic.Pointer[bart.Table[routing.Gateways]]
|
||||
l *logrus.Logger
|
||||
fd int
|
||||
vpnNetworks []netip.Prefix
|
||||
unsafeNetworks []netip.Prefix
|
||||
unsafeIPv4Origin 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, unsafeNetworks []netip.Prefix) (*tun, error) {
|
||||
@@ -78,6 +79,8 @@ func (t *tun) reload(c *config.C, initial bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
t.unsafeIPv4Origin = prepareUnsafeOriginAddr(t, t.l, c, routes)
|
||||
|
||||
routeTree, err := makeRouteTree(t.l, routes, false)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -97,6 +100,14 @@ func (t *tun) UnsafeNetworks() []netip.Prefix {
|
||||
return t.UnsafeNetworks()
|
||||
}
|
||||
|
||||
func (t *tun) UnsafeIPv4OriginAddress() netip.Prefix {
|
||||
return t.unsafeIPv4Origin
|
||||
}
|
||||
|
||||
func (t *tun) SNATAddress() netip.Prefix {
|
||||
return netip.Prefix{}
|
||||
}
|
||||
|
||||
func (t *tun) Name() string {
|
||||
return "android"
|
||||
}
|
||||
|
||||
@@ -24,15 +24,15 @@ import (
|
||||
|
||||
type tun struct {
|
||||
io.ReadWriteCloser
|
||||
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
|
||||
Device string
|
||||
vpnNetworks []netip.Prefix
|
||||
unsafeNetworks []netip.Prefix
|
||||
unsafeIPv4Origin 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
|
||||
@@ -216,8 +216,8 @@ func (t *tun) Activate() error {
|
||||
}
|
||||
}
|
||||
}
|
||||
if t.snatAddr.IsValid() && t.snatAddr.Addr().Is4() {
|
||||
if err = t.activate4(t.snatAddr); err != nil {
|
||||
if t.unsafeIPv4Origin.IsValid() && t.unsafeIPv4Origin.Addr().Is4() {
|
||||
if err = t.activate4(t.unsafeIPv4Origin); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -323,7 +323,7 @@ func (t *tun) reload(c *config.C, initial bool) error {
|
||||
}
|
||||
|
||||
if initial {
|
||||
t.snatAddr = prepareSnatAddr(t, t.l, c, routes)
|
||||
t.unsafeIPv4Origin = prepareUnsafeOriginAddr(t, t.l, c, routes)
|
||||
}
|
||||
|
||||
routeTree, err := makeRouteTree(t.l, routes, false)
|
||||
@@ -561,8 +561,12 @@ func (t *tun) UnsafeNetworks() []netip.Prefix {
|
||||
return t.unsafeNetworks
|
||||
}
|
||||
|
||||
func (t *tun) UnsafeIPv4OriginAddress() netip.Prefix {
|
||||
return t.unsafeIPv4Origin
|
||||
}
|
||||
|
||||
func (t *tun) SNATAddress() netip.Prefix {
|
||||
return t.snatAddr
|
||||
return netip.Prefix{}
|
||||
}
|
||||
|
||||
func (t *tun) Name() string {
|
||||
|
||||
@@ -22,13 +22,6 @@ 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,
|
||||
@@ -59,6 +52,17 @@ func (t *disabledTun) Networks() []netip.Prefix {
|
||||
return t.vpnNetworks
|
||||
}
|
||||
|
||||
func (*disabledTun) UnsafeNetworks() []netip.Prefix {
|
||||
return nil
|
||||
}
|
||||
func (*disabledTun) SNATAddress() netip.Prefix {
|
||||
return netip.Prefix{}
|
||||
}
|
||||
|
||||
func (*disabledTun) UnsafeIPv4OriginAddress() netip.Prefix {
|
||||
return netip.Prefix{}
|
||||
}
|
||||
|
||||
func (*disabledTun) Name() string {
|
||||
return "disabled"
|
||||
}
|
||||
|
||||
@@ -86,16 +86,16 @@ type ifreqAlias6 struct {
|
||||
}
|
||||
|
||||
type tun struct {
|
||||
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
|
||||
Device string
|
||||
vpnNetworks []netip.Prefix
|
||||
unsafeNetworks []netip.Prefix
|
||||
unsafeIPv4Origin 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) {
|
||||
@@ -414,7 +414,7 @@ func (t *tun) reload(c *config.C, initial bool) error {
|
||||
}
|
||||
|
||||
if initial {
|
||||
t.snatAddr = prepareSnatAddr(t, t.l, c, routes)
|
||||
t.unsafeIPv4Origin = prepareUnsafeOriginAddr(t, t.l, c, routes)
|
||||
}
|
||||
|
||||
routeTree, err := makeRouteTree(t.l, routes, false)
|
||||
@@ -457,8 +457,12 @@ func (t *tun) UnsafeNetworks() []netip.Prefix {
|
||||
return t.unsafeNetworks
|
||||
}
|
||||
|
||||
func (t *tun) UnsafeIPv4OriginAddress() netip.Prefix {
|
||||
return t.unsafeIPv4Origin
|
||||
}
|
||||
|
||||
func (t *tun) SNATAddress() netip.Prefix {
|
||||
return t.snatAddr
|
||||
return netip.Prefix{}
|
||||
}
|
||||
|
||||
func (t *tun) Name() string {
|
||||
|
||||
@@ -22,11 +22,12 @@ import (
|
||||
|
||||
type tun struct {
|
||||
io.ReadWriteCloser
|
||||
vpnNetworks []netip.Prefix
|
||||
unsafeNetworks []netip.Prefix
|
||||
Routes atomic.Pointer[[]Route]
|
||||
routeTree atomic.Pointer[bart.Table[routing.Gateways]]
|
||||
l *logrus.Logger
|
||||
vpnNetworks []netip.Prefix
|
||||
unsafeNetworks []netip.Prefix
|
||||
unsafeIPv4Origin 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) {
|
||||
@@ -71,6 +72,8 @@ func (t *tun) reload(c *config.C, initial bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
t.unsafeIPv4Origin = prepareUnsafeOriginAddr(t, t.l, c, routes)
|
||||
|
||||
routeTree, err := makeRouteTree(t.l, routes, false)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -153,8 +156,12 @@ func (t *tun) UnsafeNetworks() []netip.Prefix {
|
||||
return t.unsafeNetworks
|
||||
}
|
||||
|
||||
func (t *tun) UnsafeIPv4OriginAddress() netip.Prefix {
|
||||
return t.unsafeIPv4Origin
|
||||
}
|
||||
|
||||
func (t *tun) SNATAddress() netip.Prefix {
|
||||
return t.snatAddr
|
||||
return netip.Prefix{}
|
||||
}
|
||||
|
||||
func (t *tun) Name() string {
|
||||
|
||||
@@ -47,7 +47,8 @@ type tun struct {
|
||||
routesFromSystem map[netip.Prefix]routing.Gateways
|
||||
routesFromSystemLock sync.Mutex
|
||||
|
||||
snatAddr netip.Prefix
|
||||
snatAddr netip.Prefix
|
||||
unsafeIPv4Origin netip.Prefix
|
||||
|
||||
l *logrus.Logger
|
||||
}
|
||||
@@ -60,6 +61,10 @@ func (t *tun) UnsafeNetworks() []netip.Prefix {
|
||||
return t.unsafeNetworks
|
||||
}
|
||||
|
||||
func (t *tun) UnsafeIPv4OriginAddress() netip.Prefix {
|
||||
return t.unsafeIPv4Origin
|
||||
}
|
||||
|
||||
func (t *tun) SNATAddress() netip.Prefix {
|
||||
return t.snatAddr
|
||||
}
|
||||
@@ -183,7 +188,8 @@ func (t *tun) reload(c *config.C, initial bool) error {
|
||||
}
|
||||
|
||||
if initial {
|
||||
t.snatAddr = prepareSnatAddr(t, t.l, c, routes)
|
||||
t.unsafeIPv4Origin = prepareUnsafeOriginAddr(t, t.l, c, routes) //todo MUST be different from t.snatAddr!
|
||||
t.snatAddr = prepareSnatAddr(t, t.l, c)
|
||||
}
|
||||
|
||||
routeTree, err := makeRouteTree(t.l, routes, true)
|
||||
@@ -329,15 +335,15 @@ func (t *tun) addIPs(link netlink.Link) error {
|
||||
}
|
||||
}
|
||||
|
||||
if t.snatAddr.IsValid() && len(t.unsafeNetworks) == 0 { //TODO unsafe-routers should be able to snat and be snatted
|
||||
if t.unsafeIPv4Origin.IsValid() {
|
||||
newAddrs = append(newAddrs, &netlink.Addr{
|
||||
IPNet: &net.IPNet{
|
||||
IP: t.snatAddr.Addr().AsSlice(),
|
||||
Mask: net.CIDRMask(t.snatAddr.Bits(), t.snatAddr.Addr().BitLen()),
|
||||
IP: t.unsafeIPv4Origin.Addr().AsSlice(),
|
||||
Mask: net.CIDRMask(t.unsafeIPv4Origin.Bits(), t.unsafeIPv4Origin.Addr().BitLen()),
|
||||
},
|
||||
Label: t.snatAddr.Addr().Zone(),
|
||||
Label: t.unsafeIPv4Origin.Addr().Zone(),
|
||||
})
|
||||
t.l.WithField("address", t.snatAddr).Info("Adding SNAT address")
|
||||
t.l.WithField("address", t.unsafeIPv4Origin).Info("Adding origin address for IPv4 unsafe_routes")
|
||||
}
|
||||
|
||||
//add all new addresses
|
||||
@@ -431,9 +437,9 @@ func (t *tun) Activate() error {
|
||||
}
|
||||
}
|
||||
//TODO snat and be snatted
|
||||
if t.snatAddr.IsValid() && len(t.unsafeNetworks) == 0 {
|
||||
if err = t.setDefaultRoute(t.snatAddr); err != nil {
|
||||
return fmt.Errorf("failed to set default route MTU for %s: %w", t.snatAddr, err)
|
||||
if t.unsafeIPv4Origin.IsValid() {
|
||||
if err = t.setDefaultRoute(t.unsafeIPv4Origin); err != nil {
|
||||
return fmt.Errorf("failed to set default route MTU for %s: %w", t.unsafeIPv4Origin, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -565,10 +571,10 @@ func (t *tun) addRoutes(logErrors bool) error {
|
||||
}
|
||||
}
|
||||
|
||||
if len(t.unsafeNetworks) == 0 {
|
||||
return nil
|
||||
if t.snatAddr.IsValid() {
|
||||
return t.setSnatRoute()
|
||||
}
|
||||
return t.setSnatRoute()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *tun) removeRoutes(routes []Route) {
|
||||
|
||||
@@ -58,16 +58,16 @@ type addrLifetime struct {
|
||||
}
|
||||
|
||||
type tun struct {
|
||||
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
|
||||
Device string
|
||||
vpnNetworks []netip.Prefix
|
||||
unsafeNetworks []netip.Prefix
|
||||
unsafeIPv4Origin 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]+$`)
|
||||
@@ -353,7 +353,7 @@ func (t *tun) reload(c *config.C, initial bool) error {
|
||||
}
|
||||
|
||||
if initial {
|
||||
t.snatAddr = prepareSnatAddr(t, t.l, c, routes)
|
||||
t.unsafeIPv4Origin = prepareUnsafeOriginAddr(t, t.l, c, routes)
|
||||
}
|
||||
|
||||
routeTree, err := makeRouteTree(t.l, routes, false)
|
||||
@@ -396,8 +396,12 @@ func (t *tun) UnsafeNetworks() []netip.Prefix {
|
||||
return t.unsafeNetworks
|
||||
}
|
||||
|
||||
func (t *tun) UnsafeIPv4OriginAddress() netip.Prefix {
|
||||
return t.unsafeIPv4Origin
|
||||
}
|
||||
|
||||
func (t *tun) SNATAddress() netip.Prefix {
|
||||
return t.snatAddr
|
||||
return netip.Prefix{}
|
||||
}
|
||||
|
||||
func (t *tun) Name() string {
|
||||
|
||||
@@ -49,16 +49,16 @@ type ifreq struct {
|
||||
}
|
||||
|
||||
type tun struct {
|
||||
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
|
||||
Device string
|
||||
vpnNetworks []netip.Prefix
|
||||
unsafeNetworks []netip.Prefix
|
||||
unsafeIPv4Origin 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
|
||||
}
|
||||
@@ -274,7 +274,7 @@ func (t *tun) reload(c *config.C, initial bool) error {
|
||||
}
|
||||
|
||||
if initial {
|
||||
t.snatAddr = prepareSnatAddr(t, t.l, c, routes)
|
||||
t.unsafeIPv4Origin = prepareUnsafeOriginAddr(t, t.l, c, routes)
|
||||
}
|
||||
|
||||
routeTree, err := makeRouteTree(t.l, routes, false)
|
||||
@@ -317,8 +317,12 @@ func (t *tun) UnsafeNetworks() []netip.Prefix {
|
||||
return t.unsafeNetworks
|
||||
}
|
||||
|
||||
func (t *tun) UnsafeIPv4OriginAddress() netip.Prefix {
|
||||
return t.unsafeIPv4Origin
|
||||
}
|
||||
|
||||
func (t *tun) SNATAddress() netip.Prefix {
|
||||
return t.snatAddr
|
||||
return netip.Prefix{}
|
||||
}
|
||||
|
||||
func (t *tun) Name() string {
|
||||
|
||||
@@ -12,11 +12,12 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// mockDevice is a minimal Device implementation for testing prepareSnatAddr.
|
||||
// mockDevice is a minimal Device implementation for testing prepareUnsafeOriginAddr.
|
||||
type mockDevice struct {
|
||||
networks []netip.Prefix
|
||||
unsafeNetworks []netip.Prefix
|
||||
snatAddr netip.Prefix
|
||||
unsafeSnatAddr netip.Prefix
|
||||
}
|
||||
|
||||
func (d *mockDevice) Read([]byte) (int, error) { return 0, nil }
|
||||
@@ -26,6 +27,7 @@ func (d *mockDevice) Activate() error { return
|
||||
func (d *mockDevice) Networks() []netip.Prefix { return d.networks }
|
||||
func (d *mockDevice) UnsafeNetworks() []netip.Prefix { return d.unsafeNetworks }
|
||||
func (d *mockDevice) SNATAddress() netip.Prefix { return d.snatAddr }
|
||||
func (d *mockDevice) UnsafeIPv4OriginAddress() netip.Prefix { return d.unsafeSnatAddr }
|
||||
func (d *mockDevice) Name() string { return "mock" }
|
||||
func (d *mockDevice) RoutesFor(netip.Addr) routing.Gateways { return routing.Gateways{} }
|
||||
func (d *mockDevice) SupportsMultiqueue() bool { return false }
|
||||
@@ -40,7 +42,7 @@ func TestPrepareSnatAddr_V4Primary_NoSnat(t *testing.T) {
|
||||
d := &mockDevice{
|
||||
networks: []netip.Prefix{netip.MustParsePrefix("10.0.0.1/24")},
|
||||
}
|
||||
result := prepareSnatAddr(d, l, c, nil)
|
||||
result := prepareUnsafeOriginAddr(d, l, c, nil)
|
||||
assert.Equal(t, netip.Prefix{}, result, "should not assign SNAT addr when device has IPv4 primary")
|
||||
}
|
||||
|
||||
@@ -53,7 +55,7 @@ func TestPrepareSnatAddr_V6Primary_NoUnsafeOrRoutes(t *testing.T) {
|
||||
d := &mockDevice{
|
||||
networks: []netip.Prefix{netip.MustParsePrefix("fd00::1/128")},
|
||||
}
|
||||
result := prepareSnatAddr(d, l, c, nil)
|
||||
result := prepareUnsafeOriginAddr(d, l, c, nil)
|
||||
assert.Equal(t, netip.Prefix{}, result, "should not assign SNAT addr without IPv4 unsafe networks or routes")
|
||||
}
|
||||
|
||||
@@ -67,14 +69,17 @@ func TestPrepareSnatAddr_V6Primary_WithV4Unsafe(t *testing.T) {
|
||||
networks: []netip.Prefix{netip.MustParsePrefix("fd00::1/128")},
|
||||
unsafeNetworks: []netip.Prefix{netip.MustParsePrefix("192.168.0.0/16")},
|
||||
}
|
||||
result := prepareSnatAddr(d, l, c, nil)
|
||||
result := prepareSnatAddr(d, l, c)
|
||||
require.True(t, result.IsValid(), "should assign SNAT addr")
|
||||
assert.True(t, result.Addr().Is4(), "SNAT addr should be IPv4")
|
||||
assert.True(t, result.Addr().IsLinkLocalUnicast(), "SNAT addr should be link-local")
|
||||
assert.Equal(t, 32, result.Bits(), "SNAT addr should be /32")
|
||||
|
||||
result = prepareUnsafeOriginAddr(d, l, c, nil)
|
||||
require.False(t, result.IsValid(), "no routes = no origin addr needed")
|
||||
}
|
||||
|
||||
func TestPrepareSnatAddr_V6Primary_WithV4Route(t *testing.T) {
|
||||
func TestPrepareUnsafeOriginAddr_V6Primary_WithV4Route(t *testing.T) {
|
||||
l := logrus.New()
|
||||
l.SetLevel(logrus.PanicLevel)
|
||||
c := config.NewC(l)
|
||||
@@ -86,10 +91,13 @@ func TestPrepareSnatAddr_V6Primary_WithV4Route(t *testing.T) {
|
||||
routes := []Route{
|
||||
{Cidr: netip.MustParsePrefix("10.0.0.0/8")},
|
||||
}
|
||||
result := prepareSnatAddr(d, l, c, routes)
|
||||
result := prepareUnsafeOriginAddr(d, l, c, routes)
|
||||
require.True(t, result.IsValid(), "should assign SNAT addr when IPv4 route exists")
|
||||
assert.True(t, result.Addr().Is4())
|
||||
assert.True(t, result.Addr().IsLinkLocalUnicast())
|
||||
|
||||
result = prepareSnatAddr(d, l, c)
|
||||
require.False(t, result.IsValid(), "no UnsafeNetworks = no snat addr needed")
|
||||
}
|
||||
|
||||
func TestPrepareSnatAddr_V6Primary_V6UnsafeOnly(t *testing.T) {
|
||||
@@ -102,7 +110,7 @@ func TestPrepareSnatAddr_V6Primary_V6UnsafeOnly(t *testing.T) {
|
||||
networks: []netip.Prefix{netip.MustParsePrefix("fd00::1/128")},
|
||||
unsafeNetworks: []netip.Prefix{netip.MustParsePrefix("fd01::/64")},
|
||||
}
|
||||
result := prepareSnatAddr(d, l, c, nil)
|
||||
result := prepareUnsafeOriginAddr(d, l, c, nil)
|
||||
assert.Equal(t, netip.Prefix{}, result, "should not assign SNAT addr for IPv6-only unsafe networks")
|
||||
}
|
||||
|
||||
@@ -118,7 +126,7 @@ func TestPrepareSnatAddr_ManualAddress(t *testing.T) {
|
||||
networks: []netip.Prefix{netip.MustParsePrefix("fd00::1/128")},
|
||||
unsafeNetworks: []netip.Prefix{netip.MustParsePrefix("192.168.0.0/16")},
|
||||
}
|
||||
result := prepareSnatAddr(d, l, c, nil)
|
||||
result := prepareSnatAddr(d, l, c)
|
||||
require.True(t, result.IsValid())
|
||||
assert.Equal(t, netip.MustParseAddr("169.254.42.42"), result.Addr())
|
||||
assert.Equal(t, 32, result.Bits())
|
||||
@@ -136,7 +144,7 @@ func TestPrepareSnatAddr_InvalidManualAddress_Fallback(t *testing.T) {
|
||||
networks: []netip.Prefix{netip.MustParsePrefix("fd00::1/128")},
|
||||
unsafeNetworks: []netip.Prefix{netip.MustParsePrefix("192.168.0.0/16")},
|
||||
}
|
||||
result := prepareSnatAddr(d, l, c, nil)
|
||||
result := prepareSnatAddr(d, l, c)
|
||||
// Should fall back to auto-assignment
|
||||
require.True(t, result.IsValid(), "should fall back to auto-assigned address")
|
||||
assert.True(t, result.Addr().Is4())
|
||||
@@ -155,7 +163,7 @@ func TestPrepareSnatAddr_AutoGenerated_Range(t *testing.T) {
|
||||
|
||||
// Generate several addresses and verify they're all in the expected range
|
||||
for i := 0; i < 100; i++ {
|
||||
result := prepareSnatAddr(d, l, c, nil)
|
||||
result := prepareSnatAddr(d, l, c)
|
||||
require.True(t, result.IsValid())
|
||||
addr := result.Addr()
|
||||
octets := addr.As4()
|
||||
|
||||
@@ -17,13 +17,14 @@ import (
|
||||
)
|
||||
|
||||
type TestTun struct {
|
||||
Device string
|
||||
vpnNetworks []netip.Prefix
|
||||
unsafeNetworks []netip.Prefix
|
||||
snatAddr netip.Prefix
|
||||
Routes []Route
|
||||
routeTree *bart.Table[routing.Gateways]
|
||||
l *logrus.Logger
|
||||
Device string
|
||||
vpnNetworks []netip.Prefix
|
||||
unsafeNetworks []netip.Prefix
|
||||
snatAddr netip.Prefix
|
||||
unsafeIPv4Origin netip.Prefix
|
||||
Routes []Route
|
||||
routeTree *bart.Table[routing.Gateways]
|
||||
l *logrus.Logger
|
||||
|
||||
closed atomic.Bool
|
||||
rxPackets chan []byte // Packets to receive into nebula
|
||||
@@ -50,7 +51,8 @@ func newTun(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, unsafeNet
|
||||
rxPackets: make(chan []byte, 10),
|
||||
TxPackets: make(chan []byte, 10),
|
||||
}
|
||||
tt.snatAddr = prepareSnatAddr(tt, l, c, routes)
|
||||
tt.unsafeIPv4Origin = prepareUnsafeOriginAddr(tt, l, c, routes)
|
||||
tt.snatAddr = prepareSnatAddr(tt, tt.l, c)
|
||||
return tt, nil
|
||||
}
|
||||
|
||||
@@ -149,6 +151,10 @@ func (t *TestTun) UnsafeNetworks() []netip.Prefix {
|
||||
return t.unsafeNetworks
|
||||
}
|
||||
|
||||
func (t *TestTun) UnsafeIPv4OriginAddress() netip.Prefix {
|
||||
return t.unsafeIPv4Origin
|
||||
}
|
||||
|
||||
func (t *TestTun) SNATAddress() netip.Prefix {
|
||||
return t.snatAddr
|
||||
}
|
||||
|
||||
@@ -28,14 +28,14 @@ import (
|
||||
const tunGUIDLabel = "Fixed Nebula Windows GUID v1"
|
||||
|
||||
type winTun struct {
|
||||
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
|
||||
Device string
|
||||
vpnNetworks []netip.Prefix
|
||||
unsafeNetworks []netip.Prefix
|
||||
unsafeIPv4Origin netip.Prefix
|
||||
MTU int
|
||||
Routes atomic.Pointer[[]Route]
|
||||
routeTree atomic.Pointer[bart.Table[routing.Gateways]]
|
||||
l *logrus.Logger
|
||||
|
||||
tun *wintun.NativeTun
|
||||
}
|
||||
@@ -106,7 +106,7 @@ func (t *winTun) reload(c *config.C, initial bool) error {
|
||||
}
|
||||
|
||||
if initial {
|
||||
t.snatAddr = prepareSnatAddr(t, t.l, c, routes)
|
||||
t.unsafeIPv4Origin = prepareUnsafeOriginAddr(t, t.l, c, routes)
|
||||
}
|
||||
|
||||
routeTree, err := makeRouteTree(t.l, routes, false)
|
||||
@@ -140,8 +140,8 @@ func (t *winTun) Activate() error {
|
||||
luid := winipcfg.LUID(t.tun.LUID())
|
||||
|
||||
prefixes := t.vpnNetworks
|
||||
if t.snatAddr.IsValid() {
|
||||
prefixes = append(prefixes, t.snatAddr)
|
||||
if t.unsafeIPv4Origin.IsValid() {
|
||||
prefixes = append(prefixes, t.unsafeIPv4Origin)
|
||||
}
|
||||
|
||||
err := luid.SetIPAddresses(prefixes)
|
||||
@@ -241,8 +241,12 @@ func (t *winTun) UnsafeNetworks() []netip.Prefix {
|
||||
return t.unsafeNetworks
|
||||
}
|
||||
|
||||
func (t *winTun) UnsafeIPv4OriginAddress() netip.Prefix {
|
||||
return t.unsafeIPv4Origin
|
||||
}
|
||||
|
||||
func (t *winTun) SNATAddress() netip.Prefix {
|
||||
return t.snatAddr
|
||||
return netip.Prefix{}
|
||||
}
|
||||
|
||||
func (t *winTun) Name() string {
|
||||
|
||||
@@ -43,6 +43,9 @@ func (d *UserDevice) UnsafeNetworks() []netip.Prefix {
|
||||
func (d *UserDevice) SNATAddress() netip.Prefix {
|
||||
return netip.Prefix{}
|
||||
}
|
||||
func (d *UserDevice) UnsafeIPv4OriginAddress() netip.Prefix {
|
||||
return netip.Prefix{}
|
||||
}
|
||||
|
||||
func (d *UserDevice) Activate() error {
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user