firewall_handlers.go 14 KB

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