diff --git a/src/yggdrasil/tcp.go b/src/yggdrasil/tcp.go index c5f7927b..459b51b1 100644 --- a/src/yggdrasil/tcp.go +++ b/src/yggdrasil/tcp.go @@ -10,6 +10,10 @@ package yggdrasil // Could be used to DoS (connect, give someone else's keys, spew garbage) // I guess the "peer" part should watch for link packets, disconnect? +// TCP connections start with a metadata exchange. +// It involves exchanging version numbers and crypto keys +// See version.go for version metadata format + import "net" import "time" import "errors" @@ -142,29 +146,43 @@ 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) + meta := version_getBaseMetadata() + meta.box = iface.core.boxPub + meta.sig = iface.core.sigPub + meta.link = *myLinkPub + metaBytes := meta.encode() + _, err := sock.Write(metaBytes) if err != nil { return } timeout := time.Now().Add(6 * time.Second) sock.SetReadDeadline(timeout) - n, err := sock.Read(keys) + n, err := sock.Read(metaBytes) if err != nil { return } - if n < len(keys) { /*panic("Partial key packet?") ;*/ + if n != version_getMetaLength() { return } - 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?") ;*/ + meta = version_metadata{} // Reset to zero value + if !meta.decode(metaBytes) { return } + if !meta.check() { + base := version_getBaseMetadata() + if meta.meta == base.meta { + if meta.ver > base.ver { + iface.core.log.Println("Failed to connect to node:", sock.RemoteAddr().String(), "version:", meta.ver) + } else if meta.ver == base.ver && meta.minorVer > base.minorVer { + iface.core.log.Println("Failed to connect to node:", sock.RemoteAddr().String(), "version:", fmt.Sprintf("%d.%d", meta.ver, meta.minorVer)) + } + } + return + } + info := tcpInfo{ // used as a map key, so don't include ephemeral link key + box: meta.box, + sig: meta.sig, + } // Quit the parent call if this is a connection to ourself equiv := func(k1, k2 []byte) bool { for idx := range k1 { @@ -210,7 +228,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, getSharedKey(myLinkPriv, &theirLinkPub)) + p := iface.core.peers.newPeer(&info.box, &info.sig, getSharedKey(myLinkPriv, &meta.link)) p.linkOut = make(chan []byte, 1) in := func(bs []byte) { p.handlePacket(bs)