summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--applications/luci-firewall/luasrc/controller/luci_fw/luci_fw.lua10
-rw-r--r--applications/luci-firewall/luasrc/model/cbi/luci_fw/redirect.lua52
-rw-r--r--applications/luci-firewall/luasrc/model/cbi/luci_fw/rrule.lua115
-rw-r--r--applications/luci-firewall/luasrc/model/cbi/luci_fw/traffic.lua88
-rw-r--r--applications/luci-firewall/luasrc/model/cbi/luci_fw/trule.lua114
-rw-r--r--applications/luci-firewall/luasrc/model/cbi/luci_fw/zones.lua215
6 files changed, 385 insertions, 209 deletions
diff --git a/applications/luci-firewall/luasrc/controller/luci_fw/luci_fw.lua b/applications/luci-firewall/luasrc/controller/luci_fw/luci_fw.lua
index 766821af0..38670d358 100644
--- a/applications/luci-firewall/luasrc/controller/luci_fw/luci_fw.lua
+++ b/applications/luci-firewall/luasrc/controller/luci_fw/luci_fw.lua
@@ -5,9 +5,9 @@ function index()
local i18n = luci.i18n.translate
entry({"admin", "network", "firewall"}, alias("admin", "network", "firewall", "zones"), i18n("Firewall"), 60).i18n = "luci-fw"
- entry({"admin", "network", "firewall", "zones"}, cbi("luci_fw/zones"), i18n("Zones"), 10)
- entry({"admin", "network", "firewall", "redirect"}, arcombine(cbi("luci_fw/redirect"), cbi("luci_fw/rrule")), i18n("Traffic Redirection"), 30).leaf = true
- entry({"admin", "network", "firewall", "rule"}, arcombine(cbi("luci_fw/traffic"), cbi("luci_fw/trule")), i18n("Traffic Control"), 20).leaf = true
-
+ entry({"admin", "network", "firewall", "zones"}, arcombine(cbi("luci_fw/zones"), cbi("luci_fw/zone")), nil, 10).leaf = true
+ entry({"admin", "network", "firewall", "rule"}, arcombine(cbi("luci_fw/zones"), cbi("luci_fw/trule")), nil, 20).leaf = true
+ entry({"admin", "network", "firewall", "redirect"}, arcombine(cbi("luci_fw/zones"), cbi("luci_fw/rrule")), nil, 30).leaf = true
+
entry({"mini", "network", "portfw"}, cbi("luci_fw/miniportfw", {autoapply=true}), i18n("Port forwarding"), 70).i18n = "luci-fw"
-end \ No newline at end of file
+end
diff --git a/applications/luci-firewall/luasrc/model/cbi/luci_fw/redirect.lua b/applications/luci-firewall/luasrc/model/cbi/luci_fw/redirect.lua
deleted file mode 100644
index da87015c8..000000000
--- a/applications/luci-firewall/luasrc/model/cbi/luci_fw/redirect.lua
+++ /dev/null
@@ -1,52 +0,0 @@
---[[
-LuCI - Lua Configuration Interface
-
-Copyright 2008 Steven Barth <steven@midlink.org>
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-$Id$
-]]--
-require("luci.sys")
-m = Map("firewall", translate("Traffic Redirection"),
- translate("Traffic redirection allows you to change the " ..
- "destination address of forwarded packets."))
-
-
-s = m:section(TypedSection, "redirect", "")
-s.template = "cbi/tblsection"
-s.addremove = true
-s.anonymous = true
-s.extedit = luci.dispatcher.build_url("admin", "network", "firewall", "redirect", "%s")
-
-name = s:option(Value, "_name", translate("Name"), translate("(optional)"))
-name.size = 10
-
-iface = s:option(ListValue, "src", translate("Zone"))
-iface.default = "wan"
-luci.model.uci.cursor():foreach("firewall", "zone",
- function (section)
- iface:value(section.name)
- end)
-
-proto = s:option(ListValue, "proto", translate("Protocol"))
-proto:value("tcp", "TCP")
-proto:value("udp", "UDP")
-proto:value("tcpudp", "TCP+UDP")
-
-dport = s:option(Value, "src_dport", translate("Source port"))
-dport.size = 5
-
-to = s:option(Value, "dest_ip", translate("Destination IP"))
-for i, dataset in ipairs(luci.sys.net.arptable()) do
- to:value(dataset["IP address"])
-end
-
-toport = s:option(Value, "dest_port", translate("Destination port"))
-toport.size = 5
-
-return m
diff --git a/applications/luci-firewall/luasrc/model/cbi/luci_fw/rrule.lua b/applications/luci-firewall/luasrc/model/cbi/luci_fw/rrule.lua
index 63e014444..6332d8e8c 100644
--- a/applications/luci-firewall/luasrc/model/cbi/luci_fw/rrule.lua
+++ b/applications/luci-firewall/luasrc/model/cbi/luci_fw/rrule.lua
@@ -2,6 +2,7 @@
LuCI - Lua Configuration Interface
Copyright 2008 Steven Barth <steven@midlink.org>
+Copyright 2010 Jo-Philipp Wich <xm@subsignal.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -11,70 +12,130 @@ You may obtain a copy of the License at
$Id$
]]--
-require("luci.sys")
+
+local sys = require "luci.sys"
+local dsp = require "luci.dispatcher"
+
arg[1] = arg[1] or ""
m = Map("firewall", translate("Traffic Redirection"),
translate("Traffic redirection allows you to change the " ..
"destination address of forwarded packets."))
+m.redirect = dsp.build_url("admin", "network", "firewall")
+
+if not m.uci:get(arg[1]) == "redirect" then
+ luci.http.redirect(m.redirect)
+ return
+end
+
+local has_v2 = nixio.fs.access("/lib/firewall/fw.sh")
+local wan_zone = nil
+
+m.uci:foreach("firewall", "zone",
+ function(s)
+ local n = s.network or s.name
+ if n then
+ local i
+ for i in n:gmatch("%S+") do
+ if i == "wan" then
+ wan_zone = s.name
+ return false
+ end
+ end
+ end
+ end)
s = m:section(NamedSection, arg[1], "redirect", "")
s.anonymous = true
s.addremove = false
-back = s:option(DummyValue, "_overview", translate("Overview"))
+s:tab("general", translate("General Settings"))
+s:tab("advanced", translate("Advanced Settings"))
+
+back = s:taboption("general", DummyValue, "_overview", translate("Overview"))
back.value = ""
back.titleref = luci.dispatcher.build_url("admin", "network", "firewall", "redirect")
-name = s:option(Value, "_name", translate("Name"))
+name = s:taboption("general", Value, "_name", translate("Name"))
name.rmempty = true
name.size = 10
-iface = s:option(ListValue, "src", translate("Source zone"))
-iface.default = "wan"
-luci.model.uci.cursor():foreach("firewall", "zone",
- function (section)
- iface:value(section.name)
- end)
-
-s:option(Value, "src_ip", translate("Source IP address")).optional = true
-s:option(Value, "src_mac", translate("Source MAC-address")).optional = true
+src = s:taboption("general", Value, "src", translate("Source zone"))
+src.nocreate = true
+src.default = "wan"
+src.template = "cbi/firewall_zonelist"
-sport = s:option(Value, "src_port", translate("Source port"),
- translate("Match incoming traffic originating from the given " ..
- "source port or port range on the client host"))
-sport.optional = true
-sport:depends("proto", "tcp")
-sport:depends("proto", "udp")
-sport:depends("proto", "tcpudp")
-
-proto = s:option(ListValue, "proto", translate("Protocol"))
+proto = s:taboption("general", ListValue, "proto", translate("Protocol"))
proto.optional = true
-proto:value("")
+proto:value("tcpudp", "TCP+UDP")
proto:value("tcp", "TCP")
proto:value("udp", "UDP")
-proto:value("tcpudp", "TCP+UDP")
-dport = s:option(Value, "src_dport", translate("External port"),
+dport = s:taboption("general", Value, "src_dport", translate("External port"),
translate("Match incoming traffic directed at the given " ..
"destination port or port range on this host"))
-dport.size = 5
+dport.datatype = "portrange"
dport:depends("proto", "tcp")
dport:depends("proto", "udp")
dport:depends("proto", "tcpudp")
-to = s:option(Value, "dest_ip", translate("Internal IP address"),
+to = s:taboption("general", Value, "dest_ip", translate("Internal IP address"),
translate("Redirect matched incoming traffic to the specified " ..
"internal host"))
+to.datatype = "ip4addr"
for i, dataset in ipairs(luci.sys.net.arptable()) do
to:value(dataset["IP address"])
end
-toport = s:option(Value, "dest_port", translate("Internal port (optional)"),
+toport = s:taboption("general", Value, "dest_port", translate("Internal port (optional)"),
translate("Redirect matched incoming traffic to the given port on " ..
"the internal host"))
toport.optional = true
toport.size = 5
+
+target = s:taboption("advanced", ListValue, "target", translate("Redirection type"))
+target:value("DNAT")
+target:value("SNAT")
+
+dest = s:taboption("advanced", Value, "dest", translate("Destination zone"))
+dest.nocreate = true
+dest.default = "lan"
+dest.template = "cbi/firewall_zonelist"
+
+src_dip = s:taboption("advanced", Value, "src_dip",
+ translate("Intended destination address"),
+ translate(
+ "For DNAT, match incoming traffic directed at the given destination "..
+ "ip address. For SNAT rewrite the source address to the given address."
+ ))
+
+src_dip.optional = true
+src_dip.datatype = "ip4addr"
+
+src_mac = s:taboption("advanced", Value, "src_mac", translate("Source MAC address"))
+src_mac.optional = true
+src_mac.datatype = "macaddr"
+
+src_ip = s:taboption("advanced", Value, "src_ip", translate("Source IP address"))
+src_ip.optional = true
+src_ip.datatype = "ip4addr"
+
+sport = s:taboption("advanced", Value, "src_port", translate("Source port"),
+ translate("Match incoming traffic originating from the given " ..
+ "source port or port range on the client host"))
+sport.optional = true
+sport.datatype = "portrange"
+sport:depends("proto", "tcp")
+sport:depends("proto", "udp")
+sport:depends("proto", "tcpudp")
+
+reflection = s:taboption("advanced", Flag, "reflection", translate("Enable NAT Loopback"))
+reflection.rmempty = true
+reflection:depends({ target = "DNAT", src = wan_zone })
+reflection.cfgvalue = function(...)
+ return Flag.cfgvalue(...) or "1"
+end
+
return m
diff --git a/applications/luci-firewall/luasrc/model/cbi/luci_fw/traffic.lua b/applications/luci-firewall/luasrc/model/cbi/luci_fw/traffic.lua
deleted file mode 100644
index 3bdc6db4c..000000000
--- a/applications/luci-firewall/luasrc/model/cbi/luci_fw/traffic.lua
+++ /dev/null
@@ -1,88 +0,0 @@
---[[
-LuCI - Lua Configuration Interface
-
-Copyright 2008 Steven Barth <steven@midlink.org>
-Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-$Id$
-]]--
-
-m = Map("firewall", translate("Traffic Control"))
-s = m:section(TypedSection, "forwarding", translate("Zone-to-Zone traffic"),
- translate("Here you can specify which network traffic is allowed " ..
- "to flow between network zones. Only new connections will " ..
- "be matched. Packets belonging to already open " ..
- "connections are automatically allowed to pass the " ..
- "firewall. If you experience occasional connection " ..
- "problems try enabling MSS Clamping otherwise disable it " ..
- "for performance reasons."))
-s.template = "cbi/tblsection"
-s.addremove = true
-s.anonymous = true
-
-iface = s:option(ListValue, "src", translate("Source"))
-oface = s:option(ListValue, "dest", translate("Destination"))
-
-luci.model.uci.cursor():foreach("firewall", "zone",
- function (section)
- iface:value(section.name)
- oface:value(section.name)
- end)
-
-
-
-s = m:section(TypedSection, "rule", translate("Rules"))
-s.addremove = true
-s.anonymous = true
-s.template = "cbi/tblsection"
-s.extedit = luci.dispatcher.build_url("admin", "network", "firewall", "rule", "%s")
-s.defaults.target = "ACCEPT"
-
-local created = nil
-
-function s.create(self, section)
- created = TypedSection.create(self, section)
-end
-
-function s.parse(self, ...)
- TypedSection.parse(self, ...)
- if created then
- m.uci:save("firewall")
- luci.http.redirect(luci.dispatcher.build_url(
- "admin", "network", "firewall", "rule", created
- ))
- end
-end
-
-s:option(DummyValue, "_name", translate("Name"))
-s:option(DummyValue, "proto", translate("Protocol"))
-
-src = s:option(DummyValue, "src", translate("Source"))
-function src.cfgvalue(self, s)
- return "%s:%s:%s" % {
- self.map:get(s, "src") or "*",
- self.map:get(s, "src_ip") or "0.0.0.0/0",
- self.map:get(s, "src_port") or "*"
- }
-end
-
-dest = s:option(DummyValue, "dest", translate("Destination"))
-function dest.cfgvalue(self, s)
- return "%s:%s:%s" % {
- self.map:get(s, "dest") or translate("Device"),
- self.map:get(s, "dest_ip") or "0.0.0.0/0",
- self.map:get(s, "dest_port") or "*"
- }
-end
-
-
-s:option(DummyValue, "target", translate("Action"))
-
-
-return m
diff --git a/applications/luci-firewall/luasrc/model/cbi/luci_fw/trule.lua b/applications/luci-firewall/luasrc/model/cbi/luci_fw/trule.lua
index 0ce41e38c..7ee8fd8e5 100644
--- a/applications/luci-firewall/luasrc/model/cbi/luci_fw/trule.lua
+++ b/applications/luci-firewall/luasrc/model/cbi/luci_fw/trule.lua
@@ -2,6 +2,7 @@
LuCI - Lua Configuration Interface
Copyright 2008 Steven Barth <steven@midlink.org>
+Copyright 2010 Jo-Philipp Wich <xm@subsignal.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -11,62 +12,121 @@ You may obtain a copy of the License at
$Id$
]]--
+
+local has_v2 = nixio.fs.access("/lib/firewall/fw.sh")
+local dsp = require "luci.dispatcher"
+
arg[1] = arg[1] or ""
+
m = Map("firewall", translate("Advanced Rules"),
translate("Advanced rules let you customize the firewall to your " ..
"needs. Only new connections will be matched. Packets " ..
"belonging to already open connections are automatically " ..
"allowed to pass the firewall."))
+m.redirect = dsp.build_url("admin", "network", "firewall")
+
+if not m.uci:get(arg[1]) == "rule" then
+ luci.http.redirect(m.redirect)
+ return
+end
+
s = m:section(NamedSection, arg[1], "rule", "")
s.anonymous = true
s.addremove = false
+s:tab("general", translate("General Settings"))
+s:tab("advanced", translate("Advanced Options"))
+
back = s:option(DummyValue, "_overview", translate("Overview"))
back.value = ""
-back.titleref = luci.dispatcher.build_url("admin", "network", "firewall", "rule")
+back.titleref = dsp.build_url("admin", "network", "firewall", "rule")
-name = s:option(Value, "_name", translate("Name").." "..translate("(optional)"))
+name = s:taboption("general", Value, "_name", translate("Name").." "..translate("(optional)"))
name.rmempty = true
-iface = s:option(ListValue, "src", translate("Source zone"))
-iface.rmempty = true
+src = s:taboption("general", Value, "src", translate("Source zone"))
+src.nocreate = true
+src.default = "wan"
+src.template = "cbi/firewall_zonelist"
-oface = s:option(ListValue, "dest", translate("Destination zone"))
-oface:value("", translate("any"))
-oface.rmempty = true
+dest = s:taboption("advanced", Value, "dest", translate("Destination zone"))
+dest.nocreate = true
+dest.default = "lan"
+dest.template = "cbi/firewall_zonelist"
-luci.model.uci.cursor():foreach("firewall", "zone",
- function (section)
- iface:value(section.name)
- oface:value(section.name)
- end)
-
-proto = s:option(Value, "proto", translate("Protocol"))
+proto = s:taboption("general", Value, "proto", translate("Protocol"))
proto.optional = true
-proto:value("")
proto:value("all", translate("Any"))
proto:value("tcpudp", "TCP+UDP")
proto:value("tcp", "TCP")
proto:value("udp", "UDP")
proto:value("icmp", "ICMP")
-s:option(Value, "src_ip", translate("Source address")).optional = true
-s:option(Value, "dest_ip", translate("Destination address")).optional = true
-s:option(Value, "src_mac", translate("Source MAC-address")).optional = true
-
-sport = s:option(Value, "src_port", translate("Source port"))
+icmpt = s:taboption("general", Value, "icmp_type", translate("Match ICMP type"))
+icmpt:depends("proto", "icmp")
+icmpt:value("any")
+icmpt:value("echo-reply")
+icmpt:value("destination-unreachable")
+icmpt:value("network-unreachable")
+icmpt:value("host-unreachable")
+icmpt:value("protocol-unreachable")
+icmpt:value("port-unreachable")
+icmpt:value("fragmentation-needed")
+icmpt:value("source-route-failed")
+icmpt:value("network-unknown")
+icmpt:value("host-unknown")
+icmpt:value("network-prohibited")
+icmpt:value("host-prohibited")
+icmpt:value("TOS-network-unreachable")
+icmpt:value("TOS-host-unreachable")
+icmpt:value("communication-prohibited")
+icmpt:value("host-precedence-violation")
+icmpt:value("precedence-cutoff")
+icmpt:value("source-quench")
+icmpt:value("redirect")
+icmpt:value("network-redirect")
+icmpt:value("host-redirect")
+icmpt:value("TOS-network-redirect")
+icmpt:value("TOS-host-redirect")
+icmpt:value("echo-request")
+icmpt:value("router-advertisement")
+icmpt:value("router-solicitation")
+icmpt:value("time-exceeded")
+icmpt:value("ttl-zero-during-transit")
+icmpt:value("ttl-zero-during-reassembly")
+icmpt:value("parameter-problem")
+icmpt:value("ip-header-bad")
+icmpt:value("required-option-missing")
+icmpt:value("timestamp-request")
+icmpt:value("timestamp-reply")
+icmpt:value("address-mask-request")
+icmpt:value("address-mask-reply")
+
+src_ip = s:taboption("general", Value, "src_ip", translate("Source address"))
+src_ip.optional = true
+src_ip.datatype = has_v2 and "ipaddr" or "ip4addr"
+
+sport = s:taboption("general", Value, "src_port", translate("Source port"))
+sport.optional = true
+sport.datatype = "portrange"
sport:depends("proto", "tcp")
sport:depends("proto", "udp")
sport:depends("proto", "tcpudp")
-dport = s:option(Value, "dest_port", translate("Destination port"))
+dest_ip = s:taboption("general", Value, "dest_ip", translate("Destination address"))
+dest_ip.optional = true
+dest_ip.datatype = has_v2 and "ipaddr" or "ip4addr"
+
+dport = s:taboption("general", Value, "dest_port", translate("Destination port"))
+dport.optional = true
+dport.datatype = "portrange"
dport:depends("proto", "tcp")
dport:depends("proto", "udp")
dport:depends("proto", "tcpudp")
-jump = s:option(ListValue, "target", translate("Action"))
+jump = s:taboption("general", ListValue, "target", translate("Action"))
jump.rmempty = true
jump.default = "ACCEPT"
jump:value("DROP", translate("drop"))
@@ -74,4 +134,14 @@ jump:value("ACCEPT", translate("accept"))
jump:value("REJECT", translate("reject"))
+s:taboption("advanced", Value, "src_mac", translate("Source MAC-address")).optional = true
+
+if has_v2 then
+ family = s:taboption("advanced", ListValue, "family", translate("Restrict to address family"))
+ family.rmempty = true
+ family:value("", translate("IPv4 and IPv6"))
+ family:value("ipv4", translate("IPv4 only"))
+ family:value("ipv6", translate("IPv6 only"))
+end
+
return m
diff --git a/applications/luci-firewall/luasrc/model/cbi/luci_fw/zones.lua b/applications/luci-firewall/luasrc/model/cbi/luci_fw/zones.lua
index edb82a9b5..f0e7b8665 100644
--- a/applications/luci-firewall/luasrc/model/cbi/luci_fw/zones.lua
+++ b/applications/luci-firewall/luasrc/model/cbi/luci_fw/zones.lua
@@ -14,6 +14,9 @@ $Id$
local nw = require "luci.model.network"
local fw = require "luci.model.firewall"
+local ds = require "luci.dispatcher"
+
+local has_v2 = nixio.fs.access("/lib/firewall/fw.sh")
require("luci.tools.webadmin")
m = Map("firewall", translate("Firewall"), translate("The firewall creates zones over your network interfaces to control network traffic flow."))
@@ -25,18 +28,22 @@ s = m:section(TypedSection, "defaults")
s.anonymous = true
s.addremove = false
-s:option(Flag, "syn_flood", translate("Enable SYN-flood protection"))
+s:tab("general", translate("General Settings"))
+s:tab("custom", translate("Custom Rules"))
+
-local di = s:option(Flag, "drop_invalid", translate("Drop invalid packets"))
+s:taboption("general", Flag, "syn_flood", translate("Enable SYN-flood protection"))
+
+local di = s:taboption("general", Flag, "drop_invalid", translate("Drop invalid packets"))
di.rmempty = false
function di.cfgvalue(...)
return AbstractValue.cfgvalue(...) or "1"
end
p = {}
-p[1] = s:option(ListValue, "input", translate("Input"))
-p[2] = s:option(ListValue, "output", translate("Output"))
-p[3] = s:option(ListValue, "forward", translate("Forward"))
+p[1] = s:taboption("general", ListValue, "input", translate("Input"))
+p[2] = s:taboption("general", ListValue, "output", translate("Output"))
+p[3] = s:taboption("general", ListValue, "forward", translate("Forward"))
for i, v in ipairs(p) do
v:value("REJECT", translate("reject"))
@@ -44,14 +51,41 @@ for i, v in ipairs(p) do
v:value("ACCEPT", translate("accept"))
end
+custom = s:taboption("custom", Value, "_custom",
+ translate("Custom Rules (/etc/firewall.user)"))
+
+custom.template = "cbi/tvalue"
+custom.rows = 20
+
+function custom.cfgvalue(self, section)
+ return nixio.fs.readfile("/etc/firewall.user")
+end
+
+function custom.write(self, section, value)
+ nixio.fs.writefile("/etc/firewall.user", value)
+end
+
s = m:section(TypedSection, "zone", translate("Zones"))
s.template = "cbi/tblsection"
s.anonymous = true
s.addremove = true
+s.extedit = ds.build_url("admin", "network", "firewall", "zones", "%s")
-name = s:option(Value, "name", translate("Name"))
-name.size = 8
+function s.create(self)
+ local z = fw:new_zone()
+ if z then
+ luci.http.redirect(
+ ds.build_url("admin", "network", "firewall", "zones", z.sid)
+ )
+ end
+end
+
+info = s:option(DummyValue, "_info", translate("Zone ⇒ Forwardings"))
+info.template = "cbi/firewall_zoneforwards"
+function info.cfgvalue(self, section)
+ return self.map:get(section, "name")
+end
p = {}
p[1] = s:option(ListValue, "input", translate("Input"))
@@ -67,15 +101,166 @@ end
s:option(Flag, "masq", translate("Masquerading"))
s:option(Flag, "mtu_fix", translate("MSS clamping"))
-net = s:option(MultiValue, "network", translate("Network"))
-net.template = "cbi/network_netlist"
-net.widget = "checkbox"
-net.rmempty = true
-luci.tools.webadmin.cbi_add_networks(net)
-function net.cfgvalue(self, section)
- local value = MultiValue.cfgvalue(self, section)
- return value or name:cfgvalue(section)
+local created = nil
+
+--
+-- Redirects
+--
+
+s = m:section(TypedSection, "redirect", translate("Redirections"))
+s.template = "cbi/tblsection"
+s.addremove = true
+s.anonymous = true
+s.extedit = ds.build_url("admin", "network", "firewall", "redirect", "%s")
+
+function s.create(self, section)
+ created = TypedSection.create(self, section)
+end
+
+function s.parse(self, ...)
+ TypedSection.parse(self, ...)
+ if created then
+ m.uci:save("firewall")
+ luci.http.redirect(ds.build_url(
+ "admin", "network", "firewall", "redirect", created
+ ))
+ end
+end
+
+name = s:option(DummyValue, "_name", translate("Name"))
+function name.cfgvalue(self, s)
+ return self.map:get(s, "_name") or "-"
+end
+
+proto = s:option(DummyValue, "proto", translate("Protocol"))
+function proto.cfgvalue(self, s)
+ local p = self.map:get(s, "proto")
+ if not p or p == "tcpudp" then
+ return "TCP+UDP"
+ else
+ return p:upper()
+ end
+end
+
+src = s:option(DummyValue, "src", translate("Source"))
+function src.cfgvalue(self, s)
+ local rv = "%s:%s:%s" % {
+ self.map:get(s, "src") or "*",
+ self.map:get(s, "src_ip") or "0.0.0.0/0",
+ self.map:get(s, "src_port") or "*"
+ }
+
+ local mac = self.map:get(s, "src_mac")
+ if mac then
+ rv = rv .. ", MAC " .. mac
+ end
+
+ return rv
+end
+
+via = s:option(DummyValue, "via", translate("Via"))
+function via.cfgvalue(self, s)
+ return "%s:%s:%s" % {
+ translate("Device"),
+ self.map:get(s, "src_dip") or "0.0.0.0/0",
+ self.map:get(s, "src_dport") or "*"
+ }
+end
+
+dest = s:option(DummyValue, "dest", translate("Destination"))
+function dest.cfgvalue(self, s)
+ return "%s:%s:%s" % {
+ self.map:get(s, "dest") or "*",
+ self.map:get(s, "dest_ip") or "0.0.0.0/0",
+ self.map:get(s, "dest_port") or "*"
+ }
+end
+
+target = s:option(DummyValue, "target", translate("Action"))
+function target.cfgvalue(self, s)
+ return self.map:get(s, "target") or "DNAT"
+end
+
+
+--
+-- Rules
+--
+
+s = m:section(TypedSection, "rule", translate("Rules"))
+s.addremove = true
+s.anonymous = true
+s.template = "cbi/tblsection"
+s.extedit = ds.build_url("admin", "network", "firewall", "rule", "%s")
+s.defaults.target = "ACCEPT"
+
+function s.create(self, section)
+ local created = TypedSection.create(self, section)
+ m.uci:save("firewall")
+ luci.http.redirect(ds.build_url(
+ "admin", "network", "firewall", "rule", created
+ ))
+ return
end
+name = s:option(DummyValue, "_name", translate("Name"))
+function name.cfgvalue(self, s)
+ return self.map:get(s, "_name") or "-"
+end
+
+if has_v2 then
+ family = s:option(DummyValue, "family", translate("Family"))
+ function family.cfgvalue(self, s)
+ local f = self.map:get(s, "family")
+ if f and f:match("4") then
+ return translate("IPv4 only")
+ elseif f and f:match("6") then
+ return translate("IPv6 only")
+ else
+ return translate("IPv4 and IPv6")
+ end
+ end
+end
+
+proto = s:option(DummyValue, "proto", translate("Protocol"))
+function proto.cfgvalue(self, s)
+ local p = self.map:get(s, "proto")
+ local t = self.map:get(s, "icmp_type")
+ if p == "icmp" and t then
+ return "ICMP (%s)" % t
+ elseif p == "tcpudp" or not p then
+ return "TCP+UDP"
+ else
+ return p:upper()
+ end
+end
+
+src = s:option(DummyValue, "src", translate("Source"))
+function src.cfgvalue(self, s)
+ local rv = "%s:%s:%s" % {
+ self.map:get(s, "src") or "*",
+ self.map:get(s, "src_ip") or "0.0.0.0/0",
+ self.map:get(s, "src_port") or "*"
+ }
+
+ local mac = self.map:get(s, "src_mac")
+ if mac then
+ rv = rv .. ", MAC " .. mac
+ end
+
+ return rv
+end
+
+dest = s:option(DummyValue, "dest", translate("Destination"))
+function dest.cfgvalue(self, s)
+ return "%s:%s:%s" % {
+ self.map:get(s, "dest") or translate("Device"),
+ self.map:get(s, "dest_ip") or "0.0.0.0/0",
+ self.map:get(s, "dest_port") or "*"
+ }
+end
+
+
+s:option(DummyValue, "target", translate("Action"))
+
return m