applications/luci-firewall: complete rework firewall ui
authorJo-Philipp Wich <jow@openwrt.org>
Mon, 19 Dec 2011 21:16:31 +0000 (21:16 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Mon, 19 Dec 2011 21:16:31 +0000 (21:16 +0000)
- split zone setup, port forwards, traffic rules and firewall.user
- add quickadd forms for various common rules like port forwards
- add tool class for textual formatting and descriptions of rules
- simplify controller, remove old mini admin remainders

18 files changed:
applications/luci-firewall/luasrc/controller/firewall.lua [new file with mode: 0644]
applications/luci-firewall/luasrc/controller/luci_fw/luci_fw.lua [deleted file]
applications/luci-firewall/luasrc/model/cbi/firewall/custom.lua [new file with mode: 0644]
applications/luci-firewall/luasrc/model/cbi/firewall/forward-details.lua [new file with mode: 0644]
applications/luci-firewall/luasrc/model/cbi/firewall/forwards.lua [new file with mode: 0644]
applications/luci-firewall/luasrc/model/cbi/firewall/rule-details.lua [new file with mode: 0644]
applications/luci-firewall/luasrc/model/cbi/firewall/rules.lua [new file with mode: 0644]
applications/luci-firewall/luasrc/model/cbi/firewall/zone-details.lua [new file with mode: 0644]
applications/luci-firewall/luasrc/model/cbi/firewall/zones.lua [new file with mode: 0644]
applications/luci-firewall/luasrc/model/cbi/luci_fw/miniportfw.lua [deleted file]
applications/luci-firewall/luasrc/model/cbi/luci_fw/rrule.lua [deleted file]
applications/luci-firewall/luasrc/model/cbi/luci_fw/trule.lua [deleted file]
applications/luci-firewall/luasrc/model/cbi/luci_fw/zone.lua [deleted file]
applications/luci-firewall/luasrc/model/cbi/luci_fw/zones.lua [deleted file]
applications/luci-firewall/luasrc/tools/firewall.lua [new file with mode: 0644]
applications/luci-firewall/luasrc/view/cbi_addforward.htm [new file with mode: 0644]
applications/luci-firewall/luasrc/view/cbi_addrule.htm [new file with mode: 0644]
applications/luci-firewall/luasrc/view/cbi_addsnat.htm [new file with mode: 0644]

diff --git a/applications/luci-firewall/luasrc/controller/firewall.lua b/applications/luci-firewall/luasrc/controller/firewall.lua
new file mode 100644 (file)
index 0000000..c0149f8
--- /dev/null
@@ -0,0 +1,23 @@
+module("luci.controller.firewall", package.seeall)
+
+function index()
+       entry({"admin", "network", "firewall"},
+               alias("admin", "network", "firewall", "zones"),
+               _("Firewall"), 60).i18n = "firewall"
+
+       entry({"admin", "network", "firewall", "zones"},
+               arcombine(cbi("firewall/zones"), cbi("firewall/zone-details")),
+               _("General Settings"), 10).leaf = true
+
+       entry({"admin", "network", "firewall", "forwards"},
+               arcombine(cbi("firewall/forwards"), cbi("firewall/forward-details")),
+               _("Port Forwards"), 20).leaf = true
+
+       entry({"admin", "network", "firewall", "rules"},
+               arcombine(cbi("firewall/rules"), cbi("firewall/rule-details")),
+               _("Traffic Rules"), 30).leaf = true
+
+       entry({"admin", "network", "firewall", "custom"},
+               cbi("firewall/custom"),
+               _("Custom Rules"), 40).leaf = true
+end
diff --git a/applications/luci-firewall/luasrc/controller/luci_fw/luci_fw.lua b/applications/luci-firewall/luasrc/controller/luci_fw/luci_fw.lua
deleted file mode 100644 (file)
index b3d440d..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-module("luci.controller.luci_fw.luci_fw", package.seeall)
-
-function index()
-       entry({"admin", "network", "firewall"}, alias("admin", "network", "firewall", "zones"), _("Firewall"), 60).i18n = "firewall"
-       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}), _("Port forwarding"), 70).i18n = "firewall"
-end
diff --git a/applications/luci-firewall/luasrc/model/cbi/firewall/custom.lua b/applications/luci-firewall/luasrc/model/cbi/firewall/custom.lua
new file mode 100644 (file)
index 0000000..9b53a8a
--- /dev/null
@@ -0,0 +1,38 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2011 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.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+]]--
+
+local fs = require "nixio.fs"
+
+local f = SimpleForm("firewall",
+       translate("Firewall - Custom Rules"),
+       translate("Custom rules allow you to execute arbritary iptables commands \
+               which are not otherwise covered by the firewall framework. \
+               The commands are executed after each firewall restart, right after \
+               the default ruleset has been loaded."))
+
+local o = f:field(Value, "_custom")
+
+o.template = "cbi/tvalue"
+o.rows = 20
+
+function o.cfgvalue(self, section)
+       return fs.readfile("/etc/firewall.user")
+end
+
+function o.write(self, section, value)
+       value = value:gsub("\r\n?", "\n")
+       fs.writefile("/etc/firewall.user", value)
+end
+
+return f
diff --git a/applications/luci-firewall/luasrc/model/cbi/firewall/forward-details.lua b/applications/luci-firewall/luasrc/model/cbi/firewall/forward-details.lua
new file mode 100644 (file)
index 0000000..1cc5ecb
--- /dev/null
@@ -0,0 +1,148 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2011 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.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+]]--
+
+local sys = require "luci.sys"
+local dsp = require "luci.dispatcher"
+
+arg[1] = arg[1] or ""
+
+m = Map("firewall",
+       translate("Firewall - Port Forwards"),
+       translate("This page allows you to change advanced properties of the port \
+                  forwarding entry. In most cases there is no need to modify \
+                          those settings."))
+
+m.redirect = dsp.build_url("admin/network/firewall/forwards")
+
+if m.uci:get("firewall", arg[1]) ~= "redirect" then
+       luci.http.redirect(m.redirect)
+       return
+else
+       local name = m:get(arg[1], "_name")
+       if not name or #name == 0 then
+               name = translate("(Unnamed Entry)")
+       end
+       m.title = "%s - %s" %{ translate("Firewall - Port Forwards"), name }
+end
+
+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
+
+s:tab("general", translate("General Settings"))
+s:tab("advanced", translate("Advanced Settings"))
+
+name = s:taboption("general", Value, "_name", translate("Name"))
+name.rmempty = true
+name.size = 10
+
+src = s:taboption("advanced", Value, "src", translate("Source zone"))
+src.nocreate = true
+src.default = "wan"
+src.template = "cbi/firewall_zonelist"
+
+proto = s:taboption("general", Value, "proto", translate("Protocol"))
+proto.optional = true
+proto:value("tcp udp", "TCP+UDP")
+proto:value("tcp", "TCP")
+proto:value("udp", "UDP")
+proto:value("icmp", "ICMP")
+
+function proto.cfgvalue(...)
+       local v = Value.cfgvalue(...)
+       if not v or v == "tcpudp" then
+               return "tcp udp"
+       end
+       return v
+end
+
+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.datatype = "portrange"
+
+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(sys.net.arptable()) do
+       to:value(dataset["IP address"])
+end
+
+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.placeholder = "0-65535"
+toport.datatype = "portrange"
+
+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("Only match incoming traffic directed at the given IP address."))
+
+src_dip.optional = true
+src_dip.datatype = "ip4addr"
+src_dip.placeholder = translate("any")
+
+src_mac = s:taboption("advanced", DynamicList, "src_mac",
+       translate("Source MAC address"),
+       translate("Only match incoming traffic from these MACs."))
+src_mac.optional = true
+src_mac.datatype = "macaddr"
+src_mac.placeholder = translate("any")
+
+src_ip = s:taboption("advanced", Value, "src_ip",
+       translate("Source IP address"),
+       translate("Only match incoming traffic from this IP or range."))
+src_ip.optional = true
+src_ip.datatype = "neg(ip4addr)"
+src_ip.placeholder = translate("any")
+
+sport = s:taboption("advanced", Value, "src_port",
+       translate("Source port"),
+       translate("Only match incoming traffic originating from the given source port or port range on the client host"))
+sport.optional = true
+sport.datatype = "portrange"
+sport.placeholder = translate("any")
+
+reflection = s:taboption("advanced", Flag, "reflection", translate("Enable NAT Loopback"))
+reflection.rmempty = true
+reflection.default = reflection.enabled
+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/firewall/forwards.lua b/applications/luci-firewall/luasrc/model/cbi/firewall/forwards.lua
new file mode 100644 (file)
index 0000000..3ab3658
--- /dev/null
@@ -0,0 +1,141 @@
+--[[
+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$
+]]--
+
+local ds = require "luci.dispatcher"
+local ft = require "luci.tools.firewall"
+
+m = Map("firewall", translate("Firewall - Port Forwards"),
+       translate("Port forwarding allows remote computers on the Internet to \
+                  connect to a specific computer or service within the \
+                  private LAN."))
+
+--
+-- Port Forwards
+--
+
+s = m:section(TypedSection, "redirect", translate("Port Forwards"))
+s.template  = "cbi/tblsection"
+s.addremove = true
+s.anonymous = true
+s.sortable  = true
+s.extedit   = ds.build_url("admin/network/firewall/forwards/%s")
+s.template_addremove = "firewall/cbi_addforward"
+
+function s.create(self, section)
+       local n = m:formvalue("_newfwd.name")
+       local p = m:formvalue("_newfwd.proto")
+       local e = m:formvalue("_newfwd.extport")
+       local a = m:formvalue("_newfwd.intaddr")
+       local i = m:formvalue("_newfwd.intport")
+
+       if p == "other" or (p and a) then
+               created = TypedSection.create(self, section)
+
+               self.map:set(created, "target",    "DNAT")
+               self.map:set(created, "src",       "wan")
+               self.map:set(created, "dest",      "lan")
+               self.map:set(created, "proto",     (p ~= "other") and p or "all")
+               self.map:set(created, "src_dport", e)
+               self.map:set(created, "dest_ip",   a)
+               self.map:set(created, "dest_port", i)
+               self.map:set(created, "_name",     n)
+       end
+
+       if p ~= "other" then
+               created = nil
+       end
+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
+
+function s.filter(self, sid)
+       return (self.map:get(sid, "target") ~= "SNAT")
+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"))
+proto.rawhtml = true
+function proto.cfgvalue(self, s)
+       return ft.fmt_proto(self.map:get(s, "proto")) or "Any"
+end
+
+
+src = s:option(DummyValue, "src", translate("Source"))
+src.rawhtml = true
+src.width   = "20%"
+function src.cfgvalue(self, s)
+       local z = ft.fmt_zone(self.map:get(s, "src"))
+       local a = ft.fmt_ip(self.map:get(s, "src_ip"))
+       local p = ft.fmt_port(self.map:get(s, "src_port"))
+       local m = ft.fmt_mac(self.map:get(s, "src_mac"))
+
+       local s = "From %s in %s " %{
+               (a or "<var>any host</var>"),
+               (z or "<var>any zone</var>")
+       }
+
+       if p and m then
+               s = s .. "with source %s and %s" %{ p, m }
+       elseif p or m then
+               s = s .. "with source %s" %( p or m )
+       end
+
+       return s
+end
+
+via = s:option(DummyValue, "via", translate("Via"))
+via.rawhtml = true
+via.width   = "20%"
+function via.cfgvalue(self, s)
+       local a = ft.fmt_ip(self.map:get(s, "src_dip"))
+       local p = ft.fmt_port(self.map:get(s, "src_dport"))
+
+       --local z = self.map:get(s, "src")
+       --local s = "To %s " %(a or "<var>any %s IP</var>" %( z or "router" ))
+
+       return "To %s%s" %{
+               (a or "<var>any router IP</var>"),
+               (p and " at %s" % p or "")
+       }
+end
+
+dest = s:option(DummyValue, "dest", translate("Destination"))
+dest.rawhtml = true
+dest.width   = "30%"
+function dest.cfgvalue(self, s)
+       local z = ft.fmt_zone(self.map:get(s, "dest"))
+       local a = ft.fmt_ip(self.map:get(s, "dest_ip"))
+       local p = ft.fmt_port(self.map:get(s, "dest_port")) or
+               ft.fmt_port(self.map:get(s, "src_dport"))
+
+       return "Forward to %s%s in %s " %{
+               (a or "<var>any host</var>"),
+               (p and ", %s" % p or ""),
+               (z or "<var>any zone</var>")
+       }
+end
+
+return m
diff --git a/applications/luci-firewall/luasrc/model/cbi/firewall/rule-details.lua b/applications/luci-firewall/luasrc/model/cbi/firewall/rule-details.lua
new file mode 100644 (file)
index 0000000..1f7df65
--- /dev/null
@@ -0,0 +1,300 @@
+--[[
+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.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+]]--
+
+local sys = require "luci.sys"
+local dsp = require "luci.dispatcher"
+local nxo = require "nixio"
+
+local nw = require "luci.model.network"
+local m, s, o, k, v
+
+arg[1] = arg[1] or ""
+
+m = Map("firewall",
+       translate("Firewall - Traffic Rules"),
+       translate("This page allows you to change advanced properties of the \
+                  traffic rule entry, such as matched source and destination \
+                          hosts."))
+
+m.redirect = dsp.build_url("admin/network/firewall/rules")
+
+nw.init(m.uci)
+
+local rule_type = m.uci:get("firewall", arg[1])
+if rule_type == "redirect" and m:get(arg[1], "target") ~= "SNAT" then
+       rule_type = nil
+end
+
+if not rule_type then
+       luci.http.redirect(m.redirect)
+       return
+
+--
+-- SNAT
+--
+elseif rule_type == "redirect" then
+
+       local name = m:get(arg[1], "_name")
+       if not name or #name == 0 then
+               name = translate("(Unnamed SNAT)")
+       else
+               name = "SNAT %s" % name
+       end
+
+       m.title = "%s - %s" %{ translate("Firewall - Traffic Rules"), name }
+
+       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
+
+
+       o = s:option(Value, "_name", translate("Name"))
+       o.rmempty = true
+       o.size = 10
+
+
+       o = s:option(Value, "proto",
+               translate("Protocol"),
+               translate("You may specify multiple by selecting \"-- custom --\" and \
+                          then entering protocols separated by space."))
+
+       o:value("all", "All protocols")
+       o:value("tcp udp", "TCP+UDP")
+       o:value("tcp", "TCP")
+       o:value("udp", "UDP")
+       o:value("icmp", "ICMP")
+
+       function o.cfgvalue(...)
+               local v = Value.cfgvalue(...)
+               if not v or v == "tcpudp" then
+                       return "tcp udp"
+               end
+               return v
+       end
+
+
+       o = s:option(Value, "src", translate("Source zone"))
+       o.nocreate = true
+       o.default = "wan"
+       o.template = "cbi/firewall_zonelist"
+
+
+       o = s:option(DynamicList, "src_mac", translate("Source MAC address"))
+       o.rmempty = true
+       o.datatype = "neg(macaddr)"
+       o.placeholder = translate("any")
+
+
+       o = s:option(Value, "src_ip", translate("Source IP address"))
+       o.rmempty = true
+       o.datatype = "neg(ip4addr)"
+       o.placeholder = translate("any")
+
+
+       o = 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."))
+       o.rmempty = true
+       o.datatype = "neg(portrange)"
+       o.placeholder = translate("any")
+
+
+       o = s:option(Value, "dest", translate("Destination zone"))
+       o.nocreate = true
+       o.default = "lan"
+       o.template = "cbi/firewall_zonelist"
+
+
+       o = s:option(Value, "dest_ip", translate("Destination IP address"))
+       o.datatype = "neg(ip4addr)"
+
+       for i, dataset in ipairs(luci.sys.net.arptable()) do
+               o:value(dataset["IP address"])
+       end
+
+
+       o = s:option(Value, "dest_port",
+               translate("Destination port"),
+               translate("Match forwarded traffic to the given destination port or \
+                       port range."))
+
+       o.rmempty = true
+       o.placeholder = translate("any")
+       o.datatype = "portrange"
+
+
+       o = s:option(Value, "src_dip",
+               translate("SNAT IP address"),
+               translate("Rewrite matched traffic to the given address."))
+       o.rmempty = false
+       o.datatype = "ip4addr"
+
+       for k, v in ipairs(nw:get_interfaces()) do
+               local a
+               for k, a in ipairs(v:ipaddrs()) do
+                       o:value(a:host():string(), '%s (%s)' %{
+                               a:host():string(), v:shortname()
+                       })
+               end
+       end
+
+
+       o = s:option(Value, "src_dport", translate("SNAT port"),
+               translate("Rewrite matched traffic to the given source port. May be \
+                       left empty to only rewrite the IP address."))
+       o.datatype = "portrange"
+       o.rmempty = true
+       o.placeholder = translate('Do not rewrite')
+
+
+--
+-- Rule
+--
+else
+       s = m:section(NamedSection, arg[1], "rule", "")
+       s.anonymous = true
+       s.addremove = false
+
+       s:option(Value, "_name", translate("Name").." "..translate("(optional)"))
+
+
+       o = s:option(ListValue, "family", translate("Restrict to address family"))
+       o.rmempty = true
+       o:value("", translate("IPv4 and IPv6"))
+       o:value("ipv4", translate("IPv4 only"))
+       o:value("ipv6", translate("IPv6 only"))
+
+
+       o = s:option(Value, "proto", translate("Protocol"))
+       o:value("all", translate("Any"))
+       o:value("tcp udp", "TCP+UDP")
+       o:value("tcp", "TCP")
+       o:value("udp", "UDP")
+       o:value("icmp", "ICMP")
+
+       function o.cfgvalue(...)
+               local v = Value.cfgvalue(...)
+               if not v or v == "tcpudp" then
+                       return "tcp udp"
+               end
+               return v
+       end
+
+
+       o = s:option(DynamicList, "icmp_type", translate("Match ICMP type"))
+       o:value("", "any")
+       o:value("echo-reply")
+       o:value("destination-unreachable")
+       o:value("network-unreachable")
+       o:value("host-unreachable")
+       o:value("protocol-unreachable")
+       o:value("port-unreachable")
+       o:value("fragmentation-needed")
+       o:value("source-route-failed")
+       o:value("network-unknown")
+       o:value("host-unknown")
+       o:value("network-prohibited")
+       o:value("host-prohibited")
+       o:value("TOS-network-unreachable")
+       o:value("TOS-host-unreachable")
+       o:value("communication-prohibited")
+       o:value("host-precedence-violation")
+       o:value("precedence-cutoff")
+       o:value("source-quench")
+       o:value("redirect")
+       o:value("network-redirect")
+       o:value("host-redirect")
+       o:value("TOS-network-redirect")
+       o:value("TOS-host-redirect")
+       o:value("echo-request")
+       o:value("router-advertisement")
+       o:value("router-solicitation")
+       o:value("time-exceeded")
+       o:value("ttl-zero-during-transit")
+       o:value("ttl-zero-during-reassembly")
+       o:value("parameter-problem")
+       o:value("ip-header-bad")
+       o:value("required-option-missing")
+       o:value("timestamp-request")
+       o:value("timestamp-reply")
+       o:value("address-mask-request")
+       o:value("address-mask-reply")
+
+
+       o = s:option(Value, "src", translate("Source zone"))
+       o.nocreate = true
+       o.allowany = true
+       o.default = "wan"
+       o.template = "cbi/firewall_zonelist"
+
+
+       o = s:option(Value, "src_mac", translate("Source MAC address"))
+       o.datatype = "list(macaddr)"
+       o.placeholder = translate("any")
+
+
+       o = s:option(Value, "src_ip", translate("Source address"))
+       o.datatype = "neg(ipaddr)"
+       o.placeholder = translate("any")
+
+
+       o = s:option(Value, "src_port", translate("Source port"))
+       o.datatype = "list(neg,portrange)"
+       o.placeholder = translate("any")
+
+
+       o = s:option(Value, "dest", translate("Destination zone"))
+       o.nocreate = true
+       o.allowany = true
+       o.allowlocal = true
+       o.template = "cbi/firewall_zonelist"
+
+
+       o = s:option(Value, "dest_ip", translate("Destination address"))
+       o.datatype = "neg(ipaddr)"
+       o.placeholder = translate("any")
+
+
+       o = s:option(Value, "dest_port", translate("Destination port"))
+       o.datatype = "list(neg,portrange)"
+       o.placeholder = translate("any")
+
+
+       o = s:option(ListValue, "target", translate("Action"))
+       o.default = "ACCEPT"
+       o:value("DROP", translate("drop"))
+       o:value("ACCEPT", translate("accept"))
+       o:value("REJECT", translate("reject"))
+       o:value("NOTRACK", translate("don't track"))
+end
+
+return m
diff --git a/applications/luci-firewall/luasrc/model/cbi/firewall/rules.lua b/applications/luci-firewall/luasrc/model/cbi/firewall/rules.lua
new file mode 100644 (file)
index 0000000..05e98a9
--- /dev/null
@@ -0,0 +1,300 @@
+--[[
+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$
+]]--
+
+local ds = require "luci.dispatcher"
+local ft = require "luci.tools.firewall"
+
+m = Map("firewall",
+       translate("Firewall - Traffic Rules"),
+       translate("Traffic rules define policies for packets traveling between \
+               different zones, for example to reject traffic between certain hosts \
+               or to open WAN ports on the router."))
+
+--
+-- Rules
+--
+
+s = m:section(TypedSection, "rule", translate("Traffic Rules"))
+s.addremove = true
+s.anonymous = true
+s.sortable  = true
+s.template = "cbi/tblsection"
+s.extedit   = ds.build_url("admin/network/firewall/rules/%s")
+s.defaults.target = "ACCEPT"
+s.template_addremove = "firewall/cbi_addrule"
+
+
+function s.create(self, section)
+       created = TypedSection.create(self, section)
+end
+
+function s.parse(self, ...)
+       TypedSection.parse(self, ...)
+
+       local i_n = m:formvalue("_newopen.name")
+       local i_p = m:formvalue("_newopen.proto")
+       local i_e = m:formvalue("_newopen.extport")
+       local i_x = m:formvalue("_newopen.submit")
+
+       local f_n = m:formvalue("_newfwd.name")
+       local f_s = m:formvalue("_newfwd.src")
+       local f_d = m:formvalue("_newfwd.dest")
+       local f_x = m:formvalue("_newfwd.submit")
+
+       if i_x then
+               created = TypedSection.create(self, section)
+
+               self.map:set(created, "target",    "ACCEPT")
+               self.map:set(created, "src",       "wan")
+               self.map:set(created, "proto",     (i_p ~= "other") and i_p or "all")
+               self.map:set(created, "dest_port", i_e)
+               self.map:set(created, "_name",     i_n)
+
+               if i_p ~= "other" and i_e and #i_e > 0 then
+                       created = nil
+               end
+
+       elseif f_x then
+               created = TypedSection.create(self, section)
+
+               self.map:set(created, "target", "ACCEPT")
+               self.map:set(created, "src",    f_s)
+               self.map:set(created, "dest",   f_d)
+               self.map:set(created, "_name",  f_n)
+       end
+
+       if created then
+               m.uci:save("firewall")
+               luci.http.redirect(ds.build_url(
+                       "admin", "network", "firewall", "rules", created
+               ))
+       end
+end
+
+name = s:option(DummyValue, "_name", translate("Name"))
+function name.cfgvalue(self, s)
+       return self.map:get(s, "_name") or "-"
+end
+
+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")
+       elseif f and f:match("6") then
+               return translate("IPv6")
+       else
+               return translate("Any")
+       end
+end
+
+proto = s:option(DummyValue, "proto", translate("Protocol"))
+proto.rawhtml = true
+proto.width   = "20%"
+function proto.cfgvalue(self, s)
+       return ft.fmt_proto(self.map:get(s, "proto"), self.map:get(s, "icmp_type"))
+               or "TCP+UDP"
+end
+
+src = s:option(DummyValue, "src", translate("Source"))
+src.rawhtml = true
+src.width   = "20%"
+function src.cfgvalue(self, s)
+       local z = ft.fmt_zone(self.map:get(s, "src"))
+       local a = ft.fmt_ip(self.map:get(s, "src_ip"))
+       local p = ft.fmt_port(self.map:get(s, "src_port"))
+       local m = ft.fmt_mac(self.map:get(s, "src_mac"))
+
+       local s = "From %s in %s " %{
+               (a or "<var>any host</var>"),
+               (z or "<var>any zone</var>")
+       }
+
+       if p and m then
+               s = s .. "with source %s and %s" %{ p, m }
+       elseif p or m then
+               s = s .. "with source %s" %( p or m )
+       end
+
+       return s
+end
+
+dest = s:option(DummyValue, "dest", translate("Destination"))
+dest.rawhtml = true
+dest.width   = "20%"
+function dest.cfgvalue(self, s)
+       local z = ft.fmt_zone(self.map:get(s, "dest"))
+       local a = ft.fmt_ip(self.map:get(s, "dest_ip"))
+       local p = ft.fmt_port(self.map:get(s, "dest_port"))
+
+       -- Forward
+       if z then
+               return "To %s%s in %s" %{
+                       (a or "<var>any host</var>"),
+                       (p and ", %s" % p or ""),
+                       z
+               }
+
+       -- Input
+       else
+               return "To %s%s on <var>this device</var>" %{
+                       (a or "<var>any router IP</var>"),
+                       (p and " at %s" % p or "")
+               }
+       end
+end
+
+
+target = s:option(DummyValue, "target", translate("Action"))
+target.rawhtml = true
+target.width   = "20%"
+function target.cfgvalue(self, s)
+       local z = ft.fmt_zone(self.map:get(s, "dest"))
+       local l = ft.fmt_limit(self.map:get(s, "limit"), self.map:get(s, "limit_burst"))
+       local t = ft.fmt_target(self.map:get(s, "target"))
+
+       return "<var>%s</var> %s%s" %{
+               t,
+               (z and "forward" or "input"),
+               (l and " and limit to %s" % l or "")
+       }
+end
+
+
+--
+-- SNAT
+--
+
+s = m:section(TypedSection, "redirect",
+       translate("Source NAT"),
+       translate("Source NAT is a specific form of masquerading which allows \
+               fine grained control over the source IP used for outgoing traffic, \
+               for example to map multiple WAN addresses to internal subnets."))
+s.template  = "cbi/tblsection"
+s.addremove = true
+s.anonymous = true
+s.sortable  = true
+s.extedit   = ds.build_url("admin/network/firewall/rules/%s")
+s.template_addremove = "firewall/cbi_addsnat"
+
+function s.create(self, section)
+       created = TypedSection.create(self, section)
+end
+
+function s.parse(self, ...)
+       TypedSection.parse(self, ...)
+
+       local n = m:formvalue("_newsnat.name")
+       local s = m:formvalue("_newsnat.src")
+       local d = m:formvalue("_newsnat.dest")
+       local a = m:formvalue("_newsnat.dip")
+       local p = m:formvalue("_newsnat.dport")
+       local x = m:formvalue("_newsnat.submit")
+
+       if x and a and #a > 0 then
+               created = TypedSection.create(self, section)
+
+               self.map:set(created, "target",    "SNAT")
+               self.map:set(created, "src",       s)
+               self.map:set(created, "dest",      d)
+               self.map:set(created, "proto",     "all")
+               self.map:set(created, "src_dip",   a)
+               self.map:set(created, "src_dport", p)
+               self.map:set(created, "_name",     n)
+       end
+
+       if created then
+               m.uci:save("firewall")
+               luci.http.redirect(ds.build_url(
+                       "admin/network/firewall/rules", created
+               ))
+       end
+end
+
+function s.filter(self, sid)
+       return (self.map:get(sid, "target") == "SNAT")
+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"))
+proto.rawhtml = true
+function proto.cfgvalue(self, s)
+       return ft.fmt_proto(self.map:get(s, "proto")) or "TCP+UDP"
+end
+
+
+src = s:option(DummyValue, "src", translate("Source"))
+src.rawhtml = true
+src.width   = "20%"
+function src.cfgvalue(self, s)
+       local z = ft.fmt_zone(self.map:get(s, "src"))
+       local a = ft.fmt_ip(self.map:get(s, "src_ip"))
+       local p = ft.fmt_port(self.map:get(s, "src_port"))
+       local m = ft.fmt_mac(self.map:get(s, "src_mac"))
+
+       local s = "From %s in %s " %{
+               (a or "<var>any host</var>"),
+               (z or "<var>any zone</var>")
+       }
+
+       if p and m then
+               s = s .. "with source %s and %s" %{ p, m }
+       elseif p or m then
+               s = s .. "with source %s" %( p or m )
+       end
+
+       return s
+end
+
+dest = s:option(DummyValue, "dest", translate("Destination"))
+dest.rawhtml = true
+dest.width   = "30%"
+function dest.cfgvalue(self, s)
+       local z = ft.fmt_zone(self.map:get(s, "dest"))
+       local a = ft.fmt_ip(self.map:get(s, "dest_ip"))
+       local p = ft.fmt_port(self.map:get(s, "dest_port")) or
+               ft.fmt_port(self.map:get(s, "src_dport"))
+
+       return "To %s%s in %s " %{
+               (a or "<var>any host</var>"),
+               (p and ", %s" % p or ""),
+               (z or "<var>any zone</var>")
+       }
+end
+
+snat = s:option(DummyValue, "via", translate("SNAT"))
+snat.rawhtml = true
+snat.width   = "20%"
+function snat.cfgvalue(self, s)
+       local a = ft.fmt_ip(self.map:get(s, "src_dip"))
+       local p = ft.fmt_port(self.map:get(s, "src_dport"))
+
+       --local z = self.map:get(s, "src")
+       --local s = "To %s " %(a or "<var>any %s IP</var>" %( z or "router" ))
+
+       if a and p then
+               return "Rewrite to source %s, %s" %{ a, p }
+       elseif a or p then
+               return "Rewrite to source %s" %( a or p )
+       else
+               return "Bug"
+       end
+end
+
+
+return m
diff --git a/applications/luci-firewall/luasrc/model/cbi/firewall/zone-details.lua b/applications/luci-firewall/luasrc/model/cbi/firewall/zone-details.lua
new file mode 100644 (file)
index 0000000..a8ae894
--- /dev/null
@@ -0,0 +1,242 @@
+--[[
+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$
+]]--
+
+local nw = require "luci.model.network"
+local fw = require "luci.model.firewall"
+local ds = require "luci.dispatcher"
+local ut = require "luci.util"
+
+local m, p, i, v
+local s, name, net, family, msrc, mdest, log, lim
+local s2, out, inp
+
+
+m = Map("firewall", translate("Firewall - Zone Settings"))
+m.redirect = luci.dispatcher.build_url("admin/network/firewall/zones")
+
+fw.init(m.uci)
+nw.init(m.uci)
+
+
+local zone = fw:get_zone(arg[1])
+if not zone then
+       luci.http.redirect(dsp.build_url("admin/network/firewall/zones"))
+       return
+else
+       m.title = "%s - %s" %{
+               translate("Firewall - Zone Settings"),
+               translatef("Zone %q", zone:name() or "?")
+       }
+end
+
+
+s = m:section(NamedSection, zone.sid, "zone",
+       translatef("Zone %q", zone:name()),
+       translatef("This section defines common properties of %q. \
+               The <em>input</em> and <em>output</em> options set the default \
+               policies for traffic entering and leaving this zone while the \
+               <em>forward</em> option describes the policy for forwarded traffic \
+               between different networks within the zone. \
+               <em>Covered networks</em> specifies which available networks are \
+               member of this zone.", zone:name()))
+
+s.anonymous = true
+s.addremove = false
+
+m.on_commit = function(map)
+       local zone = fw:get_zone(arg[1])
+       if zone then
+               s.section  = zone.sid
+               s2.section = zone.sid
+       end
+end
+
+
+s:tab("general", translate("General Settings"))
+s:tab("advanced", translate("Advanced Settings"))
+
+
+name = s:taboption("general", Value, "name", translate("Name"))
+name.optional = false
+name.forcewrite = true
+name.datatype = "uciname"
+
+function name.write(self, section, value)
+       if zone:name() ~= value then
+               fw:rename_zone(zone:name(), value)
+               out.exclude = value
+               inp.exclude = value
+       end
+
+       m.redirect = ds.build_url("admin/network/firewall/zones", value)
+       m.title = "%s - %s" %{
+               translate("Firewall - Zone Settings"),
+               translatef("Zone %q", value or "?")
+       }
+end
+
+p = {
+       s:taboption("general", ListValue, "input", translate("Input")),
+       s:taboption("general", ListValue, "output", translate("Output")),
+       s:taboption("general", ListValue, "forward", translate("Forward"))
+}
+
+for i, v in ipairs(p) do
+       v:value("REJECT", translate("reject"))
+       v:value("DROP", translate("drop"))
+       v:value("ACCEPT", translate("accept"))
+end
+
+s:taboption("general", Flag, "masq", translate("Masquerading"))
+s:taboption("general", Flag, "mtu_fix", translate("MSS clamping"))
+
+net = s:taboption("general", Value, "network", translate("Covered networks"))
+net.template = "cbi/network_netlist"
+net.widget = "checkbox"
+net.cast = "string"
+
+function net.formvalue(self, section)
+       return Value.formvalue(self, section) or "-"
+end
+
+function net.cfgvalue(self, section)
+       return Value.cfgvalue(self, section) or name:cfgvalue(section)
+end
+
+function net.write(self, section, value)
+       zone:clear_networks()
+
+       local n
+       for n in ut.imatch(value) do
+               zone:add_network(n)
+       end
+end
+
+
+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"))
+
+msrc = s:taboption("advanced", DynamicList, "masq_src",
+       translate("Restrict Masquerading to given source subnets"))
+
+msrc.optional = true
+msrc.datatype = "neg_network_ip4addr"
+msrc.placeholder = "0.0.0.0/0"
+msrc:depends("family", "")
+msrc:depends("family", "ipv4")
+
+mdest = s:taboption("advanced", DynamicList, "masq_dest",
+       translate("Restrict Masquerading to given destination subnets"))
+
+mdest.optional = true
+mdest.datatype = "neg_network_ip4addr"
+mdest.placeholder = "0.0.0.0/0"
+mdest:depends("family", "")
+mdest:depends("family", "ipv4")
+
+s:taboption("advanced", Flag, "conntrack",
+       translate("Force connection tracking"))
+
+log = s:taboption("advanced", Flag, "log",
+       translate("Enable logging on this zone"))
+
+log.rmempty = true
+log.enabled = "1"
+
+lim = s:taboption("advanced", Value, "log_limit",
+       translate("Limit log messages"))
+
+lim.placeholder = "10/minute"
+lim:depends("log", "1")
+
+
+s2 = m:section(NamedSection, zone.sid, "fwd_out",
+       translate("Inter-Zone Forwarding"),
+       translatef("The options below control the forwarding policies between \
+               this zone (%s) and other zones. <em>Destination zones</em> cover \
+               forwarded traffic <strong>originating from %q</strong>. \
+               <em>Source zones</em> match forwarded traffic from other zones \
+               <strong>targeted at %q</strong>. The forwarding rule is \
+               <em>unidirectional</em>, e.g. a forward from lan to wan does \
+               <em>not</em> imply a permission to forward from wan to lan as well.",
+               zone:name(), zone:name(), zone:name()
+
+       ))
+
+out = s2:option(Value, "out",
+       translate("Allow forward to <em>destination zones</em>:"))
+
+out.nocreate = true
+out.widget = "checkbox"
+out.exclude = zone:name()
+out.template = "cbi/firewall_zonelist"
+
+inp = s2:option(Value, "in",
+       translate("Allow forward from <em>source zones</em>:"))
+
+inp.nocreate = true
+inp.widget = "checkbox"
+inp.exclude = zone:name()
+inp.template = "cbi/firewall_zonelist"
+
+function out.cfgvalue(self, section)
+       local v = { }
+       local f
+       for _, f in ipairs(zone:get_forwardings_by("src")) do
+               v[#v+1] = f:dest()
+       end
+       return table.concat(v, " ")
+end
+
+function inp.cfgvalue(self, section)
+       local v = { }
+       local f
+       for _, f in ipairs(zone:get_forwardings_by("dest")) do
+               v[#v+1] = f:src()
+       end
+       return v
+end
+
+function out.formvalue(self, section)
+       return Value.formvalue(self, section) or "-"
+end
+
+function inp.formvalue(self, section)
+       return Value.formvalue(self, section) or "-"
+end
+
+function out.write(self, section, value)
+       zone:del_forwardings_by("src")
+
+       local f
+       for f in ut.imatch(value) do
+               zone:add_forwarding_to(f)
+       end
+end
+
+function inp.write(self, section, value)
+       zone:del_forwardings_by("dest")
+
+       local f
+       for f in ut.imatch(value) do
+               zone:add_forwarding_from(f)
+       end
+end
+
+return m
diff --git a/applications/luci-firewall/luasrc/model/cbi/firewall/zones.lua b/applications/luci-firewall/luasrc/model/cbi/firewall/zones.lua
new file mode 100644 (file)
index 0000000..e6d8548
--- /dev/null
@@ -0,0 +1,88 @@
+--[[
+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$
+]]--
+
+local ds = require "luci.dispatcher"
+local fw = require "luci.model.firewall"
+
+local m, s, o, p, i, v
+
+m = Map("firewall",
+       translate("Firewall - Zone Settings"),
+       translate("The firewall creates zones over your network interfaces to control network traffic flow."))
+
+fw.init(m.uci)
+
+s = m:section(TypedSection, "defaults", translate("General Settings"))
+s.anonymous = true
+s.addremove = false
+
+s:option(Flag, "syn_flood", translate("Enable SYN-flood protection"))
+
+o = s:option(Flag, "drop_invalid", translate("Drop invalid packets"))
+o.default = o.disabled
+
+p = {
+       s:option(ListValue, "input", translate("Input")),
+       s:option(ListValue, "output", translate("Output")),
+       s:option(ListValue, "forward", translate("Forward"))
+}
+
+for i, v in ipairs(p) do
+       v:value("REJECT", translate("reject"))
+       v:value("DROP", translate("drop"))
+       v:value("ACCEPT", translate("accept"))
+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")
+
+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
+
+function s.remove(self, section)
+       return fw:del_zone(section)
+end
+
+o = s:option(DummyValue, "_info", translate("Zone â‡’ Forwardings"))
+o.template = "cbi/firewall_zoneforwards"
+o.cfgvalue = function(self, section)
+       return self.map:get(section, "name")
+end
+
+p = {
+       s:option(ListValue, "input", translate("Input")),
+       s:option(ListValue, "output", translate("Output")),
+       s:option(ListValue, "forward", translate("Forward"))
+}
+
+for i, v in ipairs(p) do
+       v:value("REJECT", translate("reject"))
+       v:value("DROP", translate("drop"))
+       v:value("ACCEPT", translate("accept"))
+end
+
+s:option(Flag, "masq", translate("Masquerading"))
+s:option(Flag, "mtu_fix", translate("MSS clamping"))
+
+return m
diff --git a/applications/luci-firewall/luasrc/model/cbi/luci_fw/miniportfw.lua b/applications/luci-firewall/luasrc/model/cbi/luci_fw/miniportfw.lua
deleted file mode 100644 (file)
index 44b15f2..0000000
+++ /dev/null
@@ -1,48 +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("Port forwarding"),
-       translate("Port forwarding allows to provide network services in " ..
-               "the internal network to an external network."))
-
-
-s = m:section(TypedSection, "redirect", "")
-s:depends("src", "wan")
-s.defaults.src = "wan"
-
-s.template  = "cbi/tblsection"
-s.addremove = true
-s.anonymous = true
-
-name = s:option(Value, "_name", translate("Name"), translate("(optional)"))
-name.size = 10
-
-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("External port"))
-dport.size = 5
-
-to = s:option(Value, "dest_ip", translate("Internal IP address"))
-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"),
-       translate("(optional)"))
-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
deleted file mode 100644 (file)
index 675cdbb..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
---[[
-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.
-You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-$Id$
-]]--
-
-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
-
-s:tab("general", translate("General Settings"))
-s:tab("advanced", translate("Advanced Settings"))
-
-name = s:taboption("general", Value, "_name", translate("Name"))
-name.rmempty = true
-name.size = 10
-
-src = s:taboption("general", Value, "src", translate("Source zone"))
-src.nocreate = true
-src.default = "wan"
-src.template = "cbi/firewall_zonelist"
-
-proto = s:taboption("general", Value, "proto", translate("Protocol"))
-proto.optional = true
-proto:value("tcpudp", "TCP+UDP")
-proto:value("tcp", "TCP")
-proto:value("udp", "UDP")
-
-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.datatype = "portrange"
-dport:depends("proto", "tcp")
-dport:depends("proto", "udp")
-dport:depends("proto", "tcpudp")
-
-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: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.placeholder = "0-65535"
-toport.datatype = "portrange"
-toport:depends("proto", "tcp")
-toport:depends("proto", "udp")
-toport:depends("proto", "tcpudp")
-
-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_dip.placeholder = translate("any")
-
-src_mac = s:taboption("advanced", Value, "src_mac", translate("Source MAC address"))
-src_mac.optional = true
-src_mac.datatype = "macaddr"
-src_mac.placeholder = translate("any")
-
-src_ip = s:taboption("advanced", Value, "src_ip", translate("Source IP address"))
-src_ip.optional = true
-src_ip.datatype = "neg_ip4addr"
-src_ip.placeholder = translate("any")
-
-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.placeholder = "0-65536"
-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.default = reflection.enabled
-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/trule.lua b/applications/luci-firewall/luasrc/model/cbi/luci_fw/trule.lua
deleted file mode 100644 (file)
index 10a9869..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
---[[
-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.
-You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-$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 = dsp.build_url("admin", "network", "firewall", "rule")
-
-
-name = s:taboption("general", Value, "_name", translate("Name").." "..translate("(optional)"))
-name.rmempty = true
-
-src = s:taboption("general", Value, "src", translate("Source zone"))
-src.nocreate = true
-src.default = "wan"
-src.template = "cbi/firewall_zonelist"
-
-dest = s:taboption("advanced", Value, "dest", translate("Destination zone"))
-dest.nocreate = true
-dest.allowlocal = true
-dest.template = "cbi/firewall_zonelist"
-
-proto = s:taboption("general", Value, "proto", translate("Protocol"))
-proto.optional = true
-proto:value("all", translate("Any"))
-proto:value("tcpudp", "TCP+UDP")
-proto:value("tcp", "TCP")
-proto:value("udp", "UDP")
-proto:value("icmp", "ICMP")
-
-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 "neg_ipaddr" or "neg_ip4addr"
-src_ip.placeholder = translate("any")
-
-sport = s:taboption("general", Value, "src_port", translate("Source port"))
-sport.optional = true
-sport.datatype = "portrange"
-sport.placeholder = "0-65535"
-sport:depends("proto", "tcp")
-sport:depends("proto", "udp")
-sport:depends("proto", "tcpudp")
-
-dest_ip = s:taboption("general", Value, "dest_ip", translate("Destination address"))
-dest_ip.optional = true
-dest_ip.datatype = has_v2 and "neg_ipaddr" or "neg_ip4addr"
-dest_ip.placeholder = translate("any")
-
-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")
-dport.placeholder = "0-65535"
-
-jump = s:taboption("general", ListValue, "target", translate("Action"))
-jump.rmempty = true
-jump.default = "ACCEPT"
-jump:value("DROP", translate("drop"))
-jump:value("ACCEPT", translate("accept"))
-jump:value("REJECT", translate("reject"))
-jump:value("NOTRACK", translate("don't track"))
-
-
-smac = s:taboption("advanced", Value, "src_mac", translate("Source MAC address"))
-smac.optional = true
-smac.datatype = "macaddr"
-smac.placeholder = translate("any")
-
-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/zone.lua b/applications/luci-firewall/luasrc/model/cbi/luci_fw/zone.lua
deleted file mode 100644 (file)
index 8c9c091..0000000
+++ /dev/null
@@ -1,237 +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$
-]]--
-
-local nw = require "luci.model.network"
-local fw = require "luci.model.firewall"
-local utl = require "luci.util"
-local dsp = require "luci.dispatcher"
-
-local has_v2 = nixio.fs.access("/lib/firewall/fw.sh")
-local out, inp
-
-require("luci.tools.webadmin")
-m = Map("firewall", translate("Firewall - Zone Settings"))
-m.redirect = luci.dispatcher.build_url("admin/network/firewall")
-
-fw.init(m.uci)
-nw.init(m.uci)
-
-
-local zone = fw:get_zone(arg[1])
-if not zone then
-       luci.http.redirect(dsp.build_url("admin", "network", "firewall"))
-       return
-end
-
-
-s = m:section(NamedSection, zone.sid, "zone",
-       translatef("Zone %q", zone:name()),
-       translatef("This section defines common properties of %q. " ..
-               "The <em>input</em> and <em>output</em> options set the default "..
-               "policies for traffic entering and leaving this zone while the " ..
-               "<em>forward</em> option describes the policy for forwarded traffic " ..
-               "between different networks within the zone. " ..
-               "<em>Covered networks</em> specifies which available networks are " ..
-               "member of this zone.", zone:name()))
-
-s.anonymous = true
-s.addremove = false
-
-m.on_commit = function(map)
-       local zone = fw:get_zone(arg[1])
-       if zone then
-               s.section  = zone.sid
-               s2.section = zone.sid
-       end
-end
-
-
-s:tab("general", translate("General Settings"))
-s:tab("advanced", translate("Advanced Settings"))
-
-
-name = s:taboption("general", Value, "name", translate("Name"))
-name.optional = false
-name.forcewrite = true
-name.datatype = "uciname"
-
-function name.write(self, section, value)
-       if zone:name() ~= value then
-               fw:rename_zone(zone:name(), value)
-               out.exclude = value
-               inp.exclude = value
-       end
-
-       m.redirect = luci.dispatcher.build_url(
-               "admin", "network", "firewall", "zones", value
-       )
-end
-
-p = {}
-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"))
-       v:value("DROP", translate("drop"))
-       v:value("ACCEPT", translate("accept"))
-end
-
-s:taboption("general", Flag, "masq", translate("Masquerading"))
-s:taboption("general", Flag, "mtu_fix", translate("MSS clamping"))
-
-net = s:taboption("general", Value, "network", translate("Covered networks"))
-net.template = "cbi/network_netlist"
-net.widget = "checkbox"
-net.cast = "string"
-
-function net.formvalue(self, section)
-       return Value.formvalue(self, section) or "-"
-end
-
-function net.cfgvalue(self, section)
-       return Value.cfgvalue(self, section) or name:cfgvalue(section)
-end
-
-function net.write(self, section, value)
-       zone:clear_networks()
-
-       local n
-       for n in utl.imatch(value) do
-               zone:add_network(n)
-       end
-end
-
-
-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
-
-msrc = s:taboption("advanced", DynamicList, "masq_src",
-       translate("Restrict Masquerading to given source subnets"))
-
-msrc.optional = true
-msrc.datatype = "neg(network)"
-msrc.placeholder = "0.0.0.0/0"
-msrc:depends("family", "")
-msrc:depends("family", "ipv4")
-
-mdest = s:taboption("advanced", DynamicList, "masq_dest",
-       translate("Restrict Masquerading to given destination subnets"))
-
-mdest.optional = true
-mdest.datatype = "neg(network)"
-mdest.placeholder = "0.0.0.0/0"
-mdest:depends("family", "")
-mdest:depends("family", "ipv4")
-
-s:taboption("advanced", Flag, "conntrack",
-       translate("Force connection tracking"))
-
-if has_v2 then
-       log = s:taboption("advanced", Flag, "log",
-               translate("Enable logging on this zone"))
-
-       log.rmempty = true
-       log.enabled = "1"
-
-       lim = s:taboption("advanced", Value, "log_limit",
-               translate("Limit log messages"))
-
-       lim.placeholder = "10/minute"
-       lim:depends("log", "1")
-end
-
-
-s2 = m:section(NamedSection, zone.sid, "fwd_out",
-       translate("Inter-Zone Forwarding"),
-       translatef("The options below control the forwarding policies between " ..
-               "this zone (%s) and other zones. <em>Destination zones</em> cover " ..
-               "forwarded traffic <strong>originating from %q</strong>. " ..
-               "<em>Source zones</em> match forwarded traffic from other zones " ..
-               "<strong>targeted at %q</strong>. The forwarding rule is " ..
-               "<em>unidirectional</em>, e.g. a forward from lan to wan does " ..
-               "<em>not</em> imply a permission to forward from wan to lan as well.",
-               zone:name(), zone:name(), zone:name()
-
-       ))
-
-out = s2:option(Value, "out",
-       translate("Allow forward to <em>destination zones</em>:"))
-
-out.nocreate = true
-out.widget = "checkbox"
-out.exclude = zone:name()
-out.template = "cbi/firewall_zonelist"
-
-inp = s2:option(Value, "in",
-       translate("Allow forward from <em>source zones</em>:"))
-
-inp.nocreate = true
-inp.widget = "checkbox"
-inp.exclude = zone:name()
-inp.template = "cbi/firewall_zonelist"
-
-function out.cfgvalue(self, section)
-       local v = { }
-       local f
-       for _, f in ipairs(zone:get_forwardings_by("src")) do
-               v[#v+1] = f:dest()
-       end
-       return table.concat(v, " ")
-end
-
-function inp.cfgvalue(self, section)
-       local v = { }
-       local f
-       for _, f in ipairs(zone:get_forwardings_by("dest")) do
-               v[#v+1] = f:src()
-       end
-       return v
-end
-
-function out.formvalue(self, section)
-       return Value.formvalue(self, section) or "-"
-end
-
-function inp.formvalue(self, section)
-       return Value.formvalue(self, section) or "-"
-end
-
-function out.write(self, section, value)
-       zone:del_forwardings_by("src")
-
-       local f
-       for f in utl.imatch(value) do
-               zone:add_forwarding_to(f)
-       end
-end
-
-function inp.write(self, section, value)
-       zone:del_forwardings_by("dest")
-
-       local f
-       for f in utl.imatch(value) do
-               zone:add_forwarding_from(f)
-       end
-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
deleted file mode 100644 (file)
index 79604c2..0000000
+++ /dev/null
@@ -1,273 +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$
-]]--
-
-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."))
-
-fw.init(m.uci)
-nw.init(m.uci)
-
-s = m:section(TypedSection, "defaults")
-s.anonymous = true
-s.addremove = false
-
-s:tab("general", translate("General Settings"))
-s:tab("custom", translate("Custom Rules"))
-
-
-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: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"))
-       v:value("DROP", translate("drop"))
-       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)
-       value = value:gsub("\r\n?", "\n")
-       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")
-
-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
-
-function s.remove(self, section)
-       return fw:del_zone(section)
-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"))
-p[2] = s:option(ListValue, "output", translate("Output"))
-p[3] = s:option(ListValue, "forward", translate("Forward"))
-
-for i, v in ipairs(p) do
-       v:value("REJECT", translate("reject"))
-       v:value("DROP", translate("drop"))
-       v:value("ACCEPT", translate("accept"))
-end
-
-s:option(Flag, "masq", translate("Masquerading"))
-s:option(Flag, "mtu_fix", translate("MSS clamping"))
-
-
-local created = nil
-
---
--- Redirects
---
-
-s = m:section(TypedSection, "redirect", translate("Redirections"))
-s.template  = "cbi/tblsection"
-s.addremove = true
-s.anonymous = true
-s.sortable  = 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.sortable  = 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
diff --git a/applications/luci-firewall/luasrc/tools/firewall.lua b/applications/luci-firewall/luasrc/tools/firewall.lua
new file mode 100644 (file)
index 0000000..a2e3bce
--- /dev/null
@@ -0,0 +1,213 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2011 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.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+]]--
+
+module("luci.tools.firewall", package.seeall)
+
+local ut = require "luci.util"
+local ip = require "luci.ip"
+local nx = require "nixio"
+
+local tr, trf = luci.i18n.translate, luci.i18n.translatef
+
+function fmt_neg(x)
+       if type(x) == "string" then
+               local v, neg = x:gsub("^ *! *", "")
+               if neg > 0 then
+                       return v, "%s " % tr("not")
+               else
+                       return x, ""
+               end
+       end
+       return x, ""
+end
+
+function fmt_mac(x)
+       if x and #x > 0 then
+               local m, n
+               local l = { tr("MAC"), " " }
+               for m in ut.imatch(x) do
+                       m, n = fmt_neg(m)
+                       l[#l+1] = "<var>%s%s</var>" %{ n, m }
+                       l[#l+1] = ", "
+               end
+               if #l > 1 then
+                       l[#l] = nil
+                       if #l > 3 then
+                               l[1] = tr("MACs")
+                       end
+                       return table.concat(l, "")
+               end
+       end
+end
+
+function fmt_port(x)
+       if x and #x > 0 then
+               local p, n
+               local l = { tr("port"), " " }
+               for p in ut.imatch(x) do
+                       p, n = fmt_neg(p)
+                       local a, b = p:match("(%d+)%D+(%d+)")
+                       if a and b then
+                               l[1] = tr("ports")
+                               l[#l+1] = "<var>%s%d-%d</var>" %{ n, a, b }
+                       else
+                               l[#l+1] = "<var>%s%d</var>" %{ n, p }
+                       end
+                       l[#l+1] = ", "
+               end
+               if #l > 1 then
+                       l[#l] = nil
+                       if #l > 3 then
+                               l[1] = tr("ports")
+                       end
+                       return table.concat(l, "")
+               end
+       end
+end
+
+function fmt_ip(x)
+       if x and #x > 0 then
+               local l = { tr("IP"), " " }
+               local v, a, n
+               for v in ut.imatch(x) do
+                       v, n = fmt_neg(v)
+                       a, m = v:match("(%S+)/(%d+%.%S+)")
+                       a = a or v
+                       a = a:match(":") and ip.IPv6(a, m) or ip.IPv4(a, m)
+                       if a and (a:is6() or a:prefix() < 32) then
+                               l[1] = tr("IP range")
+                               l[#l+1] = "<var title='%s - %s'>%s%s</var>" %{
+                                       a:minhost():string(),
+                                       a:maxhost():string(),
+                                       n, a:string()
+                               }
+                       else
+                               l[#l+1] = "<var>%s%s</var>" %{
+                                       n,
+                                       a and a:string() or v
+                               }
+                       end
+                       l[#l+1] = ", "
+               end
+               if #l > 1 then
+                       l[#l] = nil
+                       if #l > 3 then
+                               l[1] = tr("IPs")
+                       end
+                       return table.concat(l, "")
+               end
+       end
+end
+
+function fmt_zone(x)
+       if x == "*" then
+               return "<var>%s</var>" % tr("any zone")
+       elseif x and #x > 0 then
+               return "<var>%s</var>" % x
+       end
+end
+
+function fmt_icmp_type(x)
+       if x and #x > 0 then
+               local t, v, n
+               local l = { tr("type"), " " }
+               for v in ut.imatch(x) do
+                       v, n = fmt_neg(v)
+                       l[#l+1] = "<var>%s%s</var>" %{ n, v }
+                       l[#l+1] = ", "
+               end
+               if #l > 1 then
+                       l[#l] = nil
+                       if #l > 3 then
+                               l[1] = tr("types")
+                       end
+                       return table.concat(l, "")
+               end
+       end
+end
+
+function fmt_proto(x, icmp_types)
+       if x and #x > 0 then
+               local v, n
+               local l = { }
+               local t = fmt_icmp_type(icmp_types)
+               for v in ut.imatch(x) do
+                       v, n = fmt_neg(v)
+                       if v == "tcpudp" then
+                               l[#l+1] = "TCP"
+                               l[#l+1] = "UDP"
+                               l[#l+1] = ", "
+                       elseif v ~= "all" then
+                               local p = nx.getproto(v)
+                               if p then
+                                       -- ICMP
+                                       if (p.proto == 1 or p.proto == 58) and t then
+                                               l[#l+1] = trf(
+                                                       "%s%s with %s",
+                                                       n, p.aliases[1] or p.name, t
+                                               )
+                                       else
+                                               l[#l+1] = "%s%s" %{
+                                                       n,
+                                                       p.aliases[1] or p.name
+                                               }
+                                       end
+                                       l[#l+1] = ", "
+                               end
+                       end
+               end
+               if #l > 0 then
+                       l[#l] = nil
+                       return table.concat(l, "")
+               end
+       end
+end
+
+function fmt_limit(limit, burst)
+       burst = tonumber(burst)
+       if limit and #limit > 0 then
+               local l, u = limit:match("(%d+)/(%w+)")
+               l = tonumber(l or limit)
+               u = u or "second"
+               if l then
+                       if u:match("^s") then
+                               u = tr("second")
+                       elseif u:match("^m") then
+                               u = tr("minute")
+                       elseif u:match("^h") then
+                               u = tr("hour")
+                       elseif u:match("^d") then
+                               u = tr("day")
+                       end
+                       if burst and burst > 0 then
+                               return trf("<var>%d</var> pkts. per <var>%s</var>, \
+                                   burst <var>%d</var> pkts.", l, u, burst)
+                       else
+                               return trf("<var>%d</var> pkts. per <var>%s</var>", l, u)
+                       end
+               end
+       end
+end
+
+function fmt_target(x)
+       if x == "ACCEPT" then
+               return tr("Accept")
+       elseif x == "REJECT" then
+               return tr("Refuse")
+       elseif x == "NOTRACK" then
+               return tr("Do not track")
+       else --if x == "DROP" then
+               return tr("Discard")
+       end
+end
diff --git a/applications/luci-firewall/luasrc/view/cbi_addforward.htm b/applications/luci-firewall/luasrc/view/cbi_addforward.htm
new file mode 100644 (file)
index 0000000..6a49266
--- /dev/null
@@ -0,0 +1,90 @@
+<div class="cbi-section-create cbi-tblsection-create">
+       <br />
+       <table class="cbi-section-table" style="width:700px; margin-left:5px">
+               <tr class="cbi-section-table-titles">
+                       <th class="cbi-section-table-cell" colspan="6"><%:New port forward%>:</th>
+               </tr>
+               <tr class="cbi-section-table-descr">
+                       <th class="cbi-section-table-cell"><%:Name%></th>
+                       <th class="cbi-section-table-cell"><%:Protocol%></th>
+                       <th class="cbi-section-table-cell"><%:External port%></th>
+                       <th class="cbi-section-table-cell"><%:Internal IP address%></th>
+                       <th class="cbi-section-table-cell"><%:Internal port%></th>
+                       <th class="cbi-section-table-cell"></th>
+               </tr>
+               <tr class="cbi-section-table-row">
+                       <td class="cbi-section-table-cell">
+                               <input type="text" class="cbi-input-text" id="_newfwd.name" name="_newfwd.name" placeholder="<%:New port forward%>" />
+                       </td>
+                       <td class="cbi-section-table-cell" style="width:110px">
+                               <select class="cbi-input-select" id="_newfwd.proto" name="_newfwd.proto">
+                                       <option value="tcp udp">TCP+UDP</option>
+                                       <option value="tcp">TCP</option>
+                                       <option value="udp">UDP</option>
+                                       <option value="other"><%:Other...%></option>
+                               </select>
+                       </td>
+                       <td class="cbi-section-table-cell" style="width:110px">
+                               <input type="text" class="cbi-input-text" id="_newfwd.extport" name="_newfwd.extport" />
+                       </td>
+                       <td class="cbi-section-table-cell" style="width:110px">
+                               <input type="text" class="cbi-input-text" id="_newfwd.intaddr" name="_newfwd.intaddr" />
+                       </td>
+                       <td class="cbi-section-table-cell" style="width:110px">
+                               <input type="text" class="cbi-input-text" id="_newfwd.intport" name="_newfwd.intport" />
+                       </td>
+                       <td class="cbi-section-table-cell">
+                               <input type="submit" class="cbi-button cbi-button-add" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" value="<%:Add%>" />
+                       </td>
+               </tr>
+       </table>
+
+       <script type="text/javascript">//<![CDATA[
+               cbi_validate_field('_newfwd.extport', true, 'portrange');
+               cbi_validate_field('_newfwd.intaddr', true, 'host');
+               cbi_validate_field('_newfwd.intport', true, 'portrange');
+
+               cbi_combobox_init('_newfwd.intaddr', {
+                       <% local i, e; for i, e in ipairs(luci.sys.net.arptable()) do -%>
+                               <%- if i > 1 then %>,<% end -%>'<%=e["IP address"]%>': '<%=e["IP address"]%>'
+                       <%- end %> }, '', '<%: -- custom -- %>');
+
+               cbi_bind(document.getElementById('_newfwd.extport'), 'blur',
+                       function() {
+                               var n = document.getElementById('_newfwd.name');
+                               var p = document.getElementById('_newfwd.proto');
+                               var i = document.getElementById('_newfwd.intport');
+                               var hints = {
+                               /*  port    name     0=both, 1=tcp, 2=udp, 3=other */
+                                       21:   [ 'FTP',   1 ],
+                                       22:   [ 'SSH',   1 ],
+                                       53:   [ 'DNS',   0 ],
+                                       80:   [ 'HTTP',  1 ],
+                                       443:  [ 'HTTPS', 1 ],
+                                       3389: [ 'RDP',   1 ],
+                                       5900: [ 'VNC',   1 ],
+                               };
+
+                               if (!this.className.match(/invalid/))
+                               {
+                                       if (!i.value) i.value = this.value;
+
+                                       var hint = hints[this.value || 0] || hints[i.value || 0];
+                                       if (hint)
+                                       {
+                                               p.selectedIndex = hint[1];
+
+                                               if (!n.value)
+                                                       n.value = hint[0];
+                                       }
+                                       else if (!n.value)
+                                       {
+                                               n.value = 'Forward' + this.value;
+                                       }
+                               }
+                       });
+
+
+               cbi_validate_field('cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>', true, 'uciname');
+       //]]></script>
+</div>
diff --git a/applications/luci-firewall/luasrc/view/cbi_addrule.htm b/applications/luci-firewall/luasrc/view/cbi_addrule.htm
new file mode 100644 (file)
index 0000000..473f9f4
--- /dev/null
@@ -0,0 +1,112 @@
+<%
+       local fw = require "luci.model.firewall".init()
+       local wz = fw:get_zone("wan")
+       local lz = fw:get_zone("lan")
+%>
+
+<div class="cbi-section-create cbi-tblsection-create">
+       <% if wz and lz then %>
+               <br />
+               <table class="cbi-section-table" style="margin-left:5px">
+                       <tr class="cbi-section-table-titles">
+                               <th class="cbi-section-table-cell left" colspan="4"><%:Open ports on router%>:</th>
+                       </tr>
+                       <tr class="cbi-section-table-descr">
+                               <th class="cbi-section-table-cell"><%:Name%></th>
+                               <th class="cbi-section-table-cell"><%:Protocol%></th>
+                               <th class="cbi-section-table-cell"><%:External port%></th>
+                               <th class="cbi-section-table-cell"></th>
+                       </tr>
+                       <tr class="cbi-section-table-row">
+                               <td class="cbi-section-table-cell" style="width:130px">
+                                       <input type="text" class="cbi-input-text" id="_newopen.name" name="_newopen.name" placeholder="<%:New input rule%>" />
+                               </td>
+                               <td class="cbi-section-table-cell" style="width:110px">
+                                       <select class="cbi-input-select" id="_newopen.proto" name="_newopen.proto">
+                                               <option value="tcp udp">TCP+UDP</option>
+                                               <option value="tcp">TCP</option>
+                                               <option value="udp">UDP</option>
+                                               <option value="other"><%:Other...%></option>
+                                       </select>
+                               </td>
+                               <td class="cbi-section-table-cell" style="width:110px">
+                                       <input type="text" class="cbi-input-text" id="_newopen.extport" name="_newopen.extport" />
+                               </td>
+                               <td class="cbi-section-table-cell left">
+                                       <input type="submit" class="cbi-button cbi-button-add" name="_newopen.submit" value="<%:Add%>" />
+                               </td>
+                       </tr>
+               </table>
+
+               <table class="cbi-section-table" style="margin-left:5px">
+                       <tr class="cbi-section-table-titles">
+                               <th class="cbi-section-table-cell left" colspan="6"><br /><%:New forward rule%>:</th>
+                       </tr>
+                       <tr class="cbi-section-table-descr">
+                               <th class="cbi-section-table-cell"><%:Name%></th>
+                               <th class="cbi-section-table-cell"><%:Source zone%></th>
+                               <th class="cbi-section-table-cell"><%:Destination zone%></th>
+                               <th class="cbi-section-table-cell"></th>
+                       </tr>
+                       <tr class="cbi-section-table-row">
+                               <td class="cbi-section-table-cell" style="width:130px">
+                                       <input type="text" class="cbi-input-text" id="_newfwd.name" name="_newfwd.name" placeholder="<%:New forward rule%>" />
+                               </td>
+                               <td class="cbi-section-table-cell" style="width:110px">
+                                       <select class="cbi-input-text" id="_newfwd.src" name="_newfwd.src">
+                                               <% local k, v; for k, v in ipairs(fw:get_zones()) do -%>
+                                                       <option<%=ifattr(v:name() == "lan", "selected", "selected")%> value="<%=v:name()%>"><%=v:name()%></option>
+                                               <%- end %>
+                                       </select>
+                               </td>
+                               <td class="cbi-section-table-cell" style="width:110px">
+                                       <select class="cbi-input-text" id="_newfwd.dest" name="_newfwd.dest">
+                                               <% local k, v; for k, v in ipairs(fw:get_zones()) do -%>
+                                                       <option<%=ifattr(v:name() == "wan", "selected", "selected")%> value="<%=v:name()%>"><%=v:name()%></option>
+                                               <%- end %>
+                                       </select>
+                               </td>
+                               <td class="cbi-section-table-cell left">
+                                       <input type="submit" class="cbi-button cbi-button-link" name="_newfwd.submit" value="<%:Add and edit...%>" />
+                               </td>
+                       </tr>
+               </table>
+
+               <script type="text/javascript">//<![CDATA[
+                       cbi_validate_field('_newopen.extport', true, 'list(portrange)');
+                       cbi_bind(document.getElementById('_newopen.extport'), 'blur',
+                               function() {
+                                       var n = document.getElementById('_newopen.name');
+                                       var p = document.getElementById('_newopen.proto');
+                                       var hints = {
+                                       /*  port    name     0=both, 1=tcp, 2=udp, 3=other */
+                                               22:   [ 'SSH',   1 ],
+                                               53:   [ 'DNS',   0 ],
+                                               80:   [ 'HTTP',  1 ],
+                                               443:  [ 'HTTPS', 1 ],
+                                       };
+
+                                       if (!this.className.match(/invalid/))
+                                       {
+                                               var hint = hints[this.value || 0];
+                                               if (hint)
+                                               {
+                                                       p.selectedIndex = hint[1];
+
+                                                       if (!n.value)
+                                                               n.value = hint[0];
+                                               }
+                                               else if (!n.value && this.value)
+                                               {
+                                                       n.value = 'Open' + this.value;
+                                               }
+                                       }
+                               });
+
+
+                       cbi_validate_field('cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>', true, 'uciname');
+               //]]></script>
+       <% else %>
+               <input type="submit" class="cbi-button cbi-button-add" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" value="<%:Add%>" />
+       <% end %>
+</div>
diff --git a/applications/luci-firewall/luasrc/view/cbi_addsnat.htm b/applications/luci-firewall/luasrc/view/cbi_addsnat.htm
new file mode 100644 (file)
index 0000000..28bb22d
--- /dev/null
@@ -0,0 +1,65 @@
+<%
+       local fw = require "luci.model.firewall".init()
+       local nw = require "luci.model.network".init()
+       local wz = fw:get_zone("wan")
+       local lz = fw:get_zone("lan")
+%>
+
+<div class="cbi-section-create cbi-tblsection-create">
+       <% if wz and lz then %>
+               <br />
+               <table class="cbi-section-table" style="width:700px; margin-left:5px">
+                       <tr class="cbi-section-table-titles">
+                               <th class="cbi-section-table-cell left" colspan="6"><%:New source NAT%>:</th>
+                       </tr>
+                       <tr class="cbi-section-table-descr">
+                               <th class="cbi-section-table-cell"><%:Name%></th>
+                               <th class="cbi-section-table-cell"><%:Source zone%></th>
+                               <th class="cbi-section-table-cell"><%:Destination zone%></th>
+                               <th class="cbi-section-table-cell"><%:To source IP%></th>
+                               <th class="cbi-section-table-cell"><%:To source port%></th>
+                               <th class="cbi-section-table-cell"></th>
+                       </tr>
+                       <tr class="cbi-section-table-row">
+                               <td class="cbi-section-table-cell">
+                                       <input type="text" class="cbi-input-text" id="_newsnat.name" name="_newsnat.name" placeholder="<%:New SNAT rule%>" />
+                               </td>
+                               <td class="cbi-section-table-cell" style="width:110px">
+                                       <select class="cbi-input-text" id="_newsnat.src" name="_newsnat.src">
+                                               <% local k, v; for k, v in ipairs(fw:get_zones()) do -%>
+                                                       <option<%=ifattr(v:name() == "lan", "selected", "selected")%> value="<%=v:name()%>"><%=v:name()%></option>
+                                               <%- end %>
+                                       </select>
+                               </td>
+                               <td class="cbi-section-table-cell" style="width:110px">
+                                       <select class="cbi-input-text" id="_newsnat.dest" name="_newsnat.dest">
+                                               <% local k, v; for k, v in ipairs(fw:get_zones()) do -%>
+                                                       <option<%=ifattr(v:name() == "wan", "selected", "selected")%> value="<%=v:name()%>"><%=v:name()%></option>
+                                               <%- end %>
+                                       </select>
+                               </td>
+                               <td class="cbi-section-table-cell" style="width:110px">
+                                       <input type="text" class="cbi-input-text" id="_newsnat.dip" name="_newsnat.dip" />
+                               </td>
+                               <td class="cbi-section-table-cell" style="width:110px">
+                                       <input type="text" class="cbi-input-text" id="_newsnat.dport" name="_newsnat.dport" placeholder="<%:Do not rewrite%>" />
+                               </td>
+                               <td class="cbi-section-table-cell">
+                                       <input type="submit" class="cbi-button cbi-button-link" name="_newsnat.submit" value="<%:Add and edit...%>" />
+                               </td>
+                       </tr>
+               </table>
+
+               <script type="text/javascript">//<![CDATA[
+                       cbi_validate_field('_newsnat.dport', true, 'portrange');
+                       cbi_combobox_init('_newsnat.dip', {
+                               <% local c, k, v = 0; for k, v in ipairs(nw:get_interfaces()) do -%>
+                                       <%- local a; for k, a in ipairs(v:ipaddrs()) do c = c + 1 -%>
+                                               <% if c > 1 then %>,<% end %>'<%=a:host():string()%>': '<%=a:host():string()%> (<%=v:shortname()%>)',
+                                       <%- end %>
+                               <%- end %> }, '<%: -- Please choose -- %>', '<%: -- custom -- %>');
+               //]]></script>
+       <% else %>
+               <input type="submit" class="cbi-button cbi-button-add" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" value="<%:Add%>" />
+       <% end %>
+</div>