Add a way to trigger punch backs via lighthouse (#394)

This commit is contained in:
Nathan Brown 2021-03-01 19:06:01 -06:00 committed by GitHub
parent 2a4beb41b9
commit b6234abfb3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 65 additions and 46 deletions

View File

@ -65,6 +65,12 @@ func (c *Control) ShutdownBlock() {
// RebindUDPServer asks the UDP listener to rebind it's listener. Mainly used on mobile clients when interfaces change // RebindUDPServer asks the UDP listener to rebind it's listener. Mainly used on mobile clients when interfaces change
func (c *Control) RebindUDPServer() { func (c *Control) RebindUDPServer() {
_ = c.f.outside.Rebind() _ = c.f.outside.Rebind()
// Trigger a lighthouse update, useful for mobile clients that should have an update interval of 0
c.f.lightHouse.SendUpdate(c.f)
// Let the main interface know that we rebound so that underlying tunnels know to trigger punches from their remotes
c.f.rebindCount++
} }
// ListHostmap returns details about the actual or pending (handshaking) hostmap // ListHostmap returns details about the actual or pending (handshaking) hostmap

View File

@ -51,6 +51,11 @@ type HostInfo struct {
recvError int recvError int
remoteCidr *CIDRTree remoteCidr *CIDRTree
// lastRebindCount is the other side of Interface.rebindCount, if these values don't match then we need to ask LH
// for a punch from the remote end of this tunnel. The goal being to prime their conntrack for our traffic just like
// with a handshake
lastRebindCount int8
lastRoam time.Time lastRoam time.Time
lastRoamRemote *udpAddr lastRoamRemote *udpAddr
} }

View File

@ -229,6 +229,18 @@ func (f *Interface) sendNoMetrics(t NebulaMessageType, st NebulaMessageSubType,
out = HeaderEncode(out, Version, uint8(t), uint8(st), hostinfo.remoteIndexId, c) out = HeaderEncode(out, Version, uint8(t), uint8(st), hostinfo.remoteIndexId, c)
f.connectionManager.Out(hostinfo.hostId) f.connectionManager.Out(hostinfo.hostId)
// Query our LH if we haven't since the last time we've been rebound, this will cause the remote to punch against
// all our IPs and enable a faster roaming.
if hostinfo.lastRebindCount != f.rebindCount {
//NOTE: there is an update hole if a tunnel isn't used and exactly 256 rebinds occur before the tunnel is
// finally used again. This tunnel would eventually be torn down and recreated if this action didn't help.
f.lightHouse.Query(hostinfo.hostId, f)
hostinfo.lastRebindCount = f.rebindCount
if l.Level >= logrus.DebugLevel {
l.WithField("vpnIp", hostinfo.hostId).Debug("Lighthouse update triggered for punch due to rebind counter")
}
}
out, err = ci.eKey.EncryptDanger(out, out, p, c, nb) out, err = ci.eKey.EncryptDanger(out, out, p, c, nb)
//TODO: see above note on lock //TODO: see above note on lock
//ci.writeLock.Unlock() //ci.writeLock.Unlock()

View File

@ -61,6 +61,9 @@ type Interface struct {
dropMulticast bool dropMulticast bool
udpBatchSize int udpBatchSize int
routines int routines int
// rebindCount is used to decide if an active tunnel should trigger a punch notification through a lighthouse
rebindCount int8
version string version string
conntrackCacheTimeout time.Duration conntrackCacheTimeout time.Duration

View File

@ -41,7 +41,7 @@ type LightHouse struct {
staticList map[uint32]struct{} staticList map[uint32]struct{}
lighthouses map[uint32]struct{} lighthouses map[uint32]struct{}
interval int interval int
nebulaPort int nebulaPort uint32
punchBack bool punchBack bool
punchDelay time.Duration punchDelay time.Duration
@ -54,7 +54,7 @@ type EncWriter interface {
SendMessageToAll(t NebulaMessageType, st NebulaMessageSubType, vpnIp uint32, p, nb, out []byte) SendMessageToAll(t NebulaMessageType, st NebulaMessageSubType, vpnIp uint32, p, nb, out []byte)
} }
func NewLightHouse(amLighthouse bool, myIp uint32, ips []uint32, interval int, nebulaPort int, pc *udpConn, punchBack bool, punchDelay time.Duration, metricsEnabled bool) *LightHouse { func NewLightHouse(amLighthouse bool, myIp uint32, ips []uint32, interval int, nebulaPort uint32, pc *udpConn, punchBack bool, punchDelay time.Duration, metricsEnabled bool) *LightHouse {
h := LightHouse{ h := LightHouse{
amLighthouse: amLighthouse, amLighthouse: amLighthouse,
myIp: myIp, myIp: myIp,
@ -208,12 +208,6 @@ func (lh *LightHouse) IsLighthouseIP(vpnIP uint32) bool {
return false return false
} }
// Quick generators for protobuf
func NewLhQueryByIpString(VpnIp string) *NebulaMeta {
return NewLhQueryByInt(ip2int(net.ParseIP(VpnIp)))
}
func NewLhQueryByInt(VpnIp uint32) *NebulaMeta { func NewLhQueryByInt(VpnIp uint32) *NebulaMeta {
return &NebulaMeta{ return &NebulaMeta{
Type: NebulaMeta_HostQuery, Type: NebulaMeta_HostQuery,
@ -223,15 +217,10 @@ func NewLhQueryByInt(VpnIp uint32) *NebulaMeta {
} }
} }
func NewLhWhoami() *NebulaMeta { func NewIpAndPort(ip net.IP, port uint32) IpAndPort {
return &NebulaMeta{ return IpAndPort{Ip: ip2int(ip), Port: port}
Type: NebulaMeta_HostWhoami,
Details: &NebulaMetaDetails{},
}
} }
// End Quick generators for protobuf
func NewIpAndPortFromUDPAddr(addr udpAddr) IpAndPort { func NewIpAndPortFromUDPAddr(addr udpAddr) IpAndPort {
return IpAndPort{Ip: udp2ipInt(&addr), Port: uint32(addr.Port)} return IpAndPort{Ip: udp2ipInt(&addr), Port: uint32(addr.Port)}
} }
@ -242,20 +231,26 @@ func (lh *LightHouse) LhUpdateWorker(f EncWriter) {
} }
for { for {
ipp := []*IpAndPort{} lh.SendUpdate(f)
time.Sleep(time.Second * time.Duration(lh.interval))
}
}
func (lh *LightHouse) SendUpdate(f EncWriter) {
var ipps []*IpAndPort
for _, e := range *localIps(lh.localAllowList) { for _, e := range *localIps(lh.localAllowList) {
// Only add IPs that aren't my VPN/tun IP // Only add IPs that aren't my VPN/tun IP
if ip2int(e) != lh.myIp { if ip2int(e) != lh.myIp {
ipp = append(ipp, &IpAndPort{Ip: ip2int(e), Port: uint32(lh.nebulaPort)}) ipp := NewIpAndPort(e, lh.nebulaPort)
//fmt.Println(e) ipps = append(ipps, &ipp)
} }
} }
m := &NebulaMeta{ m := &NebulaMeta{
Type: NebulaMeta_HostUpdateNotification, Type: NebulaMeta_HostUpdateNotification,
Details: &NebulaMetaDetails{ Details: &NebulaMetaDetails{
VpnIp: lh.myIp, VpnIp: lh.myIp,
IpAndPorts: ipp, IpAndPorts: ipps,
}, },
} }
@ -271,8 +266,6 @@ func (lh *LightHouse) LhUpdateWorker(f EncWriter) {
f.SendMessageToVpnIp(lightHouse, 0, vpnIp, mm, nb, out) f.SendMessageToVpnIp(lightHouse, 0, vpnIp, mm, nb, out)
} }
time.Sleep(time.Second * time.Duration(lh.interval))
}
} }
type LightHouseHandler struct { type LightHouseHandler struct {

View File

@ -268,7 +268,7 @@ func Main(config *Config, configTest bool, buildVersion string, logger *logrus.L
lighthouseHosts, lighthouseHosts,
//TODO: change to a duration //TODO: change to a duration
config.GetInt("lighthouse.interval", 10), config.GetInt("lighthouse.interval", 10),
port, uint32(port),
udpConns[0], udpConns[0],
punchy.Respond, punchy.Respond,
punchy.Delay, punchy.Delay,