From d85e24f49f9efdeed5549a7d0874e68155e25301 Mon Sep 17 00:00:00 2001 From: Nate Brown Date: Mon, 4 Apr 2022 12:35:23 -0500 Subject: [PATCH] Allow for self reported ips to the lighthouse (#650) --- examples/config.yml | 9 ++++++++ lighthouse.go | 50 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/examples/config.yml b/examples/config.yml index 9720ef3..e0e4e29 100644 --- a/examples/config.yml +++ b/examples/config.yml @@ -81,6 +81,15 @@ lighthouse: # Example to only advertise this subnet to the lighthouse. #"10.0.0.0/8": true + # advertise_addrs are routable addresses that will be included along with discovered addresses to report to the + # lighthouse, the format is "ip:port". `port` can be `0`, in which case the actual listening port will be used in its + # place, useful if `listen.port` is set to 0. + # This option is mainly useful when there are static ip addresses the host can be reached at that nebula can not + # typically discover on its own. Examples being port forwarding or multiple paths to the internet. + #advertise_addrs: + #- "1.1.1.1:4242" + #- "1.2.3.4:0" # port will be replaced with the real listening port + # Port Nebula will be listening on. The default here is 4242. For a lighthouse node, the port should be defined, # however using port 0 will dynamically assign a port and is recommended for roaming nodes. listen: diff --git a/lighthouse.go b/lighthouse.go index 07163bd..fbd7f8a 100644 --- a/lighthouse.go +++ b/lighthouse.go @@ -26,6 +26,11 @@ import ( var ErrHostNotKnown = errors.New("host not known") +type netIpAndPort struct { + ip net.IP + port uint16 +} + type LightHouse struct { //TODO: We need a timer wheel to kick out vpnIps that haven't reported in a long time sync.RWMutex //Because we concurrently read and write to our maps @@ -64,6 +69,8 @@ type LightHouse struct { updateUdp udp.EncWriter nebulaPort uint32 // 32 bits because protobuf does not have a uint16 + atomicAdvertiseAddrs []netIpAndPort + metrics *MessageMetrics metricHolepunchTx metrics.Counter l *logrus.Logger @@ -143,11 +150,45 @@ func (lh *LightHouse) GetLocalAllowList() *LocalAllowList { return (*LocalAllowList)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&lh.atomicLocalAllowList)))) } +func (lh *LightHouse) GetAdvertiseAddrs() []netIpAndPort { + return *(*[]netIpAndPort)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&lh.atomicAdvertiseAddrs)))) +} + func (lh *LightHouse) GetUpdateInterval() int64 { return atomic.LoadInt64(&lh.atomicInterval) } func (lh *LightHouse) reload(c *config.C, initial bool) error { + if initial || c.HasChanged("lighthouse.advertise_addrs") { + rawAdvAddrs := c.GetStringSlice("lighthouse.advertise_addrs", []string{}) + advAddrs := make([]netIpAndPort, 0) + + for i, rawAddr := range rawAdvAddrs { + fIp, fPort, err := udp.ParseIPAndPort(rawAddr) + if err != nil { + return util.NewContextualError("Unable to parse lighthouse.advertise_addrs entry", m{"addr": rawAddr, "entry": i + 1}, err) + } + + if fPort == 0 { + fPort = uint16(lh.nebulaPort) + } + + if ip4 := fIp.To4(); ip4 != nil && lh.myVpnNet.Contains(fIp) { + lh.l.WithField("addr", rawAddr).WithField("entry", i+1). + Warn("Ignoring lighthouse.advertise_addrs report because it is within the nebula network range") + continue + } + + advAddrs = append(advAddrs, netIpAndPort{ip: fIp, port: fPort}) + } + + atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&lh.atomicAdvertiseAddrs)), unsafe.Pointer(&advAddrs)) + + if !initial { + lh.l.Info("lighthouse.advertise_addrs has changed") + } + } + if initial || c.HasChanged("lighthouse.interval") { atomic.StoreInt64(&lh.atomicInterval, int64(c.GetInt("lighthouse.interval", 10))) @@ -535,6 +576,14 @@ func (lh *LightHouse) SendUpdate(f udp.EncWriter) { var v4 []*Ip4AndPort var v6 []*Ip6AndPort + for _, e := range lh.GetAdvertiseAddrs() { + if ip := e.ip.To4(); ip != nil { + v4 = append(v4, NewIp4AndPort(e.ip, uint32(e.port))) + } else { + v6 = append(v6, NewIp6AndPort(e.ip, uint32(e.port))) + } + } + lal := lh.GetLocalAllowList() for _, e := range *localIps(lh.l, lal) { if ip4 := e.To4(); ip4 != nil && ipMaskContains(lh.myVpnIp, lh.myVpnZeros, iputil.Ip2VpnIp(ip4)) { @@ -548,6 +597,7 @@ func (lh *LightHouse) SendUpdate(f udp.EncWriter) { v6 = append(v6, NewIp6AndPort(e, lh.nebulaPort)) } } + m := &NebulaMeta{ Type: NebulaMeta_HostUpdateNotification, Details: &NebulaMetaDetails{