Rework nftables Generation using anonymous chains for multi service matching

This commit is contained in:
Samuel Lorch 2023-05-07 02:33:14 +02:00
parent e2aad5ec97
commit 9c1114e189
9 changed files with 102 additions and 67 deletions

View file

@ -0,0 +1,14 @@
package nftables
import (
"nfsense.net/nfsense/internal/definitions/config"
"nfsense.net/nfsense/internal/definitions/firewall"
)
func GenerateDestinationNatAction(conf config.Config, rule firewall.DestinationNATRule) string {
return ""
}
func GenerateSourceNatAction(conf config.Config, rule firewall.SourceNATRule) string {
return ""
}

View file

@ -8,58 +8,28 @@ import (
"nfsense.net/nfsense/internal/util"
)
func GenerateMatcher(services map[string]object.Service, addresses map[string]object.Address, match firewall.Match) (string, error) {
return GenerateAddressMatcher(addresses, match) + " " + GenerateServiceMatcher(services, match), nil
}
func GenerateServiceMatcher(allServices map[string]object.Service, match firewall.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 object.TCP:
if service.GetSPort() != "" {
tcpSPorts = append(tcpSPorts, service.GetSPort())
}
if service.GetDPort() != "" {
tcpDPorts = append(tcpDPorts, service.GetDPort())
}
case object.UDP:
if service.GetSPort() != "" {
udpSPorts = append(udpSPorts, service.GetSPort())
}
if service.GetDPort() != "" {
udpDPorts = append(udpDPorts, service.GetDPort())
}
case object.ICMP:
icmpCodes = append(icmpCodes, fmt.Sprint(service.ICMPCode))
default:
panic("invalid service type")
}
}
func GenerateServiceMatcher(service object.Service) string {
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) + " "
switch service.Type {
case object.TCP:
if service.GetSPort() != "" {
res = "tcp sport " + service.GetSPort()
}
if service.GetDPort() != "" {
res = res + "tcp dport " + service.GetDPort()
}
case object.UDP:
if service.GetSPort() != "" {
res = "udp sport " + service.GetSPort()
}
if service.GetDPort() != "" {
res = res + "udp dport " + service.GetDPort()
}
case object.ICMP:
res = "icmp codes " + fmt.Sprint(service.ICMPCode)
default:
panic("invalid service type")
}
return res

View file

@ -3,6 +3,8 @@ package nftables
import (
"embed"
"text/template"
"nfsense.net/nfsense/internal/util"
)
//go:embed template
@ -12,8 +14,11 @@ 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,
"addressMatcher": GenerateAddressMatcher,
"serviceMatcher": GenerateServiceMatcher,
"destinationNatAction": GenerateDestinationNatAction,
"sourceNatAction": GenerateSourceNatAction,
"getBaseServices": util.ResolveBaseServices,
}
var err error

View file

@ -1,2 +0,0 @@
{{ range $rule := .Firewall.DestinationNATRules }}
{{ matcher $.Object.Services $.Object.Addresses $rule.Match }}{{ if $rule.Counter }} counter{{ end }}{{ if ne $rule.Comment "" }} comment "{{ $rule.Comment }}"{{ end }}{{ end }}

View file

@ -1,2 +0,0 @@
{{range $rule := .Firewall.ForwardRules}}
{{ matcher $.Object.Services $.Object.Addresses $rule.Match }}{{ if $rule.Counter }} counter{{ end }} {{ $rule.Verdict.String }}{{ if ne $rule.Comment "" }} comment "{{ $rule.Comment }}"{{ end }}{{ end }}

View file

@ -1 +0,0 @@
counter accept comment "temp inbound allow"

View file

@ -2,12 +2,36 @@
flush ruleset
# Address object ipsets
{{template "addresses.tmpl" .}}
# nfsense nftables inet (ipv4 + ipv6) table
table inet nfsense_inet {
# Rule Counters for Forward Rules
{{- range $i, $rule := $.Firewall.ForwardRules }}
{{- if $rule.Counter }}
counter fw_{{ $i }} {
comment "{{ $rule.Name }}"
}
{{- end}}
{{- end}}
# Rule Counters for Destination NAT Rules
{{- range $i, $rule := $.Firewall.DestinationNATRules }}
{{- if $rule.Counter }}
counter dnat_{{ $i }} {
comment "{{ $rule.Name }}"
}
{{- end}}
{{- end}}
# Rule Counters for Source NAT Rules
{{- range $i, $rule := $.Firewall.SourceNATRules }}
{{- if $rule.Counter }}
counter snat_{{ $i }} {
comment "{{ $rule.Name }}"
}
{{- end}}
{{- end}}
# Inbound Rules
chain inbound {
type filter hook input priority 0; policy drop;
@ -15,9 +39,11 @@ table inet nfsense_inet {
# Allow traffic from established and related packets, drop invalid
ct state vmap { established : accept, related : accept, invalid : drop }
# allow loopback traffic
# Allow loopback traffic
iifname lo accept
{{template "inbound_rules.tmpl" .}}
# temp Allow Inbound traffic
counter accept comment "temp inbound allow"
}
# Forward Rules
@ -26,19 +52,46 @@ 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" .}}
# Generated Forward Rules
{{- range $i, $rule := $.Firewall.ForwardRules }}
{{ addressMatcher $.Object.Addresses $rule.Match }} jump {
{{- $baseServices := getBaseServices $.Object.Services $rule.Match.Services }}
{{- range $service := $baseServices }}
{{ serviceMatcher $service }}{{ if $rule.Counter }} counter name fw_{{ $i }}{{ end }} {{ $rule.Verdict.String }}
{{- end}}
}
{{- end}}
}
# Destination NAT Rules
chain prerouting {
type nat hook prerouting priority -100; policy accept;
{{template "destination_nat_rules.tmpl" .}}
# Generated Destination NAT Rules
{{- range $i, $rule := $.Firewall.DestinationNATRules }}
{{ addressMatcher $.Object.Addresses $rule.Match }} jump {
{{- $baseServices := getBaseServices $.Object.Services $rule.Match.Services }}
{{- range $service := $baseServices }}
{{ serviceMatcher $service }}{{ if $rule.Counter }} counter name dnat_{{ $i }}{{ end }} {{ destinationNatAction $ $rule }}
{{- end}}
}
{{- end}}
}
# Source NAT Rules
chain postrouting {
type nat hook postrouting priority 100; policy accept;
{{template "source_nat_rules.tmpl" .}}
# Generated Source NAT Rules
{{- range $i, $rule := $.Firewall.SourceNATRules }}
{{ addressMatcher $.Object.Addresses $rule.Match }} jump {
{{- $baseServices := getBaseServices $.Object.Services $rule.Match.Services }}
{{- range $service := $baseServices }}
{{ serviceMatcher $service }}{{ if $rule.Counter }} counter name snat_{{ $i }}{{ end }} {{ sourceNatAction $ $rule }}
{{- end}}
}
{{- end}}
}
}

View file

@ -1,2 +0,0 @@
{{ range $rule := .Firewall.SourceNATRules }}
{{ matcher $.Object.Services $.Object.Addresses $rule.Match }}{{ if $rule.Counter }} counter{{ end }}{{ if ne $rule.Comment "" }} comment "{{ $rule.Comment }}"{{ end }}{{ end }}