firewall_handlers.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  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 rule.ID == "" {
  85. rule.ID = fmt.Sprintf("nat-%d", time.Now().UnixNano())
  86. }
  87. if err := s.fwMgr.SaveNATRule(rule); err != nil {
  88. writeError(w, http.StatusInternalServerError, err.Error())
  89. return
  90. }
  91. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": rule.ID})
  92. }
  93. func (s *Server) handleDeleteNATRule(w http.ResponseWriter, r *http.Request) {
  94. id := r.PathValue("id")
  95. if err := s.fwMgr.DeleteNATRule(id); err != nil {
  96. writeError(w, http.StatusInternalServerError, err.Error())
  97. return
  98. }
  99. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id})
  100. }
  101. func (s *Server) handleMoveNATRule(w http.ResponseWriter, r *http.Request) {
  102. id := r.PathValue("id")
  103. var req struct {
  104. Direction string `json:"direction"`
  105. }
  106. _ = json.NewDecoder(r.Body).Decode(&req)
  107. if err := s.fwMgr.MoveNATRule(id, req.Direction); err != nil {
  108. writeError(w, http.StatusInternalServerError, err.Error())
  109. return
  110. }
  111. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id})
  112. }
  113. func (s *Server) handleSetNATRuleState(w http.ResponseWriter, r *http.Request) {
  114. id := r.PathValue("id")
  115. var req struct {
  116. Disabled bool `json:"disabled"`
  117. }
  118. _ = json.NewDecoder(r.Body).Decode(&req)
  119. if err := s.fwMgr.SetNATRuleState(id, req.Disabled); err != nil {
  120. writeError(w, http.StatusInternalServerError, err.Error())
  121. return
  122. }
  123. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id, "disabled": req.Disabled})
  124. }
  125. // ======================== Mangle Rules ========================
  126. func (s *Server) handleListMangleRules(w http.ResponseWriter, r *http.Request) {
  127. rules := s.fwMgr.ListMangleRules()
  128. writeJSON(w, http.StatusOK, rules)
  129. }
  130. func (s *Server) handleSaveMangleRule(w http.ResponseWriter, r *http.Request) {
  131. var rule firewall.MangleRule
  132. if err := json.NewDecoder(r.Body).Decode(&rule); err != nil {
  133. writeError(w, http.StatusBadRequest, "invalid request body")
  134. return
  135. }
  136. if rule.ID == "" {
  137. rule.ID = fmt.Sprintf("mangle-%d", time.Now().UnixNano())
  138. }
  139. if err := s.fwMgr.SaveMangleRule(rule); err != nil {
  140. writeError(w, http.StatusInternalServerError, err.Error())
  141. return
  142. }
  143. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": rule.ID})
  144. }
  145. func (s *Server) handleDeleteMangleRule(w http.ResponseWriter, r *http.Request) {
  146. id := r.PathValue("id")
  147. if err := s.fwMgr.DeleteMangleRule(id); err != nil {
  148. writeError(w, http.StatusInternalServerError, err.Error())
  149. return
  150. }
  151. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id})
  152. }
  153. func (s *Server) handleMoveMangleRule(w http.ResponseWriter, r *http.Request) {
  154. id := r.PathValue("id")
  155. var req struct {
  156. Direction string `json:"direction"`
  157. }
  158. _ = json.NewDecoder(r.Body).Decode(&req)
  159. if err := s.fwMgr.MoveMangleRule(id, req.Direction); err != nil {
  160. writeError(w, http.StatusInternalServerError, err.Error())
  161. return
  162. }
  163. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id})
  164. }
  165. func (s *Server) handleSetMangleRuleState(w http.ResponseWriter, r *http.Request) {
  166. id := r.PathValue("id")
  167. var req struct {
  168. Disabled bool `json:"disabled"`
  169. }
  170. _ = json.NewDecoder(r.Body).Decode(&req)
  171. if err := s.fwMgr.SetMangleRuleState(id, req.Disabled); err != nil {
  172. writeError(w, http.StatusInternalServerError, err.Error())
  173. return
  174. }
  175. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id, "disabled": req.Disabled})
  176. }
  177. // ======================== Address Lists ========================
  178. func (s *Server) handleListAddressLists(w http.ResponseWriter, r *http.Request) {
  179. lists := s.fwMgr.ListAddressLists()
  180. writeJSON(w, http.StatusOK, lists)
  181. }
  182. func (s *Server) handleSaveAddressListEntry(w http.ResponseWriter, r *http.Request) {
  183. var entry firewall.AddressListEntry
  184. if err := json.NewDecoder(r.Body).Decode(&entry); err != nil || entry.Name == "" || entry.Address == "" {
  185. writeError(w, http.StatusBadRequest, "name and address are required")
  186. return
  187. }
  188. if err := s.fwMgr.SaveAddressListEntry(entry); err != nil {
  189. writeError(w, http.StatusInternalServerError, err.Error())
  190. return
  191. }
  192. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": entry.ID})
  193. }
  194. func (s *Server) handleDeleteAddressListEntry(w http.ResponseWriter, r *http.Request) {
  195. id := r.PathValue("id")
  196. if err := s.fwMgr.DeleteAddressListEntry(id); err != nil {
  197. writeError(w, http.StatusInternalServerError, err.Error())
  198. return
  199. }
  200. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id})
  201. }
  202. func (s *Server) handleSetAddressListEntryState(w http.ResponseWriter, r *http.Request) {
  203. id := r.PathValue("id")
  204. var req struct {
  205. Disabled bool `json:"disabled"`
  206. }
  207. _ = json.NewDecoder(r.Body).Decode(&req)
  208. if err := s.fwMgr.SetAddressListEntryState(id, req.Disabled); err != nil {
  209. writeError(w, http.StatusInternalServerError, err.Error())
  210. return
  211. }
  212. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id, "disabled": req.Disabled})
  213. }
  214. // ======================== Geo-Location ========================
  215. func (s *Server) handleGeoIPStatus(w http.ResponseWriter, r *http.Request) {
  216. status := s.fwMgr.GeoIP().GetStatus()
  217. writeJSON(w, http.StatusOK, status)
  218. }
  219. func (s *Server) handleGeoIPConfig(w http.ResponseWriter, r *http.Request) {
  220. var req struct {
  221. AutoUpdate bool `json:"auto_update"`
  222. IntervalHours int `json:"interval_hours"`
  223. }
  224. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  225. writeError(w, http.StatusBadRequest, "invalid request body")
  226. return
  227. }
  228. if err := s.fwMgr.GeoIP().SetConfig(req.AutoUpdate, req.IntervalHours); err != nil {
  229. writeError(w, http.StatusInternalServerError, err.Error())
  230. return
  231. }
  232. writeJSON(w, http.StatusOK, map[string]any{"success": true, "config": req})
  233. }
  234. func (s *Server) handleListGeoCountries(w http.ResponseWriter, r *http.Request) {
  235. countries := s.fwMgr.GeoIP().ListCountries()
  236. writeJSON(w, http.StatusOK, countries)
  237. }
  238. func (s *Server) handleToggleGeoCountry(w http.ResponseWriter, r *http.Request) {
  239. code := r.PathValue("code")
  240. var req struct {
  241. Enabled bool `json:"enabled"`
  242. }
  243. _ = json.NewDecoder(r.Body).Decode(&req)
  244. if err := s.fwMgr.GeoIP().ToggleCountry(code, req.Enabled); err != nil {
  245. writeError(w, http.StatusInternalServerError, err.Error())
  246. return
  247. }
  248. writeJSON(w, http.StatusOK, map[string]any{"success": true, "code": code, "enabled": req.Enabled})
  249. }
  250. func (s *Server) handleUpdateGeoCountry(w http.ResponseWriter, r *http.Request) {
  251. code := r.PathValue("code")
  252. count, err := s.fwMgr.GeoIP().SyncCountryZone(code)
  253. if err != nil {
  254. writeError(w, http.StatusInternalServerError, err.Error())
  255. return
  256. }
  257. writeJSON(w, http.StatusOK, map[string]any{"success": true, "code": code, "subnets": count})
  258. }
  259. func (s *Server) handleGeoIPUpdateNow(w http.ResponseWriter, r *http.Request) {
  260. if err := s.fwMgr.GeoIP().UpdateNow(); err != nil {
  261. writeError(w, http.StatusConflict, err.Error())
  262. return
  263. }
  264. writeJSON(w, http.StatusOK, map[string]any{"success": true, "message": "update started"})
  265. }
  266. func (s *Server) handleGeoIPBatchToggle(w http.ResponseWriter, r *http.Request) {
  267. var req struct {
  268. Preset string `json:"preset"`
  269. Codes []string `json:"codes"`
  270. Enabled bool `json:"enabled"`
  271. }
  272. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  273. writeError(w, http.StatusBadRequest, "invalid request body")
  274. return
  275. }
  276. if err := s.fwMgr.GeoIP().BatchToggle(req.Preset, req.Enabled, req.Codes); err != nil {
  277. writeError(w, http.StatusInternalServerError, err.Error())
  278. return
  279. }
  280. writeJSON(w, http.StatusOK, map[string]any{"success": true, "preset": req.Preset, "enabled": req.Enabled})
  281. }
  282. func (s *Server) handleGeoCountrySubnets(w http.ResponseWriter, r *http.Request) {
  283. code := r.PathValue("code")
  284. subnets := s.fwMgr.GeoIP().GetCountrySubnets(code, 100)
  285. writeJSON(w, http.StatusOK, map[string]any{"code": code, "subnets": subnets})
  286. }
  287. // ======================== Active Connections ========================
  288. func (s *Server) handleListConnections(w http.ResponseWriter, r *http.Request) {
  289. conns, err := firewall.ListActiveConnections()
  290. if err != nil {
  291. writeError(w, http.StatusInternalServerError, err.Error())
  292. return
  293. }
  294. writeJSON(w, http.StatusOK, conns)
  295. }
  296. func (s *Server) handleKillConnection(w http.ResponseWriter, r *http.Request) {
  297. var req struct {
  298. Protocol string `json:"protocol"`
  299. Src string `json:"src"`
  300. Sport int `json:"sport"`
  301. Dst string `json:"dst"`
  302. Dport int `json:"dport"`
  303. }
  304. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  305. writeError(w, http.StatusBadRequest, "invalid request body")
  306. return
  307. }
  308. if err := firewall.KillConnection(req.Protocol, req.Src, req.Sport, req.Dst, req.Dport); err != nil {
  309. writeError(w, http.StatusInternalServerError, err.Error())
  310. return
  311. }
  312. writeJSON(w, http.StatusOK, map[string]any{"success": true})
  313. }
  314. // ======================== Routes & Policy Routing ========================
  315. func (s *Server) handleListRoutes(w http.ResponseWriter, r *http.Request) {
  316. routes := s.routingMgr.ListRoutes()
  317. writeJSON(w, http.StatusOK, routes)
  318. }
  319. func (s *Server) handleSaveRoute(w http.ResponseWriter, r *http.Request) {
  320. var route routing.RouteItem
  321. if err := json.NewDecoder(r.Body).Decode(&route); err != nil {
  322. writeError(w, http.StatusBadRequest, "invalid request body")
  323. return
  324. }
  325. if err := s.routingMgr.SaveRoute(route); err != nil {
  326. writeError(w, http.StatusInternalServerError, err.Error())
  327. return
  328. }
  329. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": route.ID})
  330. }
  331. func (s *Server) handleDeleteRoute(w http.ResponseWriter, r *http.Request) {
  332. id := r.PathValue("id")
  333. if err := s.routingMgr.DeleteRoute(id); err != nil {
  334. writeError(w, http.StatusInternalServerError, err.Error())
  335. return
  336. }
  337. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id})
  338. }
  339. func (s *Server) handleSetRouteState(w http.ResponseWriter, r *http.Request) {
  340. id := r.PathValue("id")
  341. var req struct {
  342. Disabled bool `json:"disabled"`
  343. }
  344. _ = json.NewDecoder(r.Body).Decode(&req)
  345. if err := s.routingMgr.SetRouteState(id, req.Disabled); err != nil {
  346. writeError(w, http.StatusInternalServerError, err.Error())
  347. return
  348. }
  349. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id, "disabled": req.Disabled})
  350. }
  351. func (s *Server) handleListPolicyRules(w http.ResponseWriter, r *http.Request) {
  352. rules := s.routingMgr.ListPolicyRules()
  353. writeJSON(w, http.StatusOK, rules)
  354. }
  355. func (s *Server) handleSavePolicyRule(w http.ResponseWriter, r *http.Request) {
  356. var rule routing.PolicyRuleItem
  357. if err := json.NewDecoder(r.Body).Decode(&rule); err != nil {
  358. writeError(w, http.StatusBadRequest, "invalid request body")
  359. return
  360. }
  361. if err := s.routingMgr.SavePolicyRule(rule); err != nil {
  362. writeError(w, http.StatusInternalServerError, err.Error())
  363. return
  364. }
  365. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": rule.ID})
  366. }
  367. func (s *Server) handleDeletePolicyRule(w http.ResponseWriter, r *http.Request) {
  368. id := r.PathValue("id")
  369. if err := s.routingMgr.DeletePolicyRule(id); err != nil {
  370. writeError(w, http.StatusInternalServerError, err.Error())
  371. return
  372. }
  373. writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id})
  374. }
  375. func (s *Server) handleListRoutingTables(w http.ResponseWriter, r *http.Request) {
  376. tables := s.routingMgr.ListTables()
  377. writeJSON(w, http.StatusOK, tables)
  378. }
  379. func (s *Server) handleSaveRoutingTable(w http.ResponseWriter, r *http.Request) {
  380. var table routing.RoutingTableItem
  381. if err := json.NewDecoder(r.Body).Decode(&table); err != nil || table.Name == "" {
  382. writeError(w, http.StatusBadRequest, "table name is required")
  383. return
  384. }
  385. if err := s.routingMgr.SaveTable(table); err != nil {
  386. writeError(w, http.StatusInternalServerError, err.Error())
  387. return
  388. }
  389. writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": table.Name})
  390. }