mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-11-22 21:10:29 +00:00
Support IPv4 in ckr.go
This commit is contained in:
parent
cb7a5f17d9
commit
424faa1c51
@ -79,15 +79,30 @@ func (c *cryptokey) addSourceSubnet(cidr string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the prefix length and size
|
||||||
|
_, prefixsize := ipnet.Mask.Size()
|
||||||
|
|
||||||
|
// Build our references to the routing sources
|
||||||
|
var routingsources *[]net.IPNet
|
||||||
|
|
||||||
|
// Check if the prefix is IPv4 or IPv6
|
||||||
|
if prefixsize == net.IPv6len*8 {
|
||||||
|
routingsources = &c.ipv6sources
|
||||||
|
} else if prefixsize == net.IPv4len*8 {
|
||||||
|
routingsources = &c.ipv4sources
|
||||||
|
} else {
|
||||||
|
return errors.New("Unexpected prefix size")
|
||||||
|
}
|
||||||
|
|
||||||
// Check if we already have this CIDR
|
// Check if we already have this CIDR
|
||||||
for _, subnet := range c.ipv6sources {
|
for _, subnet := range *routingsources {
|
||||||
if subnet.String() == ipnet.String() {
|
if subnet.String() == ipnet.String() {
|
||||||
return errors.New("Source subnet already configured")
|
return errors.New("Source subnet already configured")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the source subnet
|
// Add the source subnet
|
||||||
c.ipv6sources = append(c.ipv6sources, *ipnet)
|
*routingsources = append(*routingsources, *ipnet)
|
||||||
c.core.log.Println("Added CKR source subnet", cidr)
|
c.core.log.Println("Added CKR source subnet", cidr)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -102,92 +117,111 @@ func (c *cryptokey) addRoute(cidr string, dest string) error {
|
|||||||
// Get the prefix length and size
|
// Get the prefix length and size
|
||||||
_, prefixsize := ipnet.Mask.Size()
|
_, prefixsize := ipnet.Mask.Size()
|
||||||
|
|
||||||
|
// Build our references to the routing table and cache
|
||||||
|
var routingtable *[]cryptokey_route
|
||||||
|
var routingcache *map[address]cryptokey_route
|
||||||
|
|
||||||
// Check if the prefix is IPv4 or IPv6
|
// Check if the prefix is IPv4 or IPv6
|
||||||
if prefixsize == net.IPv6len*8 {
|
if prefixsize == net.IPv6len*8 {
|
||||||
// Is the route an Yggdrasil destination?
|
routingtable = &c.ipv6routes
|
||||||
var addr address
|
routingcache = &c.ipv6cache
|
||||||
var snet subnet
|
|
||||||
copy(addr[:], ipaddr)
|
|
||||||
copy(snet[:], ipnet.IP)
|
|
||||||
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?
|
|
||||||
for _, route := range c.ipv6routes {
|
|
||||||
if route.subnet.String() == ipnet.String() {
|
|
||||||
return errors.New(fmt.Sprintf("Route already exists for %s", cidr))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Decode the public key
|
|
||||||
if boxPubKey, err := hex.DecodeString(dest); err != nil {
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
// Add the new crypto-key route
|
|
||||||
c.ipv6routes = append(c.ipv6routes, cryptokey_route{
|
|
||||||
subnet: *ipnet,
|
|
||||||
destination: boxPubKey,
|
|
||||||
})
|
|
||||||
|
|
||||||
// Sort so most specific routes are first
|
|
||||||
sort.Slice(c.ipv6routes, func(i, j int) bool {
|
|
||||||
im, _ := c.ipv6routes[i].subnet.Mask.Size()
|
|
||||||
jm, _ := c.ipv6routes[j].subnet.Mask.Size()
|
|
||||||
return im > jm
|
|
||||||
})
|
|
||||||
|
|
||||||
// Clear the cache as this route might change future routing
|
|
||||||
// Setting an empty slice keeps the memory whereas nil invokes GC
|
|
||||||
for k := range c.ipv6cache {
|
|
||||||
delete(c.ipv6cache, k)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.core.log.Println("Added CKR destination subnet", cidr)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
} else if prefixsize == net.IPv4len*8 {
|
} else if prefixsize == net.IPv4len*8 {
|
||||||
// IPv4
|
routingtable = &c.ipv4routes
|
||||||
return errors.New("IPv4 not supported at this time")
|
routingcache = &c.ipv4cache
|
||||||
|
} else {
|
||||||
|
return errors.New("Unexpected prefix size")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Is the route an Yggdrasil destination?
|
||||||
|
var addr address
|
||||||
|
var snet subnet
|
||||||
|
copy(addr[:], ipaddr)
|
||||||
|
copy(snet[:], ipnet.IP)
|
||||||
|
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?
|
||||||
|
for _, route := range *routingtable {
|
||||||
|
if route.subnet.String() == ipnet.String() {
|
||||||
|
return errors.New(fmt.Sprintf("Route already exists for %s", cidr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Decode the public key
|
||||||
|
if boxPubKey, err := hex.DecodeString(dest); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
// Add the new crypto-key route
|
||||||
|
*routingtable = append(*routingtable, cryptokey_route{
|
||||||
|
subnet: *ipnet,
|
||||||
|
destination: boxPubKey,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Sort so most specific routes are first
|
||||||
|
sort.Slice(*routingtable, func(i, j int) bool {
|
||||||
|
im, _ := (*routingtable)[i].subnet.Mask.Size()
|
||||||
|
jm, _ := (*routingtable)[j].subnet.Mask.Size()
|
||||||
|
return im > jm
|
||||||
|
})
|
||||||
|
|
||||||
|
// Clear the cache as this route might change future routing
|
||||||
|
// Setting an empty slice keeps the memory whereas nil invokes GC
|
||||||
|
for k := range *routingcache {
|
||||||
|
delete(*routingcache, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.core.log.Println("Added CKR destination subnet", cidr)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
return errors.New("Unspecified error")
|
return errors.New("Unspecified error")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cryptokey) getPublicKeyForAddress(addr address) (boxPubKey, error) {
|
func (c *cryptokey) getPublicKeyForAddress(addr address, addrlen int) (boxPubKey, error) {
|
||||||
// Check if the address is a valid Yggdrasil address - if so it
|
// Check if the address is a valid Yggdrasil address - if so it
|
||||||
// is exempt from all CKR checking
|
// is exempt from all CKR checking
|
||||||
if addr.isValid() {
|
if addr.isValid() {
|
||||||
return boxPubKey{}, errors.New("Cannot look up CKR for Yggdrasil addresses")
|
return 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
|
||||||
|
|
||||||
|
// Check if the prefix is IPv4 or IPv6
|
||||||
|
if addrlen == net.IPv6len {
|
||||||
|
routingtable = &c.ipv6routes
|
||||||
|
routingcache = &c.ipv6cache
|
||||||
|
} else if addrlen == net.IPv4len {
|
||||||
|
routingtable = &c.ipv4routes
|
||||||
|
routingcache = &c.ipv4cache
|
||||||
|
} else {
|
||||||
|
return boxPubKey{}, errors.New("Unexpected prefix size")
|
||||||
|
}
|
||||||
|
|
||||||
// Check if there's a cache entry for this addr
|
// Check if there's a cache entry for this addr
|
||||||
if route, ok := c.ipv6cache[addr]; ok {
|
if route, ok := (*routingcache)[addr]; ok {
|
||||||
var box boxPubKey
|
var box boxPubKey
|
||||||
copy(box[:boxPubKeyLen], route.destination)
|
copy(box[:boxPubKeyLen], route.destination)
|
||||||
return box, nil
|
return box, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// No cache was found - start by converting the address into a net.IP
|
// No cache was found - start by converting the address into a net.IP
|
||||||
ip := make(net.IP, 16)
|
ip := make(net.IP, addrlen)
|
||||||
copy(ip[:16], addr[:])
|
copy(ip[:addrlen], addr[:])
|
||||||
|
|
||||||
// Check whether it's an IPv4 or an IPv6 address
|
// Check if we have a route. At this point c.ipv6routes should be
|
||||||
if ip.To4() == nil {
|
// pre-sorted so that the most specific routes are first
|
||||||
// Check if we have a route. At this point c.ipv6routes should be
|
for _, route := range *routingtable {
|
||||||
// pre-sorted so that the most specific routes are first
|
// Does this subnet match the given IP?
|
||||||
for _, route := range c.ipv6routes {
|
if route.subnet.Contains(ip) {
|
||||||
// Does this subnet match the given IP?
|
// Cache the entry for future packets to get a faster lookup
|
||||||
if route.subnet.Contains(ip) {
|
(*routingcache)[addr] = route
|
||||||
// Cache the entry for future packets to get a faster lookup
|
|
||||||
c.ipv6cache[addr] = route
|
|
||||||
|
|
||||||
// Return the boxPubKey
|
// Return the boxPubKey
|
||||||
var box boxPubKey
|
var box boxPubKey
|
||||||
copy(box[:boxPubKeyLen], route.destination)
|
copy(box[:boxPubKeyLen], route.destination)
|
||||||
return box, nil
|
return box, nil
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// IPv4 isn't supported yet
|
|
||||||
return boxPubKey{}, errors.New("IPv4 not supported at this time")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// No route was found if we got to this point
|
// No route was found if we got to this point
|
||||||
|
@ -42,4 +42,6 @@ type TunnelRouting struct {
|
|||||||
Enable bool `comment:"Enable or disable tunneling."`
|
Enable bool `comment:"Enable or disable tunneling."`
|
||||||
IPv6Destinations map[string]string `comment:"IPv6 subnets, mapped to the EncryptionPublicKey to which they should\nbe routed to."`
|
IPv6Destinations map[string]string `comment:"IPv6 subnets, mapped to the EncryptionPublicKey to which they should\nbe routed to."`
|
||||||
IPv6Sources []string `comment:"Optional IPv6 subnets which are allowed to be used as source addresses\nin addition to this node's Yggdrasil address/subnet."`
|
IPv6Sources []string `comment:"Optional IPv6 subnets which are allowed to be used as source addresses\nin addition to this node's Yggdrasil address/subnet."`
|
||||||
|
IPv4Destinations map[string]string `comment:"IPv4 subnets, mapped to the EncryptionPublicKey to which they should\nbe routed to."`
|
||||||
|
IPv4Sources []string `comment:"Optional IPv4 subnets which are allowed to be used as source addresses."`
|
||||||
}
|
}
|
||||||
|
@ -134,6 +134,16 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for ipv4, pubkey := range nc.TunnelRouting.IPv4Destinations {
|
||||||
|
if err := c.router.cryptokey.addRoute(ipv4, pubkey); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, source := range nc.TunnelRouting.IPv4Sources {
|
||||||
|
if c.router.cryptokey.addSourceSubnet(source); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.admin.start(); err != nil {
|
if err := c.admin.start(); err != nil {
|
||||||
|
@ -134,7 +134,7 @@ func (r *router) sendPacket(bs []byte) {
|
|||||||
copy(dest[:], bs[24:])
|
copy(dest[:], bs[24:])
|
||||||
copy(snet[:], bs[24:])
|
copy(snet[:], bs[24:])
|
||||||
if !dest.isValid() && !snet.isValid() {
|
if !dest.isValid() && !snet.isValid() {
|
||||||
if key, err := r.cryptokey.getPublicKeyForAddress(dest); err == nil {
|
if key, err := r.cryptokey.getPublicKeyForAddress(dest, 16); err == nil {
|
||||||
addr := *address_addrForNodeID(getNodeID(&key))
|
addr := *address_addrForNodeID(getNodeID(&key))
|
||||||
copy(dest[:], addr[:])
|
copy(dest[:], addr[:])
|
||||||
copy(snet[:], addr[:])
|
copy(snet[:], addr[:])
|
||||||
@ -273,7 +273,7 @@ func (r *router) recvPacket(bs []byte, sinfo *sessionInfo) {
|
|||||||
case source.isValid() && source == sinfo.theirAddr:
|
case source.isValid() && source == sinfo.theirAddr:
|
||||||
case snet.isValid() && snet == sinfo.theirSubnet:
|
case snet.isValid() && snet == sinfo.theirSubnet:
|
||||||
default:
|
default:
|
||||||
key, err := r.cryptokey.getPublicKeyForAddress(source)
|
key, err := r.cryptokey.getPublicKeyForAddress(source, 16)
|
||||||
if err != nil || key != sinfo.theirPermPub {
|
if err != nil || key != sinfo.theirPermPub {
|
||||||
util_putBytes(bs)
|
util_putBytes(bs)
|
||||||
return
|
return
|
||||||
|
Loading…
Reference in New Issue
Block a user