libs/core: fixes for network model
[project/luci.git] / libs / core / luasrc / model / firewall.lua
1 --[[
2 LuCI - Firewall model
3
4 Copyright 2009 Jo-Philipp Wich <xm@subsignal.org>
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17
18 ]]--
19
20 local type, pairs, ipairs, table, luci, math
21 = type, pairs, ipairs, table, luci, math
22
23 local lmo = require "lmo"
24 local utl = require "luci.util"
25 local uct = require "luci.model.uci.bind"
26
27 module "luci.model.firewall"
28
29
30 local ub = uct.bind("firewall")
31
32 function init(cursor)
33 if cursor then
34 cursor:unload("firewall")
35 cursor:load("firewall")
36 ub:init(cursor)
37 end
38 end
39
40 function add_zone(self, n)
41 if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not self:get_zone(n) then
42 local z = ub.uci:section("firewall", "zone", nil, {
43 name = n,
44 network = " ",
45 input = defaults:input() or "DROP",
46 forward = defaults:forward() or "DROP",
47 output = defaults:output() or "DROP"
48 })
49
50 return z and zone(z)
51 end
52 end
53
54 function get_zone(self, n)
55 local z
56 ub.uci:foreach("firewall", "zone",
57 function(s)
58 if n and s.name == n then
59 z = s['.name']
60 return false
61 end
62 end)
63 return z and zone(z)
64 end
65
66 function get_zones(self)
67 local zones = { }
68 ub.uci:foreach("firewall", "zone",
69 function(s)
70 if s.name then
71 zones[#zones+1] = zone(s['.name'])
72 end
73 end)
74 return zones
75 end
76
77 function get_zone_by_network(self, net)
78 local z
79 ub.uci:foreach("firewall", "zone",
80 function(s)
81 if s.name and net then
82 local n
83 for _, n in ipairs(ub:list(s.network or s.name)) do
84 if n == net then
85 z = s['.name']
86 return false
87 end
88 end
89 end
90 end)
91 return z and zone(z)
92 end
93
94 function del_zone(self, n)
95 local r = false
96 ub.uci:foreach("firewall", "zone",
97 function(s)
98 if n and s.name == n then
99 r = ub.uci:delete("firewall", s['.name'])
100 return false
101 end
102 end)
103 if r then
104 ub.uci:foreach("firewall", "rule",
105 function(s)
106 if s.src == n or s.dest == n then
107 ub.uci:delete("firewall", s['.name'])
108 end
109 end)
110 ub.uci:foreach("firewall", "redirect",
111 function(s)
112 if s.src == n then
113 ub.uci:delete("firewall", s['.name'])
114 end
115 end)
116 ub.uci:foreach("firewall", "forwarding",
117 function(s)
118 if s.src == n then
119 ub.uci:delete("firewall", s['.name'])
120 end
121 end)
122 end
123 return r
124 end
125
126 function rename_zone(self, old, new)
127 local r = false
128 if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_zone(new) then
129 ub.uci:foreach("firewall", "zone",
130 function(s)
131 if n and s.name == old then
132 ub.uci:set("firewall", s['.name'], "name", new)
133 r = true
134 return false
135 end
136 end)
137 if r then
138 ub.uci:foreach("firewall", "rule",
139 function(s)
140 if s.src == old then
141 ub.uci:set("firewall", s['.name'], "src", new)
142 elseif s.dest == old then
143 ub.uci:set("firewall", s['.name'], "dest", new)
144 end
145 end)
146 ub.uci:foreach("firewall", "redirect",
147 function(s)
148 if s.src == old then
149 ub.uci:set("firewall", s['.name'], "src", new)
150 end
151 end)
152 ub.uci:foreach("firewall", "forwarding",
153 function(s)
154 if s.src == old then
155 ub.uci:set("firewall", s['.name'], "src", new)
156 end
157 end)
158 end
159 end
160 return r
161 end
162
163 function del_network(self, net)
164 local z
165 if net then
166 for _, z in ipairs(self:get_zones()) do
167 z:del_network(net)
168 end
169 end
170 end
171
172
173 defaults = ub:usection("defaults")
174 defaults:property_bool("syn_flood")
175 defaults:property_bool("drop_invalid")
176 defaults:property("input")
177 defaults:property("forward")
178 defaults:property("output")
179
180
181 zone = ub:section("zone")
182 zone:property_bool("masq")
183 zone:property("name")
184 zone:property("network")
185 zone:property("input")
186 zone:property("forward")
187 zone:property("output")
188
189 function zone.add_network(self, net)
190 if ub.uci:get("network", net) == "interface" then
191 local networks = ub:list(self:network() or self:name(), net)
192 if #networks > 0 then
193 self:network(table.concat(networks, " "))
194 else
195 self:network(" ")
196 end
197 end
198 end
199
200 function zone.del_network(self, net)
201 local networks = ub:list(self:network() or self:name(), nil, net)
202 if #networks > 0 then
203 self:network(table.concat(networks, " "))
204 else
205 self:network(" ")
206 end
207 end
208
209 function zone.get_networks(self)
210 return ub:list(self:network() or self:name())
211 end
212
213 function zone.get_forwardings_by(self, what)
214 local name = self:name()
215 local forwards = { }
216 ub.uci:foreach("firewall", "forwarding",
217 function(s)
218 if s.src and s.dest and s[what] == name then
219 forwards[#forwards+1] = forwarding(s['.name'])
220 end
221 end)
222 return forwards
223 end
224
225 function zone.add_forwarding_to(self, dest, with_mtu_fix)
226 local exist, forward
227 for _, forward in ipairs(self:get_forwardings_by('src')) do
228 if forward:dest() == dest then
229 exist = true
230 break
231 end
232 end
233 if not exist and dest ~= self:name() then
234 local s = ub.uci:section("firewall", "forwarding", nil, {
235 src = self:name(),
236 dest = dest,
237 mtu_fix = with_mtu_fix and true or false
238 })
239 return s and forwarding(s)
240 end
241 end
242
243 function zone.add_forwarding_from(self, src, with_mtu_fix)
244 local exist, forward
245 for _, forward in ipairs(self:get_forwardings_by('dest')) do
246 if forward:src() == src then
247 exist = true
248 break
249 end
250 end
251 if not exist and src ~= self:name() then
252 local s = ub.uci:section("firewall", "forwarding", nil, {
253 src = src,
254 dest = self:name(),
255 mtu_fix = with_mtu_fix and true or false
256 })
257 return s and forwarding(s)
258 end
259 end
260
261 function zone.add_redirect(self, options)
262 options = options or { }
263 options.src = self:name()
264 local s = ub.uci:section("firewall", "redirect", nil, options)
265 return s and redirect(s)
266 end
267
268 function zone.add_rule(self, options)
269 options = options or { }
270 options.src = self:name()
271 local s = ub.uci:section("firewall", "rule", nil, options)
272 return s and rule(s)
273 end
274
275 function zone.get_color(self)
276 if self and self:name() == "lan" then
277 return "#90f090"
278 elseif self and self:name() == "wan" then
279 return "#f09090"
280 elseif self then
281 math.randomseed(lmo.hash(self:name()))
282
283 local r = math.random(128)
284 local g = math.random(128)
285 local min = 0
286 local max = 128
287
288 if ( r + g ) < 128 then
289 min = 128 - r - g
290 else
291 max = 255 - r - g
292 end
293
294 local b = min + math.floor( math.random() * ( max - min ) )
295
296 return "#%02x%02x%02x" % { 0xFF - r, 0xFF - g, 0xFF - b }
297 else
298 return "#eeeeee"
299 end
300 end
301
302
303 forwarding = ub:section("forwarding")
304 forwarding:property_bool("mtu_fix")
305 forwarding:property("src")
306 forwarding:property("dest")
307
308 function forwarding.src_zone(self)
309 return zone(self:src())
310 end
311
312 function forwarding.dest_zone(self)
313 return zone(self:dest())
314 end
315
316
317 rule = ub:section("rule")
318 rule:property("src")
319 rule:property("src_ip")
320 rule:property("src_mac")
321 rule:property("src_port")
322 rule:property("dest")
323 rule:property("dest_ip")
324 rule:property("dest_port")
325 rule:property("proto")
326 rule:property("target")
327
328 function rule.src_zone(self)
329 return zone(self:src())
330 end
331
332
333 redirect = ub:section("redirect")
334 redirect:property("src")
335 redirect:property("src_ip")
336 redirect:property("src_mac")
337 redirect:property("src_port")
338 redirect:property("src_dport")
339 redirect:property("dest_ip")
340 redirect:property("dest_port")
341 redirect:property("proto")
342
343 function redirect.src_zone(self)
344 return zone(self:src())
345 end
346