Add a way to trigger punch backs via lighthouse (#394)
This commit is contained in:
parent
2a4beb41b9
commit
b6234abfb3
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
12
inside.go
12
inside.go
|
@ -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()
|
||||||
|
|
|
@ -61,7 +61,10 @@ type Interface struct {
|
||||||
dropMulticast bool
|
dropMulticast bool
|
||||||
udpBatchSize int
|
udpBatchSize int
|
||||||
routines int
|
routines int
|
||||||
version string
|
|
||||||
|
// rebindCount is used to decide if an active tunnel should trigger a punch notification through a lighthouse
|
||||||
|
rebindCount int8
|
||||||
|
version string
|
||||||
|
|
||||||
conntrackCacheTimeout time.Duration
|
conntrackCacheTimeout time.Duration
|
||||||
|
|
||||||
|
|
|
@ -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,39 +231,43 @@ func (lh *LightHouse) LhUpdateWorker(f EncWriter) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
ipp := []*IpAndPort{}
|
lh.SendUpdate(f)
|
||||||
|
|
||||||
for _, e := range *localIps(lh.localAllowList) {
|
|
||||||
// Only add IPs that aren't my VPN/tun IP
|
|
||||||
if ip2int(e) != lh.myIp {
|
|
||||||
ipp = append(ipp, &IpAndPort{Ip: ip2int(e), Port: uint32(lh.nebulaPort)})
|
|
||||||
//fmt.Println(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m := &NebulaMeta{
|
|
||||||
Type: NebulaMeta_HostUpdateNotification,
|
|
||||||
Details: &NebulaMetaDetails{
|
|
||||||
VpnIp: lh.myIp,
|
|
||||||
IpAndPorts: ipp,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
lh.metricTx(NebulaMeta_HostUpdateNotification, int64(len(lh.lighthouses)))
|
|
||||||
nb := make([]byte, 12, 12)
|
|
||||||
out := make([]byte, mtu)
|
|
||||||
for vpnIp := range lh.lighthouses {
|
|
||||||
mm, err := proto.Marshal(m)
|
|
||||||
if err != nil {
|
|
||||||
l.Debugf("Invalid marshal to update")
|
|
||||||
}
|
|
||||||
//l.Error("LIGHTHOUSE PACKET SEND", mm)
|
|
||||||
f.SendMessageToVpnIp(lightHouse, 0, vpnIp, mm, nb, out)
|
|
||||||
|
|
||||||
}
|
|
||||||
time.Sleep(time.Second * time.Duration(lh.interval))
|
time.Sleep(time.Second * time.Duration(lh.interval))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (lh *LightHouse) SendUpdate(f EncWriter) {
|
||||||
|
var ipps []*IpAndPort
|
||||||
|
|
||||||
|
for _, e := range *localIps(lh.localAllowList) {
|
||||||
|
// Only add IPs that aren't my VPN/tun IP
|
||||||
|
if ip2int(e) != lh.myIp {
|
||||||
|
ipp := NewIpAndPort(e, lh.nebulaPort)
|
||||||
|
ipps = append(ipps, &ipp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m := &NebulaMeta{
|
||||||
|
Type: NebulaMeta_HostUpdateNotification,
|
||||||
|
Details: &NebulaMetaDetails{
|
||||||
|
VpnIp: lh.myIp,
|
||||||
|
IpAndPorts: ipps,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
lh.metricTx(NebulaMeta_HostUpdateNotification, int64(len(lh.lighthouses)))
|
||||||
|
nb := make([]byte, 12, 12)
|
||||||
|
out := make([]byte, mtu)
|
||||||
|
for vpnIp := range lh.lighthouses {
|
||||||
|
mm, err := proto.Marshal(m)
|
||||||
|
if err != nil {
|
||||||
|
l.Debugf("Invalid marshal to update")
|
||||||
|
}
|
||||||
|
//l.Error("LIGHTHOUSE PACKET SEND", mm)
|
||||||
|
f.SendMessageToVpnIp(lightHouse, 0, vpnIp, mm, nb, out)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type LightHouseHandler struct {
|
type LightHouseHandler struct {
|
||||||
lh *LightHouse
|
lh *LightHouse
|
||||||
nb []byte
|
nb []byte
|
||||||
|
|
2
main.go
2
main.go
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue