Add WireGuard, DNS and more to the web UI and router-setup
Web UI: a WireGuard page (tunnels, peers, keys made on the router, client configs with a QR code, import of wg-quick configs, live status), a DNS page (records, wildcards, forward zones), interface dropdowns with VLAN devices, IPv6 options and a local domain. router-setup asks about VLANs, IPv6 and the domain. The router publishes its own name in DNS and hands the local domain to DHCP clients; wg and jq are on the router. Includes a script that takes over antigua's tunnels. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AeFqV9dZrK6nipHkPfyM4F
This commit is contained in:
@@ -89,14 +89,14 @@ func TestApplyValidates(t *testing.T) {
|
||||
s := mustParse(t)
|
||||
f := s.form()
|
||||
f.LANs[0].Address = "not-an-ip"
|
||||
f.LANs[0].VLAN = "5000"
|
||||
f.LANs[0].Interface = "eth2.5000"
|
||||
f.LANs = append(f.LANs, LANForm{Name: "Bad Name", Interface: "eth3", Address: "10.0.0.1"})
|
||||
_, err := s.apply(f, "/pw")
|
||||
var fe FormErrors
|
||||
if !errors.As(err, &fe) {
|
||||
t.Fatalf("expected form errors, got %v", err)
|
||||
}
|
||||
for _, k := range []string{"lans[0].address", "lans[0].vlan", "lans[1].name"} {
|
||||
for _, k := range []string{"lans[0].address", "lans[0].interface", "lans[1].name"} {
|
||||
if fe[k] == "" {
|
||||
t.Errorf("no error for %s: %v", k, fe)
|
||||
}
|
||||
@@ -106,12 +106,12 @@ func TestApplyValidates(t *testing.T) {
|
||||
func TestApplyAddsAndRemovesLANs(t *testing.T) {
|
||||
s := mustParse(t)
|
||||
f := s.form()
|
||||
f.LANs = append(f.LANs, LANForm{Name: "guest", Interface: "eth2", VLAN: "20", Address: "192.168.30.1",
|
||||
f.LANs = append(f.LANs, LANForm{Name: "guest", Interface: "eth2.20", Address: "192.168.30.1",
|
||||
DHCP: true, PoolStart: "192.168.30.100", PoolEnd: "192.168.30.199"})
|
||||
if _, err := s.apply(f, "/pw"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := s.form().LANs; len(got) != 2 || got[0].Name != "guest" || got[0].VLAN != "20" {
|
||||
if got := s.form().LANs; len(got) != 2 || got[0].Name != "guest" || got[0].Interface != "eth2.20" {
|
||||
t.Fatalf("after adding: %+v", got)
|
||||
}
|
||||
f = s.form()
|
||||
@@ -153,8 +153,8 @@ func TestVLANUplinkAndIPv6(t *testing.T) {
|
||||
if !s.form().LANs[0].IPv6PD || s.form().WAN.Interface != "enp2s0.1001" {
|
||||
t.Errorf("form does not round-trip: %+v", s.form())
|
||||
}
|
||||
devs := s.form().devices([]string{"enp2s0", "wlp3s0"})
|
||||
if len(devs) != 3 || devs[1].Name != "enp2s0.1001" || devs[1].Role != "WAN" {
|
||||
devs := s.form().devices([]string{"enp2s0", "wlp3s0"}, []string{"enp2s0.77"})
|
||||
if len(devs) != 5 || !devs[2].Removable || devs[1].Name != "enp2s0.1001" || devs[1].Role != "WAN" {
|
||||
t.Errorf("devices = %+v", devs)
|
||||
}
|
||||
|
||||
@@ -174,3 +174,29 @@ func TestVLANUplinkAndIPv6(t *testing.T) {
|
||||
t.Error("IPv6 still on")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalDomain(t *testing.T) {
|
||||
s := mustParse(t)
|
||||
f := s.form()
|
||||
f.Domain = " Home.Example.org "
|
||||
if _, err := s.apply(f, "/pw"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := str(s, "router", "dns", "domain"); got != "home.example.org" {
|
||||
t.Errorf("domain = %q", got)
|
||||
}
|
||||
if s.form().Domain != "home.example.org" {
|
||||
t.Error("the form does not show it")
|
||||
}
|
||||
f.Domain = "bad domain"
|
||||
if _, err := s.apply(f, "/pw"); err == nil {
|
||||
t.Error("a domain with a space was accepted")
|
||||
}
|
||||
f.Domain = ""
|
||||
if _, err := s.apply(f, "/pw"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := str(s, "router", "dns", "domain"); got != "" {
|
||||
t.Errorf("domain not removed: %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user