// Package address contains the types used by mesh to represent IPv6 addresses or prefixes, as well as functions for working with these types. // Of particular importance are the functions used to derive addresses or subnets from a NodeID, or to get the NodeID and bitmask of the bits visible from an address, which is needed for DHT searches. package core import ( "crypto/ed25519" "encoding/hex" ) // Address represents an IPv6 address in the mesh address range. type Address [16]byte // Subnet represents an IPv6 /64 subnet in the mesh subnet range. type Subnet [8]byte // GetPrefix returns the address prefix used by mesh. // The current implementation requires this to be a multiple 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 each other using IP packets, though routing and the DHT machinery *should* still work. func (c *Core) GetPrefix() [1]byte { p, err := hex.DecodeString(c.config.networkdomain.Prefix) if err != nil { panic(err) } var prefix [1]byte copy(prefix[:], p[:1]) return prefix } // IsValid returns true if an address falls within the range used by nodes in the network. func (c *Core) IsValidAddress(a Address) bool { prefix := c.GetPrefix() for idx := range prefix { if a[idx] != prefix[idx] { return false } } return true } // IsValid returns true if a prefix falls within the range usable by the network. func (c *Core) IsValidSubnet(s Subnet) bool { prefix := c.GetPrefix() l := len(prefix) for idx := range prefix[:l-1] { if s[idx] != prefix[idx] { return false } } return s[l-1] == prefix[l-1]|0x01 } // AddrForKey takes an ed25519.PublicKey as an argument and returns an *Address. // This function returns nil if the key length is not ed25519.PublicKeySize. // This address begins with the contents of GetPrefix(), 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 bitwise inverse of the public key. // The bitwise inverse of the key, 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 (c *Core) AddrForKey(publicKey ed25519.PublicKey) *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) if len(publicKey) != ed25519.PublicKeySize { return nil } var buf [ed25519.PublicKeySize]byte copy(buf[:], publicKey) for idx := range buf { buf[idx] = ^buf[idx] } var addr Address var temp = make([]byte, 0, 32) done := false ones := byte(0) bits := byte(0) nBits := 0 for idx := 0; idx < 8*len(buf); idx++ { bit := (buf[idx/8] & (0x80 >> byte(idx%8))) >> byte(7-(idx%8)) if !done && bit != 0 { ones++ continue } if !done && bit == 0 { done = true continue // FIXME? this assumes that ones <= 127, probably only worth changing by using a variable length uint64, but that would require changes to the addressing scheme, and I'm not sure ones > 127 is realistic } bits = (bits << 1) | bit nBits++ if nBits == 8 { nBits = 0 temp = append(temp, bits) } } prefix := c.GetPrefix() copy(addr[:], prefix[:]) addr[len(prefix)] = ones copy(addr[len(prefix)+1:], temp) return &addr } // SubnetForKey takes an ed25519.PublicKey as an argument and returns a *Subnet. // This function returns nil if the key length is not ed25519.PublicKeySize. // The 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 bitwise inverse of the key. // The bitwise inverse of the key, 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 (c *Core) SubnetForKey(publicKey ed25519.PublicKey) *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 := c.AddrForKey(publicKey) if addr == nil { return nil } var snet Subnet copy(snet[:], addr[:]) prefix := c.GetPrefix() // nolint:staticcheck snet[len(prefix)-1] |= 0x01 return &snet } // GetKet returns the partial ed25519.PublicKey for the Address. // This is used for key lookup. func (c *Core) GetAddressKey(a Address) ed25519.PublicKey { var key [ed25519.PublicKeySize]byte prefix := c.GetPrefix() // nolint:staticcheck ones := int(a[len(prefix)]) for idx := 0; idx < ones; idx++ { key[idx/8] |= 0x80 >> byte(idx%8) } keyOffset := ones + 1 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) keyIdx := keyOffset + (idx - addrOffset) bits >>= byte(keyIdx % 8) idx := keyIdx / 8 if idx >= len(key) { break } key[idx] |= bits } for idx := range key { key[idx] = ^key[idx] } return ed25519.PublicKey(key[:]) } // GetKet returns the partial ed25519.PublicKey for the Subnet. // This is used for key lookup. func (c *Core) GetSubnetKey(s Subnet) ed25519.PublicKey { var addr Address copy(addr[:], s[:]) return c.GetAddressKey(addr) }