mirror of
https://github.com/speatzle/nfsense.git
synced 2025-05-10 10:38:20 +00:00
initial nftables config generation test
This commit is contained in:
parent
ba99844ae4
commit
b279746017
17 changed files with 215 additions and 0 deletions
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
config.json
|
||||||
|
nftables.conf
|
||||||
|
go.work
|
||||||
|
bin/*
|
27
api/config.go
Normal file
27
api/config.go
Normal 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
29
api/main.go
Normal 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
5
go.mod
Normal 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
2
go.sum
Normal 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=
|
6
pkg/definitions/config.go
Normal file
6
pkg/definitions/config.go
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
package definitions
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
ConfigVersion int64 `json:"config_version"`
|
||||||
|
Netfilter Netfilter `json:"netfilter"`
|
||||||
|
}
|
7
pkg/definitions/netfilter.go
Normal file
7
pkg/definitions/netfilter.go
Normal 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
23
pkg/definitions/rules.go
Normal 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
36
pkg/nftables/config.go
Normal 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
18
pkg/nftables/template.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
0
pkg/nftables/template/addresses.tmpl
Normal file
0
pkg/nftables/template/addresses.tmpl
Normal file
3
pkg/nftables/template/destination_nat_rules.tmpl
Normal file
3
pkg/nftables/template/destination_nat_rules.tmpl
Normal 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}}
|
3
pkg/nftables/template/forward_rules.tmpl
Normal file
3
pkg/nftables/template/forward_rules.tmpl
Normal 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}}
|
0
pkg/nftables/template/inbound_rules.tmpl
Normal file
0
pkg/nftables/template/inbound_rules.tmpl
Normal file
48
pkg/nftables/template/nftables.tmpl
Normal file
48
pkg/nftables/template/nftables.tmpl
Normal 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" .}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
1
pkg/nftables/template/rule_match.tmpl
Normal file
1
pkg/nftables/template/rule_match.tmpl
Normal file
|
@ -0,0 +1 @@
|
||||||
|
tcp dport {{ .TCPDestinationPort }}
|
3
pkg/nftables/template/source_nat_rules.tmpl
Normal file
3
pkg/nftables/template/source_nat_rules.tmpl
Normal 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}}
|
Loading…
Add table
Reference in a new issue