diff --git a/src/address/address.go b/src/address/address.go index dd2c410a..5c13257b 100644 --- a/src/address/address.go +++ b/src/address/address.go @@ -1,21 +1,26 @@ -package yggdrasil +package address + +import "github.com/yggdrasil-network/yggdrasil-go/src/crypto" // address represents an IPv6 address in the yggdrasil address range. -type address [16]byte +type Address [16]byte // subnet represents an IPv6 /64 subnet in the yggdrasil subnet range. -type subnet [8]byte +type Subnet [8]byte // address_prefix is the prefix used for all addresses and subnets in the network. // The current implementation requires this to be a muliple of 8 bits + 7 bits. // The 8th bit of the last byte is used to signal nodes (0) or /64 prefixes (1). // Nodes that configure this differently will be unable to communicate with eachother, though routing and the DHT machinery *should* still work. -var address_prefix = [...]byte{0x02} +func GetPrefix() [1]byte { + return [...]byte{0x02} +} // isValid returns true if an address falls within the range used by nodes in the network. -func (a *address) isValid() bool { - for idx := range address_prefix { - if (*a)[idx] != address_prefix[idx] { +func (a *Address) IsValid() bool { + prefix := GetPrefix() + for idx := range prefix { + if (*a)[idx] != prefix[idx] { return false } } @@ -23,28 +28,29 @@ func (a *address) isValid() bool { } // isValid returns true if a prefix falls within the range usable by the network. -func (s *subnet) isValid() bool { - l := len(address_prefix) - for idx := range address_prefix[:l-1] { - if (*s)[idx] != address_prefix[idx] { +func (s *Subnet) IsValid() bool { + prefix := GetPrefix() + l := len(prefix) + for idx := range prefix[:l-1] { + if (*s)[idx] != prefix[idx] { return false } } - return (*s)[l-1] == address_prefix[l-1]|0x01 + return (*s)[l-1] == prefix[l-1]|0x01 } // address_addrForNodeID takes a *NodeID as an argument and returns an *address. // This subnet begins with the address prefix, with the last bit set to 0 to indicate an address. // The following 8 bits are set to the number of leading 1 bits in the NodeID. // The NodeID, excluding the leading 1 bits and the first leading 0 bit, is truncated to the appropriate length and makes up the remainder of the address. -func address_addrForNodeID(nid *NodeID) *address { +func AddrForNodeID(nid *crypto.NodeID) *Address { // 128 bit address // Begins with prefix // Next bit is a 0 // Next 7 bits, interpreted as a uint, are # of leading 1s in the NodeID // Leading 1s and first leading 0 of the NodeID are truncated off // The rest is appended to the IPv6 address (truncated to 128 bits total) - var addr address + var addr Address var temp []byte done := false ones := byte(0) @@ -67,9 +73,10 @@ func address_addrForNodeID(nid *NodeID) *address { temp = append(temp, bits) } } - copy(addr[:], address_prefix[:]) - addr[len(address_prefix)] = ones - copy(addr[len(address_prefix)+1:], temp) + prefix := GetPrefix() + copy(addr[:], prefix[:]) + addr[len(prefix)] = ones + copy(addr[len(prefix)+1:], temp) return &addr } @@ -77,14 +84,15 @@ func address_addrForNodeID(nid *NodeID) *address { // This subnet begins with the address prefix, with the last bit set to 1 to indicate a prefix. // The following 8 bits are set to the number of leading 1 bits in the NodeID. // The NodeID, excluding the leading 1 bits and the first leading 0 bit, is truncated to the appropriate length and makes up the remainder of the subnet. -func address_subnetForNodeID(nid *NodeID) *subnet { +func SubnetForNodeID(nid *crypto.NodeID) *Subnet { // Exactly as the address version, with two exceptions: // 1) The first bit after the fixed prefix is a 1 instead of a 0 // 2) It's truncated to a subnet prefix length instead of 128 bits - addr := *address_addrForNodeID(nid) - var snet subnet + addr := *AddrForNodeID(nid) + var snet Subnet copy(snet[:], addr[:]) - snet[len(address_prefix)-1] |= 0x01 + prefix := GetPrefix() + snet[len(prefix)-1] |= 0x01 return &snet } @@ -92,17 +100,18 @@ func address_subnetForNodeID(nid *NodeID) *subnet { // The first is a NodeID with all the bits known from the address set to their correct values. // The second is a bitmask with 1 bit set for each bit that was known from the address. // This is used to look up NodeIDs in the DHT and tell if they match an address. -func (a *address) getNodeIDandMask() (*NodeID, *NodeID) { +func (a *Address) GetNodeIDandMask() (*crypto.NodeID, *crypto.NodeID) { // Mask is a bitmask to mark the bits visible from the address // This means truncated leading 1s, first leading 0, and visible part of addr - var nid NodeID - var mask NodeID - ones := int(a[len(address_prefix)]) + var nid crypto.NodeID + var mask crypto.NodeID + prefix := GetPrefix() + ones := int(a[len(prefix)]) for idx := 0; idx < ones; idx++ { nid[idx/8] |= 0x80 >> byte(idx%8) } nidOffset := ones + 1 - addrOffset := 8*len(address_prefix) + 8 + addrOffset := 8*len(prefix) + 8 for idx := addrOffset; idx < 8*len(a); idx++ { bits := a[idx/8] & (0x80 >> byte(idx%8)) bits <<= byte(idx % 8) @@ -110,7 +119,7 @@ func (a *address) getNodeIDandMask() (*NodeID, *NodeID) { bits >>= byte(nidIdx % 8) nid[nidIdx/8] |= bits } - maxMask := 8*(len(a)-len(address_prefix)-1) + ones + 1 + maxMask := 8*(len(a)-len(prefix)-1) + ones + 1 for idx := 0; idx < maxMask; idx++ { mask[idx/8] |= 0x80 >> byte(idx%8) } @@ -121,16 +130,17 @@ func (a *address) getNodeIDandMask() (*NodeID, *NodeID) { // The first is a NodeID with all the bits known from the address set to their correct values. // The second is a bitmask with 1 bit set for each bit that was known from the subnet. // This is used to look up NodeIDs in the DHT and tell if they match a subnet. -func (s *subnet) getNodeIDandMask() (*NodeID, *NodeID) { +func (s *Subnet) GetNodeIDandMask() (*crypto.NodeID, *crypto.NodeID) { // As with the address version, but visible parts of the subnet prefix instead - var nid NodeID - var mask NodeID - ones := int(s[len(address_prefix)]) + var nid crypto.NodeID + var mask crypto.NodeID + prefix := GetPrefix() + ones := int(s[len(prefix)]) for idx := 0; idx < ones; idx++ { nid[idx/8] |= 0x80 >> byte(idx%8) } nidOffset := ones + 1 - addrOffset := 8*len(address_prefix) + 8 + addrOffset := 8*len(prefix) + 8 for idx := addrOffset; idx < 8*len(s); idx++ { bits := s[idx/8] & (0x80 >> byte(idx%8)) bits <<= byte(idx % 8) @@ -138,7 +148,7 @@ func (s *subnet) getNodeIDandMask() (*NodeID, *NodeID) { bits >>= byte(nidIdx % 8) nid[nidIdx/8] |= bits } - maxMask := 8*(len(s)-len(address_prefix)-1) + ones + 1 + maxMask := 8*(len(s)-len(prefix)-1) + ones + 1 for idx := 0; idx < maxMask; idx++ { mask[idx/8] |= 0x80 >> byte(idx%8) } diff --git a/src/crypto/crypto.go b/src/crypto/crypto.go index efca41d4..c974a3c0 100644 --- a/src/crypto/crypto.go +++ b/src/crypto/crypto.go @@ -1,4 +1,4 @@ -package yggdrasil +package crypto /* @@ -16,6 +16,8 @@ import ( "golang.org/x/crypto/ed25519" "golang.org/x/crypto/nacl/box" + + "github.com/yggdrasil-network/yggdrasil-go/src/util" ) //////////////////////////////////////////////////////////////////////////////// @@ -28,20 +30,20 @@ const handleLen = 8 type NodeID [NodeIDLen]byte type TreeID [TreeIDLen]byte -type handle [handleLen]byte +type Handle [handleLen]byte -func getNodeID(pub *boxPubKey) *NodeID { +func GetNodeID(pub *BoxPubKey) *NodeID { h := sha512.Sum512(pub[:]) return (*NodeID)(&h) } -func getTreeID(pub *sigPubKey) *TreeID { +func GetTreeID(pub *SigPubKey) *TreeID { h := sha512.Sum512(pub[:]) return (*TreeID)(&h) } -func newHandle() *handle { - var h handle +func NewHandle() *Handle { + var h Handle _, err := rand.Read(h[:]) if err != nil { panic(err) @@ -53,17 +55,17 @@ func newHandle() *handle { // Signatures -const sigPubKeyLen = ed25519.PublicKeySize -const sigPrivKeyLen = ed25519.PrivateKeySize -const sigLen = ed25519.SignatureSize +const SigPubKeyLen = ed25519.PublicKeySize +const SigPrivKeyLen = ed25519.PrivateKeySize +const SigLen = ed25519.SignatureSize -type sigPubKey [sigPubKeyLen]byte -type sigPrivKey [sigPrivKeyLen]byte -type sigBytes [sigLen]byte +type SigPubKey [SigPubKeyLen]byte +type SigPrivKey [SigPrivKeyLen]byte +type SigBytes [SigLen]byte -func newSigKeys() (*sigPubKey, *sigPrivKey) { - var pub sigPubKey - var priv sigPrivKey +func NewSigKeys() (*SigPubKey, *SigPrivKey) { + var pub SigPubKey + var priv SigPrivKey pubSlice, privSlice, err := ed25519.GenerateKey(rand.Reader) if err != nil { panic(err) @@ -73,14 +75,14 @@ func newSigKeys() (*sigPubKey, *sigPrivKey) { return &pub, &priv } -func sign(priv *sigPrivKey, msg []byte) *sigBytes { - var sig sigBytes +func Sign(priv *SigPrivKey, msg []byte) *SigBytes { + var sig SigBytes sigSlice := ed25519.Sign(priv[:], msg) copy(sig[:], sigSlice) return &sig } -func verify(pub *sigPubKey, msg []byte, sig *sigBytes) bool { +func Verify(pub *SigPubKey, msg []byte, sig *SigBytes) bool { // Should sig be an array instead of a slice?... // It's fixed size, but return ed25519.Verify(pub[:], msg, sig[:]) @@ -90,60 +92,60 @@ func verify(pub *sigPubKey, msg []byte, sig *sigBytes) bool { // NaCl-like crypto "box" (curve25519+xsalsa20+poly1305) -const boxPubKeyLen = 32 -const boxPrivKeyLen = 32 -const boxSharedKeyLen = 32 -const boxNonceLen = 24 -const boxOverhead = box.Overhead +const BoxPubKeyLen = 32 +const BoxPrivKeyLen = 32 +const BoxSharedKeyLen = 32 +const BoxNonceLen = 24 +const BoxOverhead = box.Overhead -type boxPubKey [boxPubKeyLen]byte -type boxPrivKey [boxPrivKeyLen]byte -type boxSharedKey [boxSharedKeyLen]byte -type boxNonce [boxNonceLen]byte +type BoxPubKey [BoxPubKeyLen]byte +type BoxPrivKey [BoxPrivKeyLen]byte +type BoxSharedKey [BoxSharedKeyLen]byte +type BoxNonce [BoxNonceLen]byte -func newBoxKeys() (*boxPubKey, *boxPrivKey) { +func NewBoxKeys() (*BoxPubKey, *BoxPrivKey) { pubBytes, privBytes, err := box.GenerateKey(rand.Reader) if err != nil { panic(err) } - pub := (*boxPubKey)(pubBytes) - priv := (*boxPrivKey)(privBytes) + pub := (*BoxPubKey)(pubBytes) + priv := (*BoxPrivKey)(privBytes) return pub, priv } -func getSharedKey(myPrivKey *boxPrivKey, - othersPubKey *boxPubKey) *boxSharedKey { - var shared [boxSharedKeyLen]byte - priv := (*[boxPrivKeyLen]byte)(myPrivKey) - pub := (*[boxPubKeyLen]byte)(othersPubKey) +func GetSharedKey(myPrivKey *BoxPrivKey, + othersPubKey *BoxPubKey) *BoxSharedKey { + var shared [BoxSharedKeyLen]byte + priv := (*[BoxPrivKeyLen]byte)(myPrivKey) + pub := (*[BoxPubKeyLen]byte)(othersPubKey) box.Precompute(&shared, pub, priv) - return (*boxSharedKey)(&shared) + return (*BoxSharedKey)(&shared) } -func boxOpen(shared *boxSharedKey, +func BoxOpen(shared *BoxSharedKey, boxed []byte, - nonce *boxNonce) ([]byte, bool) { - out := util_getBytes() - s := (*[boxSharedKeyLen]byte)(shared) - n := (*[boxNonceLen]byte)(nonce) + nonce *BoxNonce) ([]byte, bool) { + out := util.GetBytes() + s := (*[BoxSharedKeyLen]byte)(shared) + n := (*[BoxNonceLen]byte)(nonce) unboxed, success := box.OpenAfterPrecomputation(out, boxed, n, s) return unboxed, success } -func boxSeal(shared *boxSharedKey, unboxed []byte, nonce *boxNonce) ([]byte, *boxNonce) { +func BoxSeal(shared *BoxSharedKey, unboxed []byte, nonce *BoxNonce) ([]byte, *BoxNonce) { if nonce == nil { - nonce = newBoxNonce() + nonce = NewBoxNonce() } - nonce.update() - out := util_getBytes() - s := (*[boxSharedKeyLen]byte)(shared) - n := (*[boxNonceLen]byte)(nonce) + nonce.Increment() + out := util.GetBytes() + s := (*[BoxSharedKeyLen]byte)(shared) + n := (*[BoxNonceLen]byte)(nonce) boxed := box.SealAfterPrecomputation(out, unboxed, n, s) return boxed, nonce } -func newBoxNonce() *boxNonce { - var nonce boxNonce +func NewBoxNonce() *BoxNonce { + var nonce BoxNonce _, err := rand.Read(nonce[:]) for ; err == nil && nonce[0] == 0xff; _, err = rand.Read(nonce[:]) { // Make sure nonce isn't too high @@ -156,7 +158,7 @@ func newBoxNonce() *boxNonce { return &nonce } -func (n *boxNonce) update() { +func (n *BoxNonce) Increment() { oldNonce := *n n[len(n)-1] += 2 for i := len(n) - 2; i >= 0; i-- { @@ -165,3 +167,21 @@ func (n *boxNonce) update() { } } } + +// Used to subtract one nonce from another, staying in the range +- 64. +// This is used by the nonce progression machinery to advance the bitmask of recently received packets (indexed by nonce), or to check the appropriate bit of the bitmask. +// It's basically part of the machinery that prevents replays and duplicate packets. +func (n *BoxNonce) Minus(m *BoxNonce) int64 { + diff := int64(0) + for idx := range n { + diff *= 256 + diff += int64(n[idx]) - int64(m[idx]) + if diff > 64 { + diff = 64 + } + if diff < -64 { + diff = -64 + } + } + return diff +} diff --git a/src/util/util.go b/src/util/util.go index c9897eda..65e6d463 100644 --- a/src/util/util.go +++ b/src/util/util.go @@ -1,21 +1,21 @@ -package yggdrasil +package util // These are misc. utility functions that didn't really fit anywhere else import "runtime" // A wrapper around runtime.Gosched() so it doesn't need to be imported elsewhere. -func util_yield() { +func Yield() { runtime.Gosched() } // A wrapper around runtime.LockOSThread() so it doesn't need to be imported elsewhere. -func util_lockthread() { +func LockThread() { runtime.LockOSThread() } // A wrapper around runtime.UnlockOSThread() so it doesn't need to be imported elsewhere. -func util_unlockthread() { +func UnlockThread() { runtime.UnlockOSThread() } @@ -23,15 +23,12 @@ func util_unlockthread() { // It's used like a sync.Pool, but with a fixed size and typechecked without type casts to/from interface{} (which were making the profiles look ugly). var byteStore chan []byte -// Initializes the byteStore -func util_initByteStore() { - if byteStore == nil { - byteStore = make(chan []byte, 32) - } +func init() { + byteStore = make(chan []byte, 32) } // Gets an empty slice from the byte store, if one is available, or else returns a new nil slice. -func util_getBytes() []byte { +func GetBytes() []byte { select { case bs := <-byteStore: return bs[:0] @@ -41,7 +38,7 @@ func util_getBytes() []byte { } // Puts a slice in the store, if there's room, or else returns and lets the slice get collected. -func util_putBytes(bs []byte) { +func PutBytes(bs []byte) { select { case byteStore <- bs: default: diff --git a/src/yggdrasil/admin.go b/src/yggdrasil/admin.go index 577b6efd..1f77050d 100644 --- a/src/yggdrasil/admin.go +++ b/src/yggdrasil/admin.go @@ -14,6 +14,8 @@ import ( "sync/atomic" "time" + "github.com/yggdrasil-network/yggdrasil-go/src/address" + "github.com/yggdrasil-network/yggdrasil-go/src/crypto" "github.com/yggdrasil-network/yggdrasil-go/src/defaults" ) @@ -314,7 +316,7 @@ func (a *admin) init(c *Core, listenaddr string) { "box_pub_key": hex.EncodeToString(dinfo.key[:]), "coords": fmt.Sprintf("%v", dinfo.coords), } - addr := net.IP(address_addrForNodeID(getNodeID(&dinfo.key))[:]).String() + addr := net.IP(address.AddrForNodeID(crypto.GetNodeID(&dinfo.key))[:]).String() infos[addr] = info } return admin_info{"nodes": infos}, nil @@ -536,7 +538,7 @@ func (a *admin) startTunWithMTU(ifname string, iftapmode bool, ifmtu int) error _ = a.core.router.tun.close() // Then reconfigure and start it addr := a.core.router.addr - straddr := fmt.Sprintf("%s/%v", net.IP(addr[:]).String(), 8*len(address_prefix)-1) + straddr := fmt.Sprintf("%s/%v", net.IP(addr[:]).String(), 8*len(address.GetPrefix())-1) if ifname != "none" { err := a.core.router.tun.setup(ifname, iftapmode, straddr, ifmtu) if err != nil { @@ -590,7 +592,7 @@ func (a *admin) getData_getPeers() []admin_nodeInfo { sort.Slice(ps, func(i, j int) bool { return ps[i] < ps[j] }) for _, port := range ps { p := ports[port] - addr := *address_addrForNodeID(getNodeID(&p.box)) + addr := *address.AddrForNodeID(crypto.GetNodeID(&p.box)) info := admin_nodeInfo{ {"ip", net.IP(addr[:]).String()}, {"port", port}, @@ -615,7 +617,7 @@ func (a *admin) getData_getSwitchPeers() []admin_nodeInfo { if !isIn { continue } - addr := *address_addrForNodeID(getNodeID(&peer.box)) + addr := *address.AddrForNodeID(crypto.GetNodeID(&peer.box)) coords := elem.locator.getCoords() info := admin_nodeInfo{ {"ip", net.IP(addr[:]).String()}, @@ -673,7 +675,7 @@ func (a *admin) getData_getDHT() []admin_nodeInfo { return dht_ordered(&a.core.dht.nodeID, dhtInfos[i].getNodeID(), dhtInfos[j].getNodeID()) }) for _, v := range dhtInfos { - addr := *address_addrForNodeID(v.getNodeID()) + addr := *address.AddrForNodeID(v.getNodeID()) info := admin_nodeInfo{ {"ip", net.IP(addr[:]).String()}, {"coords", fmt.Sprint(v.coords)}, @@ -723,7 +725,7 @@ func (a *admin) getAllowedEncryptionPublicKeys() []string { func (a *admin) addAllowedEncryptionPublicKey(bstr string) (err error) { boxBytes, err := hex.DecodeString(bstr) if err == nil { - var box boxPubKey + var box crypto.BoxPubKey copy(box[:], boxBytes) a.core.peers.addAllowedEncryptionPublicKey(&box) } @@ -735,7 +737,7 @@ func (a *admin) addAllowedEncryptionPublicKey(bstr string) (err error) { func (a *admin) removeAllowedEncryptionPublicKey(bstr string) (err error) { boxBytes, err := hex.DecodeString(bstr) if err == nil { - var box boxPubKey + var box crypto.BoxPubKey copy(box[:], boxBytes) a.core.peers.removeAllowedEncryptionPublicKey(&box) } @@ -744,7 +746,7 @@ func (a *admin) removeAllowedEncryptionPublicKey(bstr string) (err error) { // Send a DHT ping to the node with the provided key and coords, optionally looking up the specified target NodeID. func (a *admin) admin_dhtPing(keyString, coordString, targetString string) (dhtRes, error) { - var key boxPubKey + var key crypto.BoxPubKey if keyBytes, err := hex.DecodeString(keyString); err != nil { return dhtRes{}, err } else { @@ -775,7 +777,7 @@ func (a *admin) admin_dhtPing(keyString, coordString, targetString string) (dhtR } else if len(targetBytes) != len(target) { return dhtRes{}, errors.New("Incorrect target NodeID length") } else { - target = NodeID{} + var target crypto.NodeID copy(target[:], targetBytes) } rq := dhtReqKey{info.key, target} diff --git a/src/yggdrasil/ckr.go b/src/yggdrasil/ckr.go index d88b8d3c..a3df891e 100644 --- a/src/yggdrasil/ckr.go +++ b/src/yggdrasil/ckr.go @@ -7,6 +7,9 @@ import ( "fmt" "net" "sort" + + "github.com/yggdrasil-network/yggdrasil-go/src/address" + "github.com/yggdrasil-network/yggdrasil-go/src/crypto" ) // This module implements crypto-key routing, similar to Wireguard, where we @@ -17,15 +20,15 @@ type cryptokey struct { enabled bool ipv4routes []cryptokey_route ipv6routes []cryptokey_route - ipv4cache map[address]cryptokey_route - ipv6cache map[address]cryptokey_route + ipv4cache map[address.Address]cryptokey_route + ipv6cache map[address.Address]cryptokey_route ipv4sources []net.IPNet ipv6sources []net.IPNet } type cryptokey_route struct { subnet net.IPNet - destination boxPubKey + destination crypto.BoxPubKey } // Initialise crypto-key routing. This must be done before any other CKR calls. @@ -33,8 +36,8 @@ func (c *cryptokey) init(core *Core) { c.core = core c.ipv4routes = make([]cryptokey_route, 0) c.ipv6routes = make([]cryptokey_route, 0) - c.ipv4cache = make(map[address]cryptokey_route, 0) - c.ipv6cache = make(map[address]cryptokey_route, 0) + c.ipv4cache = make(map[address.Address]cryptokey_route, 0) + c.ipv6cache = make(map[address.Address]cryptokey_route, 0) c.ipv4sources = make([]net.IPNet, 0) c.ipv6sources = make([]net.IPNet, 0) } @@ -52,7 +55,7 @@ func (c *cryptokey) isEnabled() bool { // Check whether the given address (with the address length specified in bytes) // matches either the current node's address, the node's routed subnet or the // list of subnets specified in IPv4Sources/IPv6Sources. -func (c *cryptokey) isValidSource(addr address, addrlen int) bool { +func (c *cryptokey) isValidSource(addr address.Address, addrlen int) bool { ip := net.IP(addr[:addrlen]) if addrlen == net.IPv6len { @@ -143,7 +146,7 @@ func (c *cryptokey) addRoute(cidr string, dest string) error { // Build our references to the routing table and cache var routingtable *[]cryptokey_route - var routingcache *map[address]cryptokey_route + var routingcache *map[address.Address]cryptokey_route // Check if the prefix is IPv4 or IPv6 if prefixsize == net.IPv6len*8 { @@ -157,11 +160,11 @@ func (c *cryptokey) addRoute(cidr string, dest string) error { } // Is the route an Yggdrasil destination? - var addr address - var snet subnet + var addr address.Address + var snet address.Subnet copy(addr[:], ipaddr) copy(snet[:], ipnet.IP) - if addr.isValid() || snet.isValid() { + if addr.IsValid() || snet.IsValid() { return errors.New("Can't specify Yggdrasil destination as crypto-key route") } // Do we already have a route for this subnet? @@ -173,11 +176,11 @@ func (c *cryptokey) addRoute(cidr string, dest string) error { // Decode the public key if bpk, err := hex.DecodeString(dest); err != nil { return err - } else if len(bpk) != boxPubKeyLen { + } else if len(bpk) != crypto.BoxPubKeyLen { return errors.New(fmt.Sprintf("Incorrect key length for %s", dest)) } else { // Add the new crypto-key route - var key boxPubKey + var key crypto.BoxPubKey copy(key[:], bpk) *routingtable = append(*routingtable, cryptokey_route{ subnet: *ipnet, @@ -205,16 +208,16 @@ func (c *cryptokey) addRoute(cidr string, dest string) error { // Looks up the most specific route for the given address (with the address // length specified in bytes) from the crypto-key routing table. An error is // returned if the address is not suitable or no route was found. -func (c *cryptokey) getPublicKeyForAddress(addr address, addrlen int) (boxPubKey, error) { +func (c *cryptokey) getPublicKeyForAddress(addr address.Address, addrlen int) (crypto.BoxPubKey, error) { // Check if the address is a valid Yggdrasil address - if so it // is exempt from all CKR checking - if addr.isValid() { - return boxPubKey{}, errors.New("Cannot look up CKR for Yggdrasil addresses") + if addr.IsValid() { + return crypto.BoxPubKey{}, errors.New("Cannot look up CKR for Yggdrasil addresses") } // Build our references to the routing table and cache var routingtable *[]cryptokey_route - var routingcache *map[address]cryptokey_route + var routingcache *map[address.Address]cryptokey_route // Check if the prefix is IPv4 or IPv6 if addrlen == net.IPv6len { @@ -224,7 +227,7 @@ func (c *cryptokey) getPublicKeyForAddress(addr address, addrlen int) (boxPubKey routingtable = &c.ipv4routes routingcache = &c.ipv4cache } else { - return boxPubKey{}, errors.New("Unexpected prefix size") + return crypto.BoxPubKey{}, errors.New("Unexpected prefix size") } // Check if there's a cache entry for this addr @@ -260,7 +263,7 @@ func (c *cryptokey) getPublicKeyForAddress(addr address, addrlen int) (boxPubKey } // No route was found if we got to this point - return boxPubKey{}, errors.New(fmt.Sprintf("No route to %s", ip.String())) + return crypto.BoxPubKey{}, errors.New(fmt.Sprintf("No route to %s", ip.String())) } // Removes a source subnet, which allows traffic with these source addresses to @@ -312,7 +315,7 @@ func (c *cryptokey) removeRoute(cidr string, dest string) error { // Build our references to the routing table and cache var routingtable *[]cryptokey_route - var routingcache *map[address]cryptokey_route + var routingcache *map[address.Address]cryptokey_route // Check if the prefix is IPv4 or IPv6 if prefixsize == net.IPv6len*8 { @@ -329,7 +332,7 @@ func (c *cryptokey) removeRoute(cidr string, dest string) error { bpk, err := hex.DecodeString(dest) if err != nil { return err - } else if len(bpk) != boxPubKeyLen { + } else if len(bpk) != crypto.BoxPubKeyLen { return errors.New(fmt.Sprintf("Incorrect key length for %s", dest)) } netStr := ipnet.String() diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index bf425483..2f9c451c 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -21,10 +21,10 @@ var buildVersion string // object for each Yggdrasil node you plan to run. type Core struct { // This is the main data structure that holds everything else for a node - boxPub boxPubKey - boxPriv boxPrivKey - sigPub sigPubKey - sigPriv sigPrivKey + boxPub crypto.BoxPubKey + boxPriv crypto.BoxPrivKey + sigPub crypto.SigPubKey + sigPriv crypto.SigPrivKey switchTable switchTable peers peers sessions sessions @@ -38,15 +38,14 @@ type Core struct { ifceExpr []*regexp.Regexp // the zone of link-local IPv6 peers must match this } -func (c *Core) init(bpub *boxPubKey, - bpriv *boxPrivKey, - spub *sigPubKey, - spriv *sigPrivKey) { +func (c *Core) init(bpub *crypto.BoxPubKey, + bpriv *crypto.BoxPrivKey, + spub *crypto.SigPubKey, + spriv *crypto.SigPrivKey) { // TODO separate init and start functions // Init sets up structs // Start launches goroutines that depend on structs being set up // This is pretty much required to completely avoid race conditions - util_initByteStore() if c.log == nil { c.log = log.New(ioutil.Discard, "", 0) } @@ -96,10 +95,10 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error { c.log.Println("Starting up...") - var boxPub boxPubKey - var boxPriv boxPrivKey - var sigPub sigPubKey - var sigPriv sigPrivKey + var boxPub crypto.BoxPubKey + var boxPriv crypto.BoxPrivKey + var sigPub crypto.SigPubKey + var sigPriv crypto.SigPrivKey boxPubHex, err := hex.DecodeString(nc.EncryptionPublicKey) if err != nil { return err @@ -188,7 +187,7 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error { } ip := net.IP(c.router.addr[:]).String() - if err := c.router.tun.start(nc.IfName, nc.IfTAPMode, fmt.Sprintf("%s/%d", ip, 8*len(address_prefix)-1), nc.IfMTU); err != nil { + if err := c.router.tun.start(nc.IfName, nc.IfTAPMode, fmt.Sprintf("%s/%d", ip, 8*len(address.GetPrefix())-1), nc.IfMTU); err != nil { c.log.Println("Failed to start TUN/TAP") return err } @@ -206,35 +205,35 @@ func (c *Core) Stop() { // Generates a new encryption keypair. The encryption keys are used to // encrypt traffic and to derive the IPv6 address/subnet of the node. -func (c *Core) NewEncryptionKeys() (*boxPubKey, *boxPrivKey) { - return newBoxKeys() +func (c *Core) NewEncryptionKeys() (*crypto.BoxPubKey, *crypto.BoxPrivKey) { + return crypto.NewBoxKeys() } // Generates a new signing keypair. The signing keys are used to derive the // structure of the spanning tree. -func (c *Core) NewSigningKeys() (*sigPubKey, *sigPrivKey) { - return newSigKeys() +func (c *Core) NewSigningKeys() (*crypto.SigPubKey, *crypto.SigPrivKey) { + return crypto.NewSigKeys() } // Gets the node ID. -func (c *Core) GetNodeID() *NodeID { - return getNodeID(&c.boxPub) +func (c *Core) GetNodeID() *crypto.NodeID { + return crypto.GetNodeID(&c.boxPub) } // Gets the tree ID. -func (c *Core) GetTreeID() *TreeID { - return getTreeID(&c.sigPub) +func (c *Core) GetTreeID() *crypto.TreeID { + return crypto.GetTreeID(&c.sigPub) } // Gets the IPv6 address of the Yggdrasil node. This is always a /128. func (c *Core) GetAddress() *net.IP { - address := net.IP(address_addrForNodeID(c.GetNodeID())[:]) + address := net.IP(address.AddrForNodeID(c.GetNodeID())[:]) return &address } // Gets the routed IPv6 subnet of the Yggdrasil node. This is always a /64. func (c *Core) GetSubnet() *net.IPNet { - subnet := address_subnetForNodeID(c.GetNodeID())[:] + subnet := address.SubnetForNodeID(c.GetNodeID())[:] subnet = append(subnet, 0, 0, 0, 0, 0, 0, 0, 0) return &net.IPNet{IP: subnet, Mask: net.CIDRMask(64, 128)} } diff --git a/src/yggdrasil/debug.go b/src/yggdrasil/debug.go index e5bceee0..4a32eb64 100644 --- a/src/yggdrasil/debug.go +++ b/src/yggdrasil/debug.go @@ -22,6 +22,8 @@ import "net/http" import "runtime" import "os" +import "github.com/yggdrasil-network/yggdrasil-go/src/address" +import "github.com/yggdrasil-network/yggdrasil-go/src/crypto" import "github.com/yggdrasil-network/yggdrasil-go/src/defaults" // Start the profiler in debug builds, if the required environment variable is set. @@ -48,8 +50,8 @@ func StartProfiler(log *log.Logger) error { // This function is only called by the simulator to set up a node with random // keys. It should not be used and may be removed in the future. func (c *Core) Init() { - bpub, bpriv := newBoxKeys() - spub, spriv := newSigKeys() + bpub, bpriv := crypto.NewBoxKeys() + spub, spriv := crypto.NewSigKeys() c.init(bpub, bpriv, spub, spriv) c.switchTable.start() c.router.start() @@ -59,12 +61,12 @@ func (c *Core) Init() { // Core -func (c *Core) DEBUG_getSigningPublicKey() sigPubKey { - return (sigPubKey)(c.sigPub) +func (c *Core) DEBUG_getSigningPublicKey() crypto.SigPubKey { + return (crypto.SigPubKey)(c.sigPub) } -func (c *Core) DEBUG_getEncryptionPublicKey() boxPubKey { - return (boxPubKey)(c.boxPub) +func (c *Core) DEBUG_getEncryptionPublicKey() crypto.BoxPubKey { + return (crypto.BoxPubKey)(c.boxPub) } func (c *Core) DEBUG_getSend() chan<- []byte { @@ -81,7 +83,7 @@ func (c *Core) DEBUG_getPeers() *peers { return &c.peers } -func (ps *peers) DEBUG_newPeer(box boxPubKey, sig sigPubKey, link boxSharedKey) *peer { +func (ps *peers) DEBUG_newPeer(box crypto.BoxPubKey, sig crypto.SigPubKey, link crypto.BoxSharedKey) *peer { //in <-chan []byte, //out chan<- []byte) *peer { return ps.newPeer(&box, &sig, &link, "(simulator)") //, in, out) @@ -98,7 +100,7 @@ func (ps *peers) DEBUG_startPeers() { } */ -func (ps *peers) DEBUG_hasPeer(key sigPubKey) bool { +func (ps *peers) DEBUG_hasPeer(key crypto.SigPubKey) bool { ports := ps.ports.Load().(map[switchPort]*peer) for _, p := range ports { if p == nil { @@ -120,7 +122,7 @@ func (ps *peers) DEBUG_getPorts() map[switchPort]*peer { return newPeers } -func (p *peer) DEBUG_getSigKey() sigPubKey { +func (p *peer) DEBUG_getSigKey() crypto.SigPubKey { return p.sig } @@ -292,8 +294,8 @@ func (c *Core) DEBUG_startLoopbackUDPInterface() { //////////////////////////////////////////////////////////////////////////////// -func (c *Core) DEBUG_getAddr() *address { - return address_addrForNodeID(&c.dht.nodeID) +func (c *Core) DEBUG_getAddr() *address.Address { + return address.AddrForNodeID(&c.dht.nodeID) } func (c *Core) DEBUG_startTun(ifname string, iftapmode bool) { @@ -302,7 +304,7 @@ func (c *Core) DEBUG_startTun(ifname string, iftapmode bool) { func (c *Core) DEBUG_startTunWithMTU(ifname string, iftapmode bool, mtu int) { addr := c.DEBUG_getAddr() - straddr := fmt.Sprintf("%s/%v", net.IP(addr[:]).String(), 8*len(address_prefix)) + straddr := fmt.Sprintf("%s/%v", net.IP(addr[:]).String(), 8*len(address.GetPrefix())) if ifname != "none" { err := c.router.tun.setup(ifname, iftapmode, straddr, mtu) if err != nil { @@ -320,38 +322,38 @@ func (c *Core) DEBUG_stopTun() { //////////////////////////////////////////////////////////////////////////////// -func (c *Core) DEBUG_newBoxKeys() (*boxPubKey, *boxPrivKey) { - return newBoxKeys() +func (c *Core) DEBUG_newBoxKeys() (*crypto.BoxPubKey, *crypto.BoxPrivKey) { + return crypto.NewBoxKeys() } -func (c *Core) DEBUG_getSharedKey(myPrivKey *boxPrivKey, othersPubKey *boxPubKey) *boxSharedKey { - return getSharedKey(myPrivKey, othersPubKey) +func (c *Core) DEBUG_getSharedKey(myPrivKey *crypto.BoxPrivKey, othersPubKey *crypto.BoxPubKey) *crypto.BoxSharedKey { + return crypto.GetSharedKey(myPrivKey, othersPubKey) } -func (c *Core) DEBUG_newSigKeys() (*sigPubKey, *sigPrivKey) { - return newSigKeys() +func (c *Core) DEBUG_newSigKeys() (*crypto.SigPubKey, *crypto.SigPrivKey) { + return crypto.NewSigKeys() } -func (c *Core) DEBUG_getNodeID(pub *boxPubKey) *NodeID { - return getNodeID(pub) +func (c *Core) DEBUG_getNodeID(pub *crypto.BoxPubKey) *crypto.NodeID { + return crypto.GetNodeID(pub) } -func (c *Core) DEBUG_getTreeID(pub *sigPubKey) *TreeID { - return getTreeID(pub) +func (c *Core) DEBUG_getTreeID(pub *crypto.SigPubKey) *crypto.TreeID { + return crypto.GetTreeID(pub) } -func (c *Core) DEBUG_addrForNodeID(nodeID *NodeID) string { - return net.IP(address_addrForNodeID(nodeID)[:]).String() +func (c *Core) DEBUG_addrForNodeID(nodeID *crypto.NodeID) string { + return net.IP(address.AddrForNodeID(nodeID)[:]).String() } func (c *Core) DEBUG_init(bpub []byte, bpriv []byte, spub []byte, spriv []byte) { - var boxPub boxPubKey - var boxPriv boxPrivKey - var sigPub sigPubKey - var sigPriv sigPrivKey + var boxPub crypto.BoxPubKey + var boxPriv crypto.BoxPrivKey + var sigPub crypto.SigPubKey + var sigPriv crypto.SigPrivKey copy(boxPub[:], bpub) copy(boxPriv[:], bpriv) copy(sigPub[:], spub) @@ -553,13 +555,13 @@ func (c *Core) DEBUG_simFixMTU() { func Util_testAddrIDMask() { for idx := 0; idx < 16; idx++ { - var orig NodeID + var orig crypto.NodeID orig[8] = 42 for bidx := 0; bidx < idx; bidx++ { orig[bidx/8] |= (0x80 >> uint8(bidx%8)) } - addr := address_addrForNodeID(&orig) - nid, mask := addr.getNodeIDandMask() + addr := address.AddrForNodeID(&orig) + nid, mask := addr.GetNodeIDandMask() for b := 0; b < len(mask); b++ { nid[b] &= mask[b] orig[b] &= mask[b] diff --git a/src/yggdrasil/dht.go b/src/yggdrasil/dht.go index aa694f7a..af104f51 100644 --- a/src/yggdrasil/dht.go +++ b/src/yggdrasil/dht.go @@ -8,6 +8,8 @@ package yggdrasil import ( "sort" "time" + + "github.com/yggdrasil-network/yggdrasil-go/src/crypto" ) const dht_lookup_size = 16 @@ -15,8 +17,8 @@ const dht_lookup_size = 16 // dhtInfo represents everything we know about a node in the DHT. // This includes its key, a cache of it's NodeID, coords, and timing/ping related info for deciding who/when to ping nodes for maintenance. type dhtInfo struct { - nodeID_hidden *NodeID - key boxPubKey + nodeID_hidden *crypto.NodeID + key crypto.BoxPubKey coords []byte recv time.Time // When we last received a message pings int // Time out if at least 3 consecutive maintenance pings drop @@ -24,9 +26,9 @@ type dhtInfo struct { } // Returns the *NodeID associated with dhtInfo.key, calculating it on the fly the first time or from a cache all subsequent times. -func (info *dhtInfo) getNodeID() *NodeID { +func (info *dhtInfo) getNodeID() *crypto.NodeID { if info.nodeID_hidden == nil { - info.nodeID_hidden = getNodeID(&info.key) + info.nodeID_hidden = crypto.GetNodeID(&info.key) } return info.nodeID_hidden } @@ -34,36 +36,36 @@ func (info *dhtInfo) getNodeID() *NodeID { // Request for a node to do a lookup. // Includes our key and coords so they can send a response back, and the destination NodeID we want to ask about. type dhtReq struct { - Key boxPubKey // Key of whoever asked - Coords []byte // Coords of whoever asked - Dest NodeID // NodeID they're asking about + Key crypto.BoxPubKey // Key of whoever asked + Coords []byte // Coords of whoever asked + Dest crypto.NodeID // NodeID they're asking about } // Response to a DHT lookup. // Includes the key and coords of the node that's responding, and the destination they were asked about. // The main part is Infos []*dhtInfo, the lookup response. type dhtRes struct { - Key boxPubKey // key of the sender - Coords []byte // coords of the sender - Dest NodeID + Key crypto.BoxPubKey // key of the sender + Coords []byte // coords of the sender + Dest crypto.NodeID Infos []*dhtInfo // response } // Parts of a DHT req usable as a key in a map. type dhtReqKey struct { - key boxPubKey - dest NodeID + key crypto.BoxPubKey + dest crypto.NodeID } // The main DHT struct. type dht struct { core *Core - nodeID NodeID + nodeID crypto.NodeID peers chan *dhtInfo // other goroutines put incoming dht updates here reqs map[dhtReqKey]time.Time // Keeps track of recent outstanding requests callbacks map[dhtReqKey]dht_callbackInfo // Search and admin lookup callbacks // These next two could be replaced by a single linked list or similar... - table map[NodeID]*dhtInfo + table map[crypto.NodeID]*dhtInfo imp []*dhtInfo } @@ -80,12 +82,12 @@ func (t *dht) init(c *Core) { // This empties all info from the DHT and drops outstanding requests. func (t *dht) reset() { t.reqs = make(map[dhtReqKey]time.Time) - t.table = make(map[NodeID]*dhtInfo) + t.table = make(map[crypto.NodeID]*dhtInfo) t.imp = nil } // Does a DHT lookup and returns up to dht_lookup_size results. -func (t *dht) lookup(nodeID *NodeID, everything bool) []*dhtInfo { +func (t *dht) lookup(nodeID *crypto.NodeID, everything bool) []*dhtInfo { results := make([]*dhtInfo, 0, len(t.table)) for _, info := range t.table { results = append(results, info) @@ -133,9 +135,9 @@ func (t *dht) insert(info *dhtInfo) { } // Return true if first/second/third are (partially) ordered correctly. -func dht_ordered(first, second, third *NodeID) bool { - lessOrEqual := func(first, second *NodeID) bool { - for idx := 0; idx < NodeIDLen; idx++ { +func dht_ordered(first, second, third *crypto.NodeID) bool { + lessOrEqual := func(first, second *crypto.NodeID) bool { + for idx := 0; idx < crypto.NodeIDLen; idx++ { if first[idx] > second[idx] { return false } @@ -190,7 +192,7 @@ func (t *dht) sendRes(res *dhtRes, req *dhtReq) { // Send a reply for a dhtReq bs := res.encode() shared := t.core.sessions.getSharedKey(&t.core.boxPriv, &req.Key) - payload, nonce := boxSeal(shared, bs, nil) + payload, nonce := crypto.BoxSeal(shared, bs, nil) p := wire_protoTrafficPacket{ Coords: req.Coords, ToKey: req.Key, @@ -252,7 +254,7 @@ func (t *dht) sendReq(req *dhtReq, dest *dhtInfo) { // Send a dhtReq to the node in dhtInfo bs := req.encode() shared := t.core.sessions.getSharedKey(&t.core.boxPriv, &dest.key) - payload, nonce := boxSeal(shared, bs, nil) + payload, nonce := crypto.BoxSeal(shared, bs, nil) p := wire_protoTrafficPacket{ Coords: dest.coords, ToKey: dest.key, @@ -267,7 +269,7 @@ func (t *dht) sendReq(req *dhtReq, dest *dhtInfo) { } // Sends a lookup to this info, looking for the target. -func (t *dht) ping(info *dhtInfo, target *NodeID) { +func (t *dht) ping(info *dhtInfo, target *crypto.NodeID) { // Creates a req for the node at dhtInfo, asking them about the target (if one is given) or themself (if no target is given) if target == nil { target = &t.nodeID diff --git a/src/yggdrasil/icmpv6.go b/src/yggdrasil/icmpv6.go index 6e9a265b..baae3ab4 100644 --- a/src/yggdrasil/icmpv6.go +++ b/src/yggdrasil/icmpv6.go @@ -17,6 +17,8 @@ import ( "golang.org/x/net/icmp" "golang.org/x/net/ipv6" + + "github.com/yggdrasil-network/yggdrasil-go/src/address" ) type macAddress [6]byte @@ -27,7 +29,7 @@ type icmpv6 struct { tun *tunAdapter mylladdr net.IP mymac macAddress - peermacs map[address]neighbor + peermacs map[address.Address]neighbor } type neighbor struct { @@ -59,7 +61,7 @@ func ipv6Header_Marshal(h *ipv6.Header) ([]byte, error) { // addresses. func (i *icmpv6) init(t *tunAdapter) { i.tun = t - i.peermacs = make(map[address]neighbor) + i.peermacs = make(map[address.Address]neighbor) // Our MAC address and link-local address i.mymac = macAddress{ @@ -172,7 +174,7 @@ func (i *icmpv6) parse_packet_tun(datain []byte, datamac *[]byte) ([]byte, error } case ipv6.ICMPTypeNeighborAdvertisement: if datamac != nil { - var addr address + var addr address.Address var mac macAddress copy(addr[:], ipv6Header.Src[:]) copy(mac[:], (*datamac)[:]) @@ -254,7 +256,7 @@ func (i *icmpv6) create_icmpv6_tun(dst net.IP, src net.IP, mtype ipv6.ICMPType, return responsePacket, nil } -func (i *icmpv6) create_ndp_tap(dst address) ([]byte, error) { +func (i *icmpv6) create_ndp_tap(dst address.Address) ([]byte, error) { // Create the ND payload var payload [28]byte copy(payload[:4], []byte{0x00, 0x00, 0x00, 0x00}) @@ -263,7 +265,7 @@ func (i *icmpv6) create_ndp_tap(dst address) ([]byte, error) { copy(payload[22:28], i.mymac[:6]) // Create the ICMPv6 solicited-node address - var dstaddr address + var dstaddr address.Address copy(dstaddr[:13], []byte{ 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -296,13 +298,13 @@ func (i *icmpv6) create_ndp_tap(dst address) ([]byte, error) { // to the Yggdrasil TAP adapter. func (i *icmpv6) handle_ndp(in []byte) ([]byte, error) { // Ignore NDP requests for anything outside of fd00::/8 - var source address + var source address.Address copy(source[:], in[8:]) - var snet subnet + var snet address.Subnet copy(snet[:], in[8:]) switch { - case source.isValid(): - case snet.isValid(): + case source.IsValid(): + case snet.IsValid(): default: return nil, errors.New("Not an NDP for 0200::/7") } diff --git a/src/yggdrasil/peer.go b/src/yggdrasil/peer.go index 67aa805a..2fb505d5 100644 --- a/src/yggdrasil/peer.go +++ b/src/yggdrasil/peer.go @@ -8,6 +8,9 @@ import ( "sync" "sync/atomic" "time" + + "github.com/yggdrasil-network/yggdrasil-go/src/crypto" + "github.com/yggdrasil-network/yggdrasil-go/src/util" ) // The peers struct represents peers with an active connection. @@ -19,7 +22,7 @@ type peers struct { mutex sync.Mutex // Synchronize writes to atomic ports atomic.Value //map[switchPort]*peer, use CoW semantics authMutex sync.RWMutex - allowedEncryptionPublicKeys map[boxPubKey]struct{} + allowedEncryptionPublicKeys map[crypto.BoxPubKey]struct{} } // Initializes the peers struct. @@ -28,11 +31,11 @@ func (ps *peers) init(c *Core) { defer ps.mutex.Unlock() ps.putPorts(make(map[switchPort]*peer)) ps.core = c - ps.allowedEncryptionPublicKeys = make(map[boxPubKey]struct{}) + ps.allowedEncryptionPublicKeys = make(map[crypto.BoxPubKey]struct{}) } // Returns true if an incoming peer connection to a key is allowed, either because the key is in the whitelist or because the whitelist is empty. -func (ps *peers) isAllowedEncryptionPublicKey(box *boxPubKey) bool { +func (ps *peers) isAllowedEncryptionPublicKey(box *crypto.BoxPubKey) bool { ps.authMutex.RLock() defer ps.authMutex.RUnlock() _, isIn := ps.allowedEncryptionPublicKeys[*box] @@ -40,24 +43,24 @@ func (ps *peers) isAllowedEncryptionPublicKey(box *boxPubKey) bool { } // Adds a key to the whitelist. -func (ps *peers) addAllowedEncryptionPublicKey(box *boxPubKey) { +func (ps *peers) addAllowedEncryptionPublicKey(box *crypto.BoxPubKey) { ps.authMutex.Lock() defer ps.authMutex.Unlock() ps.allowedEncryptionPublicKeys[*box] = struct{}{} } // Removes a key from the whitelist. -func (ps *peers) removeAllowedEncryptionPublicKey(box *boxPubKey) { +func (ps *peers) removeAllowedEncryptionPublicKey(box *crypto.BoxPubKey) { ps.authMutex.Lock() defer ps.authMutex.Unlock() delete(ps.allowedEncryptionPublicKeys, *box) } // Gets the whitelist of allowed keys for incoming connections. -func (ps *peers) getAllowedEncryptionPublicKeys() []boxPubKey { +func (ps *peers) getAllowedEncryptionPublicKeys() []crypto.BoxPubKey { ps.authMutex.RLock() defer ps.authMutex.RUnlock() - keys := make([]boxPubKey, 0, len(ps.allowedEncryptionPublicKeys)) + keys := make([]crypto.BoxPubKey, 0, len(ps.allowedEncryptionPublicKeys)) for key := range ps.allowedEncryptionPublicKeys { keys = append(keys, key) } @@ -81,10 +84,10 @@ type peer struct { // BUG: sync/atomic, 32 bit platforms need the above to be the first element core *Core port switchPort - box boxPubKey - sig sigPubKey - shared boxSharedKey - linkShared boxSharedKey + box crypto.BoxPubKey + sig crypto.SigPubKey + shared crypto.BoxSharedKey + linkShared crypto.BoxSharedKey endpoint string friendlyName string firstSeen time.Time // To track uptime for getPeers @@ -96,11 +99,11 @@ type peer struct { } // Creates a new peer with the specified box, sig, and linkShared keys, using the lowest unocupied port number. -func (ps *peers) newPeer(box *boxPubKey, sig *sigPubKey, linkShared *boxSharedKey, endpoint string) *peer { +func (ps *peers) newPeer(box *crypto.BoxPubKey, sig *crypto.SigPubKey, linkShared *crypto.BoxSharedKey, endpoint string) *peer { now := time.Now() p := peer{box: *box, sig: *sig, - shared: *getSharedKey(&ps.core.boxPriv, box), + shared: *crypto.GetSharedKey(&ps.core.boxPriv, box), linkShared: *linkShared, endpoint: endpoint, firstSeen: now, @@ -212,7 +215,7 @@ func (p *peer) handlePacket(packet []byte) { case wire_LinkProtocolTraffic: p.handleLinkTraffic(packet) default: - util_putBytes(packet) + util.PutBytes(packet) } } @@ -236,13 +239,13 @@ func (p *peer) sendPacket(packet []byte) { // This wraps the packet in the inner (ephemeral) and outer (permanent) crypto layers. // It sends it to p.linkOut, which bypasses the usual packet queues. func (p *peer) sendLinkPacket(packet []byte) { - innerPayload, innerNonce := boxSeal(&p.linkShared, packet, nil) + innerPayload, innerNonce := crypto.BoxSeal(&p.linkShared, packet, nil) innerLinkPacket := wire_linkProtoTrafficPacket{ Nonce: *innerNonce, Payload: innerPayload, } outerPayload := innerLinkPacket.encode() - bs, nonce := boxSeal(&p.shared, outerPayload, nil) + bs, nonce := crypto.BoxSeal(&p.shared, outerPayload, nil) linkPacket := wire_linkProtoTrafficPacket{ Nonce: *nonce, Payload: bs, @@ -258,7 +261,7 @@ func (p *peer) handleLinkTraffic(bs []byte) { if !packet.decode(bs) { return } - outerPayload, isOK := boxOpen(&p.shared, packet.Payload, &packet.Nonce) + outerPayload, isOK := crypto.BoxOpen(&p.shared, packet.Payload, &packet.Nonce) if !isOK { return } @@ -266,7 +269,7 @@ func (p *peer) handleLinkTraffic(bs []byte) { if !innerPacket.decode(outerPayload) { return } - payload, isOK := boxOpen(&p.linkShared, innerPacket.Payload, &innerPacket.Nonce) + payload, isOK := crypto.BoxOpen(&p.linkShared, innerPacket.Payload, &innerPacket.Nonce) if !isOK { return } @@ -278,7 +281,7 @@ func (p *peer) handleLinkTraffic(bs []byte) { case wire_SwitchMsg: p.handleSwitchMsg(payload) default: - util_putBytes(bs) + util.PutBytes(bs) } } @@ -292,7 +295,7 @@ func (p *peer) sendSwitchMsg() { msg.Hops = append(msg.Hops, switchMsgHop{ Port: p.port, Next: p.sig, - Sig: *sign(&p.core.sigPriv, bs), + Sig: *crypto.Sign(&p.core.sigPriv, bs), }) packet := msg.encode() p.sendLinkPacket(packet) @@ -316,7 +319,7 @@ func (p *peer) handleSwitchMsg(packet []byte) { sigMsg.Hops = msg.Hops[:idx] loc.coords = append(loc.coords, hop.Port) bs := getBytesForSig(&hop.Next, &sigMsg) - if !verify(&prevKey, bs, &hop.Sig) { + if !crypto.Verify(&prevKey, bs, &hop.Sig) { p.core.peers.removePeer(p.port) } prevKey = hop.Next @@ -341,7 +344,7 @@ func (p *peer) handleSwitchMsg(packet []byte) { // This generates the bytes that we sign or check the signature of for a switchMsg. // It begins with the next node's key, followed by the root and the timetsamp, followed by coords being advertised to the next node. -func getBytesForSig(next *sigPubKey, msg *switchMsg) []byte { +func getBytesForSig(next *crypto.SigPubKey, msg *switchMsg) []byte { var loc switchLocator for _, hop := range msg.Hops { loc.coords = append(loc.coords, hop.Port) diff --git a/src/yggdrasil/router.go b/src/yggdrasil/router.go index 62480bc4..91972b3f 100644 --- a/src/yggdrasil/router.go +++ b/src/yggdrasil/router.go @@ -28,14 +28,18 @@ import ( "golang.org/x/net/icmp" "golang.org/x/net/ipv6" + + "github.com/yggdrasil-network/yggdrasil-go/src/address" + "github.com/yggdrasil-network/yggdrasil-go/src/crypto" + "github.com/yggdrasil-network/yggdrasil-go/src/util" ) // The router struct has channels to/from the tun/tap device and a self peer (0), which is how messages are passed between this node and the peers/switch layer. // The router's mainLoop goroutine is responsible for managing all information related to the dht, searches, and crypto sessions. type router struct { core *Core - addr address - subnet subnet + addr address.Address + subnet address.Subnet in <-chan []byte // packets we received from the network, link to peer's "out" out func([]byte) // packets we're sending to the network, link to peer's "in" toRecv chan router_recvPacket // packets to handle via recvPacket() @@ -57,17 +61,17 @@ type router_recvPacket struct { // Initializes the router struct, which includes setting up channels to/from the tun/tap. func (r *router) init(core *Core) { r.core = core - r.addr = *address_addrForNodeID(&r.core.dht.nodeID) - r.subnet = *address_subnetForNodeID(&r.core.dht.nodeID) + r.addr = *address.AddrForNodeID(&r.core.dht.nodeID) + r.subnet = *address.SubnetForNodeID(&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, &boxSharedKey{}, "(self)") + p := r.core.peers.newPeer(&r.core.boxPub, &r.core.sigPub, &crypto.BoxSharedKey{}, "(self)") p.out = func(packet []byte) { // This is to make very sure it never blocks select { case in <- packet: return default: - util_putBytes(packet) + util.PutBytes(packet) } } r.in = in @@ -121,7 +125,7 @@ func (r *router) mainLoop() { r.core.switchTable.doMaintenance() r.core.dht.doMaintenance() r.core.sessions.cleanup() - util_getBytes() // To slowly drain things + util.GetBytes() // To slowly drain things } case f := <-r.admin: f() @@ -135,11 +139,11 @@ func (r *router) mainLoop() { // If the session hasn't responded recently, it triggers a ping or search to keep things alive or deal with broken coords *relatively* quickly. // It also deals with oversized packets if there are MTU issues by calling into icmpv6.go to spoof PacketTooBig traffic, or DestinationUnreachable if the other side has their tun/tap disabled. func (r *router) sendPacket(bs []byte) { - var sourceAddr address - var destAddr address - var destSnet subnet - var destPubKey *boxPubKey - var destNodeID *NodeID + var sourceAddr address.Address + var destAddr address.Address + var destSnet address.Subnet + var destPubKey *crypto.BoxPubKey + var destNodeID *crypto.NodeID var addrlen int if bs[0]&0xf0 == 0x60 { // Check if we have a fully-sized header @@ -169,19 +173,19 @@ func (r *router) sendPacket(bs []byte) { // configured crypto-key routing source subnets return } - if !destAddr.isValid() && !destSnet.isValid() { + if !destAddr.IsValid() && !destSnet.IsValid() { // The addresses didn't match valid Yggdrasil node addresses so let's see // whether it matches a crypto-key routing range instead if key, err := r.cryptokey.getPublicKeyForAddress(destAddr, addrlen); err == nil { // A public key was found, get the node ID for the search destPubKey = &key - destNodeID = getNodeID(destPubKey) + destNodeID = crypto.GetNodeID(destPubKey) // Do a quick check to ensure that the node ID refers to a vaild Yggdrasil // address or subnet - this might be superfluous - addr := *address_addrForNodeID(destNodeID) + addr := *address.AddrForNodeID(destNodeID) copy(destAddr[:], addr[:]) copy(destSnet[:], addr[:]) - if !destAddr.isValid() && !destSnet.isValid() { + if !destAddr.IsValid() && !destSnet.IsValid() { return } } else { @@ -190,25 +194,25 @@ func (r *router) sendPacket(bs []byte) { } } doSearch := func(packet []byte) { - var nodeID, mask *NodeID + var nodeID, mask *crypto.NodeID switch { case destNodeID != nil: // We already know the full node ID, probably because it's from a CKR // route in which the public key is known ahead of time nodeID = destNodeID - var m NodeID + var m crypto.NodeID for i := range m { m[i] = 0xFF } mask = &m - case destAddr.isValid(): + case destAddr.IsValid(): // We don't know the full node ID - try and use the address to generate // a truncated node ID - nodeID, mask = destAddr.getNodeIDandMask() - case destSnet.isValid(): + nodeID, mask = destAddr.GetNodeIDandMask() + case destSnet.IsValid(): // We don't know the full node ID - try and use the subnet to generate // a truncated node ID - nodeID, mask = destSnet.getNodeIDandMask() + nodeID, mask = destSnet.GetNodeIDandMask() default: return } @@ -223,10 +227,10 @@ func (r *router) sendPacket(bs []byte) { } var sinfo *sessionInfo var isIn bool - if destAddr.isValid() { + if destAddr.IsValid() { sinfo, isIn = r.core.sessions.getByTheirAddr(&destAddr) } - if destSnet.isValid() { + if destSnet.IsValid() { sinfo, isIn = r.core.sessions.getByTheirSubnet(&destSnet) } switch { @@ -305,12 +309,12 @@ func (r *router) sendPacket(bs []byte) { func (r *router) recvPacket(bs []byte, sinfo *sessionInfo) { // Note: called directly by the session worker, not the router goroutine if len(bs) < 24 { - util_putBytes(bs) + util.PutBytes(bs) return } - var sourceAddr address - var dest address - var snet subnet + var sourceAddr address.Address + var dest address.Address + var snet address.Subnet var addrlen int if bs[0]&0xf0 == 0x60 { // IPv6 address @@ -330,17 +334,17 @@ func (r *router) recvPacket(bs []byte, sinfo *sessionInfo) { // Check that the packet is destined for either our Yggdrasil address or // subnet, or that it matches one of the crypto-key routing source routes if !r.cryptokey.isValidSource(dest, addrlen) { - util_putBytes(bs) + util.PutBytes(bs) return } // See whether the packet they sent should have originated from this session switch { - case sourceAddr.isValid() && sourceAddr == sinfo.theirAddr: - case snet.isValid() && snet == sinfo.theirSubnet: + case sourceAddr.IsValid() && sourceAddr == sinfo.theirAddr: + case snet.IsValid() && snet == sinfo.theirSubnet: default: key, err := r.cryptokey.getPublicKeyForAddress(sourceAddr, addrlen) if err != nil || key != sinfo.theirPermPub { - util_putBytes(bs) + util.PutBytes(bs) return } } @@ -366,7 +370,7 @@ func (r *router) handleIn(packet []byte) { // Handles incoming traffic, i.e. encapuslated ordinary IPv6 packets. // Passes them to the crypto session worker to be decrypted and sent to the tun/tap. func (r *router) handleTraffic(packet []byte) { - defer util_putBytes(packet) + defer util.PutBytes(packet) p := wire_trafficPacket{} if !p.decode(packet) { return @@ -386,14 +390,14 @@ func (r *router) handleProto(packet []byte) { return } // Now try to open the payload - var sharedKey *boxSharedKey + var sharedKey *crypto.BoxSharedKey if p.ToKey == r.core.boxPub { // Try to open using our permanent key sharedKey = r.core.sessions.getSharedKey(&r.core.boxPriv, &p.FromKey) } else { return } - bs, isOK := boxOpen(sharedKey, p.Payload, &p.Nonce) + bs, isOK := crypto.BoxOpen(sharedKey, p.Payload, &p.Nonce) if !isOK { return } @@ -414,12 +418,12 @@ func (r *router) handleProto(packet []byte) { case wire_DHTLookupResponse: r.handleDHTRes(bs, &p.FromKey) default: - util_putBytes(packet) + util.PutBytes(packet) } } // 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 *boxPubKey) { +func (r *router) handlePing(bs []byte, fromKey *crypto.BoxPubKey) { ping := sessionPing{} if !ping.decode(bs) { return @@ -429,12 +433,12 @@ func (r *router) handlePing(bs []byte, fromKey *boxPubKey) { } // Handles session pongs (which are really pings with an extra flag to prevent acknowledgement). -func (r *router) handlePong(bs []byte, fromKey *boxPubKey) { +func (r *router) handlePong(bs []byte, fromKey *crypto.BoxPubKey) { r.handlePing(bs, fromKey) } // Decodes dht requests and passes them to dht.handleReq to trigger a lookup/response. -func (r *router) handleDHTReq(bs []byte, fromKey *boxPubKey) { +func (r *router) handleDHTReq(bs []byte, fromKey *crypto.BoxPubKey) { req := dhtReq{} if !req.decode(bs) { return @@ -444,7 +448,7 @@ func (r *router) handleDHTReq(bs []byte, fromKey *boxPubKey) { } // Decodes dht responses and passes them to dht.handleRes to update the DHT table and further pass them to the search code (if applicable). -func (r *router) handleDHTRes(bs []byte, fromKey *boxPubKey) { +func (r *router) handleDHTRes(bs []byte, fromKey *crypto.BoxPubKey) { res := dhtRes{} if !res.decode(bs) { return diff --git a/src/yggdrasil/search.go b/src/yggdrasil/search.go index be156dc6..c85b719c 100644 --- a/src/yggdrasil/search.go +++ b/src/yggdrasil/search.go @@ -17,6 +17,8 @@ package yggdrasil import ( "sort" "time" + + "github.com/yggdrasil-network/yggdrasil-go/src/crypto" ) // This defines the maximum number of dhtInfo that we keep track of for nodes to query in an ongoing search. @@ -30,28 +32,28 @@ const search_RETRY_TIME = time.Second // Information about an ongoing search. // Includes the targed NodeID, the bitmask to match it to an IP, and the list of nodes to visit / already visited. type searchInfo struct { - dest NodeID - mask NodeID + dest crypto.NodeID + mask crypto.NodeID time time.Time packet []byte toVisit []*dhtInfo - visited map[NodeID]bool + visited map[crypto.NodeID]bool } // This stores a map of active searches. type searches struct { core *Core - searches map[NodeID]*searchInfo + searches map[crypto.NodeID]*searchInfo } // Intializes the searches struct. func (s *searches) init(core *Core) { s.core = core - s.searches = make(map[NodeID]*searchInfo) + s.searches = make(map[crypto.NodeID]*searchInfo) } // Creates a new search info, adds it to the searches struct, and returns a pointer to the info. -func (s *searches) createSearch(dest *NodeID, mask *NodeID) *searchInfo { +func (s *searches) createSearch(dest *crypto.NodeID, mask *crypto.NodeID) *searchInfo { now := time.Now() for dest, sinfo := range s.searches { if now.Sub(sinfo.time) > time.Minute { @@ -102,7 +104,7 @@ func (s *searches) addToSearch(sinfo *searchInfo, res *dhtRes) { } } // Deduplicate - vMap := make(map[NodeID]*dhtInfo) + vMap := make(map[crypto.NodeID]*dhtInfo) for _, info := range sinfo.toVisit { vMap[*info.getNodeID()] = info } @@ -163,10 +165,10 @@ func (s *searches) continueSearch(sinfo *searchInfo) { } // Calls create search, and initializes the iterative search parts of the struct before returning it. -func (s *searches) newIterSearch(dest *NodeID, mask *NodeID) *searchInfo { +func (s *searches) newIterSearch(dest *crypto.NodeID, mask *crypto.NodeID) *searchInfo { sinfo := s.createSearch(dest, mask) sinfo.toVisit = s.core.dht.lookup(dest, true) - sinfo.visited = make(map[NodeID]bool) + sinfo.visited = make(map[crypto.NodeID]bool) return sinfo } @@ -174,10 +176,10 @@ func (s *searches) newIterSearch(dest *NodeID, mask *NodeID) *searchInfo { // If the response is from the target, get/create a session, trigger a session ping, and return true. // Otherwise return false. func (s *searches) checkDHTRes(info *searchInfo, res *dhtRes) bool { - them := getNodeID(&res.Key) - var destMasked NodeID - var themMasked NodeID - for idx := 0; idx < NodeIDLen; idx++ { + them := crypto.GetNodeID(&res.Key) + var destMasked crypto.NodeID + var themMasked crypto.NodeID + for idx := 0; idx < crypto.NodeIDLen; idx++ { destMasked[idx] = info.dest[idx] & info.mask[idx] themMasked[idx] = them[idx] & info.mask[idx] } diff --git a/src/yggdrasil/session.go b/src/yggdrasil/session.go index 4f2bedf9..4f395b07 100644 --- a/src/yggdrasil/session.go +++ b/src/yggdrasil/session.go @@ -8,23 +8,27 @@ import ( "bytes" "encoding/hex" "time" + + "github.com/yggdrasil-network/yggdrasil-go/src/address" + "github.com/yggdrasil-network/yggdrasil-go/src/crypto" + "github.com/yggdrasil-network/yggdrasil-go/src/util" ) // All the information we know about an active session. // This includes coords, permanent and ephemeral keys, handles and nonces, various sorts of timing information for timeout and maintenance, and some metadata for the admin API. type sessionInfo struct { core *Core - theirAddr address - theirSubnet subnet - theirPermPub boxPubKey - theirSesPub boxPubKey - mySesPub boxPubKey - mySesPriv boxPrivKey - sharedSesKey boxSharedKey // derived from session keys - theirHandle handle - myHandle handle - theirNonce boxNonce - myNonce boxNonce + theirAddr address.Address + theirSubnet address.Subnet + theirPermPub crypto.BoxPubKey + theirSesPub crypto.BoxPubKey + mySesPub crypto.BoxPubKey + mySesPriv crypto.BoxPrivKey + sharedSesKey crypto.BoxSharedKey // derived from session keys + theirHandle crypto.Handle + myHandle crypto.Handle + theirNonce crypto.BoxNonce + myNonce crypto.BoxNonce theirMTU uint16 myMTU uint16 wasMTUFixed bool // Was the MTU fixed by a receive error? @@ -45,9 +49,9 @@ type sessionInfo struct { // Represents a session ping/pong packet, andincludes information like public keys, a session handle, coords, a timestamp to prevent replays, and the tun/tap MTU. type sessionPing struct { - SendPermPub boxPubKey // Sender's permanent key - Handle handle // Random number to ID session - SendSesPub boxPubKey // Session key to use + SendPermPub crypto.BoxPubKey // Sender's permanent key + Handle crypto.Handle // Random number to ID session + SendSesPub crypto.BoxPubKey // Session key to use Coords []byte Tstamp int64 // unix time, but the only real requirement is that it increases IsPong bool @@ -69,8 +73,8 @@ func (s *sessionInfo) update(p *sessionPing) bool { if p.SendSesPub != s.theirSesPub { s.theirSesPub = p.SendSesPub s.theirHandle = p.Handle - s.sharedSesKey = *getSharedKey(&s.mySesPriv, &s.theirSesPub) - s.theirNonce = boxNonce{} + s.sharedSesKey = *crypto.GetSharedKey(&s.mySesPriv, &s.theirSesPub) + s.theirNonce = crypto.BoxNonce{} s.nonceMask = 0 } if p.MTU >= 1280 || p.MTU == 0 { @@ -99,15 +103,15 @@ type sessions struct { core *Core lastCleanup time.Time // Maps known permanent keys to their shared key, used by DHT a lot - permShared map[boxPubKey]*boxSharedKey + permShared map[crypto.BoxPubKey]*crypto.BoxSharedKey // Maps (secret) handle onto session info - sinfos map[handle]*sessionInfo + sinfos map[crypto.Handle]*sessionInfo // Maps mySesPub onto handle - byMySes map[boxPubKey]*handle + byMySes map[crypto.BoxPubKey]*crypto.Handle // Maps theirPermPub onto handle - byTheirPerm map[boxPubKey]*handle - addrToPerm map[address]*boxPubKey - subnetToPerm map[subnet]*boxPubKey + byTheirPerm map[crypto.BoxPubKey]*crypto.Handle + addrToPerm map[address.Address]*crypto.BoxPubKey + subnetToPerm map[address.Subnet]*crypto.BoxPubKey // Options from the session firewall sessionFirewallEnabled bool sessionFirewallAllowsDirect bool @@ -120,12 +124,12 @@ type sessions struct { // Initializes the session struct. func (ss *sessions) init(core *Core) { ss.core = core - ss.permShared = make(map[boxPubKey]*boxSharedKey) - ss.sinfos = make(map[handle]*sessionInfo) - ss.byMySes = make(map[boxPubKey]*handle) - ss.byTheirPerm = make(map[boxPubKey]*handle) - ss.addrToPerm = make(map[address]*boxPubKey) - ss.subnetToPerm = make(map[subnet]*boxPubKey) + ss.permShared = make(map[crypto.BoxPubKey]*crypto.BoxSharedKey) + ss.sinfos = make(map[crypto.Handle]*sessionInfo) + ss.byMySes = make(map[crypto.BoxPubKey]*crypto.Handle) + ss.byTheirPerm = make(map[crypto.BoxPubKey]*crypto.Handle) + ss.addrToPerm = make(map[address.Address]*crypto.BoxPubKey) + ss.subnetToPerm = make(map[address.Subnet]*crypto.BoxPubKey) ss.lastCleanup = time.Now() } @@ -154,18 +158,18 @@ func (ss *sessions) setSessionFirewallBlacklist(blacklist []string) { // Determines whether the session with a given publickey is allowed based on // session firewall rules. -func (ss *sessions) isSessionAllowed(pubkey *boxPubKey, initiator bool) bool { +func (ss *sessions) isSessionAllowed(pubkey *crypto.BoxPubKey, initiator bool) bool { // Allow by default if the session firewall is disabled if !ss.sessionFirewallEnabled { return true } // Prepare for checking whitelist/blacklist - var box boxPubKey + var box crypto.BoxPubKey // Reject blacklisted nodes for _, b := range ss.sessionFirewallBlacklist { key, err := hex.DecodeString(b) if err == nil { - copy(box[:boxPubKeyLen], key) + copy(box[:crypto.BoxPubKeyLen], key) if box == *pubkey { return false } @@ -175,7 +179,7 @@ func (ss *sessions) isSessionAllowed(pubkey *boxPubKey, initiator bool) bool { for _, b := range ss.sessionFirewallWhitelist { key, err := hex.DecodeString(b) if err == nil { - copy(box[:boxPubKeyLen], key) + copy(box[:crypto.BoxPubKeyLen], key) if box == *pubkey { return true } @@ -208,7 +212,7 @@ func (ss *sessions) isSessionAllowed(pubkey *boxPubKey, initiator bool) bool { } // Gets the session corresponding to a given handle. -func (ss *sessions) getSessionForHandle(handle *handle) (*sessionInfo, bool) { +func (ss *sessions) getSessionForHandle(handle *crypto.Handle) (*sessionInfo, bool) { sinfo, isIn := ss.sinfos[*handle] if isIn && sinfo.timedout() { // We have a session, but it has timed out @@ -218,7 +222,7 @@ func (ss *sessions) getSessionForHandle(handle *handle) (*sessionInfo, bool) { } // Gets a session corresponding to an ephemeral session key used by this node. -func (ss *sessions) getByMySes(key *boxPubKey) (*sessionInfo, bool) { +func (ss *sessions) getByMySes(key *crypto.BoxPubKey) (*sessionInfo, bool) { h, isIn := ss.byMySes[*key] if !isIn { return nil, false @@ -228,7 +232,7 @@ func (ss *sessions) getByMySes(key *boxPubKey) (*sessionInfo, bool) { } // Gets a session corresponding to a permanent key used by the remote node. -func (ss *sessions) getByTheirPerm(key *boxPubKey) (*sessionInfo, bool) { +func (ss *sessions) getByTheirPerm(key *crypto.BoxPubKey) (*sessionInfo, bool) { h, isIn := ss.byTheirPerm[*key] if !isIn { return nil, false @@ -238,7 +242,7 @@ func (ss *sessions) getByTheirPerm(key *boxPubKey) (*sessionInfo, bool) { } // Gets a session corresponding to an IPv6 address used by the remote node. -func (ss *sessions) getByTheirAddr(addr *address) (*sessionInfo, bool) { +func (ss *sessions) getByTheirAddr(addr *address.Address) (*sessionInfo, bool) { p, isIn := ss.addrToPerm[*addr] if !isIn { return nil, false @@ -248,7 +252,7 @@ func (ss *sessions) getByTheirAddr(addr *address) (*sessionInfo, bool) { } // Gets a session corresponding to an IPv6 /64 subnet used by the remote node/network. -func (ss *sessions) getByTheirSubnet(snet *subnet) (*sessionInfo, bool) { +func (ss *sessions) getByTheirSubnet(snet *address.Subnet) (*sessionInfo, bool) { p, isIn := ss.subnetToPerm[*snet] if !isIn { return nil, false @@ -259,7 +263,7 @@ func (ss *sessions) getByTheirSubnet(snet *subnet) (*sessionInfo, bool) { // Creates a new session and lazily cleans up old/timedout existing sessions. // This includse initializing session info to sane defaults (e.g. lowest supported MTU). -func (ss *sessions) createSession(theirPermKey *boxPubKey) *sessionInfo { +func (ss *sessions) createSession(theirPermKey *crypto.BoxPubKey) *sessionInfo { if ss.sessionFirewallEnabled { if !ss.isSessionAllowed(theirPermKey, true) { return nil @@ -268,10 +272,10 @@ func (ss *sessions) createSession(theirPermKey *boxPubKey) *sessionInfo { sinfo := sessionInfo{} sinfo.core = ss.core sinfo.theirPermPub = *theirPermKey - pub, priv := newBoxKeys() + pub, priv := crypto.NewBoxKeys() sinfo.mySesPub = *pub sinfo.mySesPriv = *priv - sinfo.myNonce = *newBoxNonce() + sinfo.myNonce = *crypto.NewBoxNonce() sinfo.theirMTU = 1280 sinfo.myMTU = uint16(ss.core.router.tun.mtu) now := time.Now() @@ -295,9 +299,9 @@ func (ss *sessions) createSession(theirPermKey *boxPubKey) *sessionInfo { // lower => even nonce sinfo.myNonce[len(sinfo.myNonce)-1] &= 0xfe } - sinfo.myHandle = *newHandle() - sinfo.theirAddr = *address_addrForNodeID(getNodeID(&sinfo.theirPermPub)) - sinfo.theirSubnet = *address_subnetForNodeID(getNodeID(&sinfo.theirPermPub)) + sinfo.myHandle = *crypto.NewHandle() + sinfo.theirAddr = *address.AddrForNodeID(crypto.GetNodeID(&sinfo.theirPermPub)) + sinfo.theirSubnet = *address.SubnetForNodeID(crypto.GetNodeID(&sinfo.theirPermPub)) sinfo.send = make(chan []byte, 32) sinfo.recv = make(chan *wire_trafficPacket, 32) go sinfo.doWorker() @@ -324,32 +328,32 @@ func (ss *sessions) cleanup() { s.close() } } - permShared := make(map[boxPubKey]*boxSharedKey, len(ss.permShared)) + permShared := make(map[crypto.BoxPubKey]*crypto.BoxSharedKey, len(ss.permShared)) for k, v := range ss.permShared { permShared[k] = v } ss.permShared = permShared - sinfos := make(map[handle]*sessionInfo, len(ss.sinfos)) + sinfos := make(map[crypto.Handle]*sessionInfo, len(ss.sinfos)) for k, v := range ss.sinfos { sinfos[k] = v } ss.sinfos = sinfos - byMySes := make(map[boxPubKey]*handle, len(ss.byMySes)) + byMySes := make(map[crypto.BoxPubKey]*crypto.Handle, len(ss.byMySes)) for k, v := range ss.byMySes { byMySes[k] = v } ss.byMySes = byMySes - byTheirPerm := make(map[boxPubKey]*handle, len(ss.byTheirPerm)) + byTheirPerm := make(map[crypto.BoxPubKey]*crypto.Handle, len(ss.byTheirPerm)) for k, v := range ss.byTheirPerm { byTheirPerm[k] = v } ss.byTheirPerm = byTheirPerm - addrToPerm := make(map[address]*boxPubKey, len(ss.addrToPerm)) + addrToPerm := make(map[address.Address]*crypto.BoxPubKey, len(ss.addrToPerm)) for k, v := range ss.addrToPerm { addrToPerm[k] = v } ss.addrToPerm = addrToPerm - subnetToPerm := make(map[subnet]*boxPubKey, len(ss.subnetToPerm)) + subnetToPerm := make(map[address.Subnet]*crypto.BoxPubKey, len(ss.subnetToPerm)) for k, v := range ss.subnetToPerm { subnetToPerm[k] = v } @@ -380,15 +384,15 @@ func (ss *sessions) getPing(sinfo *sessionInfo) sessionPing { Coords: coords, MTU: sinfo.myMTU, } - sinfo.myNonce.update() + sinfo.myNonce.Increment() return ref } // Gets the shared key for a pair of box keys. // Used to cache recently used shared keys for protocol traffic. // This comes up with dht req/res and session ping/pong traffic. -func (ss *sessions) getSharedKey(myPriv *boxPrivKey, - theirPub *boxPubKey) *boxSharedKey { +func (ss *sessions) getSharedKey(myPriv *crypto.BoxPrivKey, + theirPub *crypto.BoxPubKey) *crypto.BoxSharedKey { if skey, isIn := ss.permShared[*theirPub]; isIn { return skey } @@ -401,7 +405,7 @@ func (ss *sessions) getSharedKey(myPriv *boxPrivKey, } delete(ss.permShared, key) } - ss.permShared[*theirPub] = getSharedKey(myPriv, theirPub) + ss.permShared[*theirPub] = crypto.GetSharedKey(myPriv, theirPub) return ss.permShared[*theirPub] } @@ -417,7 +421,7 @@ func (ss *sessions) sendPingPong(sinfo *sessionInfo, isPong bool) { ping.IsPong = isPong bs := ping.encode() shared := ss.getSharedKey(&ss.core.boxPriv, &sinfo.theirPermPub) - payload, nonce := boxSeal(shared, bs, nil) + payload, nonce := crypto.BoxSeal(shared, bs, nil) p := wire_protoTrafficPacket{ Coords: sinfo.coords, ToKey: sinfo.theirPermPub, @@ -468,24 +472,6 @@ func (ss *sessions) handlePing(ping *sessionPing) { } } -// Used to subtract one nonce from another, staying in the range +- 64. -// This is used by the nonce progression machinery to advance the bitmask of recently received packets (indexed by nonce), or to check the appropriate bit of the bitmask. -// It's basically part of the machinery that prevents replays and duplicate packets. -func (n *boxNonce) minus(m *boxNonce) int64 { - diff := int64(0) - for idx := range n { - diff *= 256 - diff += int64(n[idx]) - int64(m[idx]) - if diff > 64 { - diff = 64 - } - if diff < -64 { - diff = -64 - } - } - return diff -} - // Get the MTU of the session. // Will be equal to the smaller of this node's MTU or the remote node's MTU. // If sending over links with a maximum message size (this was a thing with the old UDP code), it could be further lowered, to a minimum of 1280. @@ -500,9 +486,9 @@ func (sinfo *sessionInfo) getMTU() uint16 { } // Checks if a packet's nonce is recent enough to fall within the window of allowed packets, and not already received. -func (sinfo *sessionInfo) nonceIsOK(theirNonce *boxNonce) bool { +func (sinfo *sessionInfo) nonceIsOK(theirNonce *crypto.BoxNonce) bool { // The bitmask is to allow for some non-duplicate out-of-order packets - diff := theirNonce.minus(&sinfo.theirNonce) + diff := theirNonce.Minus(&sinfo.theirNonce) if diff > 0 { return true } @@ -510,10 +496,10 @@ func (sinfo *sessionInfo) nonceIsOK(theirNonce *boxNonce) bool { } // Updates the nonce mask by (possibly) shifting the bitmask and setting the bit corresponding to this nonce to 1, and then updating the most recent nonce -func (sinfo *sessionInfo) updateNonce(theirNonce *boxNonce) { +func (sinfo *sessionInfo) updateNonce(theirNonce *crypto.BoxNonce) { // Shift nonce mask if needed // Set bit - diff := theirNonce.minus(&sinfo.theirNonce) + diff := theirNonce.Minus(&sinfo.theirNonce) if diff > 0 { // This nonce is newer, so shift the window before setting the bit, and update theirNonce in the session info. sinfo.nonceMask <<= uint64(diff) @@ -559,7 +545,7 @@ func (sinfo *sessionInfo) doWorker() { // This encrypts a packet, creates a trafficPacket struct, encodes it, and sends it to router.out to pass it to the switch layer. func (sinfo *sessionInfo) doSend(bs []byte) { - defer util_putBytes(bs) + defer util.PutBytes(bs) if !sinfo.init { // To prevent using empty session keys return @@ -593,8 +579,8 @@ func (sinfo *sessionInfo) doSend(bs []byte) { coords = wire_put_uint64(flowkey, coords) // Then variable-length encoded flowkey } // Prepare the payload - payload, nonce := boxSeal(&sinfo.sharedSesKey, bs, &sinfo.myNonce) - defer util_putBytes(payload) + payload, nonce := crypto.BoxSeal(&sinfo.sharedSesKey, bs, &sinfo.myNonce) + defer util.PutBytes(payload) p := wire_trafficPacket{ Coords: coords, Handle: sinfo.theirHandle, @@ -612,13 +598,13 @@ func (sinfo *sessionInfo) doSend(bs []byte) { // If a packet does not decrypt successfully, it assumes the packet was truncated, and updates the MTU accordingly. // TODO? remove the MTU updating part? That should never happen with TCP peers, and the old UDP code that caused it was removed (and if replaced, should be replaced with something that can reliably send messages with an arbitrary size). func (sinfo *sessionInfo) doRecv(p *wire_trafficPacket) { - defer util_putBytes(p.Payload) + defer util.PutBytes(p.Payload) if !sinfo.nonceIsOK(&p.Nonce) { return } - bs, isOK := boxOpen(&sinfo.sharedSesKey, p.Payload, &p.Nonce) + bs, isOK := crypto.BoxOpen(&sinfo.sharedSesKey, p.Payload, &p.Nonce) if !isOK { - util_putBytes(bs) + util.PutBytes(bs) return } sinfo.updateNonce(&p.Nonce) diff --git a/src/yggdrasil/switch.go b/src/yggdrasil/switch.go index 99ed25b4..3c1dae61 100644 --- a/src/yggdrasil/switch.go +++ b/src/yggdrasil/switch.go @@ -16,6 +16,9 @@ import ( "sync" "sync/atomic" "time" + + "github.com/yggdrasil-network/yggdrasil-go/src/crypto" + "github.com/yggdrasil-network/yggdrasil-go/src/util" ) const ( @@ -30,16 +33,16 @@ const ( // The coords represent a path from the root to a node. // This path is generally part of a spanning tree, except possibly the last hop (it can loop when sending coords to your parent, but they see this and know not to use a looping path). type switchLocator struct { - root sigPubKey + root crypto.SigPubKey tstamp int64 coords []switchPort } // Returns true if the first sigPubKey has a higher TreeID. -func firstIsBetter(first, second *sigPubKey) bool { +func firstIsBetter(first, second *crypto.SigPubKey) bool { // Higher TreeID is better - ftid := getTreeID(first) - stid := getTreeID(second) + ftid := crypto.GetTreeID(first) + stid := crypto.GetTreeID(second) for idx := 0; idx < len(ftid); idx++ { if ftid[idx] == stid[idx] { continue @@ -121,7 +124,7 @@ func (x *switchLocator) isAncestorOf(y *switchLocator) bool { // Information about a peer, used by the switch to build the tree and eventually make routing decisions. type peerInfo struct { - key sigPubKey // ID of this peer + key crypto.SigPubKey // ID of this peer locator switchLocator // Should be able to respond with signatures upon request degree uint64 // Self-reported degree time time.Time // Time this node was last seen @@ -159,26 +162,26 @@ type switchData struct { // All the information stored by the switch. type switchTable struct { core *Core - key sigPubKey // Our own key - time time.Time // Time when locator.tstamp was last updated - drop map[sigPubKey]int64 // Tstamp associated with a dropped root - mutex sync.RWMutex // Lock for reads/writes of switchData - parent switchPort // Port of whatever peer is our parent, or self if we're root - data switchData // - updater atomic.Value // *sync.Once - table atomic.Value // lookupTable - packetIn chan []byte // Incoming packets for the worker to handle - idleIn chan switchPort // Incoming idle notifications from peer links - admin chan func() // Pass a lambda for the admin socket to query stuff - queues switch_buffers // Queues - not atomic so ONLY use through admin chan - queueTotalMaxSize uint64 // Maximum combined size of queues + key crypto.SigPubKey // Our own key + time time.Time // Time when locator.tstamp was last updated + drop map[crypto.SigPubKey]int64 // Tstamp associated with a dropped root + mutex sync.RWMutex // Lock for reads/writes of switchData + parent switchPort // Port of whatever peer is our parent, or self if we're root + data switchData // + updater atomic.Value // *sync.Once + table atomic.Value // lookupTable + packetIn chan []byte // Incoming packets for the worker to handle + idleIn chan switchPort // Incoming idle notifications from peer links + admin chan func() // Pass a lambda for the admin socket to query stuff + queues switch_buffers // Queues - not atomic so ONLY use through admin chan + queueTotalMaxSize uint64 // Maximum combined size of queues } // Minimum allowed total size of switch queues. const SwitchQueueTotalMinSize = 4 * 1024 * 1024 // Initializes the switchTable struct. -func (t *switchTable) init(core *Core, key sigPubKey) { +func (t *switchTable) init(core *Core, key crypto.SigPubKey) { now := time.Now() t.core = core t.key = key @@ -187,7 +190,7 @@ func (t *switchTable) init(core *Core, key sigPubKey) { t.data = switchData{locator: locator, peers: peers} t.updater.Store(&sync.Once{}) t.table.Store(lookupTable{}) - t.drop = make(map[sigPubKey]int64) + t.drop = make(map[crypto.SigPubKey]int64) t.packetIn = make(chan []byte, 1024) t.idleIn = make(chan switchPort, 1024) t.admin = make(chan func()) @@ -302,7 +305,7 @@ func (t *switchTable) cleanDropped() { // This is exchanged with peers to construct the spanning tree. // A subset of this information, excluding the signatures, is used to construct locators that are used elsewhere in the code. type switchMsg struct { - Root sigPubKey + Root crypto.SigPubKey TStamp int64 Hops []switchMsgHop } @@ -310,8 +313,8 @@ type switchMsg struct { // This represents the signed information about the path leading from the root the Next node, via the Port specified here. type switchMsgHop struct { Port switchPort - Next sigPubKey - Sig sigBytes + Next crypto.SigPubKey + Sig crypto.SigBytes } // This returns a *switchMsg to a copy of this node's current switchMsg, which can safely have additional information appended to Hops and sent to a peer. @@ -690,7 +693,7 @@ func (b *switch_buffers) cleanup(t *switchTable) { coords := switch_getPacketCoords(packet.bytes) if t.selfIsClosest(coords) { for _, packet := range buf.packets { - util_putBytes(packet.bytes) + util.PutBytes(packet.bytes) } b.size -= buf.size delete(b.bufs, streamID) @@ -710,7 +713,7 @@ func (b *switch_buffers) cleanup(t *switchTable) { packet, buf.packets = buf.packets[0], buf.packets[1:] buf.size -= uint64(len(packet.bytes)) b.size -= uint64(len(packet.bytes)) - util_putBytes(packet.bytes) + util.PutBytes(packet.bytes) if len(buf.packets) == 0 { delete(b.bufs, streamID) } else { diff --git a/src/yggdrasil/tcp.go b/src/yggdrasil/tcp.go index 5ca66304..045932a2 100644 --- a/src/yggdrasil/tcp.go +++ b/src/yggdrasil/tcp.go @@ -25,6 +25,10 @@ import ( "time" "golang.org/x/net/proxy" + + "github.com/yggdrasil-network/yggdrasil-go/src/address" + "github.com/yggdrasil-network/yggdrasil-go/src/crypto" + "github.com/yggdrasil-network/yggdrasil-go/src/util" ) const tcp_msgSize = 2048 + 65535 // TODO figure out what makes sense @@ -52,8 +56,8 @@ type tcpInterface struct { // This is used as the key to a map that tracks existing connections, to prevent multiple connections to the same keys and local/remote address pair from occuring. // Different address combinations are allowed, so multi-homing is still technically possible (but not necessarily advisable). type tcpInfo struct { - box boxPubKey - sig sigPubKey + box crypto.BoxPubKey + sig crypto.SigPubKey localAddr string remoteAddr string } @@ -206,7 +210,7 @@ func (iface *tcpInterface) call(saddr string, socksaddr *string, sintf string) { func (iface *tcpInterface) handler(sock net.Conn, incoming bool) { defer sock.Close() // Get our keys - myLinkPub, myLinkPriv := newBoxKeys() // ephemeral link keys + myLinkPub, myLinkPriv := crypto.NewBoxKeys() // ephemeral link keys meta := version_getBaseMetadata() meta.box = iface.core.boxPub meta.sig = iface.core.sigPub @@ -287,7 +291,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, &meta.link), sock.RemoteAddr().String()) + p := iface.core.peers.newPeer(&info.box, &info.sig, crypto.GetSharedKey(myLinkPriv, &meta.link), sock.RemoteAddr().String()) p.linkOut = make(chan []byte, 1) in := func(bs []byte) { p.handlePacket(bs) @@ -301,7 +305,7 @@ func (iface *tcpInterface) handler(sock net.Conn, incoming bool) { buf := net.Buffers{tcp_msg[:], msgLen, msg} buf.WriteTo(sock) atomic.AddUint64(&p.bytesSent, uint64(len(tcp_msg)+len(msgLen)+len(msg))) - util_putBytes(msg) + util.PutBytes(msg) } timerInterval := tcp_ping_interval timer := time.NewTimer(timerInterval) @@ -350,8 +354,8 @@ func (iface *tcpInterface) handler(sock net.Conn, incoming bool) { }() us, _, _ := net.SplitHostPort(sock.LocalAddr().String()) them, _, _ := net.SplitHostPort(sock.RemoteAddr().String()) - themNodeID := getNodeID(&info.box) - themAddr := address_addrForNodeID(themNodeID) + themNodeID := crypto.GetNodeID(&info.box) + themAddr := address.AddrForNodeID(themNodeID) themAddrString := net.IP(themAddr[:]).String() themString := fmt.Sprintf("%s@%s", themAddrString, them) iface.core.log.Println("Connected:", themString, "source", us) @@ -386,9 +390,9 @@ func (iface *tcpInterface) reader(sock net.Conn, in func([]byte)) error { // We didn't get the whole message yet break } - newMsg := append(util_getBytes(), msg...) + newMsg := append(util.GetBytes(), msg...) in(newMsg) - util_yield() + util.Yield() } frag = append(bs[:0], frag...) } diff --git a/src/yggdrasil/tun.go b/src/yggdrasil/tun.go index 26d32c0b..c3ceeb65 100644 --- a/src/yggdrasil/tun.go +++ b/src/yggdrasil/tun.go @@ -10,7 +10,9 @@ import ( "github.com/songgao/packets/ethernet" "github.com/yggdrasil-network/water" + "github.com/yggdrasil-network/yggdrasil-go/src/address" "github.com/yggdrasil-network/yggdrasil-go/src/defaults" + "github.com/yggdrasil-network/yggdrasil-go/src/util" ) const tun_IPv6_HEADER_LENGTH = 40 @@ -80,7 +82,7 @@ func (tun *tunAdapter) write() error { continue } if tun.iface.IsTAP() { - var destAddr address + var destAddr address.Address if data[0]&0xf0 == 0x60 { if len(data) < 40 { panic("Tried to send a packet shorter than an IPv6 header...") @@ -94,7 +96,7 @@ func (tun *tunAdapter) write() error { } else { return errors.New("Invalid address family") } - sendndp := func(destAddr address) { + sendndp := func(destAddr address.Address) { neigh, known := tun.icmpv6.peermacs[destAddr] known = known && (time.Since(neigh.lastsolicitation).Seconds() < 30) if !known { @@ -154,7 +156,7 @@ func (tun *tunAdapter) write() error { panic(err) } } - util_putBytes(data) + util.PutBytes(data) } } @@ -191,7 +193,7 @@ func (tun *tunAdapter) read() error { // tun.icmpv6.recv <- b go tun.icmpv6.parse_packet(b) } - packet := append(util_getBytes(), buf[o:n]...) + packet := append(util.GetBytes(), buf[o:n]...) tun.send <- packet } } diff --git a/src/yggdrasil/version.go b/src/yggdrasil/version.go index 75b08a6f..f71780e0 100644 --- a/src/yggdrasil/version.go +++ b/src/yggdrasil/version.go @@ -4,6 +4,8 @@ package yggdrasil // Used in the inital connection setup and key exchange // Some of this could arguably go in wire.go instead +import "github.com/yggdrasil-network/yggdrasil-go/src/crypto" + // This is the version-specific metadata exchanged at the start of a connection. // It must always beign with the 4 bytes "meta" and a wire formatted uint64 major version number. // The current version also includes a minor version number, and the box/sig/link keys that need to be exchanged to open an connection. @@ -12,9 +14,9 @@ type version_metadata struct { ver uint64 // 1 byte in this version // Everything after this point potentially depends on the version number, and is subject to change in future versions minorVer uint64 // 1 byte in this version - box boxPubKey - sig sigPubKey - link boxPubKey + box crypto.BoxPubKey + sig crypto.SigPubKey + link crypto.BoxPubKey } // Gets a base metadata with no keys set, but with the correct version numbers. @@ -28,12 +30,12 @@ func version_getBaseMetadata() version_metadata { // Gest the length of the metadata for this version, used to know how many bytes to read from the start of a connection. func version_getMetaLength() (mlen int) { - mlen += 4 // meta - mlen += 1 // ver, as long as it's < 127, which it is in this version - mlen += 1 // minorVer, as long as it's < 127, which it is in this version - mlen += boxPubKeyLen // box - mlen += sigPubKeyLen // sig - mlen += boxPubKeyLen // link + mlen += 4 // meta + mlen += 1 // ver, as long as it's < 127, which it is in this version + mlen += 1 // minorVer, as long as it's < 127, which it is in this version + mlen += crypto.BoxPubKeyLen // box + mlen += crypto.SigPubKeyLen // sig + mlen += crypto.BoxPubKeyLen // link return } diff --git a/src/yggdrasil/wire.go b/src/yggdrasil/wire.go index d05624e2..08e8a62f 100644 --- a/src/yggdrasil/wire.go +++ b/src/yggdrasil/wire.go @@ -7,6 +7,11 @@ package yggdrasil // Packet types, as wire_encode_uint64(type) at the start of each packet +import ( + "github.com/yggdrasil-network/yggdrasil-go/src/crypto" + "github.com/yggdrasil-network/yggdrasil-go/src/util" +) + const ( wire_Traffic = iota // data being routed somewhere, handle for crypto wire_ProtocolTraffic // protocol traffic, pub keys for crypto @@ -191,14 +196,14 @@ func wire_chop_uint64(toUInt64 *uint64, fromSlice *[]byte) bool { // The wire format for ordinary IPv6 traffic encapsulated by the network. type wire_trafficPacket struct { Coords []byte - Handle handle - Nonce boxNonce + Handle crypto.Handle + Nonce crypto.BoxNonce Payload []byte } // Encodes a wire_trafficPacket into its wire format. func (p *wire_trafficPacket) encode() []byte { - bs := util_getBytes() + bs := util.GetBytes() bs = wire_put_uint64(wire_Traffic, bs) bs = wire_put_coords(p.Coords, bs) bs = append(bs, p.Handle[:]...) @@ -222,16 +227,16 @@ func (p *wire_trafficPacket) decode(bs []byte) bool { case !wire_chop_slice(p.Nonce[:], &bs): return false } - p.Payload = append(util_getBytes(), bs...) + p.Payload = append(util.GetBytes(), bs...) return true } // The wire format for protocol traffic, such as dht req/res or session ping/pong packets. type wire_protoTrafficPacket struct { Coords []byte - ToKey boxPubKey - FromKey boxPubKey - Nonce boxNonce + ToKey crypto.BoxPubKey + FromKey crypto.BoxPubKey + Nonce crypto.BoxNonce Payload []byte } @@ -273,7 +278,7 @@ func (p *wire_protoTrafficPacket) decode(bs []byte) bool { // The keys themselves are exchanged as part of the connection setup, and then omitted from the packets. // The two layer logic is handled in peers.go, but it's kind of ugly. type wire_linkProtoTrafficPacket struct { - Nonce boxNonce + Nonce crypto.BoxNonce Payload []byte }