2018-12-15 05:49:18 +03:00
package address
import "github.com/yggdrasil-network/yggdrasil-go/src/crypto"
2017-12-29 07:16:20 +03:00
2018-06-11 02:03:28 +03:00
// address represents an IPv6 address in the yggdrasil address range.
2018-12-15 05:49:18 +03:00
type Address [ 16 ] byte
2017-12-29 07:16:20 +03:00
2018-06-11 02:03:28 +03:00
// subnet represents an IPv6 /64 subnet in the yggdrasil subnet range.
2018-12-15 05:49:18 +03:00
type Subnet [ 8 ] byte
2017-12-29 07:16:20 +03:00
2018-06-11 02:03:28 +03:00
// address_prefix is the prefix used for all addresses and subnets in the network.
2018-06-15 13:02:45 +03:00
// 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).
2018-06-11 02:03:28 +03:00
// Nodes that configure this differently will be unable to communicate with eachother, though routing and the DHT machinery *should* still work.
2018-12-15 05:49:18 +03:00
func GetPrefix ( ) [ 1 ] byte {
return [ ... ] byte { 0x02 }
}
2018-06-11 02:03:28 +03:00
// isValid returns true if an address falls within the range used by nodes in the network.
2018-12-15 05:49:18 +03:00
func ( a * Address ) IsValid ( ) bool {
prefix := GetPrefix ( )
for idx := range prefix {
if ( * a ) [ idx ] != prefix [ idx ] {
2018-01-05 01:37:51 +03:00
return false
}
}
2018-06-15 13:02:45 +03:00
return true
2017-12-29 07:16:20 +03:00
}
2018-06-11 02:03:28 +03:00
// isValid returns true if a prefix falls within the range usable by the network.
2018-12-15 05:49:18 +03:00
func ( s * Subnet ) IsValid ( ) bool {
prefix := GetPrefix ( )
l := len ( prefix )
for idx := range prefix [ : l - 1 ] {
if ( * s ) [ idx ] != prefix [ idx ] {
2018-01-05 01:37:51 +03:00
return false
}
}
2018-12-15 05:49:18 +03:00
return ( * s ) [ l - 1 ] == prefix [ l - 1 ] | 0x01
2017-12-29 07:16:20 +03:00
}
2018-06-11 02:03:28 +03:00
// address_addrForNodeID takes a *NodeID as an argument and returns an *address.
2018-06-15 13:02:45 +03:00
// 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.
2018-12-15 05:49:18 +03:00
func AddrForNodeID ( nid * crypto . NodeID ) * Address {
2018-01-05 01:37:51 +03:00
// 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)
2018-12-15 05:49:18 +03:00
var addr Address
2018-01-05 01:37:51 +03:00
var temp [ ] byte
done := false
ones := byte ( 0 )
bits := byte ( 0 )
nBits := 0
for idx := 0 ; idx < 8 * len ( nid ) ; idx ++ {
bit := ( nid [ idx / 8 ] & ( 0x80 >> byte ( idx % 8 ) ) ) >> byte ( 7 - ( idx % 8 ) )
if ! done && bit != 0 {
ones ++
continue
}
if ! done && bit == 0 {
done = true
2018-01-27 02:30:51 +03:00
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
2018-01-05 01:37:51 +03:00
}
bits = ( bits << 1 ) | bit
nBits ++
if nBits == 8 {
nBits = 0
temp = append ( temp , bits )
}
}
2018-12-15 05:49:18 +03:00
prefix := GetPrefix ( )
copy ( addr [ : ] , prefix [ : ] )
addr [ len ( prefix ) ] = ones
copy ( addr [ len ( prefix ) + 1 : ] , temp )
2018-01-05 01:37:51 +03:00
return & addr
2017-12-29 07:16:20 +03:00
}
2018-06-11 02:03:28 +03:00
// address_subnetForNodeID takes a *NodeID as an argument and returns a *subnet.
2018-06-15 13:02:45 +03:00
// 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.
2018-12-15 05:49:18 +03:00
func SubnetForNodeID ( nid * crypto . NodeID ) * Subnet {
2018-01-05 01:37:51 +03:00
// 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
2018-12-15 05:49:18 +03:00
addr := * AddrForNodeID ( nid )
var snet Subnet
2018-01-05 01:37:51 +03:00
copy ( snet [ : ] , addr [ : ] )
2018-12-15 05:49:18 +03:00
prefix := GetPrefix ( )
snet [ len ( prefix ) - 1 ] |= 0x01
2018-01-05 01:37:51 +03:00
return & snet
2017-12-29 07:16:20 +03:00
}
2018-06-11 02:03:28 +03:00
// getNodeIDandMask returns two *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 address.
// This is used to look up NodeIDs in the DHT and tell if they match an address.
2018-12-15 05:49:18 +03:00
func ( a * Address ) GetNodeIDandMask ( ) ( * crypto . NodeID , * crypto . NodeID ) {
2018-01-05 01:37:51 +03:00
// 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
2018-12-15 05:49:18 +03:00
var nid crypto . NodeID
var mask crypto . NodeID
prefix := GetPrefix ( )
ones := int ( a [ len ( prefix ) ] )
2018-01-05 01:37:51 +03:00
for idx := 0 ; idx < ones ; idx ++ {
nid [ idx / 8 ] |= 0x80 >> byte ( idx % 8 )
}
nidOffset := ones + 1
2018-12-15 05:49:18 +03:00
addrOffset := 8 * len ( prefix ) + 8
2018-01-05 01:37:51 +03:00
for idx := addrOffset ; idx < 8 * len ( a ) ; idx ++ {
bits := a [ idx / 8 ] & ( 0x80 >> byte ( idx % 8 ) )
bits <<= byte ( idx % 8 )
nidIdx := nidOffset + ( idx - addrOffset )
bits >>= byte ( nidIdx % 8 )
nid [ nidIdx / 8 ] |= bits
}
2018-12-15 05:49:18 +03:00
maxMask := 8 * ( len ( a ) - len ( prefix ) - 1 ) + ones + 1
2018-01-05 01:37:51 +03:00
for idx := 0 ; idx < maxMask ; idx ++ {
mask [ idx / 8 ] |= 0x80 >> byte ( idx % 8 )
}
return & nid , & mask
2017-12-29 07:16:20 +03:00
}
2018-06-11 02:03:28 +03:00
// getNodeIDandMask returns two *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.
2018-12-15 05:49:18 +03:00
func ( s * Subnet ) GetNodeIDandMask ( ) ( * crypto . NodeID , * crypto . NodeID ) {
2018-01-21 21:55:45 +03:00
// As with the address version, but visible parts of the subnet prefix instead
2018-12-15 05:49:18 +03:00
var nid crypto . NodeID
var mask crypto . NodeID
prefix := GetPrefix ( )
ones := int ( s [ len ( prefix ) ] )
2018-01-05 01:37:51 +03:00
for idx := 0 ; idx < ones ; idx ++ {
nid [ idx / 8 ] |= 0x80 >> byte ( idx % 8 )
}
nidOffset := ones + 1
2018-12-15 05:49:18 +03:00
addrOffset := 8 * len ( prefix ) + 8
2018-01-05 01:37:51 +03:00
for idx := addrOffset ; idx < 8 * len ( s ) ; idx ++ {
bits := s [ idx / 8 ] & ( 0x80 >> byte ( idx % 8 ) )
bits <<= byte ( idx % 8 )
nidIdx := nidOffset + ( idx - addrOffset )
bits >>= byte ( nidIdx % 8 )
nid [ nidIdx / 8 ] |= bits
}
2018-12-15 05:49:18 +03:00
maxMask := 8 * ( len ( s ) - len ( prefix ) - 1 ) + ones + 1
2018-01-05 01:37:51 +03:00
for idx := 0 ; idx < maxMask ; idx ++ {
mask [ idx / 8 ] |= 0x80 >> byte ( idx % 8 )
}
return & nid , & mask
2017-12-29 07:16:20 +03:00
}