package handlers import ( "encoding/json" "fmt" "math/rand" "net/http" "nano-router/config" "nano-router/nat" "nano-router/network" ) func HandleFirewall(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: handleFirewallGet(w, r) case http.MethodPost: handleFirewallSave(w, r) default: fail(w, http.StatusMethodNotAllowed, "method not allowed") } } func handleFirewallGet(w http.ResponseWriter, r *http.Request) { cfg, err := config.Load() if err != nil { fail(w, http.StatusInternalServerError, err.Error()) return } // Collect interface names for the UI dropdowns. names, _ := network.GetInterfaces() ok(w, map[string]interface{}{ "installed": nat.IsInstalled(), "rules": cfg.Firewall.Rules, "vlan_isolation": cfg.Firewall.VLANIsolation, "interfaces": names, }) } func handleFirewallSave(w http.ResponseWriter, r *http.Request) { var body struct { Rules []config.FirewallRule `json:"rules"` VLANIsolation bool `json:"vlan_isolation"` } if err := json.NewDecoder(r.Body).Decode(&body); err != nil { fail(w, http.StatusBadRequest, "invalid json: "+err.Error()) return } // Assign IDs to new rules that lack one. for i := range body.Rules { if body.Rules[i].ID == "" { body.Rules[i].ID = fmt.Sprintf("%x", rand.Int63()) } } cfg, err := config.Load() if err != nil { fail(w, http.StatusInternalServerError, "load config: "+err.Error()) return } cfg.Firewall.Rules = body.Rules cfg.Firewall.VLANIsolation = body.VLANIsolation if err := config.Save(cfg); err != nil { fail(w, http.StatusInternalServerError, "save config: "+err.Error()) return } ok(w, map[string]string{"message": "saved"}) } func HandleFirewallApply(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { fail(w, http.StatusMethodNotAllowed, "method not allowed") return } if !nat.IsInstalled() { fail(w, http.StatusServiceUnavailable, "nftables (nft) не установлен — выполните: apk add nftables") return } cfg, err := config.Load() if err != nil { fail(w, http.StatusInternalServerError, "load config: "+err.Error()) return } if err := applyAllRules(cfg); err != nil { fail(w, http.StatusInternalServerError, "apply: "+err.Error()) return } ok(w, map[string]string{"message": "firewall applied"}) }