Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch most everything to netip in prep for ipv6 in the overlay #1173

Merged
merged 17 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 26 additions & 65 deletions allow_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,24 @@ package nebula

import (
"fmt"
"net"
"net/netip"
"regexp"

"github.com/slackhq/nebula/cidr"
"github.com/gaissmai/bart"
"github.com/slackhq/nebula/config"
"github.com/slackhq/nebula/iputil"
)

type AllowList struct {
// The values of this cidrTree are `bool`, signifying allow/deny
cidrTree *cidr.Tree6[bool]
cidrTree *bart.Table[bool]
}

type RemoteAllowList struct {
AllowList *AllowList

// Inside Range Specific, keys of this tree are inside CIDRs and values
// are *AllowList
insideAllowLists *cidr.Tree6[*AllowList]
insideAllowLists *bart.Table[*AllowList]
}

type LocalAllowList struct {
Expand Down Expand Up @@ -88,7 +87,7 @@ func newAllowList(k string, raw interface{}, handleKey func(key string, value in
return nil, fmt.Errorf("config `%s` has invalid type: %T", k, raw)
}

tree := cidr.NewTree6[bool]()
tree := new(bart.Table[bool])

// Keep track of the rules we have added for both ipv4 and ipv6
type allowListRules struct {
Expand Down Expand Up @@ -122,18 +121,20 @@ func newAllowList(k string, raw interface{}, handleKey func(key string, value in
return nil, fmt.Errorf("config `%s` has invalid value (type %T): %v", k, rawValue, rawValue)
}

_, ipNet, err := net.ParseCIDR(rawCIDR)
ipNet, err := netip.ParsePrefix(rawCIDR)
if err != nil {
return nil, fmt.Errorf("config `%s` has invalid CIDR: %s", k, rawCIDR)
return nil, fmt.Errorf("config `%s` has invalid CIDR: %s. %w", k, rawCIDR, err)
}

ipNet = netip.PrefixFrom(ipNet.Addr().Unmap(), ipNet.Bits())

// TODO: should we error on duplicate CIDRs in the config?
tree.AddCIDR(ipNet, value)
tree.Insert(ipNet, value)

maskBits, maskSize := ipNet.Mask.Size()
maskBits := ipNet.Bits()

var rules *allowListRules
if maskSize == 32 {
if ipNet.Addr().Is4() {
rules = &rules4
} else {
rules = &rules6
Expand All @@ -156,17 +157,15 @@ func newAllowList(k string, raw interface{}, handleKey func(key string, value in

if !rules4.defaultSet {
if rules4.allValuesMatch {
_, zeroCIDR, _ := net.ParseCIDR("0.0.0.0/0")
tree.AddCIDR(zeroCIDR, !rules4.allValues)
tree.Insert(netip.PrefixFrom(netip.IPv4Unspecified(), 0), !rules4.allValues)
} else {
return nil, fmt.Errorf("config `%s` contains both true and false rules, but no default set for 0.0.0.0/0", k)
}
}

if !rules6.defaultSet {
if rules6.allValuesMatch {
_, zeroCIDR, _ := net.ParseCIDR("::/0")
tree.AddCIDR(zeroCIDR, !rules6.allValues)
tree.Insert(netip.PrefixFrom(netip.IPv6Unspecified(), 0), !rules6.allValues)
} else {
return nil, fmt.Errorf("config `%s` contains both true and false rules, but no default set for ::/0", k)
}
Expand Down Expand Up @@ -218,13 +217,13 @@ func getAllowListInterfaces(k string, v interface{}) ([]AllowListNameRule, error
return nameRules, nil
}

func getRemoteAllowRanges(c *config.C, k string) (*cidr.Tree6[*AllowList], error) {
func getRemoteAllowRanges(c *config.C, k string) (*bart.Table[*AllowList], error) {
value := c.Get(k)
if value == nil {
return nil, nil
}

remoteAllowRanges := cidr.NewTree6[*AllowList]()
remoteAllowRanges := new(bart.Table[*AllowList])

rawMap, ok := value.(map[interface{}]interface{})
if !ok {
Expand All @@ -241,45 +240,27 @@ func getRemoteAllowRanges(c *config.C, k string) (*cidr.Tree6[*AllowList], error
return nil, err
}

_, ipNet, err := net.ParseCIDR(rawCIDR)
ipNet, err := netip.ParsePrefix(rawCIDR)
if err != nil {
return nil, fmt.Errorf("config `%s` has invalid CIDR: %s", k, rawCIDR)
return nil, fmt.Errorf("config `%s` has invalid CIDR: %s. %w", k, rawCIDR, err)
}

remoteAllowRanges.AddCIDR(ipNet, allowList)
remoteAllowRanges.Insert(netip.PrefixFrom(ipNet.Addr().Unmap(), ipNet.Bits()), allowList)
}

return remoteAllowRanges, nil
}

func (al *AllowList) Allow(ip net.IP) bool {
if al == nil {
return true
}

_, result := al.cidrTree.MostSpecificContains(ip)
return result
}

func (al *AllowList) AllowIpV4(ip iputil.VpnIp) bool {
if al == nil {
return true
}

_, result := al.cidrTree.MostSpecificContainsIpV4(ip)
return result
}

func (al *AllowList) AllowIpV6(hi, lo uint64) bool {
func (al *AllowList) Allow(ip netip.Addr) bool {
if al == nil {
return true
}

_, result := al.cidrTree.MostSpecificContainsIpV6(hi, lo)
result, _ := al.cidrTree.Lookup(ip)
return result
}

func (al *LocalAllowList) Allow(ip net.IP) bool {
func (al *LocalAllowList) Allow(ip netip.Addr) bool {
if al == nil {
return true
}
Expand All @@ -301,43 +282,23 @@ func (al *LocalAllowList) AllowName(name string) bool {
return !al.nameRules[0].Allow
}

func (al *RemoteAllowList) AllowUnknownVpnIp(ip net.IP) bool {
func (al *RemoteAllowList) AllowUnknownVpnIp(ip netip.Addr) bool {
if al == nil {
return true
}
return al.AllowList.Allow(ip)
}

func (al *RemoteAllowList) Allow(vpnIp iputil.VpnIp, ip net.IP) bool {
func (al *RemoteAllowList) Allow(vpnIp netip.Addr, ip netip.Addr) bool {
if !al.getInsideAllowList(vpnIp).Allow(ip) {
return false
}
return al.AllowList.Allow(ip)
}

func (al *RemoteAllowList) AllowIpV4(vpnIp iputil.VpnIp, ip iputil.VpnIp) bool {
if al == nil {
return true
}
if !al.getInsideAllowList(vpnIp).AllowIpV4(ip) {
return false
}
return al.AllowList.AllowIpV4(ip)
}

func (al *RemoteAllowList) AllowIpV6(vpnIp iputil.VpnIp, hi, lo uint64) bool {
if al == nil {
return true
}
if !al.getInsideAllowList(vpnIp).AllowIpV6(hi, lo) {
return false
}
return al.AllowList.AllowIpV6(hi, lo)
}

func (al *RemoteAllowList) getInsideAllowList(vpnIp iputil.VpnIp) *AllowList {
func (al *RemoteAllowList) getInsideAllowList(vpnIp netip.Addr) *AllowList {
if al.insideAllowLists != nil {
ok, inside := al.insideAllowLists.MostSpecificContainsIpV4(vpnIp)
inside, ok := al.insideAllowLists.Lookup(vpnIp)
if ok {
return inside
}
Expand Down
58 changes: 37 additions & 21 deletions allow_list_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package nebula

import (
"net"
"net/netip"
"regexp"
"testing"

"github.com/slackhq/nebula/cidr"
"github.com/gaissmai/bart"
"github.com/slackhq/nebula/config"
"github.com/slackhq/nebula/test"
"github.com/stretchr/testify/assert"
Expand All @@ -18,7 +18,7 @@ func TestNewAllowListFromConfig(t *testing.T) {
"192.168.0.0": true,
}
r, err := newAllowListFromConfig(c, "allowlist", nil)
assert.EqualError(t, err, "config `allowlist` has invalid CIDR: 192.168.0.0")
assert.EqualError(t, err, "config `allowlist` has invalid CIDR: 192.168.0.0. netip.ParsePrefix(\"192.168.0.0\"): no '/'")
assert.Nil(t, r)

c.Settings["allowlist"] = map[interface{}]interface{}{
Expand Down Expand Up @@ -98,26 +98,26 @@ func TestNewAllowListFromConfig(t *testing.T) {
}

func TestAllowList_Allow(t *testing.T) {
assert.Equal(t, true, ((*AllowList)(nil)).Allow(net.ParseIP("1.1.1.1")))

tree := cidr.NewTree6[bool]()
tree.AddCIDR(cidr.Parse("0.0.0.0/0"), true)
tree.AddCIDR(cidr.Parse("10.0.0.0/8"), false)
tree.AddCIDR(cidr.Parse("10.42.42.42/32"), true)
tree.AddCIDR(cidr.Parse("10.42.0.0/16"), true)
tree.AddCIDR(cidr.Parse("10.42.42.0/24"), true)
tree.AddCIDR(cidr.Parse("10.42.42.0/24"), false)
tree.AddCIDR(cidr.Parse("::1/128"), true)
tree.AddCIDR(cidr.Parse("::2/128"), false)
assert.Equal(t, true, ((*AllowList)(nil)).Allow(string2nip("1.1.1.1")))

tree := new(bart.Table[bool])
tree.Insert(string2prefix("0.0.0.0/0"), true)
tree.Insert(string2prefix("10.0.0.0/8"), false)
tree.Insert(string2prefix("10.42.42.42/32"), true)
tree.Insert(string2prefix("10.42.0.0/16"), true)
tree.Insert(string2prefix("10.42.42.0/24"), true)
tree.Insert(string2prefix("10.42.42.0/24"), false)
tree.Insert(string2prefix("::1/128"), true)
tree.Insert(string2prefix("::2/128"), false)
al := &AllowList{cidrTree: tree}

assert.Equal(t, true, al.Allow(net.ParseIP("1.1.1.1")))
assert.Equal(t, false, al.Allow(net.ParseIP("10.0.0.4")))
assert.Equal(t, true, al.Allow(net.ParseIP("10.42.42.42")))
assert.Equal(t, false, al.Allow(net.ParseIP("10.42.42.41")))
assert.Equal(t, true, al.Allow(net.ParseIP("10.42.0.1")))
assert.Equal(t, true, al.Allow(net.ParseIP("::1")))
assert.Equal(t, false, al.Allow(net.ParseIP("::2")))
assert.Equal(t, true, al.Allow(string2nip("1.1.1.1")))
assert.Equal(t, false, al.Allow(string2nip("10.0.0.4")))
assert.Equal(t, true, al.Allow(string2nip("10.42.42.42")))
assert.Equal(t, false, al.Allow(string2nip("10.42.42.41")))
assert.Equal(t, true, al.Allow(string2nip("10.42.0.1")))
assert.Equal(t, true, al.Allow(string2nip("::1")))
assert.Equal(t, false, al.Allow(string2nip("::2")))
}

func TestLocalAllowList_AllowName(t *testing.T) {
Expand All @@ -143,3 +143,19 @@ func TestLocalAllowList_AllowName(t *testing.T) {
assert.Equal(t, true, al.AllowName("eth0"))
assert.Equal(t, true, al.AllowName("ens5"))
}

func string2nip(s string) netip.Addr {
ip, err := netip.ParseAddr(s)
nbrownus marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
panic("string2nip: netip.ParseAddr failed? " + err.Error())
}
return ip
}

func string2prefix(s string) netip.Prefix {
ip, err := netip.ParsePrefix(s)
if err != nil {
panic("string2prefix: netip.ParsePrefix failed? " + err.Error())
}
return ip
}
Loading
Loading