move ckr checks into the tunConn code

This commit is contained in:
Arceliar 2019-08-20 18:10:08 -05:00
parent b79829c43b
commit 4156aa3003
3 changed files with 123 additions and 118 deletions

View File

@ -132,23 +132,9 @@ func (c *cryptokey) isEnabled() bool {
func (c *cryptokey) isValidLocalAddress(addr address.Address, addrlen int) bool { func (c *cryptokey) isValidLocalAddress(addr address.Address, addrlen int) bool {
c.mutexlocals.RLock() c.mutexlocals.RLock()
defer c.mutexlocals.RUnlock() 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? // Does it match a configured CKR source?
if c.isEnabled() { if c.isEnabled() {
ip := net.IP(addr[:addrlen])
// Build our references to the routing sources // Build our references to the routing sources
var routingsources *[]net.IPNet var routingsources *[]net.IPNet

View File

@ -6,6 +6,7 @@ import (
"time" "time"
"github.com/yggdrasil-network/yggdrasil-go/src/address" "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/util"
"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil" "github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
"golang.org/x/net/icmp" "golang.org/x/net/icmp"
@ -71,16 +72,62 @@ func (s *tunConn) reader() (err error) {
return e return e
} }
} else if len(bs) > 0 { } else if len(bs) > 0 {
if bs[0]&0xf0 == 0x60 { ipv4 := len(bs) > 20 && bs[0]&0xf0 == 0x40
ipv6 := len(bs) > 40 && bs[0]&0xf0 == 0x60
isCGA := true
// Check source addresses
switch { switch {
case bs[8] == 0x02 && !bytes.Equal(s.addr[:16], bs[8:24]): // source case ipv6 && 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 ipv6 && 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 default:
case bs[24] == 0x03 && !bytes.Equal(s.tun.subnet[:8], bs[24:32]): // destination 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) util.PutBytes(bs)
continue continue
default:
}
} }
s.tun.send <- bs s.tun.send <- bs
s.stillAlive() s.stillAlive()
@ -108,15 +155,62 @@ func (s *tunConn) writer() error {
if !ok { if !ok {
return errors.New("send closed") return errors.New("send closed")
} }
if bs[0]&0xf0 == 0x60 { v4 := len(bs) > 20 && bs[0]&0xf0 == 0x40
v6 := len(bs) > 40 && bs[0]&0xf0 == 0x60
isCGA := true
// Check source addresses
switch { switch {
case bs[8] == 0x02 && !bytes.Equal(s.tun.addr[:16], bs[8:24]): // source case v6 && 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 v6 && 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: 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{ msg := yggdrasil.FlowKeyMessage{
FlowKey: util.GetFlowKey(bs), FlowKey: util.GetFlowKey(bs),

View File

@ -2,7 +2,6 @@ package tuntap
import ( import (
"bytes" "bytes"
"errors"
"net" "net"
"time" "time"
@ -21,62 +20,6 @@ func (tun *TunAdapter) writer() error {
if n == 0 { if n == 0 {
continue 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() { if tun.iface.IsTAP() {
sendndp := func(dstAddr address.Address) { sendndp := func(dstAddr address.Address) {
neigh, known := tun.icmpv6.getNeighbor(dstAddr) neigh, known := tun.icmpv6.getNeighbor(dstAddr)
@ -86,6 +29,7 @@ func (tun *TunAdapter) writer() error {
} }
} }
peermac := net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00} peermac := net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
var dstAddr address.Address
var peerknown bool var peerknown bool
if b[0]&0xf0 == 0x40 { if b[0]&0xf0 == 0x40 {
dstAddr = tun.addr 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 // 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 // and node IDs are. We will need these in order to work out where to send
// the packet // the packet
var srcAddr address.Address
var dstAddr address.Address var dstAddr address.Address
var dstNodeID *crypto.NodeID
var dstNodeIDMask *crypto.NodeID
var dstSnet address.Subnet var dstSnet address.Subnet
var addrlen int var addrlen int
n := len(bs) n := len(bs)
@ -203,7 +144,6 @@ func (tun *TunAdapter) readerPacketHandler(ch chan []byte) {
} }
// IPv6 address // IPv6 address
addrlen = 16 addrlen = 16
copy(srcAddr[:addrlen], bs[8:])
copy(dstAddr[:addrlen], bs[24:]) copy(dstAddr[:addrlen], bs[24:])
copy(dstSnet[:addrlen/2], bs[24:]) copy(dstSnet[:addrlen/2], bs[24:])
} else if bs[0]&0xf0 == 0x40 { } else if bs[0]&0xf0 == 0x40 {
@ -217,7 +157,6 @@ func (tun *TunAdapter) readerPacketHandler(ch chan []byte) {
} }
// IPv4 address // IPv4 address
addrlen = 4 addrlen = 4
copy(srcAddr[:addrlen], bs[12:])
copy(dstAddr[:addrlen], bs[16:]) copy(dstAddr[:addrlen], bs[16:])
} else { } else {
// Unknown address length or protocol, so drop the packet and ignore it // Unknown address length or protocol, so drop the packet and ignore it
@ -225,36 +164,22 @@ func (tun *TunAdapter) readerPacketHandler(ch chan []byte) {
continue continue
} }
if tun.ckr.isEnabled() { if tun.ckr.isEnabled() {
if !tun.ckr.isValidLocalAddress(srcAddr, addrlen) { if addrlen != 16 || (!dstAddr.IsValid() && !dstSnet.IsValid()) {
continue
}
if !dstAddr.IsValid() && !dstSnet.IsValid() {
if key, err := tun.ckr.getPublicKeyForAddress(dstAddr, addrlen); err == nil { if key, err := tun.ckr.getPublicKeyForAddress(dstAddr, addrlen); err == nil {
// A public key was found, get the node ID for the search // A public key was found, get the node ID for the search
dstNodeID = crypto.GetNodeID(&key) dstNodeID := crypto.GetNodeID(&key)
// Do a quick check to ensure that the node ID refers to a vaild dstAddr = *address.AddrForNodeID(dstNodeID)
// Yggdrasil address or subnet - this might be superfluous dstSnet = *address.SubnetForNodeID(dstNodeID)
addr := *address.AddrForNodeID(dstNodeID) addrlen = 16
copy(dstAddr[:], addr[:]) }
copy(dstSnet[:], addr[:]) }
// Are we certain we looked up a valid node? }
if !dstAddr.IsValid() && !dstSnet.IsValid() { if addrlen != 16 || (!dstAddr.IsValid() && !dstSnet.IsValid()) {
// Couldn't find this node's ygg IP
continue continue
} }
} else {
// No public key was found in the CKR table so we've exhausted our options
continue
}
}
} else {
if addrlen != 16 {
continue
}
if !dstAddr.IsValid() && !dstSnet.IsValid() {
continue
}
}
// Do we have an active connection for this node address? // Do we have an active connection for this node address?
var dstNodeID, dstNodeIDMask *crypto.NodeID
tun.mutex.RLock() tun.mutex.RLock()
session, isIn := tun.addrToConn[dstAddr] session, isIn := tun.addrToConn[dstAddr]
if !isIn || session == nil { if !isIn || session == nil {