Add secmark/var + render blrules/conntrack/secmark/vars
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful

- Add secmarks (id-keyed) and vars (key-keyed) resources: migration 0009, model,
  store CRUD, REST handlers.
- Compiler rendering for the global-compiled tail: blrules, conntrack, secmarks
  render on enforcing devices; vars render on every device. This closes the
  rendering gap left by batch 1 (blrules/conntrack were stored but not rendered).
This commit is contained in:
benvin
2026-07-26 16:06:19 +10:00
parent 1da430a382
commit 725230aad0
7 changed files with 330 additions and 0 deletions
+21
View File
@@ -52,6 +52,10 @@ type Input struct {
TCFilters []model.TCFilter
TCInterfaces []model.TCInterface
TCPriorities []model.TCPriority
Blrules []model.BlruleRule
Conntrack []model.ConntrackRule
Secmarks []model.SecmarkRule
Vars []model.Var
}
// RenderedConfig is the per-device output served to the agent.
@@ -86,6 +90,10 @@ type RenderedConfig struct {
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"`
}
// RenderedSNAT is a resolved SNAT/masquerade rule: source addresses masqueraded
@@ -235,6 +243,7 @@ func Render(in Input) (*RenderedConfig, error) {
renderPerDevice(in, out)
renderPerDeviceL2(in, out)
renderTraffic(in, out)
renderGlobal2(in, out)
return out, nil
}
@@ -516,5 +525,17 @@ func Compile(ctx context.Context, s *store.Store, device string) (*RenderedConfi
if in.TCPriorities, err = s.ListTCPriorities(ctx); err != nil {
return nil, err
}
if in.Blrules, err = s.ListBlrules(ctx); err != nil {
return nil, err
}
if in.Conntrack, err = s.ListConntrack(ctx); err != nil {
return nil, err
}
if in.Secmarks, err = s.ListSecmarks(ctx); err != nil {
return nil, err
}
if in.Vars, err = s.ListVars(ctx); err != nil {
return nil, err
}
return Render(in)
}
+72
View File
@@ -0,0 +1,72 @@
package compiler
// Global-compiled long-tail: blrules, conntrack, secmarks (rendered on enforcing
// devices), and vars (substitution variables, rendered on every device).
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"`
}
// renderGlobal2 renders the global-compiled sections. blrules/conntrack/secmarks
// only apply on enforcing devices; vars are always emitted.
func renderGlobal2(in Input, out *RenderedConfig) {
if len(in.Vars) > 0 {
out.Vars = make(map[string]string, len(in.Vars))
for _, v := range in.Vars {
out.Vars[v.Key] = v.Value
}
}
if !out.Enforcing {
return
}
for _, b := range in.Blrules {
out.Blrules = append(out.Blrules, RenderedBlrule{
Priority: b.Priority, Action: b.Action, Source: b.Source, Dest: b.Dest, Proto: b.Proto,
DPort: b.DPort, SPort: b.SPort, Log: b.Log, Comment: b.Comment,
})
}
for _, c := range in.Conntrack {
out.Conntrack = append(out.Conntrack, RenderedConntrack{
Action: c.Action, Source: c.Source, Dest: c.Dest, Proto: c.Proto, DPort: c.DPort, SPort: c.SPort,
Chain: c.Chain, Helper: c.Helper, User: c.User, Comment: c.Comment,
})
}
for _, s := range in.Secmarks {
out.Secmarks = append(out.Secmarks, RenderedSecmark{
Secmark: s.Secmark, Chain: s.Chain, Source: s.Source, Dest: s.Dest, Proto: s.Proto,
DPort: s.DPort, SPort: s.SPort, Comment: s.Comment,
})
}
}