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
This commit is contained in:
HeshamTB 2024-03-12 23:35:57 +03:00
parent 1a611616bd
commit a9ad981137

View File

@ -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)