2021-07-03 11:55:32 +02:00
|
|
|
package headscale
|
|
|
|
|
|
|
|
import (
|
2021-11-05 07:24:00 +00:00
|
|
|
"encoding/json"
|
2021-07-03 11:55:32 +02:00
|
|
|
"strings"
|
|
|
|
|
2021-07-03 17:31:32 +02:00
|
|
|
"github.com/tailscale/hujson"
|
2021-07-03 11:55:32 +02:00
|
|
|
"inet.af/netaddr"
|
|
|
|
)
|
|
|
|
|
2021-07-04 13:33:00 +02:00
|
|
|
// ACLPolicy represents a Tailscale ACL Policy
|
2021-07-03 11:55:32 +02:00
|
|
|
type ACLPolicy struct {
|
|
|
|
Groups Groups `json:"Groups"`
|
|
|
|
Hosts Hosts `json:"Hosts"`
|
|
|
|
TagOwners TagOwners `json:"TagOwners"`
|
|
|
|
ACLs []ACL `json:"ACLs"`
|
|
|
|
Tests []ACLTest `json:"Tests"`
|
|
|
|
}
|
|
|
|
|
2021-07-04 13:33:00 +02:00
|
|
|
// ACL is a basic rule for the ACL Policy
|
2021-07-03 11:55:32 +02:00
|
|
|
type ACL struct {
|
|
|
|
Action string `json:"Action"`
|
|
|
|
Users []string `json:"Users"`
|
|
|
|
Ports []string `json:"Ports"`
|
|
|
|
}
|
|
|
|
|
2021-07-04 13:33:00 +02:00
|
|
|
// Groups references a series of alias in the ACL rules
|
2021-07-03 11:55:32 +02:00
|
|
|
type Groups map[string][]string
|
|
|
|
|
2021-07-04 13:33:00 +02:00
|
|
|
// Hosts are alias for IP addresses or subnets
|
2021-07-03 17:31:32 +02:00
|
|
|
type Hosts map[string]netaddr.IPPrefix
|
2021-07-03 11:55:32 +02:00
|
|
|
|
2021-07-04 13:33:00 +02:00
|
|
|
// TagOwners specify what users (namespaces?) are allow to use certain tags
|
2021-07-03 17:31:32 +02:00
|
|
|
type TagOwners map[string][]string
|
2021-07-03 11:55:32 +02:00
|
|
|
|
2021-07-04 13:33:00 +02:00
|
|
|
// ACLTest is not implemented, but should be use to check if a certain rule is allowed
|
2021-07-03 11:55:32 +02:00
|
|
|
type ACLTest struct {
|
|
|
|
User string `json:"User"`
|
|
|
|
Allow []string `json:"Allow"`
|
|
|
|
Deny []string `json:"Deny,omitempty"`
|
|
|
|
}
|
|
|
|
|
2021-07-04 13:33:00 +02:00
|
|
|
// UnmarshalJSON allows to parse the Hosts directly into netaddr objects
|
2021-07-03 17:31:32 +02:00
|
|
|
func (h *Hosts) UnmarshalJSON(data []byte) error {
|
|
|
|
hosts := Hosts{}
|
|
|
|
hs := make(map[string]string)
|
2021-11-05 07:24:00 +00:00
|
|
|
ast, err := hujson.Parse(data)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
ast.Standardize()
|
|
|
|
data = ast.Pack()
|
|
|
|
err = json.Unmarshal(data, &hs)
|
2021-07-03 17:31:32 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2021-07-03 11:55:32 +02:00
|
|
|
}
|
2021-07-03 17:31:32 +02:00
|
|
|
for k, v := range hs {
|
2021-07-03 11:55:32 +02:00
|
|
|
if !strings.Contains(v, "/") {
|
|
|
|
v = v + "/32"
|
|
|
|
}
|
|
|
|
prefix, err := netaddr.ParseIPPrefix(v)
|
|
|
|
if err != nil {
|
2021-07-03 17:31:32 +02:00
|
|
|
return err
|
2021-07-03 11:55:32 +02:00
|
|
|
}
|
|
|
|
hosts[k] = prefix
|
|
|
|
}
|
2021-07-03 17:31:32 +02:00
|
|
|
*h = hosts
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsZero is perhaps a bit naive here
|
|
|
|
func (p ACLPolicy) IsZero() bool {
|
|
|
|
if len(p.Groups) == 0 && len(p.Hosts) == 0 && len(p.ACLs) == 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
2021-07-03 11:55:32 +02:00
|
|
|
}
|