Add reachableAt

This commit is contained in:
Owen Schwartz
2024-10-26 22:45:13 -04:00
parent b524b97114
commit c26d395e83
2 changed files with 80 additions and 19 deletions

View File

@@ -1,6 +1,11 @@
all: all: build push
docker build -t gerbil .
build:
docker build -t fossorial/gerbil:latest .
push:
docker push fossorial/gerbil:latest
test: test:
docker run -it -p 3002:3002 -v ./config_example.json:/config/config.json --cap-add=NET_ADMIN --cap-add=SYS_MODULE gerbil --config /config/config.json docker run -it -p 3002:3002 -v ./config_example.json:/config/config.json --cap-add=NET_ADMIN --cap-add=SYS_MODULE gerbil --config /config/config.json

90
main.go
View File

@@ -63,6 +63,8 @@ func main() {
remoteConfigURL := flag.String("remoteConfig", "", "URL to fetch remote configuration") remoteConfigURL := flag.String("remoteConfig", "", "URL to fetch remote configuration")
listenAddrArg := flag.String("listen", ":3002", "Address to listen on") listenAddrArg := flag.String("listen", ":3002", "Address to listen on")
reportBandwidthTo := flag.String("reportBandwidthTo", "", "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")
flag.Parse() flag.Parse()
if *interfaceNameArg != "" { if *interfaceNameArg != "" {
@@ -77,23 +79,64 @@ func main() {
log.Fatal("Please provide either --config or --remoteConfig, but not both") log.Fatal("Please provide either --config or --remoteConfig, but 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) {
// generate a new private key
key, err = wgtypes.GeneratePrivateKey()
if err != nil {
log.Fatalf("Failed to generate private key: %v", err)
}
// save the key to the file
err = os.WriteFile(*generateAndSaveKeyTo, []byte(key.String()), 0644)
if err != nil {
log.Fatalf("Failed to save private key: %v", err)
}
} else {
keyData, err := os.ReadFile(*generateAndSaveKeyTo)
if err != nil {
log.Fatalf("Failed to read private key: %v", err)
}
key, err = wgtypes.ParseKey(string(keyData))
if err != nil {
log.Fatalf("Failed to parse private key: %v", err)
}
}
} else {
// if no generateAndSaveKeyTo is provided, ensure that the private key is provided
if wgconfig.PrivateKey == "" {
// generate a new one
key, err = wgtypes.GeneratePrivateKey()
if err != nil {
log.Fatalf("Failed to generate private key: %v", err)
}
}
}
// Load configuration based on provided argument
if *configFile != "" {
wgconfig, err = loadConfig(*configFile)
if err != nil {
log.Fatalf("Failed to load configuration: %v", err)
}
if wgconfig.PrivateKey == "" {
wgconfig.PrivateKey = key.String()
}
} else {
wgconfig, err = loadRemoteConfig(*remoteConfigURL, key, *reachableAt)
if err != nil {
log.Fatalf("Failed to load configuration: %v", err)
}
wgconfig.PrivateKey = key.String()
}
wgClient, err = wgctrl.New() wgClient, err = wgctrl.New()
if err != nil { if err != nil {
log.Fatalf("Failed to create WireGuard client: %v", err) log.Fatalf("Failed to create WireGuard client: %v", err)
} }
defer wgClient.Close() defer wgClient.Close()
// Load configuration based on provided argument
if *configFile != "" {
wgconfig, err = loadConfig(*configFile)
} else {
wgconfig, err = loadRemoteConfig(*remoteConfigURL)
}
if err != nil {
log.Fatalf("Failed to load configuration: %v", err)
}
// Ensure the WireGuard interface exists and is configured // Ensure the WireGuard interface exists and is configured
if err := ensureWireguardInterface(wgconfig); err != nil { if err := ensureWireguardInterface(wgconfig); err != nil {
log.Fatalf("Failed to ensure WireGuard interface: %v", err) log.Fatalf("Failed to ensure WireGuard interface: %v", err)
@@ -111,9 +154,17 @@ func main() {
log.Fatal(http.ListenAndServe(listenAddr, nil)) log.Fatal(http.ListenAndServe(listenAddr, nil))
} }
func loadRemoteConfig(url string) (WgConfig, error) { func loadRemoteConfig(url string, key wgtypes.Key, reachableAt string) (WgConfig, error) {
resp, err := http.Get(url) var body *bytes.Buffer
if reachableAt == "" {
body = bytes.NewBuffer([]byte(fmt.Sprintf(`{"publicKey": "%s"}`, key.PublicKey().String())))
} else {
body = bytes.NewBuffer([]byte(fmt.Sprintf(`{"publicKey": "%s", "reachableAt": "%s"}`, key.PublicKey().String(), reachableAt)))
}
resp, err := http.Post(url, "application/json", body)
if err != nil { if err != nil {
// print the error
fmt.Println("Error fetching remote config:", err)
return WgConfig{}, err return WgConfig{}, err
} }
defer resp.Body.Close() defer resp.Body.Close()
@@ -125,6 +176,7 @@ func loadRemoteConfig(url string) (WgConfig, error) {
var config WgConfig var config WgConfig
err = json.Unmarshal(data, &config) err = json.Unmarshal(data, &config)
return config, err return config, err
} }
@@ -433,12 +485,16 @@ func calculatePeerBandwidth() ([]PeerBandwidth, error) {
var bytesInDiff, bytesOutDiff float64 var bytesInDiff, bytesOutDiff float64
if exists { if exists {
timeDiff := now.Sub(lastReading.LastChecked).Seconds() // Calculate total bytes transferred since last reading
bytesInDiff = float64(currentReading.BytesReceived-lastReading.BytesReceived) / timeDiff bytesInDiff = float64(currentReading.BytesReceived - lastReading.BytesReceived)
bytesOutDiff = float64(currentReading.BytesTransmitted-lastReading.BytesTransmitted) / timeDiff bytesOutDiff = float64(currentReading.BytesTransmitted - lastReading.BytesTransmitted)
} else {
// For first reading, use total bytes as the increment
bytesInDiff = float64(currentReading.BytesReceived)
bytesOutDiff = float64(currentReading.BytesTransmitted)
} }
// Convert to MB/s // Convert to MB
bytesInMB := bytesInDiff / (1024 * 1024) bytesInMB := bytesInDiff / (1024 * 1024)
bytesOutMB := bytesOutDiff / (1024 * 1024) bytesOutMB := bytesOutDiff / (1024 * 1024)