mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-11-12 19:50:27 +00:00
safer pathfinding behavior
This commit is contained in:
parent
994c26e5f7
commit
e19e938f64
@ -196,9 +196,9 @@ func (r *router) _handleProto(packet []byte) {
|
||||
}
|
||||
switch bsType {
|
||||
case wire_SessionPing:
|
||||
r._handlePing(bs, &p.FromKey)
|
||||
r._handlePing(bs, &p.FromKey, p.RPath)
|
||||
case wire_SessionPong:
|
||||
r._handlePong(bs, &p.FromKey)
|
||||
r._handlePong(bs, &p.FromKey, p.RPath)
|
||||
case wire_NodeInfoRequest:
|
||||
fallthrough
|
||||
case wire_NodeInfoResponse:
|
||||
@ -212,18 +212,18 @@ func (r *router) _handleProto(packet []byte) {
|
||||
}
|
||||
|
||||
// Decodes session pings from wire format and passes them to sessions.handlePing where they either create or update a session.
|
||||
func (r *router) _handlePing(bs []byte, fromKey *crypto.BoxPubKey) {
|
||||
func (r *router) _handlePing(bs []byte, fromKey *crypto.BoxPubKey, rpath []byte) {
|
||||
ping := sessionPing{}
|
||||
if !ping.decode(bs) {
|
||||
return
|
||||
}
|
||||
ping.SendPermPub = *fromKey
|
||||
r.sessions.handlePing(&ping)
|
||||
r.sessions.handlePing(&ping, rpath)
|
||||
}
|
||||
|
||||
// Handles session pongs (which are really pings with an extra flag to prevent acknowledgement).
|
||||
func (r *router) _handlePong(bs []byte, fromKey *crypto.BoxPubKey) {
|
||||
r._handlePing(bs, fromKey)
|
||||
func (r *router) _handlePong(bs []byte, fromKey *crypto.BoxPubKey, rpath []byte) {
|
||||
r._handlePing(bs, fromKey, rpath)
|
||||
}
|
||||
|
||||
// Decodes dht requests and passes them to dht.handleReq to trigger a lookup/response.
|
||||
|
@ -51,7 +51,6 @@ type sessionInfo struct {
|
||||
callbacks []chan func() // Finished work from crypto workers
|
||||
table *lookupTable // table.self is a locator where we get our coords
|
||||
path []byte // Path from self to destination
|
||||
rpath []byte // Path from destination to self
|
||||
}
|
||||
|
||||
// Represents a session ping/pong packet, and includes information like public keys, a session handle, coords, a timestamp to prevent replays, and the tun/tap MTU.
|
||||
@ -67,41 +66,46 @@ type sessionPing struct {
|
||||
|
||||
// Updates session info in response to a ping, after checking that the ping is OK.
|
||||
// Returns true if the session was updated, or false otherwise.
|
||||
func (s *sessionInfo) _update(p *sessionPing) bool {
|
||||
if !(p.Tstamp > s.tstamp) {
|
||||
func (sinfo *sessionInfo) _update(p *sessionPing, rpath []byte) bool {
|
||||
if !(p.Tstamp > sinfo.tstamp) {
|
||||
// To protect against replay attacks
|
||||
return false
|
||||
}
|
||||
if p.SendPermPub != s.theirPermPub {
|
||||
if p.SendPermPub != sinfo.theirPermPub {
|
||||
// Should only happen if two sessions got the same handle
|
||||
// That shouldn't be allowed anyway, but if it happens then let one time out
|
||||
return false
|
||||
}
|
||||
if p.SendSesPub != s.theirSesPub {
|
||||
s.theirSesPub = p.SendSesPub
|
||||
s.theirHandle = p.Handle
|
||||
s.sharedSesKey = *crypto.GetSharedKey(&s.mySesPriv, &s.theirSesPub)
|
||||
s.theirNonce = crypto.BoxNonce{}
|
||||
if p.SendSesPub != sinfo.theirSesPub {
|
||||
sinfo.path = nil
|
||||
sinfo.theirSesPub = p.SendSesPub
|
||||
sinfo.theirHandle = p.Handle
|
||||
sinfo.sharedSesKey = *crypto.GetSharedKey(&sinfo.mySesPriv, &sinfo.theirSesPub)
|
||||
sinfo.theirNonce = crypto.BoxNonce{}
|
||||
}
|
||||
if p.MTU >= 1280 || p.MTU == 0 {
|
||||
s.theirMTU = p.MTU
|
||||
if s.conn != nil {
|
||||
s.conn.setMTU(s, s._getMTU())
|
||||
sinfo.theirMTU = p.MTU
|
||||
if sinfo.conn != nil {
|
||||
sinfo.conn.setMTU(sinfo, sinfo._getMTU())
|
||||
}
|
||||
}
|
||||
if !bytes.Equal(s.coords, p.Coords) {
|
||||
if !bytes.Equal(sinfo.coords, p.Coords) {
|
||||
// allocate enough space for additional coords
|
||||
s.coords = append(make([]byte, 0, len(p.Coords)+11), p.Coords...)
|
||||
sinfo.coords = append(make([]byte, 0, len(p.Coords)+11), p.Coords...)
|
||||
}
|
||||
s.time = time.Now()
|
||||
s.tstamp = p.Tstamp
|
||||
s.reset = false
|
||||
sinfo.time = time.Now()
|
||||
sinfo.tstamp = p.Tstamp
|
||||
if p.IsPong && sinfo.path == nil {
|
||||
path := switch_reverseCoordBytes(rpath)
|
||||
sinfo.path = append(sinfo.path[:0], path...)
|
||||
}
|
||||
sinfo.reset = false
|
||||
defer func() { recover() }() // Recover if the below panics
|
||||
select {
|
||||
case <-s.init:
|
||||
case <-sinfo.init:
|
||||
default:
|
||||
// Unblock anything waiting for the session to initialize
|
||||
close(s.init)
|
||||
close(sinfo.init)
|
||||
}
|
||||
return true
|
||||
}
|
||||
@ -306,13 +310,13 @@ func (ss *sessions) getSharedKey(myPriv *crypto.BoxPrivKey,
|
||||
// Sends a session ping by calling sendPingPong in ping mode.
|
||||
func (sinfo *sessionInfo) ping(from phony.Actor) {
|
||||
sinfo.Act(from, func() {
|
||||
sinfo._sendPingPong(false)
|
||||
sinfo._sendPingPong(false, nil)
|
||||
})
|
||||
}
|
||||
|
||||
// Calls getPing, sets the appropriate ping/pong flag, encodes to wire format, and send it.
|
||||
// Updates the time the last ping was sent in the session info.
|
||||
func (sinfo *sessionInfo) _sendPingPong(isPong bool) {
|
||||
func (sinfo *sessionInfo) _sendPingPong(isPong bool, path []byte) {
|
||||
ping := sinfo._getPing()
|
||||
ping.IsPong = isPong
|
||||
bs := ping.encode()
|
||||
@ -324,16 +328,21 @@ func (sinfo *sessionInfo) _sendPingPong(isPong bool) {
|
||||
Nonce: *nonce,
|
||||
Payload: payload,
|
||||
}
|
||||
if path != nil {
|
||||
p.Coords = append([]byte{0}, path...)
|
||||
p.Offset += 1
|
||||
}
|
||||
packet := p.encode()
|
||||
// TODO rewrite the below if/when the peer struct becomes an actor, to not go through the router first
|
||||
sinfo.sessions.router.Act(sinfo, func() { sinfo.sessions.router.out(packet) })
|
||||
if sinfo.pingTime.Before(sinfo.time) {
|
||||
if !isPong && sinfo.pingTime.Before(sinfo.time) {
|
||||
sinfo.pingTime = time.Now()
|
||||
}
|
||||
// Sending a ping may happen when we don't know if our path info is good anymore...
|
||||
// Reset paths just to be safe...
|
||||
sinfo.path = nil
|
||||
sinfo.rpath = nil
|
||||
if !isPong {
|
||||
// Sending a ping may happen when we don't know if our path info is good anymore...
|
||||
// Reset paths just to be safe...
|
||||
sinfo.path = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (sinfo *sessionInfo) setConn(from phony.Actor, conn *Conn) {
|
||||
@ -345,7 +354,7 @@ func (sinfo *sessionInfo) setConn(from phony.Actor, conn *Conn) {
|
||||
|
||||
// Handles a session ping, creating a session if needed and calling update, then possibly responding with a pong if the ping was in ping mode and the update was successful.
|
||||
// If the session has a packet cached (common when first setting up a session), it will be sent.
|
||||
func (ss *sessions) handlePing(ping *sessionPing) {
|
||||
func (ss *sessions) handlePing(ping *sessionPing, rpath []byte) {
|
||||
// Get the corresponding session (or create a new session)
|
||||
sinfo, isIn := ss.getByTheirPerm(&ping.SendPermPub)
|
||||
switch {
|
||||
@ -374,11 +383,11 @@ func (ss *sessions) handlePing(ping *sessionPing) {
|
||||
if sinfo != nil {
|
||||
sinfo.Act(ss.router, func() {
|
||||
// Update the session
|
||||
if !sinfo._update(ping) { /*panic("Should not happen in testing")*/
|
||||
if !sinfo._update(ping, rpath) { /*panic("Should not happen in testing")*/
|
||||
return
|
||||
}
|
||||
if !ping.IsPong {
|
||||
sinfo._sendPingPong(true)
|
||||
sinfo._sendPingPong(true, switch_reverseCoordBytes(rpath))
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -474,16 +483,9 @@ func (sinfo *sessionInfo) _recvPacket(p *wire_trafficPacket) {
|
||||
sinfo._updateNonce(&p.Nonce)
|
||||
sinfo.bytesRecvd += uint64(len(bs))
|
||||
sinfo.conn.recvMsg(sinfo, bs)
|
||||
a := switch_getPorts(p.RPath)
|
||||
for i := len(a)/2 - 1; i >= 0; i-- {
|
||||
opp := len(a) - 1 - i
|
||||
a[i], a[opp] = a[opp], a[i]
|
||||
if sinfo.path == nil {
|
||||
sinfo._sendPingPong(false, nil)
|
||||
}
|
||||
sinfo.path = sinfo.path[:0]
|
||||
for _, sPort := range a {
|
||||
sinfo.path = wire_put_uint64(uint64(sPort), sinfo.path)
|
||||
}
|
||||
//sinfo.rpath = append(sinfo.rpath[:0], p.Path...)
|
||||
}
|
||||
ch <- callback
|
||||
sinfo.checkCallbacks()
|
||||
@ -516,7 +518,6 @@ func (sinfo *sessionInfo) _send(msg FlowKeyMessage) {
|
||||
Coords: coords,
|
||||
Handle: sinfo.theirHandle,
|
||||
Nonce: sinfo.myNonce,
|
||||
RPath: sinfo.rpath,
|
||||
}
|
||||
sinfo.myNonce.Increment()
|
||||
k := sinfo.sharedSesKey
|
||||
|
@ -655,6 +655,19 @@ func switch_getPorts(coords []byte) []switchPort {
|
||||
return ports
|
||||
}
|
||||
|
||||
func switch_reverseCoordBytes(coords []byte) []byte {
|
||||
a := switch_getPorts(coords)
|
||||
for i := len(a)/2 - 1; i >= 0; i-- {
|
||||
opp := len(a) - 1 - i
|
||||
a[i], a[opp] = a[opp], a[i]
|
||||
}
|
||||
var reversed []byte
|
||||
for _, sPort := range a {
|
||||
reversed = wire_put_uint64(uint64(sPort), reversed)
|
||||
}
|
||||
return reversed
|
||||
}
|
||||
|
||||
func (t *lookupTable) isDescendant(ports []switchPort) bool {
|
||||
// Note that this returns true for anyone in the subtree that starts at us
|
||||
// That includes ourself, so we are our own descendant by this logic...
|
||||
|
Loading…
Reference in New Issue
Block a user