diff --git a/src/yggdrasil/router.go b/src/yggdrasil/router.go index 9d4a5cbe..a8721f22 100644 --- a/src/yggdrasil/router.go +++ b/src/yggdrasil/router.go @@ -141,12 +141,27 @@ func (r *router) sendPacket(bs []byte) { // No or unintiialized session, so we need to search first doSearch(bs) case time.Since(sinfo.time) > 6*time.Second: - // We haven't heard from the dest in a while; they may have changed coords - // Maybe the connection is idle, or maybe one of us changed coords - // Try searching to either ping them (a little overhead) or fix the coords - doSearch(nil) - fallthrough - //default: go func() { sinfo.send<-bs }() + if sinfo.time.Before(sinfo.pingTime) && time.Since(sinfo.pingTime) > 6*time.Second { + // We haven't heard from the dest in a while + // We tried pinging but didn't get a response + // They may have changed coords + // Try searching to discover new coords + // Note that search spam is throttled internally + doSearch(nil) + } else { + // We haven't heard about the dest in a while + now := time.Now() + if !sinfo.time.Before(sinfo.pingTime) { + // Update pingTime to start the clock for searches (above) + sinfo.pingTime = now + } + if time.Since(sinfo.pingSend) > time.Second { + // Send at most 1 ping per second + sinfo.pingSend = now + r.core.sessions.sendPingPong(sinfo, false) + } + } + fallthrough // Also send the packet default: // Generate an ICMPv6 Packet Too Big for packets larger than session MTU if len(bs) > int(sinfo.getMTU()) { diff --git a/src/yggdrasil/session.go b/src/yggdrasil/session.go index 13606f85..f413174d 100644 --- a/src/yggdrasil/session.go +++ b/src/yggdrasil/session.go @@ -30,6 +30,8 @@ type sessionInfo struct { nonceMask uint64 tstamp int64 // tstamp from their last session ping, replay attack mitigation mtuTime time.Time // time myMTU was last changed + pingTime time.Time // time the first ping was sent since the last received packet + pingSend time.Time // time the last ping was sent } type sessionPing struct { @@ -64,7 +66,8 @@ func (s *sessionInfo) update(p *sessionPing) bool { s.theirMTU = p.mtu } s.coords = append([]byte{}, p.coords...) - s.time = time.Now() + now := time.Now() + s.time = now s.tstamp = p.tstamp s.init = true return true @@ -153,7 +156,11 @@ func (ss *sessions) createSession(theirPermKey *boxPubKey) *sessionInfo { sinfo.myNonce = *newBoxNonce() sinfo.theirMTU = 1280 sinfo.myMTU = uint16(ss.core.tun.mtu) - sinfo.mtuTime = time.Now() + now := time.Now() + sinfo.time = now + sinfo.mtuTime = now + sinfo.pingTime = now + sinfo.pingSend = now higher := false for idx := range ss.core.boxPub { if ss.core.boxPub[idx] > sinfo.theirPermPub[idx] { @@ -176,7 +183,6 @@ func (ss *sessions) createSession(theirPermKey *boxPubKey) *sessionInfo { sinfo.send = make(chan []byte, 32) sinfo.recv = make(chan *wire_trafficPacket, 32) go sinfo.doWorker() - sinfo.time = time.Now() // Do some cleanup // Time thresholds almost certainly could use some adjusting for _, s := range ss.sinfos { @@ -255,6 +261,9 @@ func (ss *sessions) sendPingPong(sinfo *sessionInfo, isPong bool) { } packet := p.encode() ss.core.router.out(packet) + if !isPong { + sinfo.pingSend = time.Now() + } } func (ss *sessions) handlePing(ping *sessionPing) {