package api import ( "encoding/json" "net/http" "proxmox-router/internal/firewall" "proxmox-router/internal/routing" ) // ======================== Firewall Summary ======================== func (s *Server) handleFirewallSummary(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, s.fwMgr.GetSummary()) } func (s *Server) handleResetFirewallCounters(w http.ResponseWriter, r *http.Request) { if err := s.fwMgr.ResetCounters(); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true}) } // ======================== Filter Rules ======================== func (s *Server) handleListFilterRules(w http.ResponseWriter, r *http.Request) { rules := s.fwMgr.ListFilterRules() writeJSON(w, http.StatusOK, rules) } func (s *Server) handleSaveFilterRule(w http.ResponseWriter, r *http.Request) { var rule firewall.FilterRule if err := json.NewDecoder(r.Body).Decode(&rule); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if err := s.fwMgr.SaveFilterRule(rule); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": rule.ID}) } func (s *Server) handleDeleteFilterRule(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if err := s.fwMgr.DeleteFilterRule(id); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id}) } func (s *Server) handleMoveFilterRule(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") var req struct { Direction string `json:"direction"` // "up" or "down" } _ = json.NewDecoder(r.Body).Decode(&req) if err := s.fwMgr.MoveFilterRule(id, req.Direction); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id}) } func (s *Server) handleSetFilterRuleState(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") var req struct { Disabled bool `json:"disabled"` } _ = json.NewDecoder(r.Body).Decode(&req) if err := s.fwMgr.SetFilterRuleState(id, req.Disabled); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id, "disabled": req.Disabled}) } // ======================== NAT Rules ======================== func (s *Server) handleListNATRules(w http.ResponseWriter, r *http.Request) { rules := s.fwMgr.ListNATRules() writeJSON(w, http.StatusOK, rules) } func (s *Server) handleSaveNATRule(w http.ResponseWriter, r *http.Request) { var rule firewall.NATRule if err := json.NewDecoder(r.Body).Decode(&rule); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if err := s.fwMgr.SaveNATRule(rule); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": rule.ID}) } func (s *Server) handleDeleteNATRule(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if err := s.fwMgr.DeleteNATRule(id); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id}) } func (s *Server) handleMoveNATRule(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") var req struct { Direction string `json:"direction"` } _ = json.NewDecoder(r.Body).Decode(&req) if err := s.fwMgr.MoveNATRule(id, req.Direction); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id}) } func (s *Server) handleSetNATRuleState(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") var req struct { Disabled bool `json:"disabled"` } _ = json.NewDecoder(r.Body).Decode(&req) if err := s.fwMgr.SetNATRuleState(id, req.Disabled); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id, "disabled": req.Disabled}) } // ======================== Mangle Rules ======================== func (s *Server) handleListMangleRules(w http.ResponseWriter, r *http.Request) { rules := s.fwMgr.ListMangleRules() writeJSON(w, http.StatusOK, rules) } func (s *Server) handleSaveMangleRule(w http.ResponseWriter, r *http.Request) { var rule firewall.MangleRule if err := json.NewDecoder(r.Body).Decode(&rule); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if err := s.fwMgr.SaveMangleRule(rule); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": rule.ID}) } func (s *Server) handleDeleteMangleRule(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if err := s.fwMgr.DeleteMangleRule(id); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id}) } func (s *Server) handleMoveMangleRule(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") var req struct { Direction string `json:"direction"` } _ = json.NewDecoder(r.Body).Decode(&req) if err := s.fwMgr.MoveMangleRule(id, req.Direction); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id}) } func (s *Server) handleSetMangleRuleState(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") var req struct { Disabled bool `json:"disabled"` } _ = json.NewDecoder(r.Body).Decode(&req) if err := s.fwMgr.SetMangleRuleState(id, req.Disabled); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id, "disabled": req.Disabled}) } // ======================== Address Lists ======================== func (s *Server) handleListAddressLists(w http.ResponseWriter, r *http.Request) { lists := s.fwMgr.ListAddressLists() writeJSON(w, http.StatusOK, lists) } func (s *Server) handleSaveAddressListEntry(w http.ResponseWriter, r *http.Request) { var entry firewall.AddressListEntry if err := json.NewDecoder(r.Body).Decode(&entry); err != nil || entry.Name == "" || entry.Address == "" { writeError(w, http.StatusBadRequest, "name and address are required") return } if err := s.fwMgr.SaveAddressListEntry(entry); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": entry.ID}) } func (s *Server) handleDeleteAddressListEntry(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if err := s.fwMgr.DeleteAddressListEntry(id); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id}) } // ======================== Active Connections ======================== func (s *Server) handleListConnections(w http.ResponseWriter, r *http.Request) { conns, err := firewall.ListActiveConnections() if err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, conns) } func (s *Server) handleKillConnection(w http.ResponseWriter, r *http.Request) { var req struct { Protocol string `json:"protocol"` Src string `json:"src"` Sport int `json:"sport"` Dst string `json:"dst"` Dport int `json:"dport"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if err := firewall.KillConnection(req.Protocol, req.Src, req.Sport, req.Dst, req.Dport); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true}) } // ======================== Routes & Policy Routing ======================== func (s *Server) handleListRoutes(w http.ResponseWriter, r *http.Request) { routes := s.routingMgr.ListRoutes() writeJSON(w, http.StatusOK, routes) } func (s *Server) handleSaveRoute(w http.ResponseWriter, r *http.Request) { var route routing.RouteItem if err := json.NewDecoder(r.Body).Decode(&route); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if err := s.routingMgr.SaveRoute(route); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": route.ID}) } func (s *Server) handleDeleteRoute(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if err := s.routingMgr.DeleteRoute(id); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id}) } func (s *Server) handleSetRouteState(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") var req struct { Disabled bool `json:"disabled"` } _ = json.NewDecoder(r.Body).Decode(&req) if err := s.routingMgr.SetRouteState(id, req.Disabled); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id, "disabled": req.Disabled}) } func (s *Server) handleListPolicyRules(w http.ResponseWriter, r *http.Request) { rules := s.routingMgr.ListPolicyRules() writeJSON(w, http.StatusOK, rules) } func (s *Server) handleSavePolicyRule(w http.ResponseWriter, r *http.Request) { var rule routing.PolicyRuleItem if err := json.NewDecoder(r.Body).Decode(&rule); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if err := s.routingMgr.SavePolicyRule(rule); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": rule.ID}) } func (s *Server) handleDeletePolicyRule(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if err := s.routingMgr.DeletePolicyRule(id); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id}) } func (s *Server) handleListRoutingTables(w http.ResponseWriter, r *http.Request) { tables := s.routingMgr.ListTables() writeJSON(w, http.StatusOK, tables) } func (s *Server) handleSaveRoutingTable(w http.ResponseWriter, r *http.Request) { var table routing.RoutingTableItem if err := json.NewDecoder(r.Body).Decode(&table); err != nil || table.Name == "" { writeError(w, http.StatusBadRequest, "table name is required") return } if err := s.routingMgr.SaveTable(table); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": table.Name}) }