package api import ( "encoding/json" "net/http" "strings" "debtik/internal/dynamicrouting" ) // Summary func (s *Server) handleDynamicRoutingSummary(w http.ResponseWriter, r *http.Request) { summary := s.dynRoutingMgr.GetSummary() writeJSON(w, http.StatusOK, summary) } // ------------------------------------------------------------- // BGP Handlers // ------------------------------------------------------------- func (s *Server) handleGetBGPInstance(w http.ResponseWriter, r *http.Request) { inst := s.dynRoutingMgr.GetBGPInstance() writeJSON(w, http.StatusOK, inst) } func (s *Server) handleUpdateBGPInstance(w http.ResponseWriter, r *http.Request) { var inst dynamicrouting.BGPInstance if err := json.NewDecoder(r.Body).Decode(&inst); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()}) return } if err := s.dynRoutingMgr.UpdateBGPInstance(inst); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, s.dynRoutingMgr.GetBGPInstance()) } func (s *Server) handleListBGPPeers(w http.ResponseWriter, r *http.Request) { peers := s.dynRoutingMgr.ListBGPPeers() if peers == nil { peers = []dynamicrouting.BGPPeer{} } writeJSON(w, http.StatusOK, peers) } func (s *Server) handleSaveBGPPeer(w http.ResponseWriter, r *http.Request) { var peer dynamicrouting.BGPPeer if err := json.NewDecoder(r.Body).Decode(&peer); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()}) return } if peer.RemoteAddress == "" || peer.RemoteAS == 0 { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "remote_address and remote_as are required"}) return } if err := s.dynRoutingMgr.SaveBGPPeer(&peer); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]interface{}{"status": "success", "peer": peer}) } func (s *Server) handleDeleteBGPPeer(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if id == "" { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Missing peer id"}) return } if err := s.dynRoutingMgr.DeleteBGPPeer(id); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]string{"status": "deleted"}) } func (s *Server) handleSetBGPPeerState(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") var req struct { Disabled bool `json:"disabled"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON"}) return } if err := s.dynRoutingMgr.SetBGPPeerState(id, req.Disabled); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]interface{}{"status": "success", "disabled": req.Disabled}) } func (s *Server) handleListBGPNetworks(w http.ResponseWriter, r *http.Request) { nets := s.dynRoutingMgr.ListBGPNetworks() if nets == nil { nets = []dynamicrouting.BGPNetwork{} } writeJSON(w, http.StatusOK, nets) } func (s *Server) handleSaveBGPNetwork(w http.ResponseWriter, r *http.Request) { var net dynamicrouting.BGPNetwork if err := json.NewDecoder(r.Body).Decode(&net); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()}) return } if net.Network == "" { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "network (CIDR) is required"}) return } if err := s.dynRoutingMgr.SaveBGPNetwork(net); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]interface{}{"status": "success", "network": net}) } func (s *Server) handleDeleteBGPNetwork(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if id == "" { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Missing network id"}) return } if err := s.dynRoutingMgr.DeleteBGPNetwork(id); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]string{"status": "deleted"}) } func (s *Server) handleGetBGPRoutes(w http.ResponseWriter, r *http.Request) { routes := s.dynRoutingMgr.GetBGPRoutes() if routes == nil { routes = []dynamicrouting.BGPRoute{} } writeJSON(w, http.StatusOK, routes) } // ------------------------------------------------------------- // OSPF Handlers (RouterOS v7 Style OSPF) // ------------------------------------------------------------- func (s *Server) handleListOSPFInstances(w http.ResponseWriter, r *http.Request) { insts := s.dynRoutingMgr.ListOSPFInstances() if insts == nil { insts = []dynamicrouting.OSPFInstance{} } writeJSON(w, http.StatusOK, insts) } func (s *Server) handleSaveOSPFInstance(w http.ResponseWriter, r *http.Request) { var inst dynamicrouting.OSPFInstance if err := json.NewDecoder(r.Body).Decode(&inst); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()}) return } if err := s.dynRoutingMgr.SaveOSPFInstance(&inst); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]interface{}{"status": "success", "instance": inst}) } func (s *Server) handleDeleteOSPFInstance(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if id == "" { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Missing instance id"}) return } if err := s.dynRoutingMgr.DeleteOSPFInstance(id); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]string{"status": "deleted"}) } func (s *Server) handleSetOSPFInstanceState(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") var req struct { Disabled bool `json:"disabled"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON"}) return } if err := s.dynRoutingMgr.SetOSPFInstanceState(id, req.Disabled); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]interface{}{"status": "success", "disabled": req.Disabled}) } func (s *Server) handleGetOSPFInstance(w http.ResponseWriter, r *http.Request) { inst := s.dynRoutingMgr.GetOSPFInstance() writeJSON(w, http.StatusOK, inst) } func (s *Server) handleUpdateOSPFInstance(w http.ResponseWriter, r *http.Request) { var inst dynamicrouting.OSPFInstance if err := json.NewDecoder(r.Body).Decode(&inst); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()}) return } if err := s.dynRoutingMgr.UpdateOSPFInstance(inst); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, s.dynRoutingMgr.GetOSPFInstance()) } func (s *Server) handleListOSPFAreas(w http.ResponseWriter, r *http.Request) { areas := s.dynRoutingMgr.ListOSPFAreas() if areas == nil { areas = []dynamicrouting.OSPFArea{} } writeJSON(w, http.StatusOK, areas) } func (s *Server) handleSaveOSPFArea(w http.ResponseWriter, r *http.Request) { var area dynamicrouting.OSPFArea if err := json.NewDecoder(r.Body).Decode(&area); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()}) return } if area.AreaID == "" { area.AreaID = "0.0.0.0" } if err := s.dynRoutingMgr.SaveOSPFArea(area); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]interface{}{"status": "success", "area": area}) } func (s *Server) handleDeleteOSPFArea(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if id == "" { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Missing area id"}) return } if err := s.dynRoutingMgr.DeleteOSPFArea(id); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]string{"status": "deleted"}) } func (s *Server) handleSetOSPFAreaState(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") var req struct { Disabled bool `json:"disabled"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON"}) return } if err := s.dynRoutingMgr.SetOSPFAreaState(id, req.Disabled); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]interface{}{"status": "success", "disabled": req.Disabled}) } // Area Ranges func (s *Server) handleListOSPFAreaRanges(w http.ResponseWriter, r *http.Request) { ranges := s.dynRoutingMgr.ListOSPFAreaRanges() if ranges == nil { ranges = []dynamicrouting.OSPFAreaRange{} } writeJSON(w, http.StatusOK, ranges) } func (s *Server) handleSaveOSPFAreaRange(w http.ResponseWriter, r *http.Request) { var ar dynamicrouting.OSPFAreaRange if err := json.NewDecoder(r.Body).Decode(&ar); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()}) return } if ar.Prefix == "" { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Prefix is required"}) return } if err := s.dynRoutingMgr.SaveOSPFAreaRange(ar); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]interface{}{"status": "success", "area_range": ar}) } func (s *Server) handleDeleteOSPFAreaRange(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if id == "" { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Missing range id"}) return } if err := s.dynRoutingMgr.DeleteOSPFAreaRange(id); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]string{"status": "deleted"}) } // Interface Templates func (s *Server) handleListOSPFInterfaces(w http.ResponseWriter, r *http.Request) { ifaces := s.dynRoutingMgr.ListOSPFInterfaces() if ifaces == nil { ifaces = []dynamicrouting.OSPFInterface{} } writeJSON(w, http.StatusOK, ifaces) } func (s *Server) handleSaveOSPFInterface(w http.ResponseWriter, r *http.Request) { var iface dynamicrouting.OSPFInterface if err := json.NewDecoder(r.Body).Decode(&iface); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()}) return } if err := s.dynRoutingMgr.SaveOSPFInterface(iface); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]interface{}{"status": "success", "interface": iface}) } func (s *Server) handleDeleteOSPFInterface(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if id == "" { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Missing interface id"}) return } if err := s.dynRoutingMgr.DeleteOSPFInterface(id); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]string{"status": "deleted"}) } func (s *Server) handleSetOSPFInterfaceState(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") var req struct { Disabled bool `json:"disabled"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON"}) return } if err := s.dynRoutingMgr.SetOSPFInterfaceState(id, req.Disabled); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]interface{}{"status": "success", "disabled": req.Disabled}) } // Live Dynamic Interfaces func (s *Server) handleGetOSPFInterfacesLive(w http.ResponseWriter, r *http.Request) { live := s.dynRoutingMgr.GetOSPFInterfacesLive() if live == nil { live = []dynamicrouting.OSPFInterfaceLive{} } writeJSON(w, http.StatusOK, live) } // Static Neighbors func (s *Server) handleListOSPFStaticNeighbors(w http.ResponseWriter, r *http.Request) { nbrs := s.dynRoutingMgr.ListOSPFStaticNeighbors() if nbrs == nil { nbrs = []dynamicrouting.OSPFStaticNeighbor{} } writeJSON(w, http.StatusOK, nbrs) } func (s *Server) handleSaveOSPFStaticNeighbor(w http.ResponseWriter, r *http.Request) { var nbr dynamicrouting.OSPFStaticNeighbor if err := json.NewDecoder(r.Body).Decode(&nbr); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()}) return } if nbr.Address == "" { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Address is required"}) return } if err := s.dynRoutingMgr.SaveOSPFStaticNeighbor(nbr); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]interface{}{"status": "success", "neighbor": nbr}) } func (s *Server) handleDeleteOSPFStaticNeighbor(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if id == "" { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Missing static neighbor id"}) return } if err := s.dynRoutingMgr.DeleteOSPFStaticNeighbor(id); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]string{"status": "deleted"}) } func (s *Server) handleSetOSPFStaticNeighborState(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if id == "" { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Missing static neighbor id"}) return } var req struct { Disabled bool `json:"disabled"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()}) return } if err := s.dynRoutingMgr.SetOSPFStaticNeighborState(id, req.Disabled); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]interface{}{"status": "success", "disabled": req.Disabled}) } // Live Neighbors func (s *Server) handleGetOSPFNeighbors(w http.ResponseWriter, r *http.Request) { nbrs := s.dynRoutingMgr.GetOSPFNeighbors() if nbrs == nil { nbrs = []dynamicrouting.OSPFNeighbor{} } writeJSON(w, http.StatusOK, nbrs) } // Live LSA Database func (s *Server) handleGetOSPFLSA(w http.ResponseWriter, r *http.Request) { lsa := s.dynRoutingMgr.GetOSPFLSA() if lsa == nil { lsa = []dynamicrouting.OSPFLSA{} } writeJSON(w, http.StatusOK, lsa) } func (s *Server) handleGetOSPFRoutes(w http.ResponseWriter, r *http.Request) { routes := s.dynRoutingMgr.GetOSPFRoutes() if routes == nil { routes = []dynamicrouting.OSPFRoute{} } writeJSON(w, http.StatusOK, routes) } // ------------------------------------------------------------- // Routing Filters Handlers (/routing filter) // ------------------------------------------------------------- func (s *Server) handleListRoutingFilters(w http.ResponseWriter, r *http.Request) { filters := s.dynRoutingMgr.ListRoutingFilters() if filters == nil { filters = []dynamicrouting.RoutingFilterRule{} } writeJSON(w, http.StatusOK, filters) } func (s *Server) handleSaveRoutingFilter(w http.ResponseWriter, r *http.Request) { var rule dynamicrouting.RoutingFilterRule if err := json.NewDecoder(r.Body).Decode(&rule); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()}) return } if rule.Chain == "" { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Chain name is required"}) return } if rule.Action == "" && rule.Rule == "" { rule.Action = "accept" } if err := s.dynRoutingMgr.SaveRoutingFilter(&rule); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]string{"status": "success", "id": rule.ID}) } func (s *Server) handleDeleteRoutingFilter(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if id == "" { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Missing filter rule ID"}) return } if err := s.dynRoutingMgr.DeleteRoutingFilter(id); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]string{"status": "deleted"}) } func (s *Server) handleSetRoutingFilterState(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if id == "" { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Missing filter rule ID"}) return } var req struct { Disabled bool `json:"disabled"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON"}) return } if err := s.dynRoutingMgr.SetRoutingFilterState(id, req.Disabled); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]interface{}{"status": "success", "disabled": req.Disabled}) } // ------------------------------------------------------------- // Community Lists Handlers (/routing filter community-list) // ------------------------------------------------------------- func (s *Server) handleListCommunityLists(w http.ResponseWriter, r *http.Request) { lists := s.dynRoutingMgr.ListCommunityLists() if lists == nil { lists = []dynamicrouting.RoutingFilterCommunityList{} } writeJSON(w, http.StatusOK, lists) } func (s *Server) handleSaveCommunityList(w http.ResponseWriter, r *http.Request) { var cl dynamicrouting.RoutingFilterCommunityList if err := json.NewDecoder(r.Body).Decode(&cl); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()}) return } if strings.TrimSpace(cl.Name) == "" { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "List name is required"}) return } if err := s.dynRoutingMgr.SaveCommunityList(&cl); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]string{"status": "success", "id": cl.ID}) } func (s *Server) handleDeleteCommunityList(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if id == "" { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Missing community list ID"}) return } if err := s.dynRoutingMgr.DeleteCommunityList(id); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]string{"status": "deleted"}) } func (s *Server) handleSetCommunityListState(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if id == "" { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Missing community list ID"}) return } var req struct { Disabled bool `json:"disabled"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON"}) return } if err := s.dynRoutingMgr.SetCommunityListState(id, req.Disabled); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]interface{}{"status": "success", "disabled": req.Disabled}) } // ------------------------------------------------------------- // AS Lists Handlers (/routing filter num-list) // ------------------------------------------------------------- func (s *Server) handleListASLists(w http.ResponseWriter, r *http.Request) { lists := s.dynRoutingMgr.ListASLists() if lists == nil { lists = []dynamicrouting.RoutingFilterASList{} } writeJSON(w, http.StatusOK, lists) } func (s *Server) handleSaveASList(w http.ResponseWriter, r *http.Request) { var al dynamicrouting.RoutingFilterASList if err := json.NewDecoder(r.Body).Decode(&al); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()}) return } if strings.TrimSpace(al.Name) == "" { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "List name is required"}) return } if err := s.dynRoutingMgr.SaveASList(&al); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]string{"status": "success", "id": al.ID}) } func (s *Server) handleDeleteASList(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if id == "" { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Missing AS list ID"}) return } if err := s.dynRoutingMgr.DeleteASList(id); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]string{"status": "deleted"}) } func (s *Server) handleSetASListState(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if id == "" { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Missing AS list ID"}) return } var req struct { Disabled bool `json:"disabled"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON"}) return } if err := s.dynRoutingMgr.SetASListState(id, req.Disabled); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, map[string]interface{}{"status": "success", "disabled": req.Disabled}) }