From 82f90aabb8ea6de48eab62e3ca77f1a5f537631e Mon Sep 17 00:00:00 2001 From: Samuel Lorch Date: Thu, 2 Mar 2023 00:10:38 +0100 Subject: [PATCH] Implement Service Based nftables Match Generator --- pkg/definitions/match.go | 8 +-- pkg/nftables/match.go | 65 +++++++++++++++++++ pkg/nftables/template.go | 8 ++- .../template/destination_nat_rules.tmpl | 2 +- pkg/nftables/template/forward_rules.tmpl | 2 +- pkg/nftables/template/nftables.tmpl | 4 -- pkg/nftables/template/source_nat_rules.tmpl | 2 +- 7 files changed, 76 insertions(+), 15 deletions(-) create mode 100644 pkg/nftables/match.go diff --git a/pkg/definitions/match.go b/pkg/definitions/match.go index 38ad16b..1aad192 100644 --- a/pkg/definitions/match.go +++ b/pkg/definitions/match.go @@ -1,12 +1,6 @@ package definitions -import "fmt" - type Match struct { TCPDestinationPort uint64 `json:"tcp_destination_port,omitempty"` - Service []string `json:"service,omitempty"` -} - -func (m Match) Nftables() string { - return fmt.Sprintf("tcp dport %d", m.TCPDestinationPort) + Services []string `json:"services,omitempty"` } diff --git a/pkg/nftables/match.go b/pkg/nftables/match.go new file mode 100644 index 0000000..ea1a12f --- /dev/null +++ b/pkg/nftables/match.go @@ -0,0 +1,65 @@ +package nftables + +import ( + "fmt" + + "github.con/speatzle/nfsense/pkg/definitions" + "github.con/speatzle/nfsense/pkg/util" +) + +func GenerateMatcher(services *map[string]definitions.Service, addresses *map[string]definitions.Address, match definitions.Match) (string, error) { + return GenerateServiceMatcher(services, match), nil +} + +func GenerateServiceMatcher(allServices *map[string]definitions.Service, match definitions.Match) string { + serviceList := util.ResolveBaseServices(*allServices, match.Services) + + tcpSPorts := []string{} + tcpDPorts := []string{} + udpSPorts := []string{} + udpDPorts := []string{} + icmpCodes := []string{} + + for _, service := range serviceList { + switch service.Type { + case definitions.TCP: + if service.GetSPort() != "0" { + tcpSPorts = append(tcpSPorts, service.GetSPort()) + } + if service.GetDPort() != "0" { + tcpDPorts = append(tcpDPorts, service.GetDPort()) + } + case definitions.UDP: + if service.GetSPort() != "0" { + udpSPorts = append(udpSPorts, service.GetSPort()) + } + if service.GetDPort() != "0" { + udpDPorts = append(udpDPorts, service.GetDPort()) + } + case definitions.ICMP: + icmpCodes = append(icmpCodes, fmt.Sprint(service.ICMPCode)) + default: + panic("invalid service type") + } + } + + res := "" + + if len(tcpSPorts) != 0 { + res += "tcp sport " + util.ConvertSliceToSetString(tcpSPorts) + " " + } + if len(tcpDPorts) != 0 { + res += "tcp dport " + util.ConvertSliceToSetString(tcpDPorts) + " " + } + if len(udpSPorts) != 0 { + res += "udp sport " + util.ConvertSliceToSetString(udpSPorts) + " " + } + if len(udpDPorts) != 0 { + res += "udp dport " + util.ConvertSliceToSetString(udpDPorts) + " " + } + if len(icmpCodes) != 0 { + res += "icmp codes " + util.ConvertSliceToSetString(icmpCodes) + " " + } + + return res +} diff --git a/pkg/nftables/template.go b/pkg/nftables/template.go index 163ed28..6488436 100644 --- a/pkg/nftables/template.go +++ b/pkg/nftables/template.go @@ -10,8 +10,14 @@ var templateFS embed.FS var templates *template.Template func init() { + + funcMap := template.FuncMap{ + // The name "title" is what the function will be called in the template text. + "matcher": GenerateMatcher, + } + var err error - templates, err = template.ParseFS(templateFS, "template/*.tmpl") + templates, err = template.New("").Funcs(funcMap).ParseFS(templateFS, "template/*.tmpl") if err != nil { panic(err) } diff --git a/pkg/nftables/template/destination_nat_rules.tmpl b/pkg/nftables/template/destination_nat_rules.tmpl index b3114eb..2f051da 100644 --- a/pkg/nftables/template/destination_nat_rules.tmpl +++ b/pkg/nftables/template/destination_nat_rules.tmpl @@ -1,2 +1,2 @@ {{ range $rule := .Netfilter.DestinationNATRules }} - {{ .Match.Nftables }}{{ if $rule.Counter }} counter{{ end }}{{ if ne $rule.Comment "" }} comment "{{ $rule.Comment }}"{{ end }}{{ end }} \ No newline at end of file + {{ matcher .Services .Addresses $rule.Match }}{{ if $rule.Counter }} counter{{ end }}{{ if ne $rule.Comment "" }} comment "{{ $rule.Comment }}"{{ end }}{{ end }} \ No newline at end of file diff --git a/pkg/nftables/template/forward_rules.tmpl b/pkg/nftables/template/forward_rules.tmpl index 5d90757..ab69df9 100644 --- a/pkg/nftables/template/forward_rules.tmpl +++ b/pkg/nftables/template/forward_rules.tmpl @@ -1,2 +1,2 @@ {{range $rule := .Netfilter.ForwardRules}} - {{ .Match.Nftables }}{{ if $rule.Counter }} counter{{ end }} {{ $rule.Verdict.String }}{{ if ne $rule.Comment "" }} comment "{{ $rule.Comment }}"{{ end }}{{ end }} + {{ matcher .Services .Addresses $rule.Match }}{{ if $rule.Counter }} counter{{ end }} {{ $rule.Verdict.String }}{{ if ne $rule.Comment "" }} comment "{{ $rule.Comment }}"{{ end }}{{ end }} diff --git a/pkg/nftables/template/nftables.tmpl b/pkg/nftables/template/nftables.tmpl index 224343b..f5b3a17 100644 --- a/pkg/nftables/template/nftables.tmpl +++ b/pkg/nftables/template/nftables.tmpl @@ -17,7 +17,6 @@ table inet nfsense_inet { # allow loopback traffic iifname lo accept - {{template "inbound_rules.tmpl" .}} } @@ -27,21 +26,18 @@ table inet nfsense_inet { # Allow traffic from established and related packets, drop invalid ct state vmap { established : accept, related : accept, invalid : drop } - {{template "forward_rules.tmpl" .}} } # Destination NAT Rules chain prerouting { type nat hook prerouting priority -100; policy accept; - {{template "destination_nat_rules.tmpl" .}} } # Source NAT Rules chain postrouting { type nat hook postrouting priority 100; policy accept; - {{template "source_nat_rules.tmpl" .}} } } diff --git a/pkg/nftables/template/source_nat_rules.tmpl b/pkg/nftables/template/source_nat_rules.tmpl index 3b7a2a5..bab6fb2 100644 --- a/pkg/nftables/template/source_nat_rules.tmpl +++ b/pkg/nftables/template/source_nat_rules.tmpl @@ -1,2 +1,2 @@ {{ range $rule := .Netfilter.SourceNATRules }} - {{ .Match.Nftables }}{{ if $rule.Counter }} counter{{ end }}{{ if ne $rule.Comment "" }} comment "{{ $rule.Comment }}"{{ end }}{{ end }} \ No newline at end of file + {{ matcher .Services .Addresses $rule.Match }}{{ if $rule.Counter }} counter{{ end }}{{ if ne $rule.Comment "" }} comment "{{ $rule.Comment }}"{{ end }}{{ end }} \ No newline at end of file