github.com/slackhq/nebula@v1.9.0/allow_list.go (about)

     1  package nebula
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"regexp"
     7  
     8  	"github.com/slackhq/nebula/cidr"
     9  	"github.com/slackhq/nebula/config"
    10  	"github.com/slackhq/nebula/iputil"
    11  )
    12  
    13  type AllowList struct {
    14  	// The values of this cidrTree are `bool`, signifying allow/deny
    15  	cidrTree *cidr.Tree6[bool]
    16  }
    17  
    18  type RemoteAllowList struct {
    19  	AllowList *AllowList
    20  
    21  	// Inside Range Specific, keys of this tree are inside CIDRs and values
    22  	// are *AllowList
    23  	insideAllowLists *cidr.Tree6[*AllowList]
    24  }
    25  
    26  type LocalAllowList struct {
    27  	AllowList *AllowList
    28  
    29  	// To avoid ambiguity, all rules must be true, or all rules must be false.
    30  	nameRules []AllowListNameRule
    31  }
    32  
    33  type AllowListNameRule struct {
    34  	Name  *regexp.Regexp
    35  	Allow bool
    36  }
    37  
    38  func NewLocalAllowListFromConfig(c *config.C, k string) (*LocalAllowList, error) {
    39  	var nameRules []AllowListNameRule
    40  	handleKey := func(key string, value interface{}) (bool, error) {
    41  		if key == "interfaces" {
    42  			var err error
    43  			nameRules, err = getAllowListInterfaces(k, value)
    44  			if err != nil {
    45  				return false, err
    46  			}
    47  
    48  			return true, nil
    49  		}
    50  		return false, nil
    51  	}
    52  
    53  	al, err := newAllowListFromConfig(c, k, handleKey)
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  	return &LocalAllowList{AllowList: al, nameRules: nameRules}, nil
    58  }
    59  
    60  func NewRemoteAllowListFromConfig(c *config.C, k, rangesKey string) (*RemoteAllowList, error) {
    61  	al, err := newAllowListFromConfig(c, k, nil)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  	remoteAllowRanges, err := getRemoteAllowRanges(c, rangesKey)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  	return &RemoteAllowList{AllowList: al, insideAllowLists: remoteAllowRanges}, nil
    70  }
    71  
    72  // If the handleKey func returns true, the rest of the parsing is skipped
    73  // for this key. This allows parsing of special values like `interfaces`.
    74  func newAllowListFromConfig(c *config.C, k string, handleKey func(key string, value interface{}) (bool, error)) (*AllowList, error) {
    75  	r := c.Get(k)
    76  	if r == nil {
    77  		return nil, nil
    78  	}
    79  
    80  	return newAllowList(k, r, handleKey)
    81  }
    82  
    83  // If the handleKey func returns true, the rest of the parsing is skipped
    84  // for this key. This allows parsing of special values like `interfaces`.
    85  func newAllowList(k string, raw interface{}, handleKey func(key string, value interface{}) (bool, error)) (*AllowList, error) {
    86  	rawMap, ok := raw.(map[interface{}]interface{})
    87  	if !ok {
    88  		return nil, fmt.Errorf("config `%s` has invalid type: %T", k, raw)
    89  	}
    90  
    91  	tree := cidr.NewTree6[bool]()
    92  
    93  	// Keep track of the rules we have added for both ipv4 and ipv6
    94  	type allowListRules struct {
    95  		firstValue     bool
    96  		allValuesMatch bool
    97  		defaultSet     bool
    98  		allValues      bool
    99  	}
   100  
   101  	rules4 := allowListRules{firstValue: true, allValuesMatch: true, defaultSet: false}
   102  	rules6 := allowListRules{firstValue: true, allValuesMatch: true, defaultSet: false}
   103  
   104  	for rawKey, rawValue := range rawMap {
   105  		rawCIDR, ok := rawKey.(string)
   106  		if !ok {
   107  			return nil, fmt.Errorf("config `%s` has invalid key (type %T): %v", k, rawKey, rawKey)
   108  		}
   109  
   110  		if handleKey != nil {
   111  			handled, err := handleKey(rawCIDR, rawValue)
   112  			if err != nil {
   113  				return nil, err
   114  			}
   115  			if handled {
   116  				continue
   117  			}
   118  		}
   119  
   120  		value, ok := rawValue.(bool)
   121  		if !ok {
   122  			return nil, fmt.Errorf("config `%s` has invalid value (type %T): %v", k, rawValue, rawValue)
   123  		}
   124  
   125  		_, ipNet, err := net.ParseCIDR(rawCIDR)
   126  		if err != nil {
   127  			return nil, fmt.Errorf("config `%s` has invalid CIDR: %s", k, rawCIDR)
   128  		}
   129  
   130  		// TODO: should we error on duplicate CIDRs in the config?
   131  		tree.AddCIDR(ipNet, value)
   132  
   133  		maskBits, maskSize := ipNet.Mask.Size()
   134  
   135  		var rules *allowListRules
   136  		if maskSize == 32 {
   137  			rules = &rules4
   138  		} else {
   139  			rules = &rules6
   140  		}
   141  
   142  		if rules.firstValue {
   143  			rules.allValues = value
   144  			rules.firstValue = false
   145  		} else {
   146  			if value != rules.allValues {
   147  				rules.allValuesMatch = false
   148  			}
   149  		}
   150  
   151  		// Check if this is 0.0.0.0/0 or ::/0
   152  		if maskBits == 0 {
   153  			rules.defaultSet = true
   154  		}
   155  	}
   156  
   157  	if !rules4.defaultSet {
   158  		if rules4.allValuesMatch {
   159  			_, zeroCIDR, _ := net.ParseCIDR("0.0.0.0/0")
   160  			tree.AddCIDR(zeroCIDR, !rules4.allValues)
   161  		} else {
   162  			return nil, fmt.Errorf("config `%s` contains both true and false rules, but no default set for 0.0.0.0/0", k)
   163  		}
   164  	}
   165  
   166  	if !rules6.defaultSet {
   167  		if rules6.allValuesMatch {
   168  			_, zeroCIDR, _ := net.ParseCIDR("::/0")
   169  			tree.AddCIDR(zeroCIDR, !rules6.allValues)
   170  		} else {
   171  			return nil, fmt.Errorf("config `%s` contains both true and false rules, but no default set for ::/0", k)
   172  		}
   173  	}
   174  
   175  	return &AllowList{cidrTree: tree}, nil
   176  }
   177  
   178  func getAllowListInterfaces(k string, v interface{}) ([]AllowListNameRule, error) {
   179  	var nameRules []AllowListNameRule
   180  
   181  	rawRules, ok := v.(map[interface{}]interface{})
   182  	if !ok {
   183  		return nil, fmt.Errorf("config `%s.interfaces` is invalid (type %T): %v", k, v, v)
   184  	}
   185  
   186  	firstEntry := true
   187  	var allValues bool
   188  	for rawName, rawAllow := range rawRules {
   189  		name, ok := rawName.(string)
   190  		if !ok {
   191  			return nil, fmt.Errorf("config `%s.interfaces` has invalid key (type %T): %v", k, rawName, rawName)
   192  		}
   193  		allow, ok := rawAllow.(bool)
   194  		if !ok {
   195  			return nil, fmt.Errorf("config `%s.interfaces` has invalid value (type %T): %v", k, rawAllow, rawAllow)
   196  		}
   197  
   198  		nameRE, err := regexp.Compile("^" + name + "$")
   199  		if err != nil {
   200  			return nil, fmt.Errorf("config `%s.interfaces` has invalid key: %s: %v", k, name, err)
   201  		}
   202  
   203  		nameRules = append(nameRules, AllowListNameRule{
   204  			Name:  nameRE,
   205  			Allow: allow,
   206  		})
   207  
   208  		if firstEntry {
   209  			allValues = allow
   210  			firstEntry = false
   211  		} else {
   212  			if allow != allValues {
   213  				return nil, fmt.Errorf("config `%s.interfaces` values must all be the same true/false value", k)
   214  			}
   215  		}
   216  	}
   217  
   218  	return nameRules, nil
   219  }
   220  
   221  func getRemoteAllowRanges(c *config.C, k string) (*cidr.Tree6[*AllowList], error) {
   222  	value := c.Get(k)
   223  	if value == nil {
   224  		return nil, nil
   225  	}
   226  
   227  	remoteAllowRanges := cidr.NewTree6[*AllowList]()
   228  
   229  	rawMap, ok := value.(map[interface{}]interface{})
   230  	if !ok {
   231  		return nil, fmt.Errorf("config `%s` has invalid type: %T", k, value)
   232  	}
   233  	for rawKey, rawValue := range rawMap {
   234  		rawCIDR, ok := rawKey.(string)
   235  		if !ok {
   236  			return nil, fmt.Errorf("config `%s` has invalid key (type %T): %v", k, rawKey, rawKey)
   237  		}
   238  
   239  		allowList, err := newAllowList(fmt.Sprintf("%s.%s", k, rawCIDR), rawValue, nil)
   240  		if err != nil {
   241  			return nil, err
   242  		}
   243  
   244  		_, ipNet, err := net.ParseCIDR(rawCIDR)
   245  		if err != nil {
   246  			return nil, fmt.Errorf("config `%s` has invalid CIDR: %s", k, rawCIDR)
   247  		}
   248  
   249  		remoteAllowRanges.AddCIDR(ipNet, allowList)
   250  	}
   251  
   252  	return remoteAllowRanges, nil
   253  }
   254  
   255  func (al *AllowList) Allow(ip net.IP) bool {
   256  	if al == nil {
   257  		return true
   258  	}
   259  
   260  	_, result := al.cidrTree.MostSpecificContains(ip)
   261  	return result
   262  }
   263  
   264  func (al *AllowList) AllowIpV4(ip iputil.VpnIp) bool {
   265  	if al == nil {
   266  		return true
   267  	}
   268  
   269  	_, result := al.cidrTree.MostSpecificContainsIpV4(ip)
   270  	return result
   271  }
   272  
   273  func (al *AllowList) AllowIpV6(hi, lo uint64) bool {
   274  	if al == nil {
   275  		return true
   276  	}
   277  
   278  	_, result := al.cidrTree.MostSpecificContainsIpV6(hi, lo)
   279  	return result
   280  }
   281  
   282  func (al *LocalAllowList) Allow(ip net.IP) bool {
   283  	if al == nil {
   284  		return true
   285  	}
   286  	return al.AllowList.Allow(ip)
   287  }
   288  
   289  func (al *LocalAllowList) AllowName(name string) bool {
   290  	if al == nil || len(al.nameRules) == 0 {
   291  		return true
   292  	}
   293  
   294  	for _, rule := range al.nameRules {
   295  		if rule.Name.MatchString(name) {
   296  			return rule.Allow
   297  		}
   298  	}
   299  
   300  	// If no rules match, return the default, which is the inverse of the rules
   301  	return !al.nameRules[0].Allow
   302  }
   303  
   304  func (al *RemoteAllowList) AllowUnknownVpnIp(ip net.IP) bool {
   305  	if al == nil {
   306  		return true
   307  	}
   308  	return al.AllowList.Allow(ip)
   309  }
   310  
   311  func (al *RemoteAllowList) Allow(vpnIp iputil.VpnIp, ip net.IP) bool {
   312  	if !al.getInsideAllowList(vpnIp).Allow(ip) {
   313  		return false
   314  	}
   315  	return al.AllowList.Allow(ip)
   316  }
   317  
   318  func (al *RemoteAllowList) AllowIpV4(vpnIp iputil.VpnIp, ip iputil.VpnIp) bool {
   319  	if al == nil {
   320  		return true
   321  	}
   322  	if !al.getInsideAllowList(vpnIp).AllowIpV4(ip) {
   323  		return false
   324  	}
   325  	return al.AllowList.AllowIpV4(ip)
   326  }
   327  
   328  func (al *RemoteAllowList) AllowIpV6(vpnIp iputil.VpnIp, hi, lo uint64) bool {
   329  	if al == nil {
   330  		return true
   331  	}
   332  	if !al.getInsideAllowList(vpnIp).AllowIpV6(hi, lo) {
   333  		return false
   334  	}
   335  	return al.AllowList.AllowIpV6(hi, lo)
   336  }
   337  
   338  func (al *RemoteAllowList) getInsideAllowList(vpnIp iputil.VpnIp) *AllowList {
   339  	if al.insideAllowLists != nil {
   340  		ok, inside := al.insideAllowLists.MostSpecificContainsIpV4(vpnIp)
   341  		if ok {
   342  			return inside
   343  		}
   344  	}
   345  	return nil
   346  }