2017-12-28 22:16:20 -06:00
package yggdrasil
// This part does most of the work to handle packets to/from yourself
// It also manages crypto and dht info
2018-01-26 17:30:51 -06:00
// TODO clean up old/unused code, maybe improve comments on whatever is left
2017-12-28 22:16:20 -06:00
// Send:
2019-03-28 19:09:19 +00:00
// Receive a packet from the adapter
2017-12-28 22:16:20 -06:00
// Look up session (if none exists, trigger a search)
// Hand off to session (which encrypts, etc)
// Session will pass it back to router.out, which hands it off to the self peer
// The self peer triggers a lookup to find which peer to send to next
// And then passes it to that's peer's peer.out function
// The peer.out function sends it over the wire to the matching peer
// Recv:
// A packet comes in off the wire, and goes to a peer.handlePacket
// The peer does a lookup, sees no better peer than the self
// Hands it to the self peer.out, which passes it to router.in
// If it's dht/seach/etc. traffic, the router passes it to that part
// If it's an encapsulated IPv6 packet, the router looks up the session for it
// The packet is passed to the session, which decrypts it, router.recvPacket
2019-03-28 19:09:19 +00:00
// The router then runs some sanity checks before passing it to the adapter
2017-12-28 22:16:20 -06:00
2018-06-12 17:50:08 -05:00
import (
2019-04-21 20:38:14 -05:00
//"bytes"
2019-04-22 23:12:13 +01:00
2018-06-12 17:50:08 -05:00
"time"
2018-01-04 22:37:51 +00:00
2018-12-14 20:49:18 -06:00
"github.com/yggdrasil-network/yggdrasil-go/src/address"
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
"github.com/yggdrasil-network/yggdrasil-go/src/util"
2019-08-23 18:47:15 -05:00
"github.com/Arceliar/phony"
2018-06-12 17:50:08 -05:00
)
2017-12-28 22:16:20 -06:00
2019-03-28 19:09:19 +00:00
// The router struct has channels to/from the adapter device and a self peer (0), which is how messages are passed between this node and the peers/switch layer.
2019-08-25 12:10:59 -05:00
// The router's phony.Inbox goroutine is responsible for managing all information related to the dht, searches, and crypto sessions.
2017-12-28 22:16:20 -06:00
type router struct {
2019-08-25 10:36:09 -05:00
phony . Inbox
2019-08-25 12:10:59 -05:00
core * Core
addr address . Address
subnet address . Subnet
out func ( [ ] byte ) // packets we're sending to the network, link to peer's "in"
dht dht
nodeinfo nodeinfo
searches searches
sessions sessions
2019-03-28 09:50:13 +00:00
}
2019-03-28 19:09:19 +00:00
// Initializes the router struct, which includes setting up channels to/from the adapter.
2017-12-28 22:16:20 -06:00
func ( r * router ) init ( core * Core ) {
2018-01-04 22:37:51 +00:00
r . core = core
2019-08-23 20:26:15 -05:00
r . addr = * address . AddrForNodeID ( & r . dht . nodeID )
r . subnet = * address . SubnetForNodeID ( & r . dht . nodeID )
2019-03-04 20:33:08 +00:00
self := linkInterface {
name : "(self)" ,
info : linkInfo {
local : "(self)" ,
remote : "(self)" ,
linkType : "self" ,
} ,
}
p := r . core . peers . newPeer ( & r . core . boxPub , & r . core . sigPub , & crypto . BoxSharedKey { } , & self , nil )
2019-08-24 12:55:49 -05:00
p . out = func ( packets [ ] [ ] byte ) { r . handlePackets ( p , packets ) }
r . out = func ( bs [ ] byte ) { p . handlePacketFrom ( r , bs ) }
2019-01-16 13:23:26 +00:00
r . nodeinfo . init ( r . core )
2019-03-28 00:30:25 +00:00
r . core . config . Mutex . RLock ( )
r . nodeinfo . setNodeInfo ( r . core . config . Current . NodeInfo , r . core . config . Current . NodeInfoPrivacy )
r . core . config . Mutex . RUnlock ( )
2019-08-23 20:35:54 -05:00
r . dht . init ( r )
2019-08-23 20:42:38 -05:00
r . searches . init ( r )
2019-08-23 20:53:00 -05:00
r . sessions . init ( r )
2018-05-27 22:13:37 +01:00
}
2019-08-25 12:10:59 -05:00
func ( r * router ) reconfigure ( e chan error ) {
defer close ( e )
var errs [ ] error
// Reconfigure the router
<- r . SyncExec ( func ( ) {
current := r . core . config . GetCurrent ( )
err := r . nodeinfo . setNodeInfo ( current . NodeInfo , current . NodeInfoPrivacy )
if err != nil {
errs = append ( errs , err )
}
} )
for _ , err := range errs {
e <- err
}
}
// Starts the tickerLoop goroutine.
2018-05-27 22:13:37 +01:00
func ( r * router ) start ( ) error {
2019-01-27 13:31:43 +00:00
r . core . log . Infoln ( "Starting router" )
2019-08-25 17:00:02 -05:00
go r . doMaintenance ( )
2018-05-27 22:13:37 +01:00
return nil
2017-12-28 22:16:20 -06:00
}
2019-08-23 18:47:15 -05:00
// In practice, the switch will call this with 1 packet
2019-08-25 10:36:09 -05:00
func ( r * router ) handlePackets ( from phony . Actor , packets [ ] [ ] byte ) {
r . RecvFrom ( from , func ( ) {
2019-08-23 18:47:15 -05:00
for _ , packet := range packets {
2019-08-23 18:59:34 -05:00
r . _handlePacket ( packet )
2019-08-23 18:47:15 -05:00
}
} )
}
// Insert a peer info into the dht, TODO? make the dht a separate actor
2019-08-25 10:36:09 -05:00
func ( r * router ) insertPeer ( from phony . Actor , info * dhtInfo ) {
r . RecvFrom ( from , func ( ) {
2019-08-23 20:26:15 -05:00
r . dht . insertPeer ( info )
2019-08-23 18:47:15 -05:00
} )
}
// Reset sessions and DHT after the switch sees our coords change
2019-08-25 10:36:09 -05:00
func ( r * router ) reset ( from phony . Actor ) {
r . RecvFrom ( from , func ( ) {
2019-08-23 20:26:15 -05:00
r . sessions . reset ( )
r . dht . reset ( )
2019-08-23 18:47:15 -05:00
} )
}
// TODO remove reconfigure so this is just a ticker loop
// and then find something better than a ticker loop to schedule things...
2019-08-25 17:00:02 -05:00
func ( r * router ) doMaintenance ( ) {
<- r . SyncExec ( func ( ) {
// Any periodic maintenance stuff goes here
r . core . switchTable . doMaintenance ( )
r . dht . doMaintenance ( )
r . sessions . cleanup ( )
} )
time . AfterFunc ( time . Second , r . doMaintenance )
2017-12-28 22:16:20 -06:00
}
2018-06-10 18:03:28 -05:00
// Checks incoming traffic type and passes it to the appropriate handler.
2019-08-23 18:59:34 -05:00
func ( r * router ) _handlePacket ( packet [ ] byte ) {
2018-01-04 22:37:51 +00:00
pType , pTypeLen := wire_decode_uint64 ( packet )
if pTypeLen == 0 {
return
}
switch pType {
case wire_Traffic :
2019-08-23 18:59:34 -05:00
r . _handleTraffic ( packet )
2018-01-04 22:37:51 +00:00
case wire_ProtocolTraffic :
2019-08-23 18:59:34 -05:00
r . _handleProto ( packet )
2018-06-12 17:50:08 -05:00
default :
2018-01-04 22:37:51 +00:00
}
2017-12-28 22:16:20 -06:00
}
2018-06-10 18:03:28 -05:00
// Handles incoming traffic, i.e. encapuslated ordinary IPv6 packets.
2019-03-28 19:09:19 +00:00
// Passes them to the crypto session worker to be decrypted and sent to the adapter.
2019-08-23 18:59:34 -05:00
func ( r * router ) _handleTraffic ( packet [ ] byte ) {
2018-12-14 20:49:18 -06:00
defer util . PutBytes ( packet )
2018-01-04 22:37:51 +00:00
p := wire_trafficPacket { }
if ! p . decode ( packet ) {
return
}
2019-08-23 20:26:15 -05:00
sinfo , isIn := r . sessions . getSessionForHandle ( & p . Handle )
2019-08-05 19:11:28 -05:00
if ! isIn {
2019-08-05 18:49:15 -05:00
util . PutBytes ( p . Payload )
2018-01-04 22:37:51 +00:00
return
}
2019-08-23 22:23:01 -05:00
sinfo . recv ( r , & p )
2017-12-28 22:16:20 -06:00
}
2018-06-10 18:03:28 -05:00
// Handles protocol traffic by decrypting it, checking its type, and passing it to the appropriate handler for that traffic type.
2019-08-23 18:59:34 -05:00
func ( r * router ) _handleProto ( packet [ ] byte ) {
2018-01-04 22:37:51 +00:00
// First parse the packet
p := wire_protoTrafficPacket { }
if ! p . decode ( packet ) {
return
}
// Now try to open the payload
2018-12-14 20:49:18 -06:00
var sharedKey * crypto . BoxSharedKey
2018-06-02 21:21:05 +01:00
if p . ToKey == r . core . boxPub {
2018-01-04 22:37:51 +00:00
// Try to open using our permanent key
2019-08-23 20:26:15 -05:00
sharedKey = r . sessions . getSharedKey ( & r . core . boxPriv , & p . FromKey )
2018-01-04 22:37:51 +00:00
} else {
return
}
2018-12-14 20:49:18 -06:00
bs , isOK := crypto . BoxOpen ( sharedKey , p . Payload , & p . Nonce )
2018-01-04 22:37:51 +00:00
if ! isOK {
return
}
// Now do something with the bytes in bs...
2019-03-28 19:09:19 +00:00
// send dht messages to dht, sessionRefresh to sessions, data to adapter...
2018-01-04 22:37:51 +00:00
// For data, should check that key and IP match...
bsType , bsTypeLen := wire_decode_uint64 ( bs )
if bsTypeLen == 0 {
return
}
switch bsType {
case wire_SessionPing :
2019-08-23 18:59:34 -05:00
r . _handlePing ( bs , & p . FromKey )
2018-01-04 22:37:51 +00:00
case wire_SessionPong :
2019-08-23 18:59:34 -05:00
r . _handlePong ( bs , & p . FromKey )
2018-12-15 22:37:11 +00:00
case wire_NodeInfoRequest :
2018-10-21 22:58:27 +01:00
fallthrough
2018-12-15 22:37:11 +00:00
case wire_NodeInfoResponse :
2019-08-23 18:59:34 -05:00
r . _handleNodeInfo ( bs , & p . FromKey )
2018-01-04 22:37:51 +00:00
case wire_DHTLookupRequest :
2019-08-23 18:59:34 -05:00
r . _handleDHTReq ( bs , & p . FromKey )
2018-01-04 22:37:51 +00:00
case wire_DHTLookupResponse :
2019-08-23 18:59:34 -05:00
r . _handleDHTRes ( bs , & p . FromKey )
2018-06-10 18:03:28 -05:00
default :
2018-12-14 20:49:18 -06:00
util . PutBytes ( packet )
2018-01-04 22:37:51 +00:00
}
2017-12-28 22:16:20 -06:00
}
2018-06-10 18:03:28 -05:00
// Decodes session pings from wire format and passes them to sessions.handlePing where they either create or update a session.
2019-08-23 18:59:34 -05:00
func ( r * router ) _handlePing ( bs [ ] byte , fromKey * crypto . BoxPubKey ) {
2018-01-04 22:37:51 +00:00
ping := sessionPing { }
if ! ping . decode ( bs ) {
return
}
2018-06-02 22:19:42 +01:00
ping . SendPermPub = * fromKey
2019-08-23 20:26:15 -05:00
r . sessions . handlePing ( & ping )
2017-12-28 22:16:20 -06:00
}
2018-06-10 18:03:28 -05:00
// Handles session pongs (which are really pings with an extra flag to prevent acknowledgement).
2019-08-23 18:59:34 -05:00
func ( r * router ) _handlePong ( bs [ ] byte , fromKey * crypto . BoxPubKey ) {
r . _handlePing ( bs , fromKey )
2017-12-28 22:16:20 -06:00
}
2018-06-10 18:03:28 -05:00
// Decodes dht requests and passes them to dht.handleReq to trigger a lookup/response.
2019-08-23 18:59:34 -05:00
func ( r * router ) _handleDHTReq ( bs [ ] byte , fromKey * crypto . BoxPubKey ) {
2018-01-04 22:37:51 +00:00
req := dhtReq { }
if ! req . decode ( bs ) {
return
}
2018-06-02 22:19:42 +01:00
req . Key = * fromKey
2019-08-23 20:26:15 -05:00
r . dht . handleReq ( & req )
2017-12-28 22:16:20 -06:00
}
2018-06-10 18:03:28 -05:00
// Decodes dht responses and passes them to dht.handleRes to update the DHT table and further pass them to the search code (if applicable).
2019-08-23 18:59:34 -05:00
func ( r * router ) _handleDHTRes ( bs [ ] byte , fromKey * crypto . BoxPubKey ) {
2018-01-04 22:37:51 +00:00
res := dhtRes { }
if ! res . decode ( bs ) {
return
}
2018-06-02 22:19:42 +01:00
res . Key = * fromKey
2019-08-23 20:26:15 -05:00
r . dht . handleRes ( & res )
2017-12-28 22:16:20 -06:00
}
2018-12-15 22:37:11 +00:00
// Decodes nodeinfo request
2019-08-23 18:59:34 -05:00
func ( r * router ) _handleNodeInfo ( bs [ ] byte , fromKey * crypto . BoxPubKey ) {
2018-12-15 22:37:11 +00:00
req := nodeinfoReqRes { }
2018-10-21 22:58:27 +01:00
if ! req . decode ( bs ) {
return
}
req . SendPermPub = * fromKey
2019-01-14 19:05:16 +00:00
r . nodeinfo . handleNodeInfo ( & req )
2018-10-21 22:58:27 +01:00
}
2019-08-23 18:47:15 -05:00
// TODO remove this, have things either be actors that send message or else call SyncExec directly
2018-01-21 12:55:45 -06:00
func ( r * router ) doAdmin ( f func ( ) ) {
2019-08-23 20:05:18 -05:00
<- r . SyncExec ( f )
2018-01-21 12:55:45 -06:00
}