Files
awg-profiler-golang/webops.go
T

153 lines
4.2 KiB
Go
Raw Normal View History

2026-07-18 10:02:43 +03:00
package main
import (
"os"
"strings"
)
// initParams carries the init-server form fields from the web wizard. Empty
// fields fall back to the same defaults the interactive CLI prompt offers.
type initParams struct {
Interface string `json:"interface"`
Network string `json:"network"`
Port string `json:"port"`
PublicIP string `json:"public_ip"`
DNS string `json:"dns"`
MTU string `json:"mtu"`
}
// initServerWeb is the non-interactive twin of initServer used by the web
// wizard. It performs the same steps — verify deps flag, generate keys and
// obfuscation parameters, write configs, enable forwarding, start the service —
// but takes its inputs from a form instead of stdin prompts.
func initServerWeb(p initParams) *Config {
osInfo := detectOS()
st := loadState()
if !st.DepsInstalled {
die("Dependencies not installed — run install-deps first")
}
requireBinary("awg")
c := &Config{}
c.Interface = valueOr(strings.TrimSpace(p.Interface), "awg0")
c.Network = valueOr(strings.TrimSpace(p.Network), "10.0.0.0/24")
requireSlash24(c.Network)
c.Port = valueOr(strings.TrimSpace(p.Port), "51820")
c.PublicIP = strings.TrimSpace(p.PublicIP)
if c.PublicIP == "" {
c.PublicIP = detectPublicIP()
}
c.DNS = valueOr(strings.TrimSpace(p.DNS), "1.1.1.1")
c.MTU = valueOr(strings.TrimSpace(p.MTU), "1420")
mtu := atoiOrDie(c.MTU)
// Obfuscation parameters — same ceilings/constraints as initServer:
// Jmin < Jmax <= MTU ; S1 <= MTU-148 ; S2 <= MTU-92 ; S1+56 != S2.
mtuJunkCeil := mtu
mtuS1Ceil := mtu - 148
mtuS2Ceil := mtu - 92
rndJc := randRange(4, 12)
rndJmin := randRange(8, minInt(mtuJunkCeil-2, 32))
rndJmax := randRange(maxInt(rndJmin+32, 80), minInt(mtuJunkCeil, 200))
rndS1 := randRange(15, minInt(mtuS1Ceil, 150))
rndS2 := randRange(15, minInt(mtuS2Ceil, 150))
for rndS1+56 == rndS2 {
rndS2 = randRange(15, minInt(mtuS2Ceil, 150))
}
c.Jc = itoa(rndJc)
c.Jmin = itoa(rndJmin)
c.Jmax = itoa(rndJmax)
c.S1 = itoa(rndS1)
c.S2 = itoa(rndS2)
// Four distinct magic-header values in [5, 2^31-1].
h1 := randMagic()
h2 := randMagic()
for h2 == h1 {
h2 = randMagic()
}
h3 := randMagic()
for h3 == h1 || h3 == h2 {
h3 = randMagic()
}
h4 := randMagic()
for h4 == h1 || h4 == h2 || h4 == h3 {
h4 = randMagic()
}
c.H1 = itoa64(h1)
c.H2 = itoa64(h2)
c.H3 = itoa64(h3)
c.H4 = itoa64(h4)
// Server keys.
priv, err := output("awg", "genkey")
if err != nil {
die("awg genkey failed: %v", err)
}
pub, err := outputWithInput(priv, "awg", "pubkey")
if err != nil {
die("awg pubkey failed: %v", err)
}
c.ServerPriv = priv
c.ServerPub = pub
srvIP := serverIP(c.Network)
defIface := defaultRouteIface()
writeConfig(c)
confPath := awgConfPath(c.Interface)
if err := os.MkdirAll(awgConfDir, 0755); err != nil {
die("Failed to create %s: %v", awgConfDir, err)
}
if err := os.WriteFile(confPath, []byte(awgConfHeader(c, c.ServerPriv, srvIP, c.Port, c.MTU)), 0600); err != nil {
die("Failed to write %s: %v", confPath, err)
}
writeNftRules(c.Interface, defIface, c.MTU)
// IP forwarding (persistent).
enableIPForwarding()
serviceEnable(osInfo, c.Interface)
serviceStart(osInfo, c.Interface)
initStorage()
info("Server initialised via web: interface=%s pubkey=%s", c.Interface, c.ServerPub)
return c
}
// syncConfigWeb is the non-interactive twin of syncConfig: it rebuilds the
// interface conf from the ACTIVE peers in the registry and optionally restarts
// the service, without the CLI's stdin confirmation prompt.
func syncConfigWeb(c *Config, osInfo *OSInfo, restart bool) {
confPath := awgConfPath(c.Interface)
if _, err := os.Stat(confPath); err != nil {
die("%s not found — run init-server first", confPath)
}
srvIP := serverIP(c.Network)
defIface := defaultRouteIface()
mtu := c.mtuOr("1420")
clients := loadRegistry()
var b strings.Builder
b.WriteString(awgConfHeader(c, c.ServerPriv, srvIP, c.Port, mtu))
for _, cl := range clients {
if cl.IsEnabled == "ACTIVE" {
b.WriteString(peerBlock(cl.Name, cl.PublicKey, cl.PSKKey, cl.IP))
}
}
if err := os.WriteFile(confPath, []byte(b.String()), 0600); err != nil {
die("Failed to write %s: %v", confPath, err)
}
writeNftRules(c.Interface, defIface, mtu)
if restart {
serviceRestart(osInfo, c.Interface)
}
}