libs/core: rework 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 "1" or "0"
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 "1" or "0"
256 })
257 return s and forwarding(s)
258 end
259 end
260
261 function zone.del_forwardings_by(self, what)
262 local name = self:name()
263 ub.uci:foreach("firewall", "forwarding",
264 function(s)
265 if s.src and s.dest and s[what] == name then
266 ub.uci:delete("firewall", s['.name'])
267 end
268 end)
269 end
270
271 function zone.add_redirect(self, options)
272 options = options or { }
273 options.src = self:name()
274 local s = ub.uci:section("firewall", "redirect", nil, options)
275 return s and redirect(s)
276 end
277
278 function zone.add_rule(self, options)
279 options = options or { }
280 options.src = self:name()
281 local s = ub.uci:section("firewall", "rule", nil, options)
282 return s and rule(s)
283 end
284
285 function zone.get_color(self)
286 if self and self:name() == "lan" then
287 return "#90f090"
288 elseif self and self:name() == "wan" then
289 return "#f09090"
290 elseif self then
291 math.randomseed(lmo.hash(self:name()))
292
293 local r = math.random(128)
294 local g = math.random(128)
295 local min = 0
296 local max = 128
297
298 if ( r + g ) < 128 then
299 min = 128 - r - g
300 else
301 max = 255 - r - g
302 end
303
304 local b = min + math.floor( math.random() * ( max - min ) )
305
306 return "#%02x%02x%02x" % { 0xFF - r, 0xFF - g, 0xFF - b }
307 else
308 return "#eeeeee"
309 end
310 end
311
312
313 forwarding = ub:section("forwarding")
314 forwarding:property_bool("mtu_fix")
315 forwarding:property("src")
316 forwarding:property("dest")
317
318 function forwarding.src_zone(self)
319 return zone(self:src())
320 end
321
322 function forwarding.dest_zone(self)
323 return zone(self:dest())
324 end
325
326
327 rule = ub:section("rule")
328 rule:property("src")
329 rule:property("src_ip")
330 rule:property("src_mac")
331 rule:property("src_port")
332 rule:property("dest")
333 rule:property("dest_ip")
334 rule:property("dest_port")
335 rule:property("proto")
336 rule:property("target")
337
338 function rule.src_zone(self)
339 return zone(self:src())
340 end
341
342
343 redirect = ub:section("redirect")
344 redirect:property("src")
345 redirect:property("src_ip")
346 redirect:property("src_mac")
347 redirect:property("src_port")
348 redirect:property("src_dport")
349 redirect:property("dest_ip")
350 redirect:property("dest_port")
351 redirect:property("proto")
352
353 function redirect.src_zone(self)
354 return zone(self:src())
355 end
356