Redo route code (#2422)
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
This commit is contained in:
parent
16868190c8
commit
7891378f57
53 changed files with 2977 additions and 6251 deletions
|
@ -243,6 +243,7 @@ func (pol *ACLPolicy) CompileFilterRules(
|
|||
// ReduceFilterRules takes a node and a set of rules and removes all rules and destinations
|
||||
// that are not relevant to that particular node.
|
||||
func ReduceFilterRules(node *types.Node, rules []tailcfg.FilterRule) []tailcfg.FilterRule {
|
||||
// TODO(kradalby): Make this nil and not alloc unless needed
|
||||
ret := []tailcfg.FilterRule{}
|
||||
|
||||
for _, rule := range rules {
|
||||
|
@ -264,13 +265,11 @@ func ReduceFilterRules(node *types.Node, rules []tailcfg.FilterRule) []tailcfg.F
|
|||
|
||||
// If the node exposes routes, ensure they are note removed
|
||||
// when the filters are reduced.
|
||||
if node.Hostinfo != nil {
|
||||
if len(node.Hostinfo.RoutableIPs) > 0 {
|
||||
for _, routableIP := range node.Hostinfo.RoutableIPs {
|
||||
if expanded.OverlapsPrefix(routableIP) {
|
||||
dests = append(dests, dest)
|
||||
continue DEST_LOOP
|
||||
}
|
||||
if len(node.SubnetRoutes()) > 0 {
|
||||
for _, routableIP := range node.SubnetRoutes() {
|
||||
if expanded.OverlapsPrefix(routableIP) {
|
||||
dests = append(dests, dest)
|
||||
continue DEST_LOOP
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2165,6 +2165,9 @@ func TestReduceFilterRules(t *testing.T) {
|
|||
netip.MustParsePrefix("10.33.0.0/16"),
|
||||
},
|
||||
},
|
||||
ApprovedRoutes: []netip.Prefix{
|
||||
netip.MustParsePrefix("10.33.0.0/16"),
|
||||
},
|
||||
},
|
||||
peers: types.Nodes{
|
||||
&types.Node{
|
||||
|
@ -2292,6 +2295,7 @@ func TestReduceFilterRules(t *testing.T) {
|
|||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: tsaddr.ExitRoutes(),
|
||||
},
|
||||
ApprovedRoutes: tsaddr.ExitRoutes(),
|
||||
},
|
||||
peers: types.Nodes{
|
||||
&types.Node{
|
||||
|
@ -2398,6 +2402,7 @@ func TestReduceFilterRules(t *testing.T) {
|
|||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: tsaddr.ExitRoutes(),
|
||||
},
|
||||
ApprovedRoutes: tsaddr.ExitRoutes(),
|
||||
},
|
||||
peers: types.Nodes{
|
||||
&types.Node{
|
||||
|
@ -2513,6 +2518,10 @@ func TestReduceFilterRules(t *testing.T) {
|
|||
netip.MustParsePrefix("16.0.0.0/16"),
|
||||
},
|
||||
},
|
||||
ApprovedRoutes: []netip.Prefix{
|
||||
netip.MustParsePrefix("8.0.0.0/16"),
|
||||
netip.MustParsePrefix("16.0.0.0/16"),
|
||||
},
|
||||
},
|
||||
peers: types.Nodes{
|
||||
&types.Node{
|
||||
|
@ -2603,6 +2612,10 @@ func TestReduceFilterRules(t *testing.T) {
|
|||
netip.MustParsePrefix("16.0.0.0/8"),
|
||||
},
|
||||
},
|
||||
ApprovedRoutes: []netip.Prefix{
|
||||
netip.MustParsePrefix("8.0.0.0/8"),
|
||||
netip.MustParsePrefix("16.0.0.0/8"),
|
||||
},
|
||||
},
|
||||
peers: types.Nodes{
|
||||
&types.Node{
|
||||
|
@ -2683,7 +2696,8 @@ func TestReduceFilterRules(t *testing.T) {
|
|||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("172.16.0.0/24")},
|
||||
},
|
||||
ForcedTags: []string{"tag:access-servers"},
|
||||
ApprovedRoutes: []netip.Prefix{netip.MustParsePrefix("172.16.0.0/24")},
|
||||
ForcedTags: []string{"tag:access-servers"},
|
||||
},
|
||||
peers: types.Nodes{
|
||||
&types.Node{
|
||||
|
@ -3475,14 +3489,10 @@ func Test_getFilteredByACLPeers(t *testing.T) {
|
|||
IPv4: iap("100.64.0.2"),
|
||||
Hostname: "router",
|
||||
User: types.User{Name: "router"},
|
||||
Routes: types.Routes{
|
||||
types.Route{
|
||||
NodeID: 2,
|
||||
Prefix: netip.MustParsePrefix("10.33.0.0/16"),
|
||||
IsPrimary: true,
|
||||
Enabled: true,
|
||||
},
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("10.33.0.0/16")},
|
||||
},
|
||||
ApprovedRoutes: []netip.Prefix{netip.MustParsePrefix("10.33.0.0/16")},
|
||||
},
|
||||
},
|
||||
rules: []tailcfg.FilterRule{
|
||||
|
@ -3508,14 +3518,10 @@ func Test_getFilteredByACLPeers(t *testing.T) {
|
|||
IPv4: iap("100.64.0.2"),
|
||||
Hostname: "router",
|
||||
User: types.User{Name: "router"},
|
||||
Routes: types.Routes{
|
||||
types.Route{
|
||||
NodeID: 2,
|
||||
Prefix: netip.MustParsePrefix("10.33.0.0/16"),
|
||||
IsPrimary: true,
|
||||
Enabled: true,
|
||||
},
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("10.33.0.0/16")},
|
||||
},
|
||||
ApprovedRoutes: []netip.Prefix{netip.MustParsePrefix("10.33.0.0/16")},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -9,8 +9,8 @@ import (
|
|||
)
|
||||
|
||||
type Match struct {
|
||||
Srcs *netipx.IPSet
|
||||
Dests *netipx.IPSet
|
||||
srcs *netipx.IPSet
|
||||
dests *netipx.IPSet
|
||||
}
|
||||
|
||||
func MatchFromFilterRule(rule tailcfg.FilterRule) Match {
|
||||
|
@ -42,16 +42,16 @@ func MatchFromStrings(sources, destinations []string) Match {
|
|||
destsSet, _ := dests.IPSet()
|
||||
|
||||
match := Match{
|
||||
Srcs: srcsSet,
|
||||
Dests: destsSet,
|
||||
srcs: srcsSet,
|
||||
dests: destsSet,
|
||||
}
|
||||
|
||||
return match
|
||||
}
|
||||
|
||||
func (m *Match) SrcsContainsIPs(ips []netip.Addr) bool {
|
||||
func (m *Match) SrcsContainsIPs(ips ...netip.Addr) bool {
|
||||
for _, ip := range ips {
|
||||
if m.Srcs.Contains(ip) {
|
||||
if m.srcs.Contains(ip) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -59,9 +59,29 @@ func (m *Match) SrcsContainsIPs(ips []netip.Addr) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (m *Match) DestsContainsIP(ips []netip.Addr) bool {
|
||||
func (m *Match) DestsContainsIP(ips ...netip.Addr) bool {
|
||||
for _, ip := range ips {
|
||||
if m.Dests.Contains(ip) {
|
||||
if m.dests.Contains(ip) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *Match) SrcsOverlapsPrefixes(prefixes ...netip.Prefix) bool {
|
||||
for _, prefix := range prefixes {
|
||||
if m.srcs.ContainsPrefix(prefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *Match) DestsOverlapsPrefixes(prefixes ...netip.Prefix) bool {
|
||||
for _, prefix := range prefixes {
|
||||
if m.dests.ContainsPrefix(prefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,9 @@ type PolicyManager interface {
|
|||
SetPolicy([]byte) (bool, error)
|
||||
SetUsers(users []types.User) (bool, error)
|
||||
SetNodes(nodes types.Nodes) (bool, error)
|
||||
|
||||
// NodeCanApproveRoute reports whether the given node can approve the given route.
|
||||
NodeCanApproveRoute(*types.Node, netip.Prefix) bool
|
||||
}
|
||||
|
||||
func NewPolicyManagerFromPath(path string, users []types.User, nodes types.Nodes) (PolicyManager, error) {
|
||||
|
@ -185,3 +188,32 @@ func (pm *PolicyManagerV1) ExpandAlias(alias string) (*netipx.IPSet, error) {
|
|||
}
|
||||
return ips, nil
|
||||
}
|
||||
|
||||
func (pm *PolicyManagerV1) NodeCanApproveRoute(node *types.Node, route netip.Prefix) bool {
|
||||
if pm.pol == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
pm.mu.Lock()
|
||||
defer pm.mu.Unlock()
|
||||
|
||||
approvers, _ := pm.pol.AutoApprovers.GetRouteApprovers(route)
|
||||
|
||||
for _, approvedAlias := range approvers {
|
||||
if approvedAlias == node.User.Username() {
|
||||
return true
|
||||
} else {
|
||||
ips, err := pm.pol.ExpandAlias(pm.nodes, pm.users, approvedAlias)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// approvedIPs should contain all of node's IPs if it matches the rule, so check for first
|
||||
if ips.Contains(*node.IPv4) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue