diff --git a/acls.go b/acls.go index f30e46ec7c..2073ee8483 100644 --- a/acls.go +++ b/acls.go @@ -13,6 +13,7 @@ import ( "time" "github.com/rs/zerolog/log" + "github.com/samber/lo" "github.com/tailscale/hujson" "go4.org/netipx" "gopkg.in/yaml.v3" @@ -533,9 +534,11 @@ func parseProtocol(protocol string) ([]int, bool, error) { // - a group // - a tag // - a host +// - an ip +// - a cidr // and transform these in IPAddresses. func expandAlias( - machines []Machine, + machines Machines, aclPolicy ACLPolicy, alias string, stripEmailDomain bool, @@ -617,19 +620,40 @@ func expandAlias( // if alias is an host if h, ok := aclPolicy.Hosts[alias]; ok { - return []string{h.String()}, nil + log.Trace().Str("host", h.String()).Msg("expandAlias got hosts entry") + + return expandAlias(machines, aclPolicy, h.String(), stripEmailDomain) } // if alias is an IP - ip, err := netip.ParseAddr(alias) - if err == nil { - return []string{ip.String()}, nil + if ip, err := netip.ParseAddr(alias); err == nil { + log.Trace().Str("ip", ip.String()).Msg("expandAlias got ip") + ips := []string{ip.String()} + matches := machines.FilterByIP(ip) + + for _, machine := range matches { + ips = append(ips, machine.IPAddresses.ToStringSlice()...) + } + + return lo.Uniq(ips), nil } - // if alias is an CIDR - cidr, err := netip.ParsePrefix(alias) - if err == nil { - return []string{cidr.String()}, nil + if cidr, err := netip.ParsePrefix(alias); err == nil { + log.Trace().Str("cidr", cidr.String()).Msg("expandAlias got cidr") + val := []string{cidr.String()} + // This is suboptimal and quite expensive, but if we only add the cidr, we will miss all the relevant IPv6 + // addresses for the hosts that belong to tailscale. This doesnt really affect stuff like subnet routers. + for _, machine := range machines { + for _, ip := range machine.IPAddresses { + // log.Trace(). + // Msgf("checking if machine ip (%s) is part of cidr (%s): %v, is single ip cidr (%v), addr: %s", ip.String(), cidr.String(), cidr.Contains(ip), cidr.IsSingleIP(), cidr.Addr().String()) + if cidr.Contains(ip) { + val = append(val, machine.IPAddresses.ToStringSlice()...) + } + } + } + + return lo.Uniq(val), nil } log.Warn().Msgf("No IPs found with the alias %v", alias) diff --git a/acls_test.go b/acls_test.go index 7d464c71f5..eaac2a7cf3 100644 --- a/acls_test.go +++ b/acls_test.go @@ -1026,29 +1026,70 @@ func Test_expandAlias(t *testing.T) { wantErr: false, }, { - name: "private network", + name: "simple host by ip passed through", args: args{ - alias: "homeNetwork", - machines: []Machine{}, - aclPolicy: ACLPolicy{ - Hosts: Hosts{ - "homeNetwork": netip.MustParsePrefix("192.168.1.0/24"), + alias: "10.0.0.1", + machines: []Machine{}, + aclPolicy: ACLPolicy{}, + stripEmailDomain: true, + }, + want: []string{"10.0.0.1"}, + wantErr: false, + }, + { + name: "simple host by ipv4 single ipv4", + args: args{ + alias: "10.0.0.1", + machines: []Machine{ + { + IPAddresses: MachineAddresses{ + netip.MustParseAddr("10.0.0.1"), + }, + User: User{Name: "mickael"}, }, }, + aclPolicy: ACLPolicy{}, stripEmailDomain: true, }, - want: []string{"192.168.1.0/24"}, + want: []string{"10.0.0.1"}, wantErr: false, }, { - name: "simple host by ip", + name: "simple host by ipv4 single dual stack", args: args{ - alias: "10.0.0.1", - machines: []Machine{}, + alias: "10.0.0.1", + machines: []Machine{ + { + IPAddresses: MachineAddresses{ + netip.MustParseAddr("10.0.0.1"), + netip.MustParseAddr("fd7a:115c:a1e0:ab12:4843:2222:6273:2222"), + }, + User: User{Name: "mickael"}, + }, + }, aclPolicy: ACLPolicy{}, stripEmailDomain: true, }, - want: []string{"10.0.0.1"}, + want: []string{"10.0.0.1", "fd7a:115c:a1e0:ab12:4843:2222:6273:2222"}, + wantErr: false, + }, + { + name: "simple host by ipv6 single dual stack", + args: args{ + alias: "fd7a:115c:a1e0:ab12:4843:2222:6273:2222", + machines: []Machine{ + { + IPAddresses: MachineAddresses{ + netip.MustParseAddr("10.0.0.1"), + netip.MustParseAddr("fd7a:115c:a1e0:ab12:4843:2222:6273:2222"), + }, + User: User{Name: "mickael"}, + }, + }, + aclPolicy: ACLPolicy{}, + stripEmailDomain: true, + }, + want: []string{"fd7a:115c:a1e0:ab12:4843:2222:6273:2222", "10.0.0.1"}, wantErr: false, }, { @@ -1066,6 +1107,21 @@ func Test_expandAlias(t *testing.T) { want: []string{"10.0.0.132/32"}, wantErr: false, }, + { + name: "private network", + args: args{ + alias: "homeNetwork", + machines: []Machine{}, + aclPolicy: ACLPolicy{ + Hosts: Hosts{ + "homeNetwork": netip.MustParsePrefix("192.168.1.0/24"), + }, + }, + stripEmailDomain: true, + }, + want: []string{"192.168.1.0/24"}, + wantErr: false, + }, { name: "simple CIDR", args: args{ diff --git a/machine.go b/machine.go index 71217ab572..6dfa9501af 100644 --- a/machine.go +++ b/machine.go @@ -1267,3 +1267,17 @@ func (h *Headscale) GenerateGivenName(machineKey string, suppliedName string) (s return givenName, nil } + +func (machines Machines) FilterByIP(ip netip.Addr) Machines { + found := make(Machines, 0) + + for _, machine := range machines { + for _, mIP := range machine.IPAddresses { + if ip == mIP { + found = append(found, machine) + } + } + } + + return found +}