firewall_handlers.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. package api
  2. import (
  3. "encoding/json"
  4. "net/http"
  5. "proxmox-router/internal/firewall"
  6. "proxmox-router/internal/routing"
  7. )
  8. // ======================== Firewall Summary ========================
  9. func (s *Server) handleFirewallSummary(w http.ResponseWriter, r *http.Request) {
  10. writeJSON(w, http.StatusOK, s.fwMgr.GetSummary())
  11. }
  12. func (s *Server) handleResetFirewallCounters(w http.ResponseWriter, r *http.Request) {
  13. if err := s.fwMgr.ResetCounters(); err != nil {
  14. writeError(w, http.StatusInternalServerError, err.Error())
  15. return
  16. }
  17. writeJSON(w, http.StatusOK, map[string]any{"success": true})
  18. }
  19. // ======================== Filter Rules ========================
  20. func (s *Server) handleListFilterRules(w http.ResponseWriter, r *http.Request) {
  21. rules := s.fwMgr.ListFilterRules()
  22. writeJSON(w, http.StatusOK, rules)
  23. }
  24. func (s *Server) handleSaveFilterRule(w http.ResponseWriter, r *http.Request) {
  25. var rule firewall.FilterRule
  26. if err := json.NewDecoder(r.Body).Decode(&rule); err != nil {
  27. writeError(w, http.StatusBadRequest, "invalid request body")
  28. return
  29. }
  30. if err := s.fwMgr.SaveFilterRule(rule); err != nil {
  31. writeError(w, http.StatusInternalServerError, err.Error())
  32. return
  33. }
  34. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": rule.ID})
  35. }
  36. func (s *Server) handleDeleteFilterRule(w http.ResponseWriter, r *http.Request) {
  37. id := r.PathValue("id")
  38. if err := s.fwMgr.DeleteFilterRule(id); err != nil {
  39. writeError(w, http.StatusInternalServerError, err.Error())
  40. return
  41. }
  42. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id})
  43. }
  44. func (s *Server) handleMoveFilterRule(w http.ResponseWriter, r *http.Request) {
  45. id := r.PathValue("id")
  46. var req struct {
  47. Direction string `json:"direction"` // "up" or "down"
  48. }
  49. _ = json.NewDecoder(r.Body).Decode(&req)
  50. if err := s.fwMgr.MoveFilterRule(id, req.Direction); err != nil {
  51. writeError(w, http.StatusInternalServerError, err.Error())
  52. return
  53. }
  54. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id})
  55. }
  56. func (s *Server) handleSetFilterRuleState(w http.ResponseWriter, r *http.Request) {
  57. id := r.PathValue("id")
  58. var req struct {
  59. Disabled bool `json:"disabled"`
  60. }
  61. _ = json.NewDecoder(r.Body).Decode(&req)
  62. if err := s.fwMgr.SetFilterRuleState(id, req.Disabled); err != nil {
  63. writeError(w, http.StatusInternalServerError, err.Error())
  64. return
  65. }
  66. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id, "disabled": req.Disabled})
  67. }
  68. // ======================== NAT Rules ========================
  69. func (s *Server) handleListNATRules(w http.ResponseWriter, r *http.Request) {
  70. rules := s.fwMgr.ListNATRules()
  71. writeJSON(w, http.StatusOK, rules)
  72. }
  73. func (s *Server) handleSaveNATRule(w http.ResponseWriter, r *http.Request) {
  74. var rule firewall.NATRule
  75. if err := json.NewDecoder(r.Body).Decode(&rule); err != nil {
  76. writeError(w, http.StatusBadRequest, "invalid request body")
  77. return
  78. }
  79. if err := s.fwMgr.SaveNATRule(rule); err != nil {
  80. writeError(w, http.StatusInternalServerError, err.Error())
  81. return
  82. }
  83. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": rule.ID})
  84. }
  85. func (s *Server) handleDeleteNATRule(w http.ResponseWriter, r *http.Request) {
  86. id := r.PathValue("id")
  87. if err := s.fwMgr.DeleteNATRule(id); err != nil {
  88. writeError(w, http.StatusInternalServerError, err.Error())
  89. return
  90. }
  91. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id})
  92. }
  93. func (s *Server) handleMoveNATRule(w http.ResponseWriter, r *http.Request) {
  94. id := r.PathValue("id")
  95. var req struct {
  96. Direction string `json:"direction"`
  97. }
  98. _ = json.NewDecoder(r.Body).Decode(&req)
  99. if err := s.fwMgr.MoveNATRule(id, req.Direction); err != nil {
  100. writeError(w, http.StatusInternalServerError, err.Error())
  101. return
  102. }
  103. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id})
  104. }
  105. func (s *Server) handleSetNATRuleState(w http.ResponseWriter, r *http.Request) {
  106. id := r.PathValue("id")
  107. var req struct {
  108. Disabled bool `json:"disabled"`
  109. }
  110. _ = json.NewDecoder(r.Body).Decode(&req)
  111. if err := s.fwMgr.SetNATRuleState(id, req.Disabled); err != nil {
  112. writeError(w, http.StatusInternalServerError, err.Error())
  113. return
  114. }
  115. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id, "disabled": req.Disabled})
  116. }
  117. // ======================== Mangle Rules ========================
  118. func (s *Server) handleListMangleRules(w http.ResponseWriter, r *http.Request) {
  119. rules := s.fwMgr.ListMangleRules()
  120. writeJSON(w, http.StatusOK, rules)
  121. }
  122. func (s *Server) handleSaveMangleRule(w http.ResponseWriter, r *http.Request) {
  123. var rule firewall.MangleRule
  124. if err := json.NewDecoder(r.Body).Decode(&rule); err != nil {
  125. writeError(w, http.StatusBadRequest, "invalid request body")
  126. return
  127. }
  128. if err := s.fwMgr.SaveMangleRule(rule); err != nil {
  129. writeError(w, http.StatusInternalServerError, err.Error())
  130. return
  131. }
  132. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": rule.ID})
  133. }
  134. func (s *Server) handleDeleteMangleRule(w http.ResponseWriter, r *http.Request) {
  135. id := r.PathValue("id")
  136. if err := s.fwMgr.DeleteMangleRule(id); err != nil {
  137. writeError(w, http.StatusInternalServerError, err.Error())
  138. return
  139. }
  140. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id})
  141. }
  142. func (s *Server) handleMoveMangleRule(w http.ResponseWriter, r *http.Request) {
  143. id := r.PathValue("id")
  144. var req struct {
  145. Direction string `json:"direction"`
  146. }
  147. _ = json.NewDecoder(r.Body).Decode(&req)
  148. if err := s.fwMgr.MoveMangleRule(id, req.Direction); err != nil {
  149. writeError(w, http.StatusInternalServerError, err.Error())
  150. return
  151. }
  152. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id})
  153. }
  154. func (s *Server) handleSetMangleRuleState(w http.ResponseWriter, r *http.Request) {
  155. id := r.PathValue("id")
  156. var req struct {
  157. Disabled bool `json:"disabled"`
  158. }
  159. _ = json.NewDecoder(r.Body).Decode(&req)
  160. if err := s.fwMgr.SetMangleRuleState(id, req.Disabled); err != nil {
  161. writeError(w, http.StatusInternalServerError, err.Error())
  162. return
  163. }
  164. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id, "disabled": req.Disabled})
  165. }
  166. // ======================== Address Lists ========================
  167. func (s *Server) handleListAddressLists(w http.ResponseWriter, r *http.Request) {
  168. lists := s.fwMgr.ListAddressLists()
  169. writeJSON(w, http.StatusOK, lists)
  170. }
  171. func (s *Server) handleSaveAddressListEntry(w http.ResponseWriter, r *http.Request) {
  172. var entry firewall.AddressListEntry
  173. if err := json.NewDecoder(r.Body).Decode(&entry); err != nil || entry.Name == "" || entry.Address == "" {
  174. writeError(w, http.StatusBadRequest, "name and address are required")
  175. return
  176. }
  177. if err := s.fwMgr.SaveAddressListEntry(entry); err != nil {
  178. writeError(w, http.StatusInternalServerError, err.Error())
  179. return
  180. }
  181. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": entry.ID})
  182. }
  183. func (s *Server) handleDeleteAddressListEntry(w http.ResponseWriter, r *http.Request) {
  184. id := r.PathValue("id")
  185. if err := s.fwMgr.DeleteAddressListEntry(id); err != nil {
  186. writeError(w, http.StatusInternalServerError, err.Error())
  187. return
  188. }
  189. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id})
  190. }
  191. func (s *Server) handleSetAddressListEntryState(w http.ResponseWriter, r *http.Request) {
  192. id := r.PathValue("id")
  193. var req struct {
  194. Disabled bool `json:"disabled"`
  195. }
  196. _ = json.NewDecoder(r.Body).Decode(&req)
  197. if err := s.fwMgr.SetAddressListEntryState(id, req.Disabled); err != nil {
  198. writeError(w, http.StatusInternalServerError, err.Error())
  199. return
  200. }
  201. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id, "disabled": req.Disabled})
  202. }
  203. // ======================== Geo-Location ========================
  204. func (s *Server) handleGeoIPStatus(w http.ResponseWriter, r *http.Request) {
  205. status := s.fwMgr.GeoIP().GetStatus()
  206. writeJSON(w, http.StatusOK, status)
  207. }
  208. func (s *Server) handleGeoIPConfig(w http.ResponseWriter, r *http.Request) {
  209. var req struct {
  210. AutoUpdate bool `json:"auto_update"`
  211. IntervalHours int `json:"interval_hours"`
  212. }
  213. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  214. writeError(w, http.StatusBadRequest, "invalid request body")
  215. return
  216. }
  217. if err := s.fwMgr.GeoIP().SetConfig(req.AutoUpdate, req.IntervalHours); err != nil {
  218. writeError(w, http.StatusInternalServerError, err.Error())
  219. return
  220. }
  221. writeJSON(w, http.StatusOK, map[string]any{"success": true, "config": req})
  222. }
  223. func (s *Server) handleListGeoCountries(w http.ResponseWriter, r *http.Request) {
  224. countries := s.fwMgr.GeoIP().ListCountries()
  225. writeJSON(w, http.StatusOK, countries)
  226. }
  227. func (s *Server) handleToggleGeoCountry(w http.ResponseWriter, r *http.Request) {
  228. code := r.PathValue("code")
  229. var req struct {
  230. Enabled bool `json:"enabled"`
  231. }
  232. _ = json.NewDecoder(r.Body).Decode(&req)
  233. if err := s.fwMgr.GeoIP().ToggleCountry(code, req.Enabled); err != nil {
  234. writeError(w, http.StatusInternalServerError, err.Error())
  235. return
  236. }
  237. writeJSON(w, http.StatusOK, map[string]any{"success": true, "code": code, "enabled": req.Enabled})
  238. }
  239. func (s *Server) handleUpdateGeoCountry(w http.ResponseWriter, r *http.Request) {
  240. code := r.PathValue("code")
  241. count, err := s.fwMgr.GeoIP().SyncCountryZone(code)
  242. if err != nil {
  243. writeError(w, http.StatusInternalServerError, err.Error())
  244. return
  245. }
  246. writeJSON(w, http.StatusOK, map[string]any{"success": true, "code": code, "subnets": count})
  247. }
  248. func (s *Server) handleGeoIPUpdateNow(w http.ResponseWriter, r *http.Request) {
  249. if err := s.fwMgr.GeoIP().UpdateNow(); err != nil {
  250. writeError(w, http.StatusConflict, err.Error())
  251. return
  252. }
  253. writeJSON(w, http.StatusOK, map[string]any{"success": true, "message": "update started"})
  254. }
  255. func (s *Server) handleGeoIPBatchToggle(w http.ResponseWriter, r *http.Request) {
  256. var req struct {
  257. Preset string `json:"preset"`
  258. Codes []string `json:"codes"`
  259. Enabled bool `json:"enabled"`
  260. }
  261. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  262. writeError(w, http.StatusBadRequest, "invalid request body")
  263. return
  264. }
  265. if err := s.fwMgr.GeoIP().BatchToggle(req.Preset, req.Enabled, req.Codes); err != nil {
  266. writeError(w, http.StatusInternalServerError, err.Error())
  267. return
  268. }
  269. writeJSON(w, http.StatusOK, map[string]any{"success": true, "preset": req.Preset, "enabled": req.Enabled})
  270. }
  271. func (s *Server) handleGeoCountrySubnets(w http.ResponseWriter, r *http.Request) {
  272. code := r.PathValue("code")
  273. subnets := s.fwMgr.GeoIP().GetCountrySubnets(code, 100)
  274. writeJSON(w, http.StatusOK, map[string]any{"code": code, "subnets": subnets})
  275. }
  276. // ======================== Active Connections ========================
  277. func (s *Server) handleListConnections(w http.ResponseWriter, r *http.Request) {
  278. conns, err := firewall.ListActiveConnections()
  279. if err != nil {
  280. writeError(w, http.StatusInternalServerError, err.Error())
  281. return
  282. }
  283. writeJSON(w, http.StatusOK, conns)
  284. }
  285. func (s *Server) handleKillConnection(w http.ResponseWriter, r *http.Request) {
  286. var req struct {
  287. Protocol string `json:"protocol"`
  288. Src string `json:"src"`
  289. Sport int `json:"sport"`
  290. Dst string `json:"dst"`
  291. Dport int `json:"dport"`
  292. }
  293. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  294. writeError(w, http.StatusBadRequest, "invalid request body")
  295. return
  296. }
  297. if err := firewall.KillConnection(req.Protocol, req.Src, req.Sport, req.Dst, req.Dport); err != nil {
  298. writeError(w, http.StatusInternalServerError, err.Error())
  299. return
  300. }
  301. writeJSON(w, http.StatusOK, map[string]any{"success": true})
  302. }
  303. // ======================== Routes & Policy Routing ========================
  304. func (s *Server) handleListRoutes(w http.ResponseWriter, r *http.Request) {
  305. routes := s.routingMgr.ListRoutes()
  306. writeJSON(w, http.StatusOK, routes)
  307. }
  308. func (s *Server) handleSaveRoute(w http.ResponseWriter, r *http.Request) {
  309. var route routing.RouteItem
  310. if err := json.NewDecoder(r.Body).Decode(&route); err != nil {
  311. writeError(w, http.StatusBadRequest, "invalid request body")
  312. return
  313. }
  314. if err := s.routingMgr.SaveRoute(route); err != nil {
  315. writeError(w, http.StatusInternalServerError, err.Error())
  316. return
  317. }
  318. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": route.ID})
  319. }
  320. func (s *Server) handleDeleteRoute(w http.ResponseWriter, r *http.Request) {
  321. id := r.PathValue("id")
  322. if err := s.routingMgr.DeleteRoute(id); err != nil {
  323. writeError(w, http.StatusInternalServerError, err.Error())
  324. return
  325. }
  326. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id})
  327. }
  328. func (s *Server) handleSetRouteState(w http.ResponseWriter, r *http.Request) {
  329. id := r.PathValue("id")
  330. var req struct {
  331. Disabled bool `json:"disabled"`
  332. }
  333. _ = json.NewDecoder(r.Body).Decode(&req)
  334. if err := s.routingMgr.SetRouteState(id, req.Disabled); err != nil {
  335. writeError(w, http.StatusInternalServerError, err.Error())
  336. return
  337. }
  338. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id, "disabled": req.Disabled})
  339. }
  340. func (s *Server) handleListPolicyRules(w http.ResponseWriter, r *http.Request) {
  341. rules := s.routingMgr.ListPolicyRules()
  342. writeJSON(w, http.StatusOK, rules)
  343. }
  344. func (s *Server) handleSavePolicyRule(w http.ResponseWriter, r *http.Request) {
  345. var rule routing.PolicyRuleItem
  346. if err := json.NewDecoder(r.Body).Decode(&rule); err != nil {
  347. writeError(w, http.StatusBadRequest, "invalid request body")
  348. return
  349. }
  350. if err := s.routingMgr.SavePolicyRule(rule); err != nil {
  351. writeError(w, http.StatusInternalServerError, err.Error())
  352. return
  353. }
  354. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": rule.ID})
  355. }
  356. func (s *Server) handleDeletePolicyRule(w http.ResponseWriter, r *http.Request) {
  357. id := r.PathValue("id")
  358. if err := s.routingMgr.DeletePolicyRule(id); err != nil {
  359. writeError(w, http.StatusInternalServerError, err.Error())
  360. return
  361. }
  362. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id})
  363. }
  364. func (s *Server) handleListRoutingTables(w http.ResponseWriter, r *http.Request) {
  365. tables := s.routingMgr.ListTables()
  366. writeJSON(w, http.StatusOK, tables)
  367. }
  368. func (s *Server) handleSaveRoutingTable(w http.ResponseWriter, r *http.Request) {
  369. var table routing.RoutingTableItem
  370. if err := json.NewDecoder(r.Body).Decode(&table); err != nil || table.Name == "" {
  371. writeError(w, http.StatusBadRequest, "table name is required")
  372. return
  373. }
  374. if err := s.routingMgr.SaveTable(table); err != nil {
  375. writeError(w, http.StatusInternalServerError, err.Error())
  376. return
  377. }
  378. writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": table.Name})
  379. }