Skip to content

Commit

Permalink
Merge pull request #4 from fosrl/dev
Browse files Browse the repository at this point in the history
MTU Set to 1280 and Env Var Support
  • Loading branch information
oschwartz10612 authored Jan 16, 2025
2 parents f0f63f2 + bc69b62 commit c04a6ec
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 47 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Gerbil is a simple [WireGuard](https://www.wireguard.com/) interface management

### Installation and Documentation

Gerbil can be used stand alone with your own API, a static JSON file, or with Pangolin and Newt as part of the larger system. See documentation below:
Gerbil can be used standalone with your own API, a static JSON file, or with Pangolin and Newt as part of the larger system. See documentation below:

- [Installation Instructions](https://docs.fossorial.io)
- [Full Documentation](https://docs.fossorial.io)
Expand All @@ -19,15 +19,15 @@ _Sample output of a Gerbil container connected to Pangolin and terminating vario

### Setup WireGuard

A WireGuard interface will be created and configured on the local Linux machine or in the Docker container according to the values given in either a JSON config file or via the remote server. If the interface already exists it will be reconfigured.
A WireGuard interface will be created and configured on the local Linux machine or in the Docker container according to the values given in either a JSON config file or via the remote server. If the interface already exists, it will be reconfigured.

### Manage Peers

Gerbil will create the peers defined in the config on the WireGuard interface. The HTTP API can be used to remove, create, and update peers on the interface dynamically.

### Report Bandwidth

Bytes transmitted in and out of each peer is collected every 10 seconds and incremental usage is reported via the "reportBandwidthTo" endpoint. This can be used to track data usage of each peer on the remote server.
Bytes transmitted in and out of each peer are collected every 10 seconds, and incremental usage is reported via the "reportBandwidthTo" endpoint. This can be used to track data usage of each peer on the remote server.

## CLI Args

Expand Down Expand Up @@ -97,4 +97,4 @@ Gerbil is dual licensed under the AGPLv3 and the Fossorial Commercial license. F

## Contributions

Please see [CONTRIBUTIONS](./CONTRIBUTING.md) in the repository for guidelines and best practices.
Please see [CONTRIBUTIONS](./CONTRIBUTING.md) in the repository for guidelines and best practices.
11 changes: 0 additions & 11 deletions entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,21 +1,10 @@
#!/bin/sh

# Sample from https://github.com/traefik/traefik-library-image/blob/5070edb25b03cca6802d75d5037576c840f73fdd/v3.1/alpine/entrypoint.sh

set -e

# first arg is `-f` or `--some-option`
if [ "${1#-}" != "$1" ]; then
set -- gerbil "$@"
fi

# if our command is a valid Gerbil subcommand, let's invoke it through Gerbil instead
# (this allows for "docker run gerbil version", etc)
if gerbil "$1" --help >/dev/null 2>&1
then
set -- gerbil "$@"
else
echo "= '$1' is not a Gerbil command: assuming shell execution." 1>&2
fi

exec "$@"
110 changes: 78 additions & 32 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"net"
"net/http"
"os"
"strconv"
"strings"
"sync"
"time"
Expand All @@ -20,8 +21,9 @@ import (
)

var (
interfaceName = "wg0"
listenAddr = ":3003"
interfaceName string
listenAddr string
mtuInt int
lastReadings = make(map[string]PeerReading)
mu sync.Mutex
)
Expand Down Expand Up @@ -72,52 +74,91 @@ func parseLogLevel(level string) logger.LogLevel {
}

func main() {
var err error
var wgconfig WgConfig

// Define command line flags
interfaceNameArg := flag.String("interface", "wg0", "Name of the WireGuard interface")
configFile := flag.String("config", "", "Path to local configuration file")
remoteConfigURL := flag.String("remoteConfig", "", "URL to fetch remote configuration")
listenAddrArg := flag.String("listen", ":3003", "Address to listen on")
reportBandwidthTo := flag.String("reportBandwidthTo", "", "Address to listen on")
generateAndSaveKeyTo := flag.String("generateAndSaveKeyTo", "", "Path to save generated private key")
reachableAt := flag.String("reachableAt", "", "Endpoint of the http server to tell remote config about")
logLevel := flag.String("log-level", "INFO", "Log level (DEBUG, INFO, WARN, ERROR, FATAL)")

var (
err error
wgconfig WgConfig
configFile string
remoteConfigURL string
reportBandwidthTo string
generateAndSaveKeyTo string
reachableAt string
logLevel string
mtu string
)

interfaceName = os.Getenv("INTERFACE")
configFile = os.Getenv("CONFIG")
remoteConfigURL = os.Getenv("REMOTE_CONFIG")
listenAddr = os.Getenv("LISTEN")
reportBandwidthTo = os.Getenv("REPORT_BANDWIDTH_TO")
generateAndSaveKeyTo = os.Getenv("GENERATE_AND_SAVE_KEY_TO")
reachableAt = os.Getenv("REACHABLE_AT")
logLevel = os.Getenv("LOG_LEVEL")
mtu = os.Getenv("MTU")

if interfaceName == "" {
flag.StringVar(&interfaceName, "interface", "wg0", "Name of the WireGuard interface")
}
if configFile == "" {
flag.StringVar(&configFile, "config", "", "Path to local configuration file")
}
if remoteConfigURL == "" {
flag.StringVar(&remoteConfigURL, "remoteConfig", "", "URL to fetch remote configuration")
}
if listenAddr == "" {
flag.StringVar(&listenAddr, "listen", ":3003", "Address to listen on")
}
if reportBandwidthTo == "" {
flag.StringVar(&reportBandwidthTo, "reportBandwidthTo", "", "Address to listen on")
}
if generateAndSaveKeyTo == "" {
flag.StringVar(&generateAndSaveKeyTo, "generateAndSaveKeyTo", "", "Path to save generated private key")
}
if reachableAt == "" {
flag.StringVar(&reachableAt, "reachableAt", "", "Endpoint of the http server to tell remote config about")
}
if logLevel == "" {
flag.StringVar(&logLevel, "log-level", "INFO", "Log level (DEBUG, INFO, WARN, ERROR, FATAL)")
}
if mtu == "" {
flag.StringVar(&mtu, "mtu", "1280", "MTU of the WireGuard interface")
}
flag.Parse()

logger.Init()
logger.GetLogger().SetLevel(parseLogLevel(*logLevel))
logger.GetLogger().SetLevel(parseLogLevel(logLevel))

if *interfaceNameArg != "" {
interfaceName = *interfaceNameArg
mtuInt, err = strconv.Atoi(mtu)
if err != nil {
logger.Fatal("Failed to parse MTU: %v", err)
}
if *listenAddrArg != "" {
listenAddr = *listenAddrArg

// are they missing either the config file or the remote config URL?
if configFile == "" && remoteConfigURL == "" {
logger.Fatal("You must provide either a config file or a remote config URL")
}

// Validate that only one config option is provided
if (*configFile != "" && *remoteConfigURL != "") || (*configFile == "" && *remoteConfigURL == "") {
logger.Fatal("Please provide either --config or --remoteConfig, but not both")
// do they have both the config file and the remote config URL?
if configFile != "" && remoteConfigURL != "" {
logger.Fatal("You must provide either a config file or a remote config URL, not both")
}

var key wgtypes.Key
// if generateAndSaveKeyTo is provided, generate a private key and save it to the file. if the file already exists, load the key from the file
if *generateAndSaveKeyTo != "" {
if _, err := os.Stat(*generateAndSaveKeyTo); os.IsNotExist(err) {
if generateAndSaveKeyTo != "" {
if _, err := os.Stat(generateAndSaveKeyTo); os.IsNotExist(err) {
// generate a new private key
key, err = wgtypes.GeneratePrivateKey()
if err != nil {
logger.Fatal("Failed to generate private key: %v", err)
}
// save the key to the file
err = os.WriteFile(*generateAndSaveKeyTo, []byte(key.String()), 0644)
err = os.WriteFile(generateAndSaveKeyTo, []byte(key.String()), 0644)
if err != nil {
logger.Fatal("Failed to save private key: %v", err)
}
} else {
keyData, err := os.ReadFile(*generateAndSaveKeyTo)
keyData, err := os.ReadFile(generateAndSaveKeyTo)
if err != nil {
logger.Fatal("Failed to read private key: %v", err)
}
Expand All @@ -138,16 +179,16 @@ func main() {
}

// Load configuration based on provided argument
if *configFile != "" {
wgconfig, err = loadConfig(*configFile)
if configFile != "" {
wgconfig, err = loadConfig(configFile)
if err != nil {
logger.Fatal("Failed to load configuration: %v", err)
}
if wgconfig.PrivateKey == "" {
wgconfig.PrivateKey = key.String()
}
} else {
wgconfig, err = loadRemoteConfig(*remoteConfigURL, key, *reachableAt)
wgconfig, err = loadRemoteConfig(remoteConfigURL, key, reachableAt)
if err != nil {
logger.Fatal("Failed to load configuration: %v", err)
}
Expand All @@ -168,8 +209,8 @@ func main() {
// Ensure the WireGuard peers exist
ensureWireguardPeers(wgconfig.Peers)

if *reportBandwidthTo != "" {
go periodicBandwidthCheck(*reportBandwidthTo)
if reportBandwidthTo != "" {
go periodicBandwidthCheck(reportBandwidthTo)
}

http.HandleFunc("/peer", handlePeer)
Expand Down Expand Up @@ -288,6 +329,11 @@ func ensureWireguardInterface(wgconfig WgConfig) error {
if err != nil {
return fmt.Errorf("failed to get interface: %v", err)
}

if err := netlink.LinkSetMTU(link, mtuInt); err != nil {
return fmt.Errorf("failed to set MTU: %v", err)
}

if err := netlink.LinkSetUp(link); err != nil {
return fmt.Errorf("failed to bring up interface: %v", err)
}
Expand Down

0 comments on commit c04a6ec

Please sign in to comment.