| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 | package nebulaimport (	"fmt"	"net"	"regexp"	"github.com/slackhq/nebula/cidr"	"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}type RemoteAllowList struct {	AllowList *AllowList	// Inside Range Specific, keys of this tree are inside CIDRs and values	// are *AllowList	insideAllowLists *cidr.Tree6}type LocalAllowList struct {	AllowList *AllowList	// To avoid ambiguity, all rules must be true, or all rules must be false.	nameRules []AllowListNameRule}type AllowListNameRule struct {	Name  *regexp.Regexp	Allow bool}func NewLocalAllowListFromConfig(c *config.C, k string) (*LocalAllowList, error) {	var nameRules []AllowListNameRule	handleKey := func(key string, value interface{}) (bool, error) {		if key == "interfaces" {			var err error			nameRules, err = getAllowListInterfaces(k, value)			if err != nil {				return false, err			}			return true, nil		}		return false, nil	}	al, err := newAllowListFromConfig(c, k, handleKey)	if err != nil {		return nil, err	}	return &LocalAllowList{AllowList: al, nameRules: nameRules}, nil}func NewRemoteAllowListFromConfig(c *config.C, k, rangesKey string) (*RemoteAllowList, error) {	al, err := newAllowListFromConfig(c, k, nil)	if err != nil {		return nil, err	}	remoteAllowRanges, err := getRemoteAllowRanges(c, rangesKey)	if err != nil {		return nil, err	}	return &RemoteAllowList{AllowList: al, insideAllowLists: remoteAllowRanges}, nil}// If the handleKey func returns true, the rest of the parsing is skipped// for this key. This allows parsing of special values like `interfaces`.func newAllowListFromConfig(c *config.C, k string, handleKey func(key string, value interface{}) (bool, error)) (*AllowList, error) {	r := c.Get(k)	if r == nil {		return nil, nil	}	return newAllowList(k, r, handleKey)}// If the handleKey func returns true, the rest of the parsing is skipped// for this key. This allows parsing of special values like `interfaces`.func newAllowList(k string, raw interface{}, handleKey func(key string, value interface{}) (bool, error)) (*AllowList, error) {	rawMap, ok := raw.(map[interface{}]interface{})	if !ok {		return nil, fmt.Errorf("config `%s` has invalid type: %T", k, raw)	}	tree := cidr.NewTree6()	// Keep track of the rules we have added for both ipv4 and ipv6	type allowListRules struct {		firstValue     bool		allValuesMatch bool		defaultSet     bool		allValues      bool	}	rules4 := allowListRules{firstValue: true, allValuesMatch: true, defaultSet: false}	rules6 := allowListRules{firstValue: true, allValuesMatch: true, defaultSet: false}	for rawKey, rawValue := range rawMap {		rawCIDR, ok := rawKey.(string)		if !ok {			return nil, fmt.Errorf("config `%s` has invalid key (type %T): %v", k, rawKey, rawKey)		}		if handleKey != nil {			handled, err := handleKey(rawCIDR, rawValue)			if err != nil {				return nil, err			}			if handled {				continue			}		}		value, ok := rawValue.(bool)		if !ok {			return nil, fmt.Errorf("config `%s` has invalid value (type %T): %v", k, rawValue, rawValue)		}		_, ipNet, err := net.ParseCIDR(rawCIDR)		if err != nil {			return nil, fmt.Errorf("config `%s` has invalid CIDR: %s", k, rawCIDR)		}		// TODO: should we error on duplicate CIDRs in the config?		tree.AddCIDR(ipNet, value)		maskBits, maskSize := ipNet.Mask.Size()		var rules *allowListRules		if maskSize == 32 {			rules = &rules4		} else {			rules = &rules6		}		if rules.firstValue {			rules.allValues = value			rules.firstValue = false		} else {			if value != rules.allValues {				rules.allValuesMatch = false			}		}		// Check if this is 0.0.0.0/0 or ::/0		if maskBits == 0 {			rules.defaultSet = true		}	}	if !rules4.defaultSet {		if rules4.allValuesMatch {			_, zeroCIDR, _ := net.ParseCIDR("0.0.0.0/0")			tree.AddCIDR(zeroCIDR, !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)		} else {			return nil, fmt.Errorf("config `%s` contains both true and false rules, but no default set for ::/0", k)		}	}	return &AllowList{cidrTree: tree}, nil}func getAllowListInterfaces(k string, v interface{}) ([]AllowListNameRule, error) {	var nameRules []AllowListNameRule	rawRules, ok := v.(map[interface{}]interface{})	if !ok {		return nil, fmt.Errorf("config `%s.interfaces` is invalid (type %T): %v", k, v, v)	}	firstEntry := true	var allValues bool	for rawName, rawAllow := range rawRules {		name, ok := rawName.(string)		if !ok {			return nil, fmt.Errorf("config `%s.interfaces` has invalid key (type %T): %v", k, rawName, rawName)		}		allow, ok := rawAllow.(bool)		if !ok {			return nil, fmt.Errorf("config `%s.interfaces` has invalid value (type %T): %v", k, rawAllow, rawAllow)		}		nameRE, err := regexp.Compile("^" + name + "$")		if err != nil {			return nil, fmt.Errorf("config `%s.interfaces` has invalid key: %s: %v", k, name, err)		}		nameRules = append(nameRules, AllowListNameRule{			Name:  nameRE,			Allow: allow,		})		if firstEntry {			allValues = allow			firstEntry = false		} else {			if allow != allValues {				return nil, fmt.Errorf("config `%s.interfaces` values must all be the same true/false value", k)			}		}	}	return nameRules, nil}func getRemoteAllowRanges(c *config.C, k string) (*cidr.Tree6, error) {	value := c.Get(k)	if value == nil {		return nil, nil	}	remoteAllowRanges := cidr.NewTree6()	rawMap, ok := value.(map[interface{}]interface{})	if !ok {		return nil, fmt.Errorf("config `%s` has invalid type: %T", k, value)	}	for rawKey, rawValue := range rawMap {		rawCIDR, ok := rawKey.(string)		if !ok {			return nil, fmt.Errorf("config `%s` has invalid key (type %T): %v", k, rawKey, rawKey)		}		allowList, err := newAllowList(fmt.Sprintf("%s.%s", k, rawCIDR), rawValue, nil)		if err != nil {			return nil, err		}		_, ipNet, err := net.ParseCIDR(rawCIDR)		if err != nil {			return nil, fmt.Errorf("config `%s` has invalid CIDR: %s", k, rawCIDR)		}		remoteAllowRanges.AddCIDR(ipNet, allowList)	}	return remoteAllowRanges, nil}func (al *AllowList) Allow(ip net.IP) bool {	if al == nil {		return true	}	result := al.cidrTree.MostSpecificContains(ip)	switch v := result.(type) {	case bool:		return v	default:		panic(fmt.Errorf("invalid state, allowlist returned: %T %v", result, result))	}}func (al *AllowList) AllowIpV4(ip iputil.VpnIp) bool {	if al == nil {		return true	}	result := al.cidrTree.MostSpecificContainsIpV4(ip)	switch v := result.(type) {	case bool:		return v	default:		panic(fmt.Errorf("invalid state, allowlist returned: %T %v", result, result))	}}func (al *AllowList) AllowIpV6(hi, lo uint64) bool {	if al == nil {		return true	}	result := al.cidrTree.MostSpecificContainsIpV6(hi, lo)	switch v := result.(type) {	case bool:		return v	default:		panic(fmt.Errorf("invalid state, allowlist returned: %T %v", result, result))	}}func (al *LocalAllowList) Allow(ip net.IP) bool {	if al == nil {		return true	}	return al.AllowList.Allow(ip)}func (al *LocalAllowList) AllowName(name string) bool {	if al == nil || len(al.nameRules) == 0 {		return true	}	for _, rule := range al.nameRules {		if rule.Name.MatchString(name) {			return rule.Allow		}	}	// If no rules match, return the default, which is the inverse of the rules	return !al.nameRules[0].Allow}func (al *RemoteAllowList) AllowUnknownVpnIp(ip net.IP) bool {	if al == nil {		return true	}	return al.AllowList.Allow(ip)}func (al *RemoteAllowList) Allow(vpnIp iputil.VpnIp, ip net.IP) 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 {	if al.insideAllowLists != nil {		inside := al.insideAllowLists.MostSpecificContainsIpV4(vpnIp)		if inside != nil {			return inside.(*AllowList)		}	}	return nil}
 |