From 8c2327a2bf15e6388b03957983023b704b4266a1 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Mon, 5 Nov 2018 23:59:41 +0000 Subject: [PATCH] Add source addresses option and more intelligent source checking --- src/yggdrasil/ckr.go | 62 ++++++++++++++++++++++++++++++---- src/yggdrasil/config/config.go | 5 +-- src/yggdrasil/router.go | 9 ++--- 3 files changed, 64 insertions(+), 12 deletions(-) diff --git a/src/yggdrasil/ckr.go b/src/yggdrasil/ckr.go index 2b6c0d1f..96fde27e 100644 --- a/src/yggdrasil/ckr.go +++ b/src/yggdrasil/ckr.go @@ -12,12 +12,14 @@ import ( // allow traffic for non-Yggdrasil ranges to be routed over Yggdrasil. type cryptokey struct { - core *Core - enabled bool - ipv4routes []cryptokey_route - ipv6routes []cryptokey_route - ipv4cache map[address]cryptokey_route - ipv6cache map[address]cryptokey_route + core *Core + enabled bool + ipv4routes []cryptokey_route + ipv6routes []cryptokey_route + ipv4cache map[address]cryptokey_route + ipv6cache map[address]cryptokey_route + ipv4sources []net.IPNet + ipv6sources []net.IPNet } type cryptokey_route struct { @@ -31,12 +33,60 @@ func (c *cryptokey) init(core *Core) { c.ipv6routes = make([]cryptokey_route, 0) c.ipv4cache = make(map[address]cryptokey_route, 0) c.ipv6cache = make(map[address]cryptokey_route, 0) + c.ipv4sources = make([]net.IPNet, 0) + c.ipv6sources = make([]net.IPNet, 0) } func (c *cryptokey) isEnabled() bool { return c.enabled } +func (c *cryptokey) isValidSource(addr address) bool { + ip := net.IP(addr[:]) + + // Does this match our node's address? + if addr == c.core.router.addr { + return true + } + + // Does this match our node's subnet? + var subnet net.IPNet + copy(subnet.IP, c.core.router.subnet[:]) + copy(subnet.Mask, net.CIDRMask(64, 128)) + if subnet.Contains(ip) { + return true + } + + // Does it match a configured CKR source? + for _, subnet := range c.ipv6sources { + if subnet.Contains(ip) { + return true + } + } + + // Doesn't match any of the above + return false +} + +func (c *cryptokey) addSourceSubnet(cidr string) error { + // Is the CIDR we've been given valid? + _, ipnet, err := net.ParseCIDR(cidr) + if err != nil { + return err + } + + // Check if we already have this CIDR + for _, subnet := range c.ipv6sources { + if subnet.String() == ipnet.String() { + return errors.New("Source subnet already configured") + } + } + + // Add the source subnet + c.ipv6sources = append(c.ipv6sources, *ipnet) + return nil +} + func (c *cryptokey) addRoute(cidr string, dest string) error { // Is the CIDR we've been given valid? ipaddr, ipnet, err := net.ParseCIDR(cidr) diff --git a/src/yggdrasil/config/config.go b/src/yggdrasil/config/config.go index 6f1871fc..95947454 100644 --- a/src/yggdrasil/config/config.go +++ b/src/yggdrasil/config/config.go @@ -39,6 +39,7 @@ type SessionFirewall struct { // TunnelRouting contains the crypto-key routing tables for tunneling type TunnelRouting struct { - Enable bool `comment:"Enable or disable tunneling."` - IPv6Routes map[string]string `comment:"IPv6 subnets, mapped to the public keys to which they should be routed."` + Enable bool `comment:"Enable or disable tunneling."` + IPv6Routes map[string]string `comment:"IPv6 subnets, mapped to the public keys to which they should be routed."` + IPv6Sources []string `comment:"Allow source addresses in these subnets."` } diff --git a/src/yggdrasil/router.go b/src/yggdrasil/router.go index dcce7271..e3634640 100644 --- a/src/yggdrasil/router.go +++ b/src/yggdrasil/router.go @@ -34,6 +34,7 @@ import ( type router struct { core *Core addr address + subnet 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" recv chan<- []byte // place where the tun pulls received packets from @@ -47,6 +48,7 @@ type router struct { 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) in := make(chan []byte, 32) // TODO something better than this... p := r.core.peers.newPeer(&r.core.boxPub, &r.core.sigPub, &boxSharedKey{}, "(self)") p.out = func(packet []byte) { @@ -128,6 +130,9 @@ func (r *router) sendPacket(bs []byte) { var snet subnet copy(sourceAddr[:], bs[8:]) copy(sourceSubnet[:], bs[8:]) + if !r.cryptokey.isValidSource(sourceAddr) { + return + } copy(dest[:], bs[24:]) copy(snet[:], bs[24:]) if !dest.isValid() && !snet.isValid() { @@ -141,10 +146,6 @@ func (r *router) sendPacket(bs []byte) { } else { return } - } else { - if !sourceAddr.isValid() && !sourceSubnet.isValid() { - return - } } doSearch := func(packet []byte) { var nodeID, mask *NodeID