diff --git a/misc/sim/treesim.go b/misc/sim/treesim.go index 0316b8fd..c5c67e79 100644 --- a/misc/sim/treesim.go +++ b/misc/sim/treesim.go @@ -54,10 +54,12 @@ func linkNodes(m, n *Node) { // Create peers // Buffering reduces packet loss in the sim // This slightly speeds up testing (fewer delays before retrying a ping) + pLinkPub, pLinkPriv := m.core.DEBUG_newBoxKeys() + qLinkPub, qLinkPriv := m.core.DEBUG_newBoxKeys() p := m.core.DEBUG_getPeers().DEBUG_newPeer(n.core.DEBUG_getEncryptionPublicKey(), - n.core.DEBUG_getSigningPublicKey()) + n.core.DEBUG_getSigningPublicKey(), *m.core.DEBUG_getSharedKey(pLinkPriv, qLinkPub)) q := n.core.DEBUG_getPeers().DEBUG_newPeer(m.core.DEBUG_getEncryptionPublicKey(), - m.core.DEBUG_getSigningPublicKey()) + m.core.DEBUG_getSigningPublicKey(), *n.core.DEBUG_getSharedKey(qLinkPriv, pLinkPub)) DEBUG_simLinkPeers(p, q) return } diff --git a/src/yggdrasil/debug.go b/src/yggdrasil/debug.go index 6b8211cb..61b4c2f1 100644 --- a/src/yggdrasil/debug.go +++ b/src/yggdrasil/debug.go @@ -64,11 +64,10 @@ func (c *Core) DEBUG_getPeers() *peers { return &c.peers } -func (ps *peers) DEBUG_newPeer(box boxPubKey, - sig sigPubKey) *peer { +func (ps *peers) DEBUG_newPeer(box boxPubKey, sig sigPubKey, link boxSharedKey) *peer { //in <-chan []byte, //out chan<- []byte) *peer { - return ps.newPeer(&box, &sig) //, in, out) + return ps.newPeer(&box, &sig, &link) //, in, out) } /* @@ -275,6 +274,10 @@ func (c *Core) DEBUG_newBoxKeys() (*boxPubKey, *boxPrivKey) { return newBoxKeys() } +func (c *Core) DEBUG_getSharedKey(myPrivKey *boxPrivKey, othersPubKey *boxPubKey) *boxSharedKey { + return getSharedKey(myPrivKey, othersPubKey) +} + func (c *Core) DEBUG_newSigKeys() (*sigPubKey, *sigPrivKey) { return newSigKeys() } diff --git a/src/yggdrasil/peer.go b/src/yggdrasil/peer.go index 51175ef3..2a322cf7 100644 --- a/src/yggdrasil/peer.go +++ b/src/yggdrasil/peer.go @@ -76,17 +76,18 @@ type peer struct { bytesSent uint64 // To track bandwidth usage for getPeers bytesRecvd uint64 // To track bandwidth usage for getPeers // BUG: sync/atomic, 32 bit platforms need the above to be the first element - core *Core - port switchPort - box boxPubKey - sig sigPubKey - shared boxSharedKey - firstSeen time.Time // To track uptime for getPeers - linkOut (chan []byte) // used for protocol traffic (to bypass queues) - doSend (chan struct{}) // tell the linkLoop to send a switchMsg - dinfo *dhtInfo // used to keep the DHT working - out func([]byte) // Set up by whatever created the peers struct, used to send packets to other nodes - close func() // Called when a peer is removed, to close the underlying connection, or via admin api + core *Core + port switchPort + box boxPubKey + sig sigPubKey + shared boxSharedKey + linkShared boxSharedKey + firstSeen time.Time // To track uptime for getPeers + linkOut (chan []byte) // used for protocol traffic (to bypass queues) + doSend (chan struct{}) // tell the linkLoop to send a switchMsg + dinfo *dhtInfo // used to keep the DHT working + out func([]byte) // Set up by whatever created the peers struct, used to send packets to other nodes + close func() // Called when a peer is removed, to close the underlying connection, or via admin api } func (p *peer) getQueueSize() int64 { @@ -97,14 +98,15 @@ func (p *peer) updateQueueSize(delta int64) { atomic.AddInt64(&p.queueSize, delta) } -func (ps *peers) newPeer(box *boxPubKey, sig *sigPubKey) *peer { +func (ps *peers) newPeer(box *boxPubKey, sig *sigPubKey, linkShared *boxSharedKey) *peer { now := time.Now() p := peer{box: *box, - sig: *sig, - shared: *getSharedKey(&ps.core.boxPriv, box), - firstSeen: now, - doSend: make(chan struct{}, 1), - core: ps.core} + sig: *sig, + shared: *getSharedKey(&ps.core.boxPriv, box), + linkShared: *linkShared, + firstSeen: now, + doSend: make(chan struct{}, 1), + core: ps.core} ps.mutex.Lock() defer ps.mutex.Unlock() oldPorts := ps.getPorts() @@ -228,7 +230,13 @@ func (p *peer) sendPacket(packet []byte) { } func (p *peer) sendLinkPacket(packet []byte) { - bs, nonce := boxSeal(&p.shared, packet, nil) + innerPayload, innerNonce := boxSeal(&p.linkShared, packet, nil) + innerLinkPacket := wire_linkProtoTrafficPacket{ + Nonce: *innerNonce, + Payload: innerPayload, + } + outerPayload := innerLinkPacket.encode() + bs, nonce := boxSeal(&p.shared, outerPayload, nil) linkPacket := wire_linkProtoTrafficPacket{ Nonce: *nonce, Payload: bs, @@ -242,7 +250,15 @@ func (p *peer) handleLinkTraffic(bs []byte) { if !packet.decode(bs) { return } - payload, isOK := boxOpen(&p.shared, packet.Payload, &packet.Nonce) + outerPayload, isOK := boxOpen(&p.shared, packet.Payload, &packet.Nonce) + if !isOK { + return + } + innerPacket := wire_linkProtoTrafficPacket{} + if !innerPacket.decode(outerPayload) { + return + } + payload, isOK := boxOpen(&p.linkShared, innerPacket.Payload, &innerPacket.Nonce) if !isOK { return } @@ -297,6 +313,13 @@ func (p *peer) handleSwitchMsg(packet []byte) { prevKey = hop.Next } p.core.switchTable.handleMsg(&msg, p.port) + if !p.core.switchTable.checkRoot(&msg) { + // Bad switch message + // Stop forwarding traffic from it + // Stop refreshing it in the DHT + p.dinfo = nil + return + } // Pass a mesage to the dht informing it that this peer (still) exists loc.coords = loc.coords[:len(loc.coords)-1] dinfo := dhtInfo{ diff --git a/src/yggdrasil/router.go b/src/yggdrasil/router.go index ddb48486..9e48668e 100644 --- a/src/yggdrasil/router.go +++ b/src/yggdrasil/router.go @@ -43,8 +43,8 @@ type router struct { func (r *router) init(core *Core) { r.core = core r.addr = *address_addrForNodeID(&r.core.dht.nodeID) - in := make(chan []byte, 32) // TODO something better than this... - p := r.core.peers.newPeer(&r.core.boxPub, &r.core.sigPub) //, out, in) + in := make(chan []byte, 32) // TODO something better than this... + p := r.core.peers.newPeer(&r.core.boxPub, &r.core.sigPub, &boxSharedKey{}) p.out = func(packet []byte) { // This is to make very sure it never blocks select { diff --git a/src/yggdrasil/switch.go b/src/yggdrasil/switch.go index 4db4c67f..6c42f456 100644 --- a/src/yggdrasil/switch.go +++ b/src/yggdrasil/switch.go @@ -263,6 +263,27 @@ func (t *switchTable) getMsg() *switchMsg { } } +func (t *switchTable) checkRoot(msg *switchMsg) bool { + // returns false if it's a dropped root, not a better root, or has an older timestamp + // returns true otherwise + // used elsewhere to keep inserting peers into the dht only if root info is OK + t.mutex.RLock() + defer t.mutex.RUnlock() + dropTstamp, isIn := t.drop[msg.Root] + switch { + case isIn && dropTstamp >= msg.TStamp: + return false + case firstIsBetter(&msg.Root, &t.data.locator.root): + return true + case t.data.locator.root != msg.Root: + return false + case t.data.locator.tstamp > msg.TStamp: + return false + default: + return true + } +} + func (t *switchTable) handleMsg(msg *switchMsg, fromPort switchPort) { t.mutex.Lock() defer t.mutex.Unlock() diff --git a/src/yggdrasil/tcp.go b/src/yggdrasil/tcp.go index e7b682c9..c5f7927b 100644 --- a/src/yggdrasil/tcp.go +++ b/src/yggdrasil/tcp.go @@ -141,10 +141,12 @@ func (iface *tcpInterface) call(saddr string) { func (iface *tcpInterface) handler(sock net.Conn, incoming bool) { defer sock.Close() // Get our keys + myLinkPub, myLinkPriv := newBoxKeys() // ephemeral link keys keys := []byte{} keys = append(keys, tcp_key[:]...) keys = append(keys, iface.core.boxPub[:]...) keys = append(keys, iface.core.sigPub[:]...) + keys = append(keys, myLinkPub[:]...) _, err := sock.Write(keys) if err != nil { return @@ -158,8 +160,9 @@ func (iface *tcpInterface) handler(sock net.Conn, incoming bool) { if n < len(keys) { /*panic("Partial key packet?") ;*/ return } - info := tcpInfo{} - if !tcp_chop_keys(&info.box, &info.sig, &keys) { /*panic("Invalid key packet?") ;*/ + info := tcpInfo{} // used as a map key, so don't include ephemeral link eys + var theirLinkPub boxPubKey + if !tcp_chop_keys(&info.box, &info.sig, &theirLinkPub, &keys) { /*panic("Invalid key packet?") ;*/ return } // Quit the parent call if this is a connection to ourself @@ -207,7 +210,7 @@ func (iface *tcpInterface) handler(sock net.Conn, incoming bool) { }() // Note that multiple connections to the same node are allowed // E.g. over different interfaces - p := iface.core.peers.newPeer(&info.box, &info.sig) + p := iface.core.peers.newPeer(&info.box, &info.sig, getSharedKey(myLinkPriv, &theirLinkPub)) p.linkOut = make(chan []byte, 1) in := func(bs []byte) { p.handlePacket(bs) @@ -336,10 +339,10 @@ func (iface *tcpInterface) reader(sock net.Conn, in func([]byte)) { var tcp_key = [...]byte{'k', 'e', 'y', 's'} var tcp_msg = [...]byte{0xde, 0xad, 0xb1, 0x75} // "dead bits" -func tcp_chop_keys(box *boxPubKey, sig *sigPubKey, bs *[]byte) bool { +func tcp_chop_keys(box *boxPubKey, sig *sigPubKey, link *boxPubKey, bs *[]byte) bool { // This one is pretty simple: we know how long the message should be // So don't call this with a message that's too short - if len(*bs) < len(tcp_key)+len(*box)+len(*sig) { + if len(*bs) < len(tcp_key)+2*len(*box)+len(*sig) { return false } for idx := range tcp_key { @@ -352,6 +355,8 @@ func tcp_chop_keys(box *boxPubKey, sig *sigPubKey, bs *[]byte) bool { (*bs) = (*bs)[len(box):] copy(sig[:], *bs) (*bs) = (*bs)[len(sig):] + copy(link[:], *bs) + (*bs) = (*bs)[len(sig):] return true }