firewall.lua 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. -- Copyright 2009 Jo-Philipp Wich <jow@openwrt.org>
  2. -- Licensed to the public under the Apache License 2.0.
  3. local type, pairs, ipairs, table, luci, math
  4. = type, pairs, ipairs, table, luci, math
  5. local tpl = require "luci.template.parser"
  6. local utl = require "luci.util"
  7. local uci = require "luci.model.uci"
  8. module "luci.model.firewall"
  9. local uci_r, uci_s
  10. function _valid_id(x)
  11. return (x and #x > 0 and x:match("^[a-zA-Z0-9_]+$"))
  12. end
  13. function _get(c, s, o)
  14. return uci_r:get(c, s, o)
  15. end
  16. function _set(c, s, o, v)
  17. if v ~= nil then
  18. if type(v) == "boolean" then v = v and "1" or "0" end
  19. return uci_r:set(c, s, o, v)
  20. else
  21. return uci_r:delete(c, s, o)
  22. end
  23. end
  24. function init(cursor)
  25. uci_r = cursor or uci_r or uci.cursor()
  26. uci_s = uci_r:substate()
  27. return _M
  28. end
  29. function save(self, ...)
  30. uci_r:save(...)
  31. uci_r:load(...)
  32. end
  33. function commit(self, ...)
  34. uci_r:commit(...)
  35. uci_r:load(...)
  36. end
  37. function get_defaults()
  38. return defaults()
  39. end
  40. function new_zone(self)
  41. local name = "newzone"
  42. local count = 1
  43. while self:get_zone(name) do
  44. count = count + 1
  45. name = "newzone%d" % count
  46. end
  47. return self:add_zone(name)
  48. end
  49. function add_zone(self, n)
  50. if _valid_id(n) and not self:get_zone(n) then
  51. local d = defaults()
  52. local z = uci_r:section("firewall", "zone", nil, {
  53. name = n,
  54. network = " ",
  55. input = d:input() or "DROP",
  56. forward = d:forward() or "DROP",
  57. output = d:output() or "DROP"
  58. })
  59. return z and zone(z)
  60. end
  61. end
  62. function get_zone(self, n)
  63. if uci_r:get("firewall", n) == "zone" then
  64. return zone(n)
  65. else
  66. local z
  67. uci_r:foreach("firewall", "zone",
  68. function(s)
  69. if n and s.name == n then
  70. z = s['.name']
  71. return false
  72. end
  73. end)
  74. return z and zone(z)
  75. end
  76. end
  77. function get_zones(self)
  78. local zones = { }
  79. local znl = { }
  80. uci_r:foreach("firewall", "zone",
  81. function(s)
  82. if s.name then
  83. znl[s.name] = zone(s['.name'])
  84. end
  85. end)
  86. local z
  87. for z in utl.kspairs(znl) do
  88. zones[#zones+1] = znl[z]
  89. end
  90. return zones
  91. end
  92. function get_zone_by_network(self, net)
  93. local z
  94. uci_r:foreach("firewall", "zone",
  95. function(s)
  96. if s.name and net then
  97. local n
  98. for n in utl.imatch(s.network or s.name) do
  99. if n == net then
  100. z = s['.name']
  101. return false
  102. end
  103. end
  104. end
  105. end)
  106. return z and zone(z)
  107. end
  108. function del_zone(self, n)
  109. local r = false
  110. if uci_r:get("firewall", n) == "zone" then
  111. local z = uci_r:get("firewall", n, "name")
  112. r = uci_r:delete("firewall", n)
  113. n = z
  114. else
  115. uci_r:foreach("firewall", "zone",
  116. function(s)
  117. if n and s.name == n then
  118. r = uci_r:delete("firewall", s['.name'])
  119. return false
  120. end
  121. end)
  122. end
  123. if r then
  124. uci_r:foreach("firewall", "rule",
  125. function(s)
  126. if s.src == n or s.dest == n then
  127. uci_r:delete("firewall", s['.name'])
  128. end
  129. end)
  130. uci_r:foreach("firewall", "redirect",
  131. function(s)
  132. if s.src == n or s.dest == n then
  133. uci_r:delete("firewall", s['.name'])
  134. end
  135. end)
  136. uci_r:foreach("firewall", "forwarding",
  137. function(s)
  138. if s.src == n or s.dest == n then
  139. uci_r:delete("firewall", s['.name'])
  140. end
  141. end)
  142. end
  143. return r
  144. end
  145. function rename_zone(self, old, new)
  146. local r = false
  147. if _valid_id(new) and not self:get_zone(new) then
  148. uci_r:foreach("firewall", "zone",
  149. function(s)
  150. if old and s.name == old then
  151. if not s.network then
  152. uci_r:set("firewall", s['.name'], "network", old)
  153. end
  154. uci_r:set("firewall", s['.name'], "name", new)
  155. r = true
  156. return false
  157. end
  158. end)
  159. if r then
  160. uci_r:foreach("firewall", "rule",
  161. function(s)
  162. if s.src == old then
  163. uci_r:set("firewall", s['.name'], "src", new)
  164. end
  165. if s.dest == old then
  166. uci_r:set("firewall", s['.name'], "dest", new)
  167. end
  168. end)
  169. uci_r:foreach("firewall", "redirect",
  170. function(s)
  171. if s.src == old then
  172. uci_r:set("firewall", s['.name'], "src", new)
  173. end
  174. if s.dest == old then
  175. uci_r:set("firewall", s['.name'], "dest", new)
  176. end
  177. end)
  178. uci_r:foreach("firewall", "forwarding",
  179. function(s)
  180. if s.src == old then
  181. uci_r:set("firewall", s['.name'], "src", new)
  182. end
  183. if s.dest == old then
  184. uci_r:set("firewall", s['.name'], "dest", new)
  185. end
  186. end)
  187. end
  188. end
  189. return r
  190. end
  191. function del_network(self, net)
  192. local z
  193. if net then
  194. for _, z in ipairs(self:get_zones()) do
  195. z:del_network(net)
  196. end
  197. end
  198. end
  199. defaults = utl.class()
  200. function defaults.__init__(self)
  201. uci_r:foreach("firewall", "defaults",
  202. function(s)
  203. self.sid = s['.name']
  204. return false
  205. end)
  206. self.sid = self.sid or uci_r:section("firewall", "defaults", nil, { })
  207. end
  208. function defaults.get(self, opt)
  209. return _get("firewall", self.sid, opt)
  210. end
  211. function defaults.set(self, opt, val)
  212. return _set("firewall", self.sid, opt, val)
  213. end
  214. function defaults.syn_flood(self)
  215. return (self:get("syn_flood") == "1")
  216. end
  217. function defaults.drop_invalid(self)
  218. return (self:get("drop_invalid") == "1")
  219. end
  220. function defaults.input(self)
  221. return self:get("input") or "DROP"
  222. end
  223. function defaults.forward(self)
  224. return self:get("forward") or "DROP"
  225. end
  226. function defaults.output(self)
  227. return self:get("output") or "DROP"
  228. end
  229. zone = utl.class()
  230. function zone.__init__(self, z)
  231. if uci_r:get("firewall", z) == "zone" then
  232. self.sid = z
  233. self.data = uci_r:get_all("firewall", z)
  234. else
  235. uci_r:foreach("firewall", "zone",
  236. function(s)
  237. if s.name == z then
  238. self.sid = s['.name']
  239. self.data = s
  240. return false
  241. end
  242. end)
  243. end
  244. end
  245. function zone.get(self, opt)
  246. return _get("firewall", self.sid, opt)
  247. end
  248. function zone.set(self, opt, val)
  249. return _set("firewall", self.sid, opt, val)
  250. end
  251. function zone.masq(self)
  252. return (self:get("masq") == "1")
  253. end
  254. function zone.name(self)
  255. return self:get("name")
  256. end
  257. function zone.network(self)
  258. return self:get("network")
  259. end
  260. function zone.input(self)
  261. return self:get("input") or defaults():input() or "DROP"
  262. end
  263. function zone.forward(self)
  264. return self:get("forward") or defaults():forward() or "DROP"
  265. end
  266. function zone.output(self)
  267. return self:get("output") or defaults():output() or "DROP"
  268. end
  269. function zone.add_network(self, net)
  270. if uci_r:get("network", net) == "interface" then
  271. local nets = { }
  272. local n
  273. for n in utl.imatch(self:get("network") or self:get("name")) do
  274. if n ~= net then
  275. nets[#nets+1] = n
  276. end
  277. end
  278. nets[#nets+1] = net
  279. _M:del_network(net)
  280. self:set("network", table.concat(nets, " "))
  281. end
  282. end
  283. function zone.del_network(self, net)
  284. local nets = { }
  285. local n
  286. for n in utl.imatch(self:get("network") or self:get("name")) do
  287. if n ~= net then
  288. nets[#nets+1] = n
  289. end
  290. end
  291. if #nets > 0 then
  292. self:set("network", table.concat(nets, " "))
  293. else
  294. self:set("network", " ")
  295. end
  296. end
  297. function zone.get_networks(self)
  298. local nets = { }
  299. local n
  300. for n in utl.imatch(self:get("network") or self:get("name")) do
  301. nets[#nets+1] = n
  302. end
  303. return nets
  304. end
  305. function zone.clear_networks(self)
  306. self:set("network", " ")
  307. end
  308. function zone.get_forwardings_by(self, what)
  309. local name = self:name()
  310. local forwards = { }
  311. uci_r:foreach("firewall", "forwarding",
  312. function(s)
  313. if s.src and s.dest and s[what] == name then
  314. forwards[#forwards+1] = forwarding(s['.name'])
  315. end
  316. end)
  317. return forwards
  318. end
  319. function zone.add_forwarding_to(self, dest)
  320. local exist, forward
  321. for _, forward in ipairs(self:get_forwardings_by('src')) do
  322. if forward:dest() == dest then
  323. exist = true
  324. break
  325. end
  326. end
  327. if not exist and dest ~= self:name() and _valid_id(dest) then
  328. local s = uci_r:section("firewall", "forwarding", nil, {
  329. src = self:name(),
  330. dest = dest
  331. })
  332. return s and forwarding(s)
  333. end
  334. end
  335. function zone.add_forwarding_from(self, src)
  336. local exist, forward
  337. for _, forward in ipairs(self:get_forwardings_by('dest')) do
  338. if forward:src() == src then
  339. exist = true
  340. break
  341. end
  342. end
  343. if not exist and src ~= self:name() and _valid_id(src) then
  344. local s = uci_r:section("firewall", "forwarding", nil, {
  345. src = src,
  346. dest = self:name()
  347. })
  348. return s and forwarding(s)
  349. end
  350. end
  351. function zone.del_forwardings_by(self, what)
  352. local name = self:name()
  353. uci_r:delete_all("firewall", "forwarding",
  354. function(s)
  355. return (s.src and s.dest and s[what] == name)
  356. end)
  357. end
  358. function zone.add_redirect(self, options)
  359. options = options or { }
  360. options.src = self:name()
  361. local s = uci_r:section("firewall", "redirect", nil, options)
  362. return s and redirect(s)
  363. end
  364. function zone.add_rule(self, options)
  365. options = options or { }
  366. options.src = self:name()
  367. local s = uci_r:section("firewall", "rule", nil, options)
  368. return s and rule(s)
  369. end
  370. function zone.get_color(self)
  371. if self and self:name() == "lan" then
  372. return "#90f090"
  373. elseif self and self:name() == "wan" then
  374. return "#f09090"
  375. elseif self then
  376. math.randomseed(tpl.hash(self:name()))
  377. local r = math.random(128)
  378. local g = math.random(128)
  379. local min = 0
  380. local max = 128
  381. if ( r + g ) < 128 then
  382. min = 128 - r - g
  383. else
  384. max = 255 - r - g
  385. end
  386. local b = min + math.floor( math.random() * ( max - min ) )
  387. return "#%02x%02x%02x" % { 0xFF - r, 0xFF - g, 0xFF - b }
  388. else
  389. return "#eeeeee"
  390. end
  391. end
  392. forwarding = utl.class()
  393. function forwarding.__init__(self, f)
  394. self.sid = f
  395. end
  396. function forwarding.src(self)
  397. return uci_r:get("firewall", self.sid, "src")
  398. end
  399. function forwarding.dest(self)
  400. return uci_r:get("firewall", self.sid, "dest")
  401. end
  402. function forwarding.src_zone(self)
  403. return zone(self:src())
  404. end
  405. function forwarding.dest_zone(self)
  406. return zone(self:dest())
  407. end
  408. rule = utl.class()
  409. function rule.__init__(self, f)
  410. self.sid = f
  411. end
  412. function rule.get(self, opt)
  413. return _get("firewall", self.sid, opt)
  414. end
  415. function rule.set(self, opt, val)
  416. return _set("firewall", self.sid, opt, val)
  417. end
  418. function rule.src(self)
  419. return uci_r:get("firewall", self.sid, "src")
  420. end
  421. function rule.dest(self)
  422. return uci_r:get("firewall", self.sid, "dest")
  423. end
  424. function rule.src_zone(self)
  425. return zone(self:src())
  426. end
  427. function rule.dest_zone(self)
  428. return zone(self:dest())
  429. end
  430. redirect = utl.class()
  431. function redirect.__init__(self, f)
  432. self.sid = f
  433. end
  434. function redirect.get(self, opt)
  435. return _get("firewall", self.sid, opt)
  436. end
  437. function redirect.set(self, opt, val)
  438. return _set("firewall", self.sid, opt, val)
  439. end
  440. function redirect.src(self)
  441. return uci_r:get("firewall", self.sid, "src")
  442. end
  443. function redirect.dest(self)
  444. return uci_r:get("firewall", self.sid, "dest")
  445. end
  446. function redirect.src_zone(self)
  447. return zone(self:src())
  448. end
  449. function redirect.dest_zone(self)
  450. return zone(self:dest())
  451. end