| 1 | --[[ |
|---|
| 2 | LuCI - Lua Configuration Interface |
|---|
| 3 | |
|---|
| 4 | Copyright 2008 Steven Barth <steven@midlink.org> |
|---|
| 5 | Copyright 2010 Jo-Philipp Wich <xm@subsignal.org> |
|---|
| 6 | |
|---|
| 7 | Licensed under the Apache License, Version 2.0 (the "License"); |
|---|
| 8 | you may not use this file except in compliance with the License. |
|---|
| 9 | You may obtain a copy of the License at |
|---|
| 10 | |
|---|
| 11 | http://www.apache.org/licenses/LICENSE-2.0 |
|---|
| 12 | |
|---|
| 13 | $Id$ |
|---|
| 14 | ]]-- |
|---|
| 15 | |
|---|
| 16 | local sys = require "luci.sys" |
|---|
| 17 | local dsp = require "luci.dispatcher" |
|---|
| 18 | local nxo = require "nixio" |
|---|
| 19 | |
|---|
| 20 | local ft = require "luci.tools.firewall" |
|---|
| 21 | local nw = require "luci.model.network" |
|---|
| 22 | local m, s, o, k, v |
|---|
| 23 | |
|---|
| 24 | arg[1] = arg[1] or "" |
|---|
| 25 | |
|---|
| 26 | m = Map("firewall", |
|---|
| 27 | translate("Firewall - Traffic Rules"), |
|---|
| 28 | translate("This page allows you to change advanced properties of the \ |
|---|
| 29 | traffic rule entry, such as matched source and destination \ |
|---|
| 30 | hosts.")) |
|---|
| 31 | |
|---|
| 32 | m.redirect = dsp.build_url("admin/network/firewall/rules") |
|---|
| 33 | |
|---|
| 34 | nw.init(m.uci) |
|---|
| 35 | |
|---|
| 36 | local rule_type = m.uci:get("firewall", arg[1]) |
|---|
| 37 | if rule_type == "redirect" and m:get(arg[1], "target") ~= "SNAT" then |
|---|
| 38 | rule_type = nil |
|---|
| 39 | end |
|---|
| 40 | |
|---|
| 41 | if not rule_type then |
|---|
| 42 | luci.http.redirect(m.redirect) |
|---|
| 43 | return |
|---|
| 44 | |
|---|
| 45 | -- |
|---|
| 46 | -- SNAT |
|---|
| 47 | -- |
|---|
| 48 | elseif rule_type == "redirect" then |
|---|
| 49 | |
|---|
| 50 | local name = m:get(arg[1], "name") or m:get(arg[1], "_name") |
|---|
| 51 | if not name or #name == 0 then |
|---|
| 52 | name = translate("(Unnamed SNAT)") |
|---|
| 53 | else |
|---|
| 54 | name = "SNAT %s" % name |
|---|
| 55 | end |
|---|
| 56 | |
|---|
| 57 | m.title = "%s - %s" %{ translate("Firewall - Traffic Rules"), name } |
|---|
| 58 | |
|---|
| 59 | local wan_zone = nil |
|---|
| 60 | |
|---|
| 61 | m.uci:foreach("firewall", "zone", |
|---|
| 62 | function(s) |
|---|
| 63 | local n = s.network or s.name |
|---|
| 64 | if n then |
|---|
| 65 | local i |
|---|
| 66 | for i in n:gmatch("%S+") do |
|---|
| 67 | if i == "wan" then |
|---|
| 68 | wan_zone = s.name |
|---|
| 69 | return false |
|---|
| 70 | end |
|---|
| 71 | end |
|---|
| 72 | end |
|---|
| 73 | end) |
|---|
| 74 | |
|---|
| 75 | s = m:section(NamedSection, arg[1], "redirect", "") |
|---|
| 76 | s.anonymous = true |
|---|
| 77 | s.addremove = false |
|---|
| 78 | |
|---|
| 79 | |
|---|
| 80 | ft.opt_enabled(s, Button) |
|---|
| 81 | ft.opt_name(s, Value, translate("Name")) |
|---|
| 82 | |
|---|
| 83 | |
|---|
| 84 | o = s:option(Value, "proto", |
|---|
| 85 | translate("Protocol"), |
|---|
| 86 | translate("You may specify multiple by selecting \"-- custom --\" and \ |
|---|
| 87 | then entering protocols separated by space.")) |
|---|
| 88 | |
|---|
| 89 | o:value("all", "All protocols") |
|---|
| 90 | o:value("tcp udp", "TCP+UDP") |
|---|
| 91 | o:value("tcp", "TCP") |
|---|
| 92 | o:value("udp", "UDP") |
|---|
| 93 | o:value("icmp", "ICMP") |
|---|
| 94 | |
|---|
| 95 | function o.cfgvalue(...) |
|---|
| 96 | local v = Value.cfgvalue(...) |
|---|
| 97 | if not v or v == "tcpudp" then |
|---|
| 98 | return "tcp udp" |
|---|
| 99 | end |
|---|
| 100 | return v |
|---|
| 101 | end |
|---|
| 102 | |
|---|
| 103 | |
|---|
| 104 | o = s:option(Value, "src", translate("Source zone")) |
|---|
| 105 | o.nocreate = true |
|---|
| 106 | o.default = "wan" |
|---|
| 107 | o.template = "cbi/firewall_zonelist" |
|---|
| 108 | |
|---|
| 109 | |
|---|
| 110 | o = s:option(DynamicList, "src_mac", translate("Source MAC address")) |
|---|
| 111 | o.rmempty = true |
|---|
| 112 | o.datatype = "neg(macaddr)" |
|---|
| 113 | o.placeholder = translate("any") |
|---|
| 114 | |
|---|
| 115 | |
|---|
| 116 | o = s:option(Value, "src_ip", translate("Source IP address")) |
|---|
| 117 | o.rmempty = true |
|---|
| 118 | o.datatype = "neg(ipaddr)" |
|---|
| 119 | o.placeholder = translate("any") |
|---|
| 120 | |
|---|
| 121 | |
|---|
| 122 | o = s:option(Value, "src_port", |
|---|
| 123 | translate("Source port"), |
|---|
| 124 | translate("Match incoming traffic originating from the given source \ |
|---|
| 125 | port or port range on the client host.")) |
|---|
| 126 | o.rmempty = true |
|---|
| 127 | o.datatype = "neg(portrange)" |
|---|
| 128 | o.placeholder = translate("any") |
|---|
| 129 | |
|---|
| 130 | |
|---|
| 131 | o = s:option(Value, "dest", translate("Destination zone")) |
|---|
| 132 | o.nocreate = true |
|---|
| 133 | o.default = "lan" |
|---|
| 134 | o.template = "cbi/firewall_zonelist" |
|---|
| 135 | |
|---|
| 136 | |
|---|
| 137 | o = s:option(Value, "dest_ip", translate("Destination IP address")) |
|---|
| 138 | o.datatype = "neg(ip4addr)" |
|---|
| 139 | |
|---|
| 140 | for i, dataset in ipairs(luci.sys.net.arptable()) do |
|---|
| 141 | o:value(dataset["IP address"]) |
|---|
| 142 | end |
|---|
| 143 | |
|---|
| 144 | |
|---|
| 145 | o = s:option(Value, "dest_port", |
|---|
| 146 | translate("Destination port"), |
|---|
| 147 | translate("Match forwarded traffic to the given destination port or \ |
|---|
| 148 | port range.")) |
|---|
| 149 | |
|---|
| 150 | o.rmempty = true |
|---|
| 151 | o.placeholder = translate("any") |
|---|
| 152 | o.datatype = "portrange" |
|---|
| 153 | |
|---|
| 154 | |
|---|
| 155 | o = s:option(Value, "src_dip", |
|---|
| 156 | translate("SNAT IP address"), |
|---|
| 157 | translate("Rewrite matched traffic to the given address.")) |
|---|
| 158 | o.rmempty = false |
|---|
| 159 | o.datatype = "ip4addr" |
|---|
| 160 | |
|---|
| 161 | for k, v in ipairs(nw:get_interfaces()) do |
|---|
| 162 | local a |
|---|
| 163 | for k, a in ipairs(v:ipaddrs()) do |
|---|
| 164 | o:value(a:host():string(), '%s (%s)' %{ |
|---|
| 165 | a:host():string(), v:shortname() |
|---|
| 166 | }) |
|---|
| 167 | end |
|---|
| 168 | end |
|---|
| 169 | |
|---|
| 170 | |
|---|
| 171 | o = s:option(Value, "src_dport", translate("SNAT port"), |
|---|
| 172 | translate("Rewrite matched traffic to the given source port. May be \ |
|---|
| 173 | left empty to only rewrite the IP address.")) |
|---|
| 174 | o.datatype = "portrange" |
|---|
| 175 | o.rmempty = true |
|---|
| 176 | o.placeholder = translate('Do not rewrite') |
|---|
| 177 | |
|---|
| 178 | |
|---|
| 179 | s:option(Value, "extra", |
|---|
| 180 | translate("Extra arguments"), |
|---|
| 181 | translate("Passes additional arguments to iptables. Use with care!")) |
|---|
| 182 | |
|---|
| 183 | |
|---|
| 184 | -- |
|---|
| 185 | -- Rule |
|---|
| 186 | -- |
|---|
| 187 | else |
|---|
| 188 | local name = m:get(arg[1], "name") or m:get(arg[1], "_name") |
|---|
| 189 | if not name or #name == 0 then |
|---|
| 190 | name = translate("(Unnamed Rule)") |
|---|
| 191 | end |
|---|
| 192 | |
|---|
| 193 | m.title = "%s - %s" %{ translate("Firewall - Traffic Rules"), name } |
|---|
| 194 | |
|---|
| 195 | |
|---|
| 196 | s = m:section(NamedSection, arg[1], "rule", "") |
|---|
| 197 | s.anonymous = true |
|---|
| 198 | s.addremove = false |
|---|
| 199 | |
|---|
| 200 | ft.opt_enabled(s, Button) |
|---|
| 201 | ft.opt_name(s, Value, translate("Name")) |
|---|
| 202 | |
|---|
| 203 | |
|---|
| 204 | o = s:option(ListValue, "family", translate("Restrict to address family")) |
|---|
| 205 | o.rmempty = true |
|---|
| 206 | o:value("", translate("IPv4 and IPv6")) |
|---|
| 207 | o:value("ipv4", translate("IPv4 only")) |
|---|
| 208 | o:value("ipv6", translate("IPv6 only")) |
|---|
| 209 | |
|---|
| 210 | |
|---|
| 211 | o = s:option(Value, "proto", translate("Protocol")) |
|---|
| 212 | o:value("all", translate("Any")) |
|---|
| 213 | o:value("tcp udp", "TCP+UDP") |
|---|
| 214 | o:value("tcp", "TCP") |
|---|
| 215 | o:value("udp", "UDP") |
|---|
| 216 | o:value("icmp", "ICMP") |
|---|
| 217 | |
|---|
| 218 | function o.cfgvalue(...) |
|---|
| 219 | local v = Value.cfgvalue(...) |
|---|
| 220 | if not v or v == "tcpudp" then |
|---|
| 221 | return "tcp udp" |
|---|
| 222 | end |
|---|
| 223 | return v |
|---|
| 224 | end |
|---|
| 225 | |
|---|
| 226 | |
|---|
| 227 | o = s:option(DynamicList, "icmp_type", translate("Match ICMP type")) |
|---|
| 228 | o:value("", "any") |
|---|
| 229 | o:value("echo-reply") |
|---|
| 230 | o:value("destination-unreachable") |
|---|
| 231 | o:value("network-unreachable") |
|---|
| 232 | o:value("host-unreachable") |
|---|
| 233 | o:value("protocol-unreachable") |
|---|
| 234 | o:value("port-unreachable") |
|---|
| 235 | o:value("fragmentation-needed") |
|---|
| 236 | o:value("source-route-failed") |
|---|
| 237 | o:value("network-unknown") |
|---|
| 238 | o:value("host-unknown") |
|---|
| 239 | o:value("network-prohibited") |
|---|
| 240 | o:value("host-prohibited") |
|---|
| 241 | o:value("TOS-network-unreachable") |
|---|
| 242 | o:value("TOS-host-unreachable") |
|---|
| 243 | o:value("communication-prohibited") |
|---|
| 244 | o:value("host-precedence-violation") |
|---|
| 245 | o:value("precedence-cutoff") |
|---|
| 246 | o:value("source-quench") |
|---|
| 247 | o:value("redirect") |
|---|
| 248 | o:value("network-redirect") |
|---|
| 249 | o:value("host-redirect") |
|---|
| 250 | o:value("TOS-network-redirect") |
|---|
| 251 | o:value("TOS-host-redirect") |
|---|
| 252 | o:value("echo-request") |
|---|
| 253 | o:value("router-advertisement") |
|---|
| 254 | o:value("router-solicitation") |
|---|
| 255 | o:value("time-exceeded") |
|---|
| 256 | o:value("ttl-zero-during-transit") |
|---|
| 257 | o:value("ttl-zero-during-reassembly") |
|---|
| 258 | o:value("parameter-problem") |
|---|
| 259 | o:value("ip-header-bad") |
|---|
| 260 | o:value("required-option-missing") |
|---|
| 261 | o:value("timestamp-request") |
|---|
| 262 | o:value("timestamp-reply") |
|---|
| 263 | o:value("address-mask-request") |
|---|
| 264 | o:value("address-mask-reply") |
|---|
| 265 | |
|---|
| 266 | |
|---|
| 267 | o = s:option(Value, "src", translate("Source zone")) |
|---|
| 268 | o.nocreate = true |
|---|
| 269 | o.allowany = true |
|---|
| 270 | o.default = "wan" |
|---|
| 271 | o.template = "cbi/firewall_zonelist" |
|---|
| 272 | |
|---|
| 273 | |
|---|
| 274 | o = s:option(Value, "src_mac", translate("Source MAC address")) |
|---|
| 275 | o.datatype = "list(macaddr)" |
|---|
| 276 | o.placeholder = translate("any") |
|---|
| 277 | |
|---|
| 278 | |
|---|
| 279 | o = s:option(Value, "src_ip", translate("Source address")) |
|---|
| 280 | o.datatype = "neg(ipaddr)" |
|---|
| 281 | o.placeholder = translate("any") |
|---|
| 282 | |
|---|
| 283 | |
|---|
| 284 | o = s:option(Value, "src_port", translate("Source port")) |
|---|
| 285 | o.datatype = "list(neg,portrange)" |
|---|
| 286 | o.placeholder = translate("any") |
|---|
| 287 | |
|---|
| 288 | |
|---|
| 289 | o = s:option(Value, "dest", translate("Destination zone")) |
|---|
| 290 | o.nocreate = true |
|---|
| 291 | o.allowany = true |
|---|
| 292 | o.allowlocal = true |
|---|
| 293 | o.template = "cbi/firewall_zonelist" |
|---|
| 294 | |
|---|
| 295 | |
|---|
| 296 | o = s:option(Value, "dest_ip", translate("Destination address")) |
|---|
| 297 | o.datatype = "neg(ipaddr)" |
|---|
| 298 | o.placeholder = translate("any") |
|---|
| 299 | |
|---|
| 300 | |
|---|
| 301 | o = s:option(Value, "dest_port", translate("Destination port")) |
|---|
| 302 | o.datatype = "list(neg,portrange)" |
|---|
| 303 | o.placeholder = translate("any") |
|---|
| 304 | |
|---|
| 305 | |
|---|
| 306 | o = s:option(ListValue, "target", translate("Action")) |
|---|
| 307 | o.default = "ACCEPT" |
|---|
| 308 | o:value("DROP", translate("drop")) |
|---|
| 309 | o:value("ACCEPT", translate("accept")) |
|---|
| 310 | o:value("REJECT", translate("reject")) |
|---|
| 311 | o:value("NOTRACK", translate("don't track")) |
|---|
| 312 | |
|---|
| 313 | |
|---|
| 314 | s:option(Value, "extra", |
|---|
| 315 | translate("Extra arguments"), |
|---|
| 316 | translate("Passes additional arguments to iptables. Use with care!")) |
|---|
| 317 | end |
|---|
| 318 | |
|---|
| 319 | return m |
|---|