mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-11-14 15:00:28 +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 {
|
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…
Reference in New Issue
Block a user