From a9ad9811371f2dfb8067ea95bb9ade4f04da60c6 Mon Sep 17 00:00:00 2001 From: HeshamTB Date: Tue, 12 Mar 2024 23:35:57 +0300 Subject: [PATCH] Reorg and add host flag, and catch error when not root: - A previous workaround done to recover from a panic on nil ref is now not needed and removed. The issue was that I assumed cli.Exit(err, int) was a way to exit; i.e. it uses os.Exit() under the hood. However, it only constructs a struct that implements error. Hence, we should return it, not just execute it. - Also warn on root and Windows - Move IPPool init to setup rather than run --- cmd/hvpn-node/hvpn-node.go | 102 +++++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 38 deletions(-) diff --git a/cmd/hvpn-node/hvpn-node.go b/cmd/hvpn-node/hvpn-node.go index faec3a4..c452528 100644 --- a/cmd/hvpn-node/hvpn-node.go +++ b/cmd/hvpn-node/hvpn-node.go @@ -1,10 +1,10 @@ package main import ( - "errors" "fmt" "log/slog" "net/http" + "net/netip" "os" "os/signal" "time" @@ -15,7 +15,13 @@ import ( hvpnnode3 "gitea.hbanafa.com/HeshamTB/hvpn-node3" ) -var IPPool *hvpnnode3.IPPool +/* + Can change all therse vars to local func vars + IPPool can be internal to wglink or other abstraction. As well as + POrt, ifname and CIDR and so on. Use Clie.ctx to get the values +*/ + +var IPPool hvpnnode3.IPPool var VPNIPCIDR string var PrivateKeyPath cli.Path var InterfaceName string @@ -30,6 +36,13 @@ func main() { // TODO: Define error exit codes slog.SetLogLoggerLevel(slog.LevelDebug) + uid := os.Getuid() + if uid == -1 { + slog.Warn("Running on windows! whatrr u doing?") + } else if uid == 0 { + slog.Warn("Running as root! avoid running as root by setting CAP_NET_ADMIN") + } + app := createCliApp() err := app.Run(os.Args) if err != nil { @@ -40,27 +53,8 @@ func main() { } -func run() { - IPPool, err := hvpnnode3.NewPool(VPNIPCIDR) - if err != nil { - slog.Error(fmt.Sprintf("main.IPPool: %s", err)) - os.Exit(1) - } - slog.Info(fmt.Sprintf("Init ip pool %s", VPNIPCIDR)) - - testVip, err := IPPool.Allocate() - if err != nil { - slog.Error("main.testVip: ", err) - os.Exit(1) - } - - slog.Info(fmt.Sprintf("main.testVip: IP Pool Test IP: %s", testVip.String())) - err = IPPool.Free(testVip) - if err != nil { - slog.Error("main.testVip: Could not free test Vip from IPPool!", err) - os.Exit(1) - } - slog.Info("main.testVip: Test IP Freed") +func run(ctx *cli.Context) { + slog.Debug("Starting run()") apiMux := http.NewServeMux() apiMux.HandleFunc("GET /peer", hvpnnode3.HandleGetPeer(wgLink)) @@ -71,7 +65,11 @@ func run() { handler = hvpnnode3.HttpLogHandler2(handler) port := fmt.Sprintf("%d", httpPort) - host := "0.0.0.0" + host := ctx.String("host") + if host == "" { + slog.Info("Host is not set. Using 0.0.0.0") + host = "0.0.0.0" + } hostPort := fmt.Sprintf("%s:%s", host, port) slog.Info(fmt.Sprintf("Starting HVPN node on %s", hostPort)) @@ -156,6 +154,20 @@ func createCliApp() *cli.App { } app.Flags = append(app.Flags, &wgPort) + httpListenAddr := cli.StringFlag{ + Name: "host", + Usage: "IP address to listen on for HTTP API requests", + Value: "0.0.0.0", + Action: func(ctx *cli.Context, s string) error { + _, err := netip.ParseAddr(s) + if err != nil { + return cli.Exit(fmt.Sprintf("Can not parse %s as a network IP", s), 1) + } + return nil + }, + } + app.Flags = append(app.Flags, &httpListenAddr) + httpPort := cli.IntFlag{ Name: "http-port", Usage: "TCP Port for HTTP API", @@ -170,7 +182,7 @@ func createCliApp() *cli.App { if err != nil { return err } - run() + run(ctx) return nil } @@ -178,6 +190,7 @@ func createCliApp() *cli.App { } func setup() error { + slog.Debug("Starting setup()") privKeyFile, err := os.Open(PrivateKeyPath) if err != nil { return cli.Exit(err, 1) @@ -208,24 +221,14 @@ func setup() error { WgPort, ) if err != nil { + slog.Warn("Error while initlizing Wireguard netlink and device!") + slog.Warn("Ensure to run as root or with CAP_NET_ADMIN") return cli.Exit(err, 1) } wgLink = wg - // this is done to recover from the next call to wgLink.Device call - // idk a better way to recover or prevent the panic when running user - // does not have root or CAP_NET_ADMIN. - defer func() { - if r := recover(); r != nil { - slog.Error(fmt.Sprint(r)) - slog.Error("Recovered from panic. Ensure to run as root or with CAP_NET_ADMIN") - cli.Exit(errors.New("Recovered from panic. Ensure to run as root or with CAP_NET_ADMIN"),1) - os.Exit(-1) - } - }() - - slog.Info("Wireguard device is setup and running") + slog.Info("Wireguard netlink is setup and running") dev, err := wgLink.Device(InterfaceName) @@ -241,6 +244,29 @@ func setup() error { ), ) + ipPool, err := hvpnnode3.NewPool(VPNIPCIDR) + if err != nil { + slog.Error(fmt.Sprintf("main.IPPool: %s", err)) + os.Exit(1) + } + slog.Info(fmt.Sprintf("Init ip pool %s", VPNIPCIDR)) + + testVip, err := ipPool.Allocate() + if err != nil { + slog.Error("main.testVip: ", err) + os.Exit(1) + } + + slog.Info(fmt.Sprintf("main.testVip: IP Pool Test IP: %s", testVip.String())) + err = ipPool.Free(testVip) + if err != nil { + slog.Error("main.testVip: Could not free test Vip from IPPool!", err) + os.Exit(1) + } + slog.Info("main.testVip: Test IP Freed") + + IPPool = ipPool + //defer wgLink.Close() c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, os.Kill)