applications/luci-firewall: allow negated uci identifiers, hostnames and ip addresses...
[project/luci.git] / applications / luci-firewall / luasrc / model / cbi / luci_fw / zone.lua
1 --[[
2 LuCI - Lua Configuration Interface
3
4 Copyright 2008 Steven Barth <steven@midlink.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 $Id$
13 ]]--
14
15 local nw = require "luci.model.network"
16 local fw = require "luci.model.firewall"
17 local utl = require "luci.util"
18 local dsp = require "luci.dispatcher"
19
20 local has_v2 = nixio.fs.access("/lib/firewall/fw.sh")
21 local out, inp
22
23 require("luci.tools.webadmin")
24 m = Map("firewall", translate("Firewall - Zone Settings"))
25 m.redirect = luci.dispatcher.build_url("admin/network/firewall")
26
27 fw.init(m.uci)
28 nw.init(m.uci)
29
30
31 local zone = fw:get_zone(arg[1])
32 if not zone then
33         luci.http.redirect(dsp.build_url("admin", "network", "firewall"))
34         return
35 end
36
37
38 s = m:section(NamedSection, zone.sid, "zone",
39         translatef("Zone %q", zone:name()),
40         translatef("This section defines common properties of %q. " ..
41                 "The <em>input</em> and <em>output</em> options set the default "..
42                 "policies for traffic entering and leaving this zone while the " ..
43                 "<em>forward</em> option describes the policy for forwarded traffic " ..
44                 "between different networks within the zone. " ..
45                 "<em>Covered networks</em> specifies which available networks are " ..
46                 "member of this zone.", zone:name()))
47
48 s.anonymous = true
49 s.addremove = false
50
51 m.on_commit = function(map)
52         local zone = fw:get_zone(arg[1])
53         if zone then
54                 s.section  = zone.sid
55                 s2.section = zone.sid
56         end
57 end
58
59
60 s:tab("general", translate("General Settings"))
61 s:tab("advanced", translate("Advanced Settings"))
62
63
64 name = s:taboption("general", Value, "name", translate("Name"))
65 name.optional = false
66 name.forcewrite = true
67 name.datatype = "uciname"
68
69 function name.write(self, section, value)
70         if zone:name() ~= value then
71                 fw:rename_zone(zone:name(), value)
72                 out.exclude = value
73                 inp.exclude = value
74         end
75
76         m.redirect = luci.dispatcher.build_url(
77                 "admin", "network", "firewall", "zones", value
78         )
79 end
80
81 p = {}
82 p[1] = s:taboption("general", ListValue, "input", translate("Input"))
83 p[2] = s:taboption("general", ListValue, "output", translate("Output"))
84 p[3] = s:taboption("general", ListValue, "forward", translate("Forward"))
85
86 for i, v in ipairs(p) do
87         v:value("REJECT", translate("reject"))
88         v:value("DROP", translate("drop"))
89         v:value("ACCEPT", translate("accept"))
90 end
91
92 s:taboption("general", Flag, "masq", translate("Masquerading"))
93 s:taboption("general", Flag, "mtu_fix", translate("MSS clamping"))
94
95 net = s:taboption("general", Value, "network", translate("Covered networks"))
96 net.template = "cbi/network_netlist"
97 net.widget = "checkbox"
98 net.cast = "string"
99
100 function net.formvalue(self, section)
101         return Value.formvalue(self, section) or "-"
102 end
103
104 function net.cfgvalue(self, section)
105         return Value.cfgvalue(self, section) or name:cfgvalue(section)
106 end
107
108 function net.write(self, section, value)
109         zone:clear_networks()
110
111         local n
112         for n in utl.imatch(value) do
113                 zone:add_network(n)
114         end
115 end
116
117
118 if has_v2 then
119         family = s:taboption("advanced", ListValue, "family",
120                 translate("Restrict to address family"))
121
122         family.rmempty = true
123         family:value("", translate("IPv4 and IPv6"))
124         family:value("ipv4", translate("IPv4 only"))
125         family:value("ipv6", translate("IPv6 only"))
126 end
127
128 msrc = s:taboption("advanced", DynamicList, "masq_src",
129         translate("Restrict Masquerading to given source subnets"))
130
131 msrc.optional = true
132 msrc.datatype = "neg(network)"
133 msrc.placeholder = "0.0.0.0/0"
134 msrc:depends("family", "")
135 msrc:depends("family", "ipv4")
136
137 mdest = s:taboption("advanced", DynamicList, "masq_dest",
138         translate("Restrict Masquerading to given destination subnets"))
139
140 mdest.optional = true
141 mdest.datatype = "neg(network)"
142 mdest.placeholder = "0.0.0.0/0"
143 mdest:depends("family", "")
144 mdest:depends("family", "ipv4")
145
146 s:taboption("advanced", Flag, "conntrack",
147         translate("Force connection tracking"))
148
149 if has_v2 then
150         log = s:taboption("advanced", Flag, "log",
151                 translate("Enable logging on this zone"))
152
153         log.rmempty = true
154         log.enabled = "1"
155
156         lim = s:taboption("advanced", Value, "log_limit",
157                 translate("Limit log messages"))
158
159         lim.placeholder = "10/minute"
160         lim:depends("log", "1")
161 end
162
163
164 s2 = m:section(NamedSection, zone.sid, "fwd_out",
165         translate("Inter-Zone Forwarding"),
166         translatef("The options below control the forwarding policies between " ..
167                 "this zone (%s) and other zones. <em>Destination zones</em> cover " ..
168                 "forwarded traffic <strong>originating from %q</strong>. " ..
169                 "<em>Source zones</em> match forwarded traffic from other zones " ..
170                 "<strong>targeted at %q</strong>. The forwarding rule is " ..
171                 "<em>unidirectional</em>, e.g. a forward from lan to wan does " ..
172                 "<em>not</em> imply a permission to forward from wan to lan as well.",
173                 zone:name(), zone:name(), zone:name()
174
175         ))
176
177 out = s2:option(Value, "out",
178         translate("Allow forward to <em>destination zones</em>:"))
179
180 out.nocreate = true
181 out.widget = "checkbox"
182 out.exclude = zone:name()
183 out.template = "cbi/firewall_zonelist"
184
185 inp = s2:option(Value, "in",
186         translate("Allow forward from <em>source zones</em>:"))
187
188 inp.nocreate = true
189 inp.widget = "checkbox"
190 inp.exclude = zone:name()
191 inp.template = "cbi/firewall_zonelist"
192
193 function out.cfgvalue(self, section)
194         local v = { }
195         local f
196         for _, f in ipairs(zone:get_forwardings_by("src")) do
197                 v[#v+1] = f:dest()
198         end
199         return table.concat(v, " ")
200 end
201
202 function inp.cfgvalue(self, section)
203         local v = { }
204         local f
205         for _, f in ipairs(zone:get_forwardings_by("dest")) do
206                 v[#v+1] = f:src()
207         end
208         return v
209 end
210
211 function out.formvalue(self, section)
212         return Value.formvalue(self, section) or "-"
213 end
214
215 function inp.formvalue(self, section)
216         return Value.formvalue(self, section) or "-"
217 end
218
219 function out.write(self, section, value)
220         zone:del_forwardings_by("src")
221
222         local f
223         for f in utl.imatch(value) do
224                 zone:add_forwarding_to(f)
225         end
226 end
227
228 function inp.write(self, section, value)
229         zone:del_forwardings_by("dest")
230
231         local f
232         for f in utl.imatch(value) do
233                 zone:add_forwarding_from(f)
234         end
235 end
236
237 return m