From 4156aa30034f50f848725627dcf42cbdb6ef53bd Mon Sep 17 00:00:00 2001 From: Arceliar Date: Tue, 20 Aug 2019 18:10:08 -0500 Subject: [PATCH] move ckr checks into the tunConn code --- src/tuntap/ckr.go | 16 +----- src/tuntap/conn.go | 128 ++++++++++++++++++++++++++++++++++++++------ src/tuntap/iface.go | 97 ++++----------------------------- 3 files changed, 123 insertions(+), 118 deletions(-) diff --git a/src/tuntap/ckr.go b/src/tuntap/ckr.go index 9ce0120..ad8c89d 100644 --- a/src/tuntap/ckr.go +++ b/src/tuntap/ckr.go @@ -132,23 +132,9 @@ func (c *cryptokey) isEnabled() bool { func (c *cryptokey) isValidLocalAddress(addr address.Address, addrlen int) bool { c.mutexlocals.RLock() defer c.mutexlocals.RUnlock() - - ip := net.IP(addr[:addrlen]) - - if addrlen == net.IPv6len { - // Does this match our node's address? - if bytes.Equal(addr[:16], c.tun.addr[:16]) { - return true - } - - // Does this match our node's subnet? - if bytes.Equal(addr[:8], c.tun.subnet[:8]) { - return true - } - } - // Does it match a configured CKR source? if c.isEnabled() { + ip := net.IP(addr[:addrlen]) // Build our references to the routing sources var routingsources *[]net.IPNet diff --git a/src/tuntap/conn.go b/src/tuntap/conn.go index d1dc60d..3fb7a54 100644 --- a/src/tuntap/conn.go +++ b/src/tuntap/conn.go @@ -6,6 +6,7 @@ import ( "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" "github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil" "golang.org/x/net/icmp" @@ -71,16 +72,62 @@ func (s *tunConn) reader() (err error) { return e } } else if len(bs) > 0 { - if bs[0]&0xf0 == 0x60 { - switch { - case bs[8] == 0x02 && !bytes.Equal(s.addr[:16], bs[8:24]): // source - case bs[8] == 0x03 && !bytes.Equal(s.snet[:8], bs[8:16]): // source - case bs[24] == 0x02 && !bytes.Equal(s.tun.addr[:16], bs[24:40]): // destination - case bs[24] == 0x03 && !bytes.Equal(s.tun.subnet[:8], bs[24:32]): // destination - util.PutBytes(bs) - continue - default: + ipv4 := len(bs) > 20 && bs[0]&0xf0 == 0x40 + ipv6 := len(bs) > 40 && bs[0]&0xf0 == 0x60 + isCGA := true + // Check source addresses + switch { + case ipv6 && bs[8] == 0x02 && bytes.Equal(s.addr[:16], bs[8:24]): // source + case ipv6 && bs[8] == 0x03 && bytes.Equal(s.snet[:8], bs[8:16]): // source + default: + isCGA = false + } + // Check destiantion addresses + switch { + case ipv6 && bs[24] == 0x02 && bytes.Equal(s.tun.addr[:16], bs[24:40]): // destination + case ipv6 && bs[24] == 0x03 && bytes.Equal(s.tun.subnet[:8], bs[24:32]): // destination + default: + isCGA = false + } + // Decide how to handle the packet + var skip bool + switch { + case isCGA: // Allowed + case s.tun.ckr.isEnabled() && (ipv4 || ipv6): + var srcAddr address.Address + var dstAddr address.Address + var addrlen int + if ipv4 { + copy(srcAddr[:], bs[12:16]) + copy(dstAddr[:], bs[16:20]) + addrlen = 4 } + if ipv6 { + copy(srcAddr[:], bs[8:24]) + copy(dstAddr[:], bs[24:40]) + addrlen = 16 + } + if !s.tun.ckr.isValidLocalAddress(dstAddr, addrlen) { + // The destination address isn't in our CKR allowed range + skip = true + } else if key, err := s.tun.ckr.getPublicKeyForAddress(srcAddr, addrlen); err == nil { + srcNodeID := crypto.GetNodeID(&key) + if s.conn.RemoteAddr() == *srcNodeID { + // This is the one allowed CKR case, where source and destination addresses are both good + } else { + // The CKR key associated with this address doesn't match the sender's NodeID + skip = true + } + } else { + // We have no CKR route for this source address + skip = true + } + default: + skip = true + } + if skip { + util.PutBytes(bs) + continue } s.tun.send <- bs s.stillAlive() @@ -108,15 +155,62 @@ func (s *tunConn) writer() error { if !ok { return errors.New("send closed") } - if bs[0]&0xf0 == 0x60 { - switch { - case bs[8] == 0x02 && !bytes.Equal(s.tun.addr[:16], bs[8:24]): // source - case bs[8] == 0x03 && !bytes.Equal(s.tun.subnet[:8], bs[8:16]): // source - case bs[24] == 0x02 && !bytes.Equal(s.addr[:16], bs[24:40]): // destination - case bs[24] == 0x03 && !bytes.Equal(s.snet[:8], bs[24:32]): // destination - continue - default: + v4 := len(bs) > 20 && bs[0]&0xf0 == 0x40 + v6 := len(bs) > 40 && bs[0]&0xf0 == 0x60 + isCGA := true + // Check source addresses + switch { + case v6 && bs[8] == 0x02 && bytes.Equal(s.tun.addr[:16], bs[8:24]): // source + case v6 && bs[8] == 0x03 && bytes.Equal(s.tun.subnet[:8], bs[8:16]): // source + default: + isCGA = false + } + // Check destiantion addresses + switch { + case v6 && bs[24] == 0x02 && bytes.Equal(s.addr[:16], bs[24:40]): // destination + case v6 && bs[24] == 0x03 && bytes.Equal(s.snet[:8], bs[24:32]): // destination + default: + isCGA = false + } + // Decide how to handle the packet + var skip bool + switch { + case isCGA: // Allowed + case s.tun.ckr.isEnabled() && (v4 || v6): + var srcAddr address.Address + var dstAddr address.Address + var addrlen int + if v4 { + copy(srcAddr[:], bs[12:16]) + copy(dstAddr[:], bs[16:20]) + addrlen = 4 } + if v6 { + copy(srcAddr[:], bs[8:24]) + copy(dstAddr[:], bs[24:40]) + addrlen = 16 + } + if !s.tun.ckr.isValidLocalAddress(srcAddr, addrlen) { + // The source address isn't in our CKR allowed range + skip = true + } else if key, err := s.tun.ckr.getPublicKeyForAddress(dstAddr, addrlen); err == nil { + dstNodeID := crypto.GetNodeID(&key) + if s.conn.RemoteAddr() == *dstNodeID { + // This is the one allowed CKR case, where source and destination addresses are both good + } else { + // The CKR key associated with this address doesn't match the sender's NodeID + skip = true + } + } else { + // We have no CKR route for this destination address... why do we have the packet in the first place? + skip = true + } + default: + skip = true + } + if skip { + util.PutBytes(bs) + continue } msg := yggdrasil.FlowKeyMessage{ FlowKey: util.GetFlowKey(bs), diff --git a/src/tuntap/iface.go b/src/tuntap/iface.go index f5b8813..35657a9 100644 --- a/src/tuntap/iface.go +++ b/src/tuntap/iface.go @@ -2,7 +2,6 @@ package tuntap import ( "bytes" - "errors" "net" "time" @@ -21,62 +20,6 @@ func (tun *TunAdapter) writer() error { if n == 0 { continue } - var srcAddr address.Address - var dstAddr address.Address - var addrlen int - // Check whether the packet is IPv4, IPv6 or neither - if b[0]&0xf0 == 0x60 { - // IPv6 packet found - if len(b) < 40 { - // Packet was too short - util.PutBytes(b) - continue - } - // Extract the IPv6 addresses - copy(srcAddr[:16], b[8:24]) - copy(dstAddr[:16], b[24:40]) - addrlen = 16 - } else if b[0]&0xf0 == 0x40 { - // IPv4 packet found - if len(b) < 20 { - // Packet was too short - util.PutBytes(b) - continue - } - // Extract the IPv4 addresses - copy(srcAddr[:4], b[12:16]) - copy(dstAddr[:4], b[16:20]) - addrlen = 4 - } else { - // Neither IPv4 nor IPv6 - return errors.New("Invalid address family") - } - // Check the crypto-key routing rules next - if tun.ckr.isEnabled() { - if !tun.ckr.isValidLocalAddress(dstAddr, addrlen) { - util.PutBytes(b) - continue - } - if srcAddr[0] != 0x02 && srcAddr[0] != 0x03 { - // TODO: is this check useful? this doesn't actually guarantee that the - // packet came from the configured public key for that remote, just that - // it came from *a* configured remote. at this stage we have no ability - // to know which Conn or public key was involved - if _, err := tun.ckr.getPublicKeyForAddress(srcAddr, addrlen); err != nil { - util.PutBytes(b) - continue - } - } - } else { - if addrlen != 16 { - util.PutBytes(b) - continue - } - if !bytes.Equal(tun.addr[:16], dstAddr[:16]) && !bytes.Equal(tun.subnet[:8], dstAddr[:8]) { - util.PutBytes(b) - continue - } - } if tun.iface.IsTAP() { sendndp := func(dstAddr address.Address) { neigh, known := tun.icmpv6.getNeighbor(dstAddr) @@ -86,6 +29,7 @@ func (tun *TunAdapter) writer() error { } } peermac := net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + var dstAddr address.Address var peerknown bool if b[0]&0xf0 == 0x40 { dstAddr = tun.addr @@ -183,10 +127,7 @@ func (tun *TunAdapter) readerPacketHandler(ch chan []byte) { // From the IP header, work out what our source and destination addresses // and node IDs are. We will need these in order to work out where to send // the packet - var srcAddr address.Address var dstAddr address.Address - var dstNodeID *crypto.NodeID - var dstNodeIDMask *crypto.NodeID var dstSnet address.Subnet var addrlen int n := len(bs) @@ -203,7 +144,6 @@ func (tun *TunAdapter) readerPacketHandler(ch chan []byte) { } // IPv6 address addrlen = 16 - copy(srcAddr[:addrlen], bs[8:]) copy(dstAddr[:addrlen], bs[24:]) copy(dstSnet[:addrlen/2], bs[24:]) } else if bs[0]&0xf0 == 0x40 { @@ -217,7 +157,6 @@ func (tun *TunAdapter) readerPacketHandler(ch chan []byte) { } // IPv4 address addrlen = 4 - copy(srcAddr[:addrlen], bs[12:]) copy(dstAddr[:addrlen], bs[16:]) } else { // Unknown address length or protocol, so drop the packet and ignore it @@ -225,36 +164,22 @@ func (tun *TunAdapter) readerPacketHandler(ch chan []byte) { continue } if tun.ckr.isEnabled() { - if !tun.ckr.isValidLocalAddress(srcAddr, addrlen) { - continue - } - if !dstAddr.IsValid() && !dstSnet.IsValid() { + if addrlen != 16 || (!dstAddr.IsValid() && !dstSnet.IsValid()) { if key, err := tun.ckr.getPublicKeyForAddress(dstAddr, addrlen); err == nil { // A public key was found, get the node ID for the search - dstNodeID = crypto.GetNodeID(&key) - // 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(dstNodeID) - copy(dstAddr[:], addr[:]) - copy(dstSnet[:], addr[:]) - // Are we certain we looked up a valid node? - if !dstAddr.IsValid() && !dstSnet.IsValid() { - continue - } - } else { - // No public key was found in the CKR table so we've exhausted our options - continue + dstNodeID := crypto.GetNodeID(&key) + dstAddr = *address.AddrForNodeID(dstNodeID) + dstSnet = *address.SubnetForNodeID(dstNodeID) + addrlen = 16 } } - } else { - if addrlen != 16 { - continue - } - if !dstAddr.IsValid() && !dstSnet.IsValid() { - continue - } + } + if addrlen != 16 || (!dstAddr.IsValid() && !dstSnet.IsValid()) { + // Couldn't find this node's ygg IP + continue } // Do we have an active connection for this node address? + var dstNodeID, dstNodeIDMask *crypto.NodeID tun.mutex.RLock() session, isIn := tun.addrToConn[dstAddr] if !isIn || session == nil {