mirror of
https://github.com/slackhq/nebula.git
synced 2026-04-01 07:05:17 +02:00
bolt more stuff onto tun to help auto-assign snat addresses
This commit is contained in:
18
firewall.go
18
firewall.go
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
3
main.go
3
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)
|
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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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{}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
10
test/tun.go
10
test/tun.go
@@ -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{}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user