15 Commits

Author SHA1 Message Date
Owen Schwartz
c04a6ecfd7 Merge pull request #4 from fosrl/dev
MTU Set to 1280 and Env Var Support
2025-01-15 22:37:04 -05:00
Owen Schwartz
bc69b625fa Better feedback about config 2025-01-15 21:55:18 -05:00
Owen Schwartz
1712b88e18 MTU 1280 by default 2025-01-15 20:54:24 -05:00
Owen Schwartz
fc451baa06 Mtu flag working 2025-01-15 00:01:34 -05:00
Owen Schwartz
fcb3b5de6a Merge branch 'env-vars' into dev 2025-01-14 23:45:12 -05:00
Owen Schwartz
5101e6f125 Add env vars 2025-01-14 22:04:06 -05:00
Owen Schwartz
217379d286 Working on mtu 2025-01-14 21:57:00 -05:00
Owen Schwartz
dc4297e6c4 Merge branch 'dev' of https://github.com/fosrl/gerbil into dev 2025-01-13 22:53:41 -05:00
Owen Schwartz
b7f1d09d4d Merge branch 'main' into dev 2025-01-13 22:53:03 -05:00
Owen Schwartz
b44d320968 Allow changing mtu; set default low 2025-01-13 22:52:11 -05:00
Milo Schwartz
29a0f02ceb fix typos in readme 2025-01-09 16:57:17 -05:00
Milo Schwartz
f0f63f22b4 Merge pull request #3 from fosrl/dev
add security policy
2025-01-08 21:58:11 -05:00
Milo Schwartz
91367f0e68 add security policy 2025-01-08 21:35:00 -05:00
Milo Schwartz
81a0ac576f Merge pull request #2 from fosrl/dev
update CONTRIBUTING.md
2025-01-06 22:45:30 -05:00
Milo Schwartz
ad0633c42d update CONTRIBUTING.md 2025-01-06 22:29:10 -05:00
5 changed files with 103 additions and 48 deletions

View File

@@ -1,6 +1,12 @@
## Contributing
Contributions are welcome! Please see the following page in our documentation with future plans and feature ideas if you are looking for a place to start.
Contributions are welcome!
Please see the contribution and local development guide on the docs page before getting started:
https://docs.fossorial.io/development
For ideas about what features to work on and our future plans, please see the roadmap:
https://docs.fossorial.io/roadmap
@@ -15,4 +21,4 @@ By creating this pull request, I grant the project maintainers an unlimited,
perpetual license to use, modify, and redistribute these contributions under any terms they
choose, including both the AGPLv3 and the Fossorial Commercial license terms. I
represent that I have the right to grant this license for all contributed content.
```
```

View File

@@ -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)
@@ -19,7 +19,7 @@ _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
@@ -27,7 +27,7 @@ Gerbil will create the peers defined in the config on the WireGuard interface. T
### 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
@@ -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.

14
SECURITY.md Normal file
View File

@@ -0,0 +1,14 @@
# Security Policy
If you discover a security vulnerability, please follow the steps below to responsibly disclose it to us:
1. **Do not create a public GitHub issue or discussion post.** This could put the security of other users at risk.
2. Send a detailed report to [security@fossorial.io](mailto:security@fossorial.io) or send a **private** message to a maintainer on [Discord](https://discord.gg/HCJR8Xhme4). Include:
- Description and location of the vulnerability.
- Potential impact of the vulnerability.
- Steps to reproduce the vulnerability.
- Potential solutions to fix the vulnerability.
- Your name/handle and a link for recognition (optional).
We aim to address the issue as soon as possible.

View File

@@ -1,7 +1,5 @@
#!/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`
@@ -9,13 +7,4 @@ 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 "$@"

108
main.go
View File

@@ -9,6 +9,7 @@ import (
"net"
"net/http"
"os"
"strconv"
"strings"
"sync"
"time"
@@ -20,8 +21,9 @@ import (
)
var (
interfaceName = "wg0"
listenAddr = ":3003"
interfaceName string
listenAddr string
mtuInt int
lastReadings = make(map[string]PeerReading)
mu sync.Mutex
)
@@ -72,52 +74,91 @@ func parseLogLevel(level string) logger.LogLevel {
}
func main() {
var err error
var wgconfig WgConfig
var (
err error
wgconfig WgConfig
configFile string
remoteConfigURL string
reportBandwidthTo string
generateAndSaveKeyTo string
reachableAt string
logLevel string
mtu string
)
// 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)")
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
}
if *listenAddrArg != "" {
listenAddr = *listenAddrArg
mtuInt, err = strconv.Atoi(mtu)
if err != nil {
logger.Fatal("Failed to parse MTU: %v", err)
}
// Validate that only one config option is provided
if (*configFile != "" && *remoteConfigURL != "") || (*configFile == "" && *remoteConfigURL == "") {
logger.Fatal("Please provide either --config or --remoteConfig, but not both")
// 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")
}
// 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)
}
@@ -138,8 +179,8 @@ 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)
}
@@ -147,7 +188,7 @@ func main() {
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)
}
@@ -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)
@@ -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)
}