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:
		
							parent
							
								
									1a611616bd
								
							
						
					
					
						commit
						a9ad981137
					
				@ -1,10 +1,10 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"errors"
 | 
					 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"log/slog"
 | 
						"log/slog"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/netip"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"os/signal"
 | 
						"os/signal"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
@ -15,7 +15,13 @@ import (
 | 
				
			|||||||
	hvpnnode3 "gitea.hbanafa.com/HeshamTB/hvpn-node3"
 | 
						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 VPNIPCIDR string
 | 
				
			||||||
var PrivateKeyPath cli.Path
 | 
					var PrivateKeyPath cli.Path
 | 
				
			||||||
var InterfaceName string
 | 
					var InterfaceName string
 | 
				
			||||||
@ -30,6 +36,13 @@ func main() {
 | 
				
			|||||||
    // TODO: Define error exit codes
 | 
					    // TODO: Define error exit codes
 | 
				
			||||||
    slog.SetLogLoggerLevel(slog.LevelDebug)
 | 
					    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()
 | 
					    app := createCliApp()
 | 
				
			||||||
    err := app.Run(os.Args)
 | 
					    err := app.Run(os.Args)
 | 
				
			||||||
    if err != nil {
 | 
					    if err != nil {
 | 
				
			||||||
@ -40,27 +53,8 @@ func main() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func run() {
 | 
					func run(ctx *cli.Context) {
 | 
				
			||||||
    IPPool, err := hvpnnode3.NewPool(VPNIPCIDR)
 | 
					    slog.Debug("Starting run()")
 | 
				
			||||||
    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")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    apiMux := http.NewServeMux()
 | 
					    apiMux := http.NewServeMux()
 | 
				
			||||||
    apiMux.HandleFunc("GET /peer", hvpnnode3.HandleGetPeer(wgLink))
 | 
					    apiMux.HandleFunc("GET /peer", hvpnnode3.HandleGetPeer(wgLink))
 | 
				
			||||||
@ -71,7 +65,11 @@ func run() {
 | 
				
			|||||||
    handler = hvpnnode3.HttpLogHandler2(handler)
 | 
					    handler = hvpnnode3.HttpLogHandler2(handler)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    port := fmt.Sprintf("%d", httpPort)
 | 
					    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)
 | 
					    hostPort := fmt.Sprintf("%s:%s", host, port)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    slog.Info(fmt.Sprintf("Starting HVPN node on %s", hostPort))
 | 
					    slog.Info(fmt.Sprintf("Starting HVPN node on %s", hostPort))
 | 
				
			||||||
@ -156,6 +154,20 @@ func createCliApp() *cli.App {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    app.Flags = append(app.Flags, &wgPort)
 | 
					    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{
 | 
					    httpPort := cli.IntFlag{
 | 
				
			||||||
        Name: "http-port",
 | 
					        Name: "http-port",
 | 
				
			||||||
        Usage: "TCP Port for HTTP API",
 | 
					        Usage: "TCP Port for HTTP API",
 | 
				
			||||||
@ -170,7 +182,7 @@ func createCliApp() *cli.App {
 | 
				
			|||||||
        if err != nil {
 | 
					        if err != nil {
 | 
				
			||||||
            return err
 | 
					            return err
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        run()
 | 
					        run(ctx)
 | 
				
			||||||
        return nil
 | 
					        return nil
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -178,6 +190,7 @@ func createCliApp() *cli.App {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func setup() error {
 | 
					func setup() error {
 | 
				
			||||||
 | 
					    slog.Debug("Starting setup()")
 | 
				
			||||||
    privKeyFile, err := os.Open(PrivateKeyPath)
 | 
					    privKeyFile, err := os.Open(PrivateKeyPath)
 | 
				
			||||||
    if err != nil {
 | 
					    if err != nil {
 | 
				
			||||||
        return cli.Exit(err, 1)
 | 
					        return cli.Exit(err, 1)
 | 
				
			||||||
@ -208,24 +221,14 @@ func setup() error {
 | 
				
			|||||||
        WgPort,
 | 
					        WgPort,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    if err != nil {
 | 
					    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)
 | 
					        return cli.Exit(err, 1)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wgLink = wg
 | 
					    wgLink = wg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // this is done to recover from the next call to wgLink.Device call
 | 
					    slog.Info("Wireguard netlink is setup and running")
 | 
				
			||||||
    // 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")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dev, err := wgLink.Device(InterfaceName)
 | 
					    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()
 | 
					    //defer wgLink.Close()
 | 
				
			||||||
    c := make(chan os.Signal, 1)
 | 
					    c := make(chan os.Signal, 1)
 | 
				
			||||||
    signal.Notify(c, os.Interrupt, os.Kill)
 | 
					    signal.Notify(c, os.Interrupt, os.Kill)
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user