Compare commits

..

2 Commits

Author SHA1 Message Date
Antonio Ojea fa641e9cea
Merge 5dae564e86 into 69f487d596 2025-02-02 12:08:44 -05:00
Antonio Ojea 5dae564e86 nf2go: convert nftables rules to golang code
One of the biggest barriers to adopt the netlink format for nftables is
the complexity of writing bytecode.

This commits adds a tool that allows to take an nftables dump and
generate the corresponding golang code and validating that the generated
code produces the exact same output.

Change-Id: I491b35e0d8062de33c67091dd4126d843b231838
Signed-off-by: Antonio Ojea <aojea@google.com>
2025-02-02 17:08:37 +00:00
2 changed files with 56 additions and 67 deletions

View File

@ -209,8 +209,6 @@ func exprFromName(name string) Any {
e = &CtTimeout{} e = &CtTimeout{}
case "fib": case "fib":
e = &Fib{} e = &Fib{}
case "numgen":
e = &Numgen{}
} }
return e return e
} }

View File

@ -2,7 +2,6 @@ package main
import ( import (
"bytes" "bytes"
"context"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
@ -13,7 +12,6 @@ import (
"regexp" "regexp"
"runtime" "runtime"
"strings" "strings"
"time"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/google/nftables" "github.com/google/nftables"
@ -71,7 +69,6 @@ func main() {
pf("\n") pf("\n")
pf("\tvar expressions []expr.Any\n") pf("\tvar expressions []expr.Any\n")
pf("\tvar chain *nftables.Chain\n") pf("\tvar chain *nftables.Chain\n")
pf("\tvar table *nftables.Table\n")
tables, err := n.ListTables() tables, err := n.ListTables()
if err != nil { if err != nil {
@ -84,9 +81,7 @@ func main() {
} }
for _, table := range tables { for _, table := range tables {
log.Printf("processing table: %s", table.Name) pf("\ttable:= n.AddTable(&nftables.Table{Family: %s,Name: \"%s\"})\n", TableFamilyString(table.Family), table.Name)
pf("\ttable = n.AddTable(&nftables.Table{Family: %s,Name: \"%s\"})\n", TableFamilyString(table.Family), table.Name)
for _, chain := range chains { for _, chain := range chains {
if chain.Table.Name != table.Name { if chain.Table.Name != table.Name {
continue continue
@ -125,10 +120,9 @@ func main() {
pf("\t})\n") pf("\t})\n")
} }
} }
}
pf("\n\tif err:= n.Flush(); err!= nil {\n") pf("\n\tif err:= n.Flush(); err!= nil {\n")
pf("\t\tlog.Fatal(err)\n") pf("\t\tlog.Fatalf(\"fail to flush rules: %v\", err)\n")
pf("\t}\n\n") pf("\t}\n\n")
pf("\tfmt.Println(\"nft ruleset applied.\")\n") pf("\tfmt.Println(\"nft ruleset applied.\")\n")
pf("}\n") pf("}\n")
@ -154,11 +148,12 @@ func main() {
} }
defer f.Close() defer f.Close()
fmt.Println("Generated code:")
mw := io.MultiWriter(f, os.Stdout) mw := io.MultiWriter(f, os.Stdout)
buf.WriteTo(mw) buf.WriteTo(mw)
// Format the generated code // Format the generated code
log.Printf("formating file: %s", tempGoFile)
cmd := exec.Command("gofmt", "-w", "-s", tempGoFile) cmd := exec.Command("gofmt", "-w", "-s", tempGoFile)
output, err := cmd.CombinedOutput() output, err := cmd.CombinedOutput()
if err != nil { if err != nil {
@ -166,18 +161,13 @@ func main() {
} }
// Run the generated code // Run the generated code
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) cmd = exec.Command("go", "run", tempGoFile)
defer cancel()
log.Printf("executing file: %s", tempGoFile)
cmd = exec.CommandContext(ctx, "go", "run", tempGoFile)
output, err = cmd.CombinedOutput() output, err = cmd.CombinedOutput()
if err != nil { if err != nil {
log.Fatalf("Execution error: %v\nOutput: %s", err, output) log.Fatalf("Execution error: %v\nOutput: %s", err, output)
} }
// Retrieve nftables state using nft // Retrieve nftables state using nft
log.Printf("obtain current ruleset: %s", tempGoFile)
actualOutput, err := listNFTRuleset() actualOutput, err := listNFTRuleset()
if err != nil { if err != nil {
log.Fatalf("Failed to list nftables ruleset: %v\noutput:%s", err, actualOutput) log.Fatalf("Failed to list nftables ruleset: %v\noutput:%s", err, actualOutput)
@ -199,6 +189,7 @@ func main() {
log.Fatalf("Failed to flush nftables ruleset: %v", err) log.Fatalf("Failed to flush nftables ruleset: %v", err)
} }
} }
}
func applyNFTRuleset(scriptPath string) (string, error) { func applyNFTRuleset(scriptPath string) (string, error) {
cmd := exec.Command("nft", "--debug=netlink", "-f", scriptPath) cmd := exec.Command("nft", "--debug=netlink", "-f", scriptPath)