From 784c0c5d3a533831f4dace19c66356f2c69b24a6 Mon Sep 17 00:00:00 2001 From: Alex Tomic Date: Fri, 9 Aug 2024 15:08:12 -0400 Subject: [PATCH] ms8.1 - further improvements for single-binary operation Embed web-based and BPF C file templates so that nethadone can run entirely from a pre-built binary and not require a checkout of the source code External JS libraries will still be pulled from CDNs when accessing the web interface, tbd whether it's worth the trouble to embed those --- cmd/nethadone.go | 6 ++-- handlers/bpf.go | 41 ++++++++++++++++++--------- handlers/embed.go | 10 +++++++ handlers/handlers.go | 2 -- {ebpf => handlers}/throttle.bpf.c.tpl | 0 views/embed.go | 7 +++++ 6 files changed, 48 insertions(+), 18 deletions(-) create mode 100644 handlers/embed.go rename {ebpf => handlers}/throttle.bpf.c.tpl (100%) create mode 100644 views/embed.go diff --git a/cmd/nethadone.go b/cmd/nethadone.go index a7c332e..31102a3 100644 --- a/cmd/nethadone.go +++ b/cmd/nethadone.go @@ -3,12 +3,14 @@ package main import ( "flag" "log" + "net/http" "github.com/alecthomas/repr" "github.com/atomic77/nethadone/config" "github.com/atomic77/nethadone/database" "github.com/atomic77/nethadone/handlers" "github.com/atomic77/nethadone/policy" + "github.com/atomic77/nethadone/views" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/adaptor" "github.com/gofiber/fiber/v2/middleware/logger" @@ -32,8 +34,8 @@ func main() { database.Connect() handlers.Initialize() - // Pass the engine to the Views - engine := html.New("./views", ".tpl") + // Use embedded templates + engine := html.NewFileSystem(http.FS(views.EmbedTemplates), ".tpl") app := fiber.New(fiber.Config{ Views: engine, }) diff --git a/handlers/bpf.go b/handlers/bpf.go index 06a8b10..1bf44ca 100644 --- a/handlers/bpf.go +++ b/handlers/bpf.go @@ -88,28 +88,41 @@ func Initialize() { } func ApplyPolicies(ipPolicies *[]models.IpPolicy) { - rebuildBpf("ebpf/throttle.bpf.c.tpl", "ebpf/throttle.bpf.c", ipPolicies) - reattachThrottler(config.Cfg.LanInterface, tc.HandleMinEgress) + targFile, err := os.CreateTemp("", "throttle-*.bpf.c") + if err != nil { + log.Fatal("could not create throttler file: ", err) + } + objFile, err := os.CreateTemp("", "throttle-*.o") + if err != nil { + log.Fatal("could not create throttler object file: ", err) + } + + rebuildBpf("throttle.bpf.c.tpl", targFile, objFile, ipPolicies) + reattachThrottler(objFile, config.Cfg.LanInterface, tc.HandleMinEgress) + os.Remove(targFile.Name()) + os.Remove(objFile.Name()) } -func rebuildBpf(tplfile string, target string, ipPolicies *[]models.IpPolicy) { +func rebuildBpf(tplfile string, target *os.File, objFile *os.File, ipPolicies *[]models.IpPolicy) { log.Println("Rebuilding with ", len(*ipPolicies), " throttle targets from policy database") - - f, err := os.Create(target) - if err != nil { - log.Fatal("failed to create rendered file ", err) - } - tpl := template.Must(template.ParseFiles(tplfile)) + tpl := template.Must(template.ParseFS(EmbedThrottlerCode, tplfile)) type fdata struct { IpPolicies *[]models.IpPolicy } - err = tpl.Execute(f, fdata{IpPolicies: ipPolicies}) + + log.Println("Temporary file ", target.Name()) + err := tpl.Execute(target, fdata{IpPolicies: ipPolicies}) if err != nil { log.Fatal("failed to render file ", err) } // FIXME There surely must be a better way of doing this dynamically - cmd := exec.Command("make", "build-throttler") - cmd.Dir = "ebpf/" + cmd := exec.Command( + "clang", "-g", "-O2", + // Include both armv7 and aarch64 include folders + "-I/usr/include/aarch64-linux-gnu", "-I/usr/arm-linux-gnueabi/include", + "-Wall", "-target", "bpf", "-c", target.Name(), "-o", objFile.Name(), + ) + cmd.Dir = os.TempDir() out, err := cmd.CombinedOutput() if err != nil { log.Fatal("failed to rebuild throttler eBPF, out: ", string(out), " err: ", err) @@ -144,7 +157,7 @@ func cleanupThrottler(iface *net.Interface) { } -func reattachThrottler(ifname string, direction uint32) { +func reattachThrottler(objFile *os.File, ifname string, direction uint32) { log.Println("(Re)attaching throttler BPF to if ", ifname, " direction ", direction) @@ -157,7 +170,7 @@ func reattachThrottler(ifname string, direction uint32) { cleanupThrottler(iface) BpfCtx.ThrottleObjs = &throttleObjects{} - spec, err := ebpf.LoadCollectionSpec("ebpf/throttle.o") + spec, err := ebpf.LoadCollectionSpec(objFile.Name()) if err != nil { log.Fatal("failed to load spec ", err) } diff --git a/handlers/embed.go b/handlers/embed.go new file mode 100644 index 0000000..7943771 --- /dev/null +++ b/handlers/embed.go @@ -0,0 +1,10 @@ +package handlers + +import "embed" + +// Currently we are handling the management of the throttler +// ebpf outside of bpf2go due to challenges figuring out how to allow +// live recompiling + +//go:embed throttle.bpf.c.tpl +var EmbedThrottlerCode embed.FS diff --git a/handlers/handlers.go b/handlers/handlers.go index f31c51e..22abcc4 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -17,8 +17,6 @@ import ( "net" ) -// var config Config - func Index(c *fiber.Ctx) error { // Render index return c.Render("index", fiber.Map{ diff --git a/ebpf/throttle.bpf.c.tpl b/handlers/throttle.bpf.c.tpl similarity index 100% rename from ebpf/throttle.bpf.c.tpl rename to handlers/throttle.bpf.c.tpl diff --git a/views/embed.go b/views/embed.go new file mode 100644 index 0000000..d75a4a2 --- /dev/null +++ b/views/embed.go @@ -0,0 +1,7 @@ +package views + +import "embed" + +//go:embed *.tpl +//go:embed **/*.tpl +var EmbedTemplates embed.FS