8ae09c0941
Map the rendered global-compiled tail into native config.Blrules/Conntrack/ Secmarks/Vars.
321 lines
17 KiB
Go
321 lines
17 KiB
Go
// Package agent implements `tomswall agent`: it pulls a device's compiled config
|
|
// from tomswallapi, differentially applies it, and reports the applied generation.
|
|
// It never fails closed — if the control plane is unreachable it keeps the last
|
|
// known-good config running.
|
|
package agent
|
|
|
|
// RenderedConfig is the per-device document served by tomswallapi at
|
|
// GET /api/v1/devices/{name}/config. It mirrors the control plane's compiler
|
|
// output: interface-agnostic, address-matched rules plus named sets.
|
|
type RenderedConfig struct {
|
|
Generation int64 `yaml:"generation" json:"generation"`
|
|
Device string `yaml:"device" json:"device"`
|
|
Class string `yaml:"class" json:"class"`
|
|
Enforcing bool `yaml:"enforcing" json:"enforcing"`
|
|
Settings RenderedSettings `yaml:"settings" json:"settings"`
|
|
Resolver []string `yaml:"resolver,omitempty" json:"resolver,omitempty"`
|
|
Bindings map[string][]string `yaml:"bindings,omitempty" json:"bindings,omitempty"` // zone -> interfaces
|
|
Sets []RenderedSet `yaml:"sets,omitempty" json:"sets,omitempty"`
|
|
Rules []RenderedRule `yaml:"rules,omitempty" json:"rules,omitempty"`
|
|
Policies []RenderedPolicy `yaml:"policies,omitempty" json:"policies,omitempty"`
|
|
SNAT []RenderedSNAT `yaml:"snat,omitempty" json:"snat,omitempty"`
|
|
Netmap []RenderedNetmap `yaml:"netmap,omitempty" json:"netmap,omitempty"`
|
|
NAT []RenderedNAT `yaml:"nat,omitempty" json:"nat,omitempty"`
|
|
Hosts []RenderedHost `yaml:"hosts,omitempty" json:"hosts,omitempty"`
|
|
Providers []RenderedProvider `yaml:"providers,omitempty" json:"providers,omitempty"`
|
|
Routes []RenderedRoute `yaml:"routes,omitempty" json:"routes,omitempty"`
|
|
RoutingRules []RenderedRoutingRule `yaml:"routing_rules,omitempty" json:"routing_rules,omitempty"`
|
|
Tunnels []RenderedTunnel `yaml:"tunnels,omitempty" json:"tunnels,omitempty"`
|
|
StoppedRules []RenderedStoppedRule `yaml:"stopped_rules,omitempty" json:"stopped_rules,omitempty"`
|
|
ProxyARP []RenderedProxy `yaml:"proxy_arp,omitempty" json:"proxy_arp,omitempty"`
|
|
ProxyNDP []RenderedProxy `yaml:"proxy_ndp,omitempty" json:"proxy_ndp,omitempty"`
|
|
ArpRules []RenderedArpRule `yaml:"arp_rules,omitempty" json:"arp_rules,omitempty"`
|
|
Maclist []RenderedMaclist `yaml:"maclist,omitempty" json:"maclist,omitempty"`
|
|
Mangle []RenderedMangle `yaml:"mangle,omitempty" json:"mangle,omitempty"`
|
|
Accounting []RenderedAccounting `yaml:"accounting,omitempty" json:"accounting,omitempty"`
|
|
TCDevices []RenderedTCDevice `yaml:"tc_devices,omitempty" json:"tc_devices,omitempty"`
|
|
TCClasses []RenderedTCClass `yaml:"tc_classes,omitempty" json:"tc_classes,omitempty"`
|
|
TCFilters []RenderedTCFilter `yaml:"tc_filters,omitempty" json:"tc_filters,omitempty"`
|
|
TCInterfaces []RenderedTCInterface `yaml:"tc_interfaces,omitempty" json:"tc_interfaces,omitempty"`
|
|
TCPriorities []RenderedTCPriority `yaml:"tc_priorities,omitempty" json:"tc_priorities,omitempty"`
|
|
Blrules []RenderedBlrule `yaml:"blrules,omitempty" json:"blrules,omitempty"`
|
|
Conntrack []RenderedConntrack `yaml:"conntrack,omitempty" json:"conntrack,omitempty"`
|
|
Secmarks []RenderedSecmark `yaml:"secmarks,omitempty" json:"secmarks,omitempty"`
|
|
Vars map[string]string `yaml:"vars,omitempty" json:"vars,omitempty"`
|
|
}
|
|
|
|
type RenderedBlrule struct {
|
|
Priority int `yaml:"priority,omitempty" json:"priority,omitempty"`
|
|
Action string `yaml:"action" json:"action"`
|
|
Source string `yaml:"source,omitempty" json:"source,omitempty"`
|
|
Dest string `yaml:"dest,omitempty" json:"dest,omitempty"`
|
|
Proto string `yaml:"proto,omitempty" json:"proto,omitempty"`
|
|
DPort []string `yaml:"dport,omitempty" json:"dport,omitempty"`
|
|
SPort []string `yaml:"sport,omitempty" json:"sport,omitempty"`
|
|
Log string `yaml:"log,omitempty" json:"log,omitempty"`
|
|
Comment string `yaml:"comment,omitempty" json:"comment,omitempty"`
|
|
}
|
|
|
|
type RenderedConntrack struct {
|
|
Action string `yaml:"action" json:"action"`
|
|
Source string `yaml:"source,omitempty" json:"source,omitempty"`
|
|
Dest string `yaml:"dest,omitempty" json:"dest,omitempty"`
|
|
Proto string `yaml:"proto,omitempty" json:"proto,omitempty"`
|
|
DPort []string `yaml:"dport,omitempty" json:"dport,omitempty"`
|
|
SPort []string `yaml:"sport,omitempty" json:"sport,omitempty"`
|
|
Chain string `yaml:"chain,omitempty" json:"chain,omitempty"`
|
|
Helper string `yaml:"helper,omitempty" json:"helper,omitempty"`
|
|
User string `yaml:"user,omitempty" json:"user,omitempty"`
|
|
Comment string `yaml:"comment,omitempty" json:"comment,omitempty"`
|
|
}
|
|
|
|
type RenderedSecmark struct {
|
|
Secmark string `yaml:"secmark" json:"secmark"`
|
|
Chain string `yaml:"chain" json:"chain"`
|
|
Source string `yaml:"source,omitempty" json:"source,omitempty"`
|
|
Dest string `yaml:"dest,omitempty" json:"dest,omitempty"`
|
|
Proto string `yaml:"proto,omitempty" json:"proto,omitempty"`
|
|
DPort []string `yaml:"dport,omitempty" json:"dport,omitempty"`
|
|
SPort []string `yaml:"sport,omitempty" json:"sport,omitempty"`
|
|
Comment string `yaml:"comment,omitempty" json:"comment,omitempty"`
|
|
}
|
|
|
|
type RenderedMangle struct {
|
|
Action string `yaml:"action" json:"action"`
|
|
Chain string `yaml:"chain,omitempty" json:"chain,omitempty"`
|
|
MarkValue string `yaml:"mark_value,omitempty" json:"mark_value,omitempty"`
|
|
Source string `yaml:"source,omitempty" json:"source,omitempty"`
|
|
Dest string `yaml:"dest,omitempty" json:"dest,omitempty"`
|
|
Proto string `yaml:"proto,omitempty" json:"proto,omitempty"`
|
|
DPort []string `yaml:"dport,omitempty" json:"dport,omitempty"`
|
|
SPort []string `yaml:"sport,omitempty" json:"sport,omitempty"`
|
|
User string `yaml:"user,omitempty" json:"user,omitempty"`
|
|
Mark string `yaml:"mark,omitempty" json:"mark,omitempty"`
|
|
Length string `yaml:"length,omitempty" json:"length,omitempty"`
|
|
TOS string `yaml:"tos,omitempty" json:"tos,omitempty"`
|
|
Helper string `yaml:"helper,omitempty" json:"helper,omitempty"`
|
|
Probability *float64 `yaml:"probability,omitempty" json:"probability,omitempty"`
|
|
Comment string `yaml:"comment,omitempty" json:"comment,omitempty"`
|
|
}
|
|
|
|
type RenderedAccounting struct {
|
|
Action string `yaml:"action" json:"action"`
|
|
Section string `yaml:"section,omitempty" json:"section,omitempty"`
|
|
Chain string `yaml:"chain,omitempty" json:"chain,omitempty"`
|
|
Source string `yaml:"source,omitempty" json:"source,omitempty"`
|
|
Dest string `yaml:"dest,omitempty" json:"dest,omitempty"`
|
|
Proto string `yaml:"proto,omitempty" json:"proto,omitempty"`
|
|
DPort []string `yaml:"dport,omitempty" json:"dport,omitempty"`
|
|
SPort []string `yaml:"sport,omitempty" json:"sport,omitempty"`
|
|
Mark string `yaml:"mark,omitempty" json:"mark,omitempty"`
|
|
Comment string `yaml:"comment,omitempty" json:"comment,omitempty"`
|
|
}
|
|
|
|
type RenderedTCDevice struct {
|
|
Interface string `yaml:"interface" json:"interface"`
|
|
InBandwidth string `yaml:"in_bandwidth,omitempty" json:"in_bandwidth,omitempty"`
|
|
OutBandwidth string `yaml:"out_bandwidth,omitempty" json:"out_bandwidth,omitempty"`
|
|
Comment string `yaml:"comment,omitempty" json:"comment,omitempty"`
|
|
}
|
|
|
|
type RenderedTCClass struct {
|
|
Interface string `yaml:"interface" json:"interface"`
|
|
Mark int `yaml:"mark,omitempty" json:"mark,omitempty"`
|
|
Rate string `yaml:"rate,omitempty" json:"rate,omitempty"`
|
|
Ceil string `yaml:"ceil,omitempty" json:"ceil,omitempty"`
|
|
Priority int `yaml:"priority,omitempty" json:"priority,omitempty"`
|
|
Comment string `yaml:"comment,omitempty" json:"comment,omitempty"`
|
|
}
|
|
|
|
type RenderedTCFilter struct {
|
|
Class string `yaml:"class" json:"class"`
|
|
Source string `yaml:"source,omitempty" json:"source,omitempty"`
|
|
Dest string `yaml:"dest,omitempty" json:"dest,omitempty"`
|
|
Proto string `yaml:"proto,omitempty" json:"proto,omitempty"`
|
|
DPort []string `yaml:"dport,omitempty" json:"dport,omitempty"`
|
|
SPort []string `yaml:"sport,omitempty" json:"sport,omitempty"`
|
|
TOS string `yaml:"tos,omitempty" json:"tos,omitempty"`
|
|
Length int `yaml:"length,omitempty" json:"length,omitempty"`
|
|
Priority int `yaml:"priority,omitempty" json:"priority,omitempty"`
|
|
Comment string `yaml:"comment,omitempty" json:"comment,omitempty"`
|
|
}
|
|
|
|
type RenderedTCInterface struct {
|
|
Interface string `yaml:"interface" json:"interface"`
|
|
Type string `yaml:"type,omitempty" json:"type,omitempty"`
|
|
InBandwidth string `yaml:"in_bandwidth,omitempty" json:"in_bandwidth,omitempty"`
|
|
OutBandwidth string `yaml:"out_bandwidth,omitempty" json:"out_bandwidth,omitempty"`
|
|
Comment string `yaml:"comment,omitempty" json:"comment,omitempty"`
|
|
}
|
|
|
|
type RenderedTCPriority struct {
|
|
Band int `yaml:"band" json:"band"`
|
|
Proto string `yaml:"proto,omitempty" json:"proto,omitempty"`
|
|
DPort []string `yaml:"dport,omitempty" json:"dport,omitempty"`
|
|
SPort []string `yaml:"sport,omitempty" json:"sport,omitempty"`
|
|
Address string `yaml:"address,omitempty" json:"address,omitempty"`
|
|
Interface string `yaml:"interface,omitempty" json:"interface,omitempty"`
|
|
Helper string `yaml:"helper,omitempty" json:"helper,omitempty"`
|
|
Comment string `yaml:"comment,omitempty" json:"comment,omitempty"`
|
|
}
|
|
|
|
type RenderedTunnel struct {
|
|
Type string `yaml:"type" json:"type"`
|
|
Zone string `yaml:"zone" json:"zone"`
|
|
Gateways []string `yaml:"gateways,omitempty" json:"gateways,omitempty"`
|
|
GatewayZones []string `yaml:"gateway_zones,omitempty" json:"gateway_zones,omitempty"`
|
|
Port int `yaml:"port,omitempty" json:"port,omitempty"`
|
|
Comment string `yaml:"comment,omitempty" json:"comment,omitempty"`
|
|
}
|
|
|
|
type RenderedStoppedRule struct {
|
|
Action string `yaml:"action" json:"action"`
|
|
Source string `yaml:"source,omitempty" json:"source,omitempty"`
|
|
Dest string `yaml:"dest,omitempty" json:"dest,omitempty"`
|
|
Proto string `yaml:"proto,omitempty" json:"proto,omitempty"`
|
|
DPort []string `yaml:"dport,omitempty" json:"dport,omitempty"`
|
|
SPort []string `yaml:"sport,omitempty" json:"sport,omitempty"`
|
|
Comment string `yaml:"comment,omitempty" json:"comment,omitempty"`
|
|
}
|
|
|
|
type RenderedProxy struct {
|
|
Address string `yaml:"address" json:"address"`
|
|
Interface string `yaml:"interface,omitempty" json:"interface,omitempty"`
|
|
External string `yaml:"external" json:"external"`
|
|
HaveRoute bool `yaml:"haveroute,omitempty" json:"haveroute,omitempty"`
|
|
Persistent bool `yaml:"persistent,omitempty" json:"persistent,omitempty"`
|
|
Comment string `yaml:"comment,omitempty" json:"comment,omitempty"`
|
|
}
|
|
|
|
type RenderedArpRule struct {
|
|
Action string `yaml:"action" json:"action"`
|
|
ActionAddress string `yaml:"action_address,omitempty" json:"action_address,omitempty"`
|
|
ActionMAC string `yaml:"action_mac,omitempty" json:"action_mac,omitempty"`
|
|
Source string `yaml:"source,omitempty" json:"source,omitempty"`
|
|
Dest string `yaml:"dest,omitempty" json:"dest,omitempty"`
|
|
Opcode int `yaml:"opcode,omitempty" json:"opcode,omitempty"`
|
|
Comment string `yaml:"comment,omitempty" json:"comment,omitempty"`
|
|
}
|
|
|
|
type RenderedMaclist struct {
|
|
Action string `yaml:"action" json:"action"`
|
|
Interface string `yaml:"interface" json:"interface"`
|
|
MAC string `yaml:"mac,omitempty" json:"mac,omitempty"`
|
|
Addresses []string `yaml:"addresses,omitempty" json:"addresses,omitempty"`
|
|
Log string `yaml:"log,omitempty" json:"log,omitempty"`
|
|
Comment string `yaml:"comment,omitempty" json:"comment,omitempty"`
|
|
}
|
|
|
|
type RenderedHost struct {
|
|
Zone string `yaml:"zone" json:"zone"`
|
|
Interface string `yaml:"interface" json:"interface"`
|
|
Addresses []string `yaml:"addresses,omitempty" json:"addresses,omitempty"`
|
|
Exclusions []string `yaml:"exclusions,omitempty" json:"exclusions,omitempty"`
|
|
Dynamic bool `yaml:"dynamic,omitempty" json:"dynamic,omitempty"`
|
|
}
|
|
|
|
type RenderedProvider struct {
|
|
Name string `yaml:"name" json:"name"`
|
|
Number int `yaml:"number" json:"number"`
|
|
Mark int `yaml:"mark,omitempty" json:"mark,omitempty"`
|
|
Duplicate string `yaml:"duplicate,omitempty" json:"duplicate,omitempty"`
|
|
Interface string `yaml:"interface" json:"interface"`
|
|
Gateway string `yaml:"gateway,omitempty" json:"gateway,omitempty"`
|
|
Copy []string `yaml:"copy,omitempty" json:"copy,omitempty"`
|
|
}
|
|
|
|
type RenderedRoute struct {
|
|
Provider string `yaml:"provider,omitempty" json:"provider,omitempty"`
|
|
Dest string `yaml:"dest" json:"dest"`
|
|
Gateway string `yaml:"gateway,omitempty" json:"gateway,omitempty"`
|
|
Oif string `yaml:"oif,omitempty" json:"oif,omitempty"`
|
|
Persistent bool `yaml:"persistent,omitempty" json:"persistent,omitempty"`
|
|
Comment string `yaml:"comment,omitempty" json:"comment,omitempty"`
|
|
}
|
|
|
|
type RenderedRoutingRule struct {
|
|
Source string `yaml:"source,omitempty" json:"source,omitempty"`
|
|
Dest string `yaml:"dest,omitempty" json:"dest,omitempty"`
|
|
Provider string `yaml:"provider" json:"provider"`
|
|
Priority int `yaml:"priority,omitempty" json:"priority,omitempty"`
|
|
Persistent bool `yaml:"persistent,omitempty" json:"persistent,omitempty"`
|
|
Mark string `yaml:"mark,omitempty" json:"mark,omitempty"`
|
|
Comment string `yaml:"comment,omitempty" json:"comment,omitempty"`
|
|
}
|
|
|
|
// RenderedSNAT is a resolved SNAT/masquerade rule (egress carries interface names).
|
|
type RenderedSNAT struct {
|
|
Action string `yaml:"action" json:"action"`
|
|
Source []string `yaml:"source,omitempty" json:"source,omitempty"`
|
|
Egress []string `yaml:"egress" json:"egress"`
|
|
Address string `yaml:"address,omitempty" json:"address,omitempty"`
|
|
Probability *float64 `yaml:"probability,omitempty" json:"probability,omitempty"`
|
|
Comment string `yaml:"comment,omitempty" json:"comment,omitempty"`
|
|
}
|
|
|
|
// RenderedNetmap is a resolved network-to-network mapping on one interface.
|
|
type RenderedNetmap struct {
|
|
Type string `yaml:"type" json:"type"`
|
|
FromNet string `yaml:"from_net" json:"from_net"`
|
|
ToNet string `yaml:"to_net" json:"to_net"`
|
|
Interface string `yaml:"interface,omitempty" json:"interface,omitempty"`
|
|
Comment string `yaml:"comment,omitempty" json:"comment,omitempty"`
|
|
}
|
|
|
|
// RenderedNAT is a resolved one-to-one static NAT on one interface.
|
|
type RenderedNAT struct {
|
|
External string `yaml:"external" json:"external"`
|
|
Internal string `yaml:"internal" json:"internal"`
|
|
Interface string `yaml:"interface,omitempty" json:"interface,omitempty"`
|
|
Comment string `yaml:"comment,omitempty" json:"comment,omitempty"`
|
|
}
|
|
|
|
type RenderedSettings struct {
|
|
AddressFamily string `yaml:"address_family" json:"address_family"`
|
|
LogLevel string `yaml:"log_level" json:"log_level"`
|
|
IPForwarding bool `yaml:"ip_forwarding" json:"ip_forwarding"`
|
|
TableName string `yaml:"table_name" json:"table_name"`
|
|
}
|
|
|
|
// RenderedSet is an address group's nftables set. Members carries the concrete
|
|
// elements the control plane knows (static CIDRs, expanded ASN prefixes); FQDNs
|
|
// are resolved on-device; ASNs are informational (already expanded into Members).
|
|
type RenderedSet struct {
|
|
Name string `yaml:"name" json:"name"`
|
|
Kind string `yaml:"kind" json:"kind"` // static | dns | asn
|
|
Members []string `yaml:"members,omitempty" json:"members,omitempty"`
|
|
FQDNs []string `yaml:"fqdns,omitempty" json:"fqdns,omitempty"`
|
|
ASNs []string `yaml:"asns,omitempty" json:"asns,omitempty"`
|
|
Refresh string `yaml:"refresh,omitempty" json:"refresh,omitempty"`
|
|
}
|
|
|
|
// RenderedMatch is one OR'd element of a rule direction: a zone's subnets AND,
|
|
// optionally, a named set to intersect with.
|
|
type RenderedMatch struct {
|
|
Zone string `yaml:"zone" json:"zone"`
|
|
Subnets []string `yaml:"subnets,omitempty" json:"subnets,omitempty"`
|
|
Set string `yaml:"set,omitempty" json:"set,omitempty"`
|
|
}
|
|
|
|
type RenderedRule struct {
|
|
Action string `yaml:"action" json:"action"`
|
|
Source []RenderedMatch `yaml:"source" json:"source"`
|
|
Dest []RenderedMatch `yaml:"dest" json:"dest"`
|
|
Proto string `yaml:"proto,omitempty" json:"proto,omitempty"`
|
|
Ports []string `yaml:"ports,omitempty" json:"ports,omitempty"`
|
|
Log string `yaml:"log,omitempty" json:"log,omitempty"`
|
|
Comment string `yaml:"comment,omitempty" json:"comment,omitempty"`
|
|
}
|
|
|
|
type RenderedPolicy struct {
|
|
Priority int `yaml:"priority" json:"priority"`
|
|
Source string `yaml:"source" json:"source"`
|
|
Dest string `yaml:"dest" json:"dest"`
|
|
Action string `yaml:"action" json:"action"`
|
|
Log string `yaml:"log,omitempty" json:"log,omitempty"`
|
|
}
|
|
|
|
// setMembers returns the concrete address elements for a set: static/asn use
|
|
// Members; dns is resolved separately and merged in before translation.
|
|
func (s RenderedSet) staticMembers() []string { return s.Members }
|