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) } }