mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 03:05:07 +03:00 
			
		
		
		
	safer pathfinding behavior
This commit is contained in:
		
							parent
							
								
									994c26e5f7
								
							
						
					
					
						commit
						e19e938f64
					
				
					 3 changed files with 59 additions and 45 deletions
				
			
		| 
						 | 
					@ -196,9 +196,9 @@ func (r *router) _handleProto(packet []byte) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	switch bsType {
 | 
						switch bsType {
 | 
				
			||||||
	case wire_SessionPing:
 | 
						case wire_SessionPing:
 | 
				
			||||||
		r._handlePing(bs, &p.FromKey)
 | 
							r._handlePing(bs, &p.FromKey, p.RPath)
 | 
				
			||||||
	case wire_SessionPong:
 | 
						case wire_SessionPong:
 | 
				
			||||||
		r._handlePong(bs, &p.FromKey)
 | 
							r._handlePong(bs, &p.FromKey, p.RPath)
 | 
				
			||||||
	case wire_NodeInfoRequest:
 | 
						case wire_NodeInfoRequest:
 | 
				
			||||||
		fallthrough
 | 
							fallthrough
 | 
				
			||||||
	case wire_NodeInfoResponse:
 | 
						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.
 | 
					// 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{}
 | 
						ping := sessionPing{}
 | 
				
			||||||
	if !ping.decode(bs) {
 | 
						if !ping.decode(bs) {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ping.SendPermPub = *fromKey
 | 
						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).
 | 
					// Handles session pongs (which are really pings with an extra flag to prevent acknowledgement).
 | 
				
			||||||
func (r *router) _handlePong(bs []byte, fromKey *crypto.BoxPubKey) {
 | 
					func (r *router) _handlePong(bs []byte, fromKey *crypto.BoxPubKey, rpath []byte) {
 | 
				
			||||||
	r._handlePing(bs, fromKey)
 | 
						r._handlePing(bs, fromKey, rpath)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Decodes dht requests and passes them to dht.handleReq to trigger a lookup/response.
 | 
					// 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
 | 
						callbacks     []chan func()       // Finished work from crypto workers
 | 
				
			||||||
	table         *lookupTable        // table.self is a locator where we get our coords
 | 
						table         *lookupTable        // table.self is a locator where we get our coords
 | 
				
			||||||
	path          []byte              // Path from self to destination
 | 
						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.
 | 
					// 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.
 | 
					// 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.
 | 
					// Returns true if the session was updated, or false otherwise.
 | 
				
			||||||
func (s *sessionInfo) _update(p *sessionPing) bool {
 | 
					func (sinfo *sessionInfo) _update(p *sessionPing, rpath []byte) bool {
 | 
				
			||||||
	if !(p.Tstamp > s.tstamp) {
 | 
						if !(p.Tstamp > sinfo.tstamp) {
 | 
				
			||||||
		// To protect against replay attacks
 | 
							// To protect against replay attacks
 | 
				
			||||||
		return false
 | 
							return false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if p.SendPermPub != s.theirPermPub {
 | 
						if p.SendPermPub != sinfo.theirPermPub {
 | 
				
			||||||
		// Should only happen if two sessions got the same handle
 | 
							// 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
 | 
							// That shouldn't be allowed anyway, but if it happens then let one time out
 | 
				
			||||||
		return false
 | 
							return false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if p.SendSesPub != s.theirSesPub {
 | 
						if p.SendSesPub != sinfo.theirSesPub {
 | 
				
			||||||
		s.theirSesPub = p.SendSesPub
 | 
							sinfo.path = nil
 | 
				
			||||||
		s.theirHandle = p.Handle
 | 
							sinfo.theirSesPub = p.SendSesPub
 | 
				
			||||||
		s.sharedSesKey = *crypto.GetSharedKey(&s.mySesPriv, &s.theirSesPub)
 | 
							sinfo.theirHandle = p.Handle
 | 
				
			||||||
		s.theirNonce = crypto.BoxNonce{}
 | 
							sinfo.sharedSesKey = *crypto.GetSharedKey(&sinfo.mySesPriv, &sinfo.theirSesPub)
 | 
				
			||||||
 | 
							sinfo.theirNonce = crypto.BoxNonce{}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if p.MTU >= 1280 || p.MTU == 0 {
 | 
						if p.MTU >= 1280 || p.MTU == 0 {
 | 
				
			||||||
		s.theirMTU = p.MTU
 | 
							sinfo.theirMTU = p.MTU
 | 
				
			||||||
		if s.conn != nil {
 | 
							if sinfo.conn != nil {
 | 
				
			||||||
			s.conn.setMTU(s, s._getMTU())
 | 
								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
 | 
							// 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()
 | 
						sinfo.time = time.Now()
 | 
				
			||||||
	s.tstamp = p.Tstamp
 | 
						sinfo.tstamp = p.Tstamp
 | 
				
			||||||
	s.reset = false
 | 
						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
 | 
						defer func() { recover() }() // Recover if the below panics
 | 
				
			||||||
	select {
 | 
						select {
 | 
				
			||||||
	case <-s.init:
 | 
						case <-sinfo.init:
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		// Unblock anything waiting for the session to initialize
 | 
							// Unblock anything waiting for the session to initialize
 | 
				
			||||||
		close(s.init)
 | 
							close(sinfo.init)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return true
 | 
						return true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -306,13 +310,13 @@ func (ss *sessions) getSharedKey(myPriv *crypto.BoxPrivKey,
 | 
				
			||||||
// Sends a session ping by calling sendPingPong in ping mode.
 | 
					// Sends a session ping by calling sendPingPong in ping mode.
 | 
				
			||||||
func (sinfo *sessionInfo) ping(from phony.Actor) {
 | 
					func (sinfo *sessionInfo) ping(from phony.Actor) {
 | 
				
			||||||
	sinfo.Act(from, func() {
 | 
						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.
 | 
					// 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.
 | 
					// 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 := sinfo._getPing()
 | 
				
			||||||
	ping.IsPong = isPong
 | 
						ping.IsPong = isPong
 | 
				
			||||||
	bs := ping.encode()
 | 
						bs := ping.encode()
 | 
				
			||||||
| 
						 | 
					@ -324,16 +328,21 @@ func (sinfo *sessionInfo) _sendPingPong(isPong bool) {
 | 
				
			||||||
		Nonce:   *nonce,
 | 
							Nonce:   *nonce,
 | 
				
			||||||
		Payload: payload,
 | 
							Payload: payload,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if path != nil {
 | 
				
			||||||
 | 
							p.Coords = append([]byte{0}, path...)
 | 
				
			||||||
 | 
							p.Offset += 1
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	packet := p.encode()
 | 
						packet := p.encode()
 | 
				
			||||||
	// TODO rewrite the below if/when the peer struct becomes an actor, to not go through the router first
 | 
						// 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) })
 | 
						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()
 | 
							sinfo.pingTime = time.Now()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// Sending a ping may happen when we don't know if our path info is good anymore...
 | 
						if !isPong {
 | 
				
			||||||
	// Reset paths just to be safe...
 | 
							// Sending a ping may happen when we don't know if our path info is good anymore...
 | 
				
			||||||
	sinfo.path = nil
 | 
							// Reset paths just to be safe...
 | 
				
			||||||
	sinfo.rpath = nil
 | 
							sinfo.path = nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (sinfo *sessionInfo) setConn(from phony.Actor, conn *Conn) {
 | 
					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.
 | 
					// 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.
 | 
					// 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)
 | 
						// Get the corresponding session (or create a new session)
 | 
				
			||||||
	sinfo, isIn := ss.getByTheirPerm(&ping.SendPermPub)
 | 
						sinfo, isIn := ss.getByTheirPerm(&ping.SendPermPub)
 | 
				
			||||||
	switch {
 | 
						switch {
 | 
				
			||||||
| 
						 | 
					@ -374,11 +383,11 @@ func (ss *sessions) handlePing(ping *sessionPing) {
 | 
				
			||||||
	if sinfo != nil {
 | 
						if sinfo != nil {
 | 
				
			||||||
		sinfo.Act(ss.router, func() {
 | 
							sinfo.Act(ss.router, func() {
 | 
				
			||||||
			// Update the session
 | 
								// 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
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if !ping.IsPong {
 | 
								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._updateNonce(&p.Nonce)
 | 
				
			||||||
			sinfo.bytesRecvd += uint64(len(bs))
 | 
								sinfo.bytesRecvd += uint64(len(bs))
 | 
				
			||||||
			sinfo.conn.recvMsg(sinfo, bs)
 | 
								sinfo.conn.recvMsg(sinfo, bs)
 | 
				
			||||||
			a := switch_getPorts(p.RPath)
 | 
								if sinfo.path == nil {
 | 
				
			||||||
			for i := len(a)/2 - 1; i >= 0; i-- {
 | 
									sinfo._sendPingPong(false, nil)
 | 
				
			||||||
				opp := len(a) - 1 - i
 | 
					 | 
				
			||||||
				a[i], a[opp] = a[opp], a[i]
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			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
 | 
							ch <- callback
 | 
				
			||||||
		sinfo.checkCallbacks()
 | 
							sinfo.checkCallbacks()
 | 
				
			||||||
| 
						 | 
					@ -516,7 +518,6 @@ func (sinfo *sessionInfo) _send(msg FlowKeyMessage) {
 | 
				
			||||||
		Coords: coords,
 | 
							Coords: coords,
 | 
				
			||||||
		Handle: sinfo.theirHandle,
 | 
							Handle: sinfo.theirHandle,
 | 
				
			||||||
		Nonce:  sinfo.myNonce,
 | 
							Nonce:  sinfo.myNonce,
 | 
				
			||||||
		RPath:  sinfo.rpath,
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	sinfo.myNonce.Increment()
 | 
						sinfo.myNonce.Increment()
 | 
				
			||||||
	k := sinfo.sharedSesKey
 | 
						k := sinfo.sharedSesKey
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -655,6 +655,19 @@ func switch_getPorts(coords []byte) []switchPort {
 | 
				
			||||||
	return ports
 | 
						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 {
 | 
					func (t *lookupTable) isDescendant(ports []switchPort) bool {
 | 
				
			||||||
	// Note that this returns true for anyone in the subtree that starts at us
 | 
						// 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...
 | 
						// That includes ourself, so we are our own descendant by this logic...
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue