GHOSTWIRE 0.1.2: WireGuard server manager with web UI and API
Single Go binary that manages a WireGuard server based on pivpn's defaults: - config.json as the single source of truth, reconciled to the kernel via netlink, wgctrl and its own nftables table (NAT, forward, input) - web interface (dashboard, peers, peer detail, add peer, server, settings) and a JSON API for the future iOS app, with session and API-token auth - client private keys are never stored; configs and QR codes shown once - per-peer traffic statistics in stats.json, logs in GHOSTWIRE.jsonl - HTTPS via Let's Encrypt, self-signed, certificate files or off - self-managing: install, update (restores the old binary on failure), uninstall and passwd subcommands; systemd unit generated by the binary Tested end to end on Ubuntu 26.04 (kernel 7.0) at dev.redetzke.aero. Claude-Session: https://claude.ai/code/session_01RAnLbyQZ5ZTA7KqwXP98nw
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
//go:build !linux
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"math/rand/v2"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// simKernel stands in for the Linux kernel on other platforms. It does not
|
||||
// touch the system; it invents traffic for enabled peers so the web UI has
|
||||
// data during development.
|
||||
type simKernel struct {
|
||||
mu sync.Mutex
|
||||
peers map[string]*PeerSample
|
||||
}
|
||||
|
||||
func newKernel() (Kernel, error) {
|
||||
slog.Warn("not running on Linux: using the traffic simulator, no WireGuard interface is created")
|
||||
return &simKernel{peers: map[string]*PeerSample{}}, nil
|
||||
}
|
||||
|
||||
func (k *simKernel) Close() error { return nil }
|
||||
|
||||
func (k *simKernel) Apply(c *Config) error {
|
||||
k.mu.Lock()
|
||||
defer k.mu.Unlock()
|
||||
keep := map[string]bool{}
|
||||
for i, p := range c.Peers {
|
||||
if !p.Enabled {
|
||||
continue
|
||||
}
|
||||
keep[p.PublicKey] = true
|
||||
if k.peers[p.PublicKey] == nil {
|
||||
k.peers[p.PublicKey] = &PeerSample{
|
||||
PublicKey: p.PublicKey,
|
||||
Endpoint: fmt.Sprintf("198.51.100.%d:%d", 10+i, 40000+i*7),
|
||||
}
|
||||
}
|
||||
}
|
||||
for key := range k.peers {
|
||||
if !keep[key] {
|
||||
delete(k.peers, key)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *simKernel) Sample(string) ([]PeerSample, error) {
|
||||
k.mu.Lock()
|
||||
defer k.mu.Unlock()
|
||||
var out []PeerSample
|
||||
i := 0
|
||||
for _, p := range k.peers {
|
||||
// Every third peer stays idle; the others move some data.
|
||||
if i%3 != 2 {
|
||||
p.TxBytes += rand.Int64N(40 << 20)
|
||||
p.RxBytes += rand.Int64N(6 << 20)
|
||||
p.LastHandshake = time.Now().Add(-time.Duration(rand.IntN(90)) * time.Second)
|
||||
}
|
||||
out = append(out, *p)
|
||||
i++
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (k *simKernel) Checks(c *Config) []Check {
|
||||
return []Check{
|
||||
{"WireGuard interface", true, "simulated (not Linux)"},
|
||||
{"IPv4 forwarding", true, "simulated"},
|
||||
{"nftables rules", true, "simulated"},
|
||||
{"Uplink", true, "IPv4 via eth0 (simulated)"},
|
||||
}
|
||||
}
|
||||
|
||||
func (k *simKernel) Uplink(c *Config, v6 bool) string {
|
||||
if v6 && c.Server.UplinkV6 != "" {
|
||||
return c.Server.UplinkV6
|
||||
}
|
||||
if !v6 && c.Server.UplinkV4 != "" {
|
||||
return c.Server.UplinkV4
|
||||
}
|
||||
return "eth0"
|
||||
}
|
||||
|
||||
func (k *simKernel) Down(*Config) error { return nil }
|
||||
Reference in New Issue
Block a user