initial nftables config generation test

This commit is contained in:
Samuel Lorch 2023-03-01 11:10:33 +01:00
parent ba99844ae4
commit b279746017
17 changed files with 215 additions and 0 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
config.json
nftables.conf
go.work
bin/*

27
api/config.go Normal file
View file

@ -0,0 +1,27 @@
package main
import (
"encoding/json"
"fmt"
"os"
"github.con/speatzle/nfsense/pkg/definitions"
)
func LoadConfiguration(file string) (*definitions.Config, error) {
var config definitions.Config
configFile, err := os.Open(file)
if err != nil {
return nil, fmt.Errorf("opening Config File %w", err)
}
defer configFile.Close()
if err != nil {
fmt.Println(err.Error())
}
jsonParser := json.NewDecoder(configFile)
err = jsonParser.Decode(&config)
if err != nil {
return nil, fmt.Errorf("decoding Config File %w", err)
}
return &config, nil
}

29
api/main.go Normal file
View file

@ -0,0 +1,29 @@
package main
import (
"github.con/speatzle/nfsense/pkg/nftables"
"golang.org/x/exp/slog"
)
func main() {
slog.Info("Starting...")
conf, err := LoadConfiguration("config.json")
if err != nil {
slog.Error("Loading Config", err)
return
}
slog.Info("Config Loaded", "config", conf)
fileContent, err := nftables.GenerateNfTablesFile(*conf)
if err != nil {
slog.Error("Generating nftables file", err)
return
}
err = nftables.ApplyNfTablesFile(fileContent)
if err != nil {
slog.Error("Applying nftables", err)
return
}
slog.Info("Wrote nftables File!")
}

5
go.mod Normal file
View file

@ -0,0 +1,5 @@
module github.con/speatzle/nfsense
go 1.19
require golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2

2
go.sum Normal file
View file

@ -0,0 +1,2 @@
golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 h1:Jvc7gsqn21cJHCmAWx0LiimpP18LZmUxkT5Mp7EZ1mI=
golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=

View file

@ -0,0 +1,6 @@
package definitions
type Config struct {
ConfigVersion int64 `json:"config_version"`
Netfilter Netfilter `json:"netfilter"`
}

View file

@ -0,0 +1,7 @@
package definitions
type Netfilter struct {
ForwardRules []ForwardRule `json:"forward_rules"`
DestinationNATRules []DestinationNATRule `json:"destination_nat_rules"`
SourceNATRules []SourceNATRule `json:"source_nat_rules"`
}

23
pkg/definitions/rules.go Normal file
View file

@ -0,0 +1,23 @@
package definitions
type Rule struct {
Match RuleMatch `json:"match"`
Comment string `json:"comment"`
Counter bool `json:"counter"`
}
type RuleMatch struct {
TCPDestinationPort uint64 `json:"tcp_destination_port"`
}
type ForwardRule struct {
Rule
}
type DestinationNATRule struct {
Rule
}
type SourceNATRule struct {
Rule
}

36
pkg/nftables/config.go Normal file
View file

@ -0,0 +1,36 @@
package nftables
import (
"bytes"
"fmt"
"os"
"github.con/speatzle/nfsense/pkg/definitions"
)
func GenerateNfTablesFile(conf definitions.Config) (string, error) {
buf := new(bytes.Buffer)
err := templates.ExecuteTemplate(buf, "nftables.tmpl", conf)
if err != nil {
return "", fmt.Errorf("executing template: %w", err)
}
return buf.String(), nil
}
func ApplyNfTablesFile(content string) error {
f, err := os.Create("nftables.conf")
if err != nil {
return fmt.Errorf("creating File: %w", err)
}
_, err = f.WriteString(content + "\n")
if err != nil {
return fmt.Errorf("writing File: %w", err)
}
err = f.Sync()
if err != nil {
return fmt.Errorf("syncing File: %w", err)
}
return nil
}

18
pkg/nftables/template.go Normal file
View file

@ -0,0 +1,18 @@
package nftables
import (
"embed"
"text/template"
)
//go:embed template
var templateFS embed.FS
var templates *template.Template
func init() {
var err error
templates, err = template.ParseFS(templateFS, "template/*.tmpl")
if err != nil {
panic(err)
}
}

View file

View file

@ -0,0 +1,3 @@
{{range $rule := .Netfilter.DestinationNATRules}}
{{template "rule_match.tmpl" .Match}} {{ if $rule.Counter }} counter {{ end }} {{ if ne $rule.Comment "" }} comment "{{ $rule.Comment }}" {{ end }}
{{end}}

View file

@ -0,0 +1,3 @@
{{range $rule := .Netfilter.ForwardRules}}
{{template "rule_match.tmpl" .Match}} {{ if $rule.Counter }} counter {{ end }} {{ if ne $rule.Comment "" }} comment "{{ $rule.Comment }}" {{ end }}
{{end}}

View file

View file

@ -0,0 +1,48 @@
#!/usr/sbin/nft -f
flush ruleset
# Address object ipsets
{{template "addresses.tmpl" .}}
# nfsense nftables inet (ipv4 + ipv6) table
table inet nfsense_inet {
# Inbound Rules
chain inbound {
type filter hook input priority 0; policy drop;
# Allow traffic from established and related packets, drop invalid
ct state vmap { established : accept, related : accept, invalid : drop }
# allow loopback traffic, anything else jump to chain for further evaluation
iifname vmap { lo : accept, $DEV_WORLD : jump inbound_world, $DEV_PRIVATE : jump inbound_private }
{{template "inbound_rules.tmpl" .}}
}
# Forward Rules
chain forward {
type filter hook forward priority 0; policy drop;
# 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" .}}
}
}

View file

@ -0,0 +1 @@
tcp dport {{ .TCPDestinationPort }}

View file

@ -0,0 +1,3 @@
{{range $rule := .Netfilter.SourceNATRules}}
{{template "rule_match.tmpl" .Match}} {{ if $rule.Counter }} counter {{ end }} {{ if ne $rule.Comment "" }} comment "{{ $rule.Comment }}" {{ end }}
{{end}}