applications/luci-splash:
- rewrote init script, cli - introduce download traffic counters - adept user interface
This commit is contained in:
parent
9525fb76bd
commit
b0771c43ea
4 changed files with 506 additions and 322 deletions
|
@ -24,7 +24,7 @@ function action_activate()
|
||||||
local ip = luci.http.getenv("REMOTE_ADDR") or "127.0.0.1"
|
local ip = luci.http.getenv("REMOTE_ADDR") or "127.0.0.1"
|
||||||
local mac = luci.sys.net.ip4mac(ip:match("^[\[::ffff:]*(%d+.%d+%.%d+%.%d+)\]*$"))
|
local mac = luci.sys.net.ip4mac(ip:match("^[\[::ffff:]*(%d+.%d+%.%d+%.%d+)\]*$"))
|
||||||
if mac and luci.http.formvalue("accept") then
|
if mac and luci.http.formvalue("accept") then
|
||||||
os.execute("luci-splash add "..mac.." >/dev/null 2>&1")
|
os.execute("luci-splash lease "..mac.." >/dev/null 2>&1")
|
||||||
luci.http.redirect(luci.model.uci.cursor():get("freifunk", "community", "homepage"))
|
luci.http.redirect(luci.model.uci.cursor():get("freifunk", "community", "homepage"))
|
||||||
else
|
else
|
||||||
luci.http.redirect(luci.dispatcher.build_url())
|
luci.http.redirect(luci.dispatcher.build_url())
|
||||||
|
@ -35,63 +35,44 @@ function action_status_admin()
|
||||||
local uci = luci.model.uci.cursor_state()
|
local uci = luci.model.uci.cursor_state()
|
||||||
local macs = luci.http.formvaluetable("save")
|
local macs = luci.http.formvaluetable("save")
|
||||||
|
|
||||||
local function delete_mac(what, mac)
|
local changes = {
|
||||||
uci:delete_all("luci_splash", what,
|
whitelist = { },
|
||||||
function(s)
|
blacklist = { },
|
||||||
return ( s.mac and s.mac:lower() == mac )
|
lease = { },
|
||||||
end)
|
remove = { }
|
||||||
end
|
|
||||||
|
|
||||||
local function leases(mac)
|
|
||||||
local leases = { }
|
|
||||||
|
|
||||||
uci:foreach("luci_splash", "lease", function(s)
|
|
||||||
if s.start and s.mac and s.mac:lower() ~= mac then
|
|
||||||
leases[#leases+1] = {
|
|
||||||
start = s.start,
|
|
||||||
mac = s.mac
|
|
||||||
}
|
}
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
uci:revert("luci_splash")
|
|
||||||
|
|
||||||
return leases
|
|
||||||
end
|
|
||||||
|
|
||||||
local function commit(leases, no_commit)
|
|
||||||
if not no_commit then
|
|
||||||
uci:save("luci_splash")
|
|
||||||
uci:commit("luci_splash")
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, l in ipairs(leases) do
|
|
||||||
uci:section("luci_splash", "lease", nil, l)
|
|
||||||
end
|
|
||||||
|
|
||||||
uci:save("luci_splash")
|
|
||||||
os.execute("/etc/init.d/luci_splash restart")
|
|
||||||
end
|
|
||||||
|
|
||||||
for key, _ in pairs(macs) do
|
for key, _ in pairs(macs) do
|
||||||
local policy = luci.http.formvalue("policy.%s" % key)
|
local policy = luci.http.formvalue("policy.%s" % key)
|
||||||
local mac = luci.http.protocol.urldecode(key)
|
local mac = luci.http.protocol.urldecode(key)
|
||||||
local lslist = leases(policy ~= "kick" and mac)
|
|
||||||
|
|
||||||
delete_mac("blacklist", mac)
|
|
||||||
delete_mac("whitelist", mac)
|
|
||||||
|
|
||||||
if policy == "whitelist" or policy == "blacklist" then
|
if policy == "whitelist" or policy == "blacklist" then
|
||||||
uci:section("luci_splash", policy, nil, { mac = mac })
|
changes[policy][#changes[policy]+1] = mac
|
||||||
elseif policy == "normal" then
|
elseif policy == "normal" then
|
||||||
lslist[#lslist+1] = { mac = mac, start = os.time() }
|
changes["lease"][#changes["lease"]+1] = mac
|
||||||
elseif policy == "kick" then
|
elseif policy == "kicked" then
|
||||||
for _, l in ipairs(lslist) do
|
changes["remove"][#changes["remove"]+1] = mac
|
||||||
if l.mac:lower() == mac then l.kicked="1" end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
commit(lslist)
|
if #changes.whitelist > 0 then
|
||||||
|
os.execute("luci-splash whitelist %s >/dev/null"
|
||||||
|
% table.concat(changes.whitelist))
|
||||||
|
end
|
||||||
|
|
||||||
|
if #changes.blacklist > 0 then
|
||||||
|
os.execute("luci-splash blacklist %s >/dev/null"
|
||||||
|
% table.concat(changes.blacklist))
|
||||||
|
end
|
||||||
|
|
||||||
|
if #changes.lease > 0 then
|
||||||
|
os.execute("luci-splash lease %s >/dev/null"
|
||||||
|
% table.concat(changes.lease))
|
||||||
|
end
|
||||||
|
|
||||||
|
if #changes.remove > 0 then
|
||||||
|
os.execute("luci-splash remove %s >/dev/null"
|
||||||
|
% table.concat(changes.remove))
|
||||||
end
|
end
|
||||||
|
|
||||||
luci.template.render("admin_status/splash", { is_admin = true })
|
luci.template.render("admin_status/splash", { is_admin = true })
|
||||||
|
|
|
@ -35,10 +35,10 @@ uci:foreach("luci_splash", "lease",
|
||||||
start = tonumber(s.start),
|
start = tonumber(s.start),
|
||||||
limit = ( tonumber(s.start) + leasetime ),
|
limit = ( tonumber(s.start) + leasetime ),
|
||||||
mac = s.mac:upper(),
|
mac = s.mac:upper(),
|
||||||
|
ipaddr = s.ipaddr,
|
||||||
policy = "normal",
|
policy = "normal",
|
||||||
packets = 0,
|
packets = 0,
|
||||||
bytes = 0,
|
bytes = 0,
|
||||||
kicked = s.kicked and true or false
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
@ -58,11 +58,25 @@ for _, r in ipairs(ipt:find({table="nat", chain="luci_splash_leases"})) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, r in ipairs(ipt:find({table="filter", chain="luci_splash_filter", options={"MAC"}})) do
|
for mac, client in pairs(clients) do
|
||||||
local c = clients[r.options[2]:lower()]
|
client.bytes_in = 0
|
||||||
if c and c.packets == 0 then
|
client.bytes_out = 0
|
||||||
c.bytes = tonumber(r.bytes)
|
client.packets_in = 0
|
||||||
c.packets = tonumber(r.packets)
|
client.packets_out = 0
|
||||||
|
|
||||||
|
if client.ipaddr then
|
||||||
|
local rin = ipt:find({table="mangle", chain="luci_splash_mark_in", destination=client.ipaddr})
|
||||||
|
local rout = ipt:find({table="mangle", chain="luci_splash_mark_out", options={"MAC", client.mac:upper()}})
|
||||||
|
|
||||||
|
if rin and #rin > 0 then
|
||||||
|
client.bytes_in = rin[1].bytes
|
||||||
|
client.packets_in = rin[1].packets
|
||||||
|
end
|
||||||
|
|
||||||
|
if rout and #rout > 0 then
|
||||||
|
client.bytes_out = rout[1].bytes
|
||||||
|
client.packets_out = rout[1].packets
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -123,7 +137,7 @@ end
|
||||||
<th class="cbi-section-table-cell"><%:ff_splash_ip IP Address%></th>
|
<th class="cbi-section-table-cell"><%:ff_splash_ip IP Address%></th>
|
||||||
<th class="cbi-section-table-cell"><%:ff_splash_mac MAC Address%></th>
|
<th class="cbi-section-table-cell"><%:ff_splash_mac MAC Address%></th>
|
||||||
<th class="cbi-section-table-cell"><%:ff_splash_timeleft Time remaining%></th>
|
<th class="cbi-section-table-cell"><%:ff_splash_timeleft Time remaining%></th>
|
||||||
<th class="cbi-section-table-cell"><%:ff_splash_traffic Outgoing traffic%></th>
|
<th class="cbi-section-table-cell"><%:ff_splash_traffic Traffic in/out%></th>
|
||||||
<th class="cbi-section-table-cell"><%:ff_splash_policy Policy%></th>
|
<th class="cbi-section-table-cell"><%:ff_splash_policy Policy%></th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
@ -149,7 +163,7 @@ end
|
||||||
(c.limit >= os.time()) and wat.date_format(c.limit-os.time()) or
|
(c.limit >= os.time()) and wat.date_format(c.limit-os.time()) or
|
||||||
(c.policy ~= "normal") and "-" or "<em>" .. translate("ff_splash_expired", "expired") .. "</em>"
|
(c.policy ~= "normal") and "-" or "<em>" .. translate("ff_splash_expired", "expired") .. "</em>"
|
||||||
%></td>
|
%></td>
|
||||||
<td class="cbi-section-table-cell"><%=wat.byte_format(c.bytes)%></td>
|
<td class="cbi-section-table-cell"><%=wat.byte_format(c.bytes_in)%> / <%=wat.byte_format(c.bytes_out)%></td>
|
||||||
<td class="cbi-section-table-cell">
|
<td class="cbi-section-table-cell">
|
||||||
<% if is_admin then %>
|
<% if is_admin then %>
|
||||||
<select name="policy.<%=c.mac:lower()%>" style="width:200px">
|
<select name="policy.<%=c.mac:lower()%>" style="width:200px">
|
||||||
|
@ -157,7 +171,7 @@ end
|
||||||
<option value="normal"<%=c.policy=="normal" and not c.kicked and ' selected="selected"'%>><%:ff_splash_splashed splashed%></option>
|
<option value="normal"<%=c.policy=="normal" and not c.kicked and ' selected="selected"'%>><%:ff_splash_splashed splashed%></option>
|
||||||
<option value="blacklist"<%=c.policy=="blacklist" and ' selected="selected"'%>><%:ff_splash_blacklisted blacklisted%></option>
|
<option value="blacklist"<%=c.policy=="blacklist" and ' selected="selected"'%>><%:ff_splash_blacklisted blacklisted%></option>
|
||||||
<% if c.policy == "normal" then -%>
|
<% if c.policy == "normal" then -%>
|
||||||
<option value="kick"<%=c.kicked and ' selected="selected"'%>><%:ff_splash_tempblock temporarily blocked%> (<%=wat.date_format(c.limit-os.time())%>)</option>
|
<option value="kicked"><%:ff_splash_tempblock temporarily blocked%></option>
|
||||||
<%- end %>
|
<%- end %>
|
||||||
</select>
|
</select>
|
||||||
<input type="submit" class="cbi-button cbi-button-save" name="save.<%=c.mac:lower()%>" value="<%:save Save%>" />
|
<input type="submit" class="cbi-button cbi-button-save" name="save.<%=c.mac:lower()%>" value="<%:save Save%>" />
|
||||||
|
|
|
@ -1,15 +1,29 @@
|
||||||
#!/bin/sh /etc/rc.common
|
#!/bin/sh /etc/rc.common
|
||||||
|
|
||||||
START=70
|
START=70
|
||||||
EXTRA_COMMANDS=clear_leases
|
EXTRA_COMMANDS=clear_leases
|
||||||
SPLASH_INTERFACES=""
|
|
||||||
LIMIT_DOWN=0
|
LIMIT_DOWN=0
|
||||||
LIMIT_DOWN_BURST=0
|
LIMIT_DOWN_BURST=0
|
||||||
LIMIT_UP=0
|
LIMIT_UP=0
|
||||||
|
|
||||||
|
IPT_REPLAY=/var/run/luci_splash.iptlog
|
||||||
|
LOCK=/var/run/luci_splash.lock
|
||||||
|
|
||||||
|
include /lib/network
|
||||||
|
scan_interfaces
|
||||||
|
config_load luci_splash
|
||||||
|
|
||||||
|
set -x
|
||||||
|
|
||||||
silent() {
|
silent() {
|
||||||
"$@" 2>/dev/null
|
"$@" 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ipt_log() {
|
||||||
|
iptables -I "$@"
|
||||||
|
echo iptables -D "$@" >> $IPT_REPLAY
|
||||||
|
}
|
||||||
|
|
||||||
iface_add() {
|
iface_add() {
|
||||||
local cfg="$1"
|
local cfg="$1"
|
||||||
|
|
||||||
|
@ -37,95 +51,45 @@ iface_add() {
|
||||||
|
|
||||||
eval "$(ipcalc.sh $ipaddr $netmask)"
|
eval "$(ipcalc.sh $ipaddr $netmask)"
|
||||||
|
|
||||||
iptables -t nat -A prerouting_${zone} -j luci_splash_prerouting
|
### Add interface specific chain entry rules
|
||||||
iptables -t nat -A luci_splash_prerouting -j luci_splash_portal
|
ipt_log "zone_${zone}_prerouting" -i "${ifname%:*}" -s "$NETWORK/$PREFIX" -j luci_splash_prerouting -t nat
|
||||||
|
ipt_log "zone_${zone}_forward" -i "${ifname%:*}" -s "$NETWORK/$PREFIX" -j luci_splash_forwarding -t filter
|
||||||
|
|
||||||
iptables -t filter -I luci_splash_filter -s ! "$NETWORK/$PREFIX" -j RETURN
|
### Allow traffic to the same subnet
|
||||||
iptables -t nat -I luci_splash_leases -s ! "$NETWORK/$PREFIX" -j RETURN
|
iptables -t nat -I luci_splash_prerouting -d "$ipaddr/${netmask:-32}" -j RETURN
|
||||||
|
iptables -t filter -I luci_splash_forwarding -d "$ipaddr/${netmask:-32}" -j RETURN
|
||||||
iptables -t filter -I luci_splash_filter -s "$NETWORK/$PREFIX" -d "$ipaddr/${netmask:-32}" -j RETURN
|
|
||||||
iptables -t nat -I luci_splash_leases -s "$NETWORK/$PREFIX" -d "$ipaddr/${netmask:-32}" -j RETURN
|
|
||||||
|
|
||||||
|
### Allow traffic to the mesh subnet
|
||||||
[ "$parentproto" = "static" -a -n "$parentipaddr" ] && {
|
[ "$parentproto" = "static" -a -n "$parentipaddr" ] && {
|
||||||
iptables -t filter -I luci_splash_filter -s "$NETWORK/$PREFIX" -d "$parentipaddr/${parentnetmask:-32}" -j RETURN
|
iptables -t nat -I luci_splash_prerouting -d "$parentipaddr/${parentnetmask:-32}" -j RETURN
|
||||||
iptables -t nat -I luci_splash_leases -s "$NETWORK/$PREFIX" -d "$parentipaddr/${parentnetmask:-32}" -j RETURN
|
iptables -t filter -I luci_splash_forwarding -d "$parentipaddr/${parentnetmask:-32}" -j RETURN
|
||||||
}
|
}
|
||||||
|
|
||||||
iptables -t filter -A luci_splash_filter -s "$NETWORK/$PREFIX" -p udp --dport 53 -j RETURN
|
|
||||||
iptables -t filter -A luci_splash_filter -s "$NETWORK/$PREFIX" -p tcp --dport 22 -j RETURN # XXX: ssh really needed?
|
|
||||||
iptables -t filter -A luci_splash_filter -s "$NETWORK/$PREFIX" -p tcp --dport 80 -j RETURN
|
|
||||||
iptables -t filter -A luci_splash_filter -s "$NETWORK/$PREFIX" -j REJECT --reject-with icmp-admin-prohibited
|
|
||||||
|
|
||||||
qos_iface_add "$ifname"
|
qos_iface_add "$ifname"
|
||||||
|
|
||||||
append SPLASH_INTERFACES "$ifname"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
iface_del() {
|
iface_del() {
|
||||||
config_get zone "$1" zone
|
config_get zone "$1" zone
|
||||||
[ -n "$zone" ] || return 0
|
[ -n "$zone" ] || return 0
|
||||||
|
|
||||||
while iptables -t nat -D prerouting_${zone} -j luci_splash_prerouting 2>&-; do :; done
|
|
||||||
|
|
||||||
config_get net "$1" network
|
config_get net "$1" network
|
||||||
[ -n "$net" ] || return 0
|
[ -n "$net" ] || return 0
|
||||||
|
|
||||||
config_get ifname "$net" ifname
|
config_get ifname "$net" ifname
|
||||||
[ -n "$ifname" ] || return 0
|
[ -n "$ifname" ] || return 0
|
||||||
|
|
||||||
|
# Clear interface specific rules
|
||||||
|
[ -s $IPT_REPLAY ] && {
|
||||||
|
grep -- "-i ${ifname%:*}" $IPT_REPLAY | while read ln; do silent $ln; done
|
||||||
|
sed -ie "/-i ${ifname%:*}/d" $IPT_REPLAY
|
||||||
|
}
|
||||||
|
|
||||||
qos_iface_del "$ifname"
|
qos_iface_del "$ifname"
|
||||||
}
|
}
|
||||||
|
|
||||||
blacklist_add() {
|
mac_add() {
|
||||||
local cfg="$1"
|
config_get mac "$1" mac
|
||||||
|
append MACS "$mac"
|
||||||
config_get mac "$cfg" mac
|
|
||||||
[ -n "$mac" ] && {
|
|
||||||
iptables -t filter -I luci_splash_filter -m mac --mac-source "$mac" -j DROP
|
|
||||||
iptables -t nat -I luci_splash_leases -m mac --mac-source "$mac" -j DROP
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
whitelist_add() {
|
|
||||||
local cfg="$1"
|
|
||||||
|
|
||||||
config_get mac "$cfg" mac
|
|
||||||
[ -n "$mac" ] && {
|
|
||||||
iptables -t filter -I luci_splash_filter -m mac --mac-source "$mac" -j RETURN
|
|
||||||
iptables -t nat -I luci_splash_leases -m mac --mac-source "$mac" -j RETURN
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lease_add() {
|
|
||||||
local cfg="$1"
|
|
||||||
|
|
||||||
config_get mac "$cfg" mac
|
|
||||||
config_get ban "$cfg" kicked
|
|
||||||
|
|
||||||
ban=${ban:+DROP}
|
|
||||||
|
|
||||||
[ -n "$mac" ] && {
|
|
||||||
local oIFS="$IFS"; IFS=":"
|
|
||||||
set -- $mac
|
|
||||||
IFS="$oIFS"; unset oIFS
|
|
||||||
|
|
||||||
local mac_pre="$1$2"
|
|
||||||
local mac_post="$3$4$5$6"
|
|
||||||
local handle="$6"
|
|
||||||
|
|
||||||
iptables -t filter -I luci_splash_filter -m mac --mac-source "$mac" -j RETURN
|
|
||||||
iptables -t nat -I luci_splash_leases -m mac --mac-source "$mac" -j "${ban:-RETURN}"
|
|
||||||
|
|
||||||
[ "$LIMIT_UP" -gt 0 -a "$LIMIT_DOWN" -gt 0 ] && {
|
|
||||||
iptables -t mangle -I luci_splash_mark -m mac --mac-source "$mac" -j MARK --set-mark 79
|
|
||||||
|
|
||||||
for i in $SPLASH_INTERFACES; do
|
|
||||||
tc filter add dev $i parent 77:0 protocol ip prio 2 handle ::$handle u32 \
|
|
||||||
match u16 0x0800 0xFFFF at -2 match u32 0x$mac_post 0xFFFFFFFF at -12 \
|
|
||||||
match u16 0x$mac_pre 0xFFFF at -14 flowid 77:10
|
|
||||||
done
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
subnet_add() {
|
subnet_add() {
|
||||||
|
@ -135,8 +99,8 @@ subnet_add() {
|
||||||
config_get netmask "$cfg" netmask
|
config_get netmask "$cfg" netmask
|
||||||
|
|
||||||
[ -n "$ipaddr" ] && {
|
[ -n "$ipaddr" ] && {
|
||||||
iptables -t filter -I luci_splash_filter -d "$ipaddr/${netmask:-32}" -j RETURN
|
iptables -t nat -I luci_splash_prerouting -d "$ipaddr/${netmask:-32}" -j RETURN
|
||||||
iptables -t nat -I luci_splash_portal -d "$ipaddr/${netmask:-32}" -j RETURN
|
iptables -t filter -I luci_splash_forwarding -d "$ipaddr/${netmask:-32}" -j RETURN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,7 +109,8 @@ qos_iface_add() {
|
||||||
|
|
||||||
# 77 -> download root qdisc
|
# 77 -> download root qdisc
|
||||||
# 78 -> upload root qdisc
|
# 78 -> upload root qdisc
|
||||||
# 79 -> fwmark
|
# 79 -> fwmark: client->inet
|
||||||
|
# 80 -> fwmark: inet->client
|
||||||
|
|
||||||
silent tc qdisc del dev "$iface" root handle 77:
|
silent tc qdisc del dev "$iface" root handle 77:
|
||||||
|
|
||||||
|
@ -157,16 +122,20 @@ qos_iface_add() {
|
||||||
|
|
||||||
# set download limit and burst
|
# set download limit and burst
|
||||||
tc class add dev "$iface" parent 77:1 classid 77:10 htb \
|
tc class add dev "$iface" parent 77:1 classid 77:10 htb \
|
||||||
rate ${LIMIT_DOWN}kb ceil ${LIMIT_DOWN_BURST}kb prio 2
|
rate ${LIMIT_DOWN}kbit ceil ${LIMIT_DOWN_BURST}kbit prio 2
|
||||||
|
|
||||||
tc qdisc add dev "$iface" parent 77:10 handle 78: sfq perturb 10
|
tc qdisc add dev "$iface" parent 77:10 handle 78: sfq perturb 10
|
||||||
|
|
||||||
# adding ingress can result in "File exists" if qos-scripts are active
|
# adding ingress can result in "File exists" if qos-scripts are active
|
||||||
silent tc qdisc add dev "$iface" ingress
|
silent tc qdisc add dev "$iface" ingress
|
||||||
|
|
||||||
|
# set client download speed
|
||||||
|
tc filter add dev "$iface" parent 77: protocol ip prio 2 \
|
||||||
|
handle 80 fw flowid 77:10
|
||||||
|
|
||||||
# set client upload speed
|
# set client upload speed
|
||||||
tc filter add dev "$iface" parent ffff: protocol ip prio 1 \
|
tc filter add dev "$iface" parent ffff: protocol ip prio 1 \
|
||||||
handle 79 fw police rate ${LIMIT_UP}kb mtu 6k burst 6k drop
|
handle 79 fw police rate ${LIMIT_UP}kbit mtu 6k burst 6k drop
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,7 +149,7 @@ qos_iface_del() {
|
||||||
|
|
||||||
boot() {
|
boot() {
|
||||||
### Setup splash-relay
|
### Setup splash-relay
|
||||||
uci get lucid.splashr || {
|
uci get lucid.splashr 2>/dev/null || {
|
||||||
uci batch <<EOF
|
uci batch <<EOF
|
||||||
set lucid.splashr=daemon
|
set lucid.splashr=daemon
|
||||||
set lucid.splashr.slave=httpd
|
set lucid.splashr.slave=httpd
|
||||||
|
@ -202,101 +171,113 @@ EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
### Read chains from config
|
lock -w $LOCK && lock $LOCK
|
||||||
include /lib/network
|
|
||||||
scan_interfaces
|
|
||||||
config_load luci_splash
|
|
||||||
|
|
||||||
### Find QoS limits
|
### Find QoS limits
|
||||||
config_get LIMIT_UP general limit_up
|
config_get LIMIT_UP general limit_up
|
||||||
config_get LIMIT_DOWN general limit_down
|
config_get LIMIT_DOWN general limit_down
|
||||||
config_get LIMIT_DOWN_BURST general limit_down_burst
|
config_get LIMIT_DOWN_BURST general limit_down_burst
|
||||||
|
|
||||||
LIMIT_UP="${LIMIT_UP:-0}"
|
LIMIT_UP="$((8*${LIMIT_UP:-0}))"
|
||||||
LIMIT_DOWN="${LIMIT_DOWN:-0}"
|
LIMIT_DOWN="$((8*${LIMIT_DOWN:-0}))"
|
||||||
LIMIT_DOWN_BURST="${LIMIT_DOWN_BURST:-$(($LIMIT_DOWN * 2))}"
|
LIMIT_DOWN_BURST="${LIMIT_DOWN_BURST:+$((8*$LIMIT_DOWN_BURST))}"
|
||||||
|
LIMIT_DOWN_BURST="${LIMIT_DOWN_BURST:-$(($LIMIT_DOWN / 5 * 6))}"
|
||||||
|
|
||||||
### Load required modules
|
### Load required modules
|
||||||
[ "$LIMIT_UP" -gt 0 -a "$LIMIT_DOWN" -gt 0 ] && {
|
[ "$LIMIT_UP" -gt 0 -a "$LIMIT_DOWN" -gt 0 ] && {
|
||||||
silent insmod cls_fw
|
silent insmod cls_fw
|
||||||
silent insmod cls_u32
|
silent insmod cls_u32
|
||||||
silent insmod sch_htb
|
silent insmod sch_htb
|
||||||
|
silent insmod sch_sfq
|
||||||
silent insmod sch_ingress
|
silent insmod sch_ingress
|
||||||
}
|
}
|
||||||
|
|
||||||
### Create subchains
|
### Create subchains
|
||||||
iptables -t filter -N luci_splash_filter
|
|
||||||
iptables -t nat -N luci_splash_portal
|
|
||||||
iptables -t nat -N luci_splash_leases
|
|
||||||
iptables -t nat -N luci_splash_prerouting
|
iptables -t nat -N luci_splash_prerouting
|
||||||
|
iptables -t nat -N luci_splash_leases
|
||||||
|
iptables -t filter -N luci_splash_forwarding
|
||||||
|
iptables -t filter -N luci_splash_filter
|
||||||
|
|
||||||
[ "$LIMIT_UP" -gt 0 -a "$LIMIT_DOWN" -gt 0 ] && \
|
### Clear iptables replay log
|
||||||
iptables -t mangle -N luci_splash_mark
|
[ -s $IPT_REPLAY ] && . $IPT_REPLAY
|
||||||
|
echo -n > $IPT_REPLAY
|
||||||
|
|
||||||
### Build the main and portal rule
|
### Build the main and portal rule
|
||||||
config_foreach iface_add iface
|
config_foreach iface_add iface
|
||||||
config_foreach subnet_add subnet
|
config_foreach subnet_add subnet
|
||||||
config_foreach blacklist_add blacklist
|
|
||||||
config_foreach whitelist_add whitelist
|
|
||||||
config_foreach lease_add lease
|
|
||||||
|
|
||||||
### Build the portal rule
|
### Add interface independant prerouting rules
|
||||||
iptables -t filter -I INPUT -j luci_splash_filter
|
iptables -t nat -A luci_splash_prerouting -j luci_splash_leases
|
||||||
iptables -t filter -I FORWARD -j luci_splash_filter
|
iptables -t nat -A luci_splash_leases -p udp --dport 53 -j REDIRECT --to-ports 53
|
||||||
|
|
||||||
[ "$LIMIT_UP" -gt 0 -a "$LIMIT_DOWN" -gt 0 ] && \
|
|
||||||
iptables -t mangle -I PREROUTING -j luci_splash_mark
|
|
||||||
|
|
||||||
### Allow icmp, dns and traceroute
|
|
||||||
iptables -t nat -A luci_splash_portal -p udp --dport 33434:33523 -j RETURN
|
|
||||||
iptables -t nat -A luci_splash_portal -p icmp -j RETURN
|
|
||||||
iptables -t nat -A luci_splash_portal -p udp --dport 53 -j RETURN
|
|
||||||
|
|
||||||
### Redirect the rest into the lease chain
|
|
||||||
iptables -t nat -A luci_splash_portal -j luci_splash_leases
|
|
||||||
|
|
||||||
### Build the leases rule
|
|
||||||
iptables -t nat -A luci_splash_leases -p tcp --dport 80 -j REDIRECT --to-ports 8082
|
iptables -t nat -A luci_splash_leases -p tcp --dport 80 -j REDIRECT --to-ports 8082
|
||||||
|
|
||||||
|
### Add interface independant forwarding rules
|
||||||
|
iptables -t filter -A luci_splash_forwarding -j luci_splash_filter
|
||||||
|
iptables -t filter -A luci_splash_filter -p tcp -j REJECT --reject-with tcp-reset
|
||||||
|
iptables -t filter -A luci_splash_filter -j REJECT --reject-with icmp-net-prohibited
|
||||||
|
|
||||||
|
### Add QoS chain
|
||||||
|
[ "$LIMIT_UP" -gt 0 -a "$LIMIT_DOWN" -gt 0 ] && {
|
||||||
|
iptables -t mangle -N luci_splash_mark_out
|
||||||
|
iptables -t mangle -N luci_splash_mark_in
|
||||||
|
iptables -t mangle -I PREROUTING -j luci_splash_mark_out
|
||||||
|
iptables -t mangle -I POSTROUTING -j luci_splash_mark_in
|
||||||
|
}
|
||||||
|
|
||||||
|
### Find active mac addresses
|
||||||
|
MACS=""
|
||||||
|
config_foreach mac_add lease
|
||||||
|
config_foreach mac_add blacklist
|
||||||
|
config_foreach mac_add whitelist
|
||||||
|
|
||||||
### Add crontab entry
|
### Add crontab entry
|
||||||
test -f /etc/crontabs/root || touch /etc/crontabs/root
|
test -f /etc/crontabs/root || touch /etc/crontabs/root
|
||||||
grep -q luci-splash /etc/crontabs/root || {
|
grep -q luci-splash /etc/crontabs/root || {
|
||||||
echo '*/5 * * * * /usr/sbin/luci-splash sync' >> /etc/crontabs/root
|
echo '*/5 * * * * /usr/sbin/luci-splash sync' >> /etc/crontabs/root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lock -u $LOCK
|
||||||
|
|
||||||
|
### Populate iptables
|
||||||
|
[ -n "$MACS" ] && luci-splash add-rules $MACS
|
||||||
}
|
}
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
|
lock -w $LOCK && lock $LOCK
|
||||||
|
|
||||||
### Clear interface rules
|
### Clear interface rules
|
||||||
include /lib/network
|
|
||||||
scan_interfaces
|
|
||||||
config_load luci_splash
|
|
||||||
config_foreach iface_del iface
|
config_foreach iface_del iface
|
||||||
|
|
||||||
silent iptables -t filter -D INPUT -j luci_splash_filter
|
silent iptables -t mangle -D PREROUTING -j luci_splash_mark_out
|
||||||
silent iptables -t filter -D FORWARD -j luci_splash_filter
|
silent iptables -t mangle -D POSTROUTING -j luci_splash_mark_in
|
||||||
silent iptables -t mangle -D PREROUTING -j luci_splash_mark
|
|
||||||
|
|
||||||
### Clear subchains
|
### Clear subchains
|
||||||
silent iptables -t nat -F luci_splash_leases
|
|
||||||
silent iptables -t nat -F luci_splash_portal
|
|
||||||
silent iptables -t nat -F luci_splash_prerouting
|
silent iptables -t nat -F luci_splash_prerouting
|
||||||
|
silent iptables -t nat -F luci_splash_leases
|
||||||
|
silent iptables -t filter -F luci_splash_forwarding
|
||||||
silent iptables -t filter -F luci_splash_filter
|
silent iptables -t filter -F luci_splash_filter
|
||||||
silent iptables -t mangle -F luci_splash_mark
|
silent iptables -t mangle -F luci_splash_mark_out
|
||||||
|
silent iptables -t mangle -F luci_splash_mark_in
|
||||||
|
|
||||||
### Delete subchains
|
### Delete subchains
|
||||||
silent iptables -t nat -X luci_splash_leases
|
|
||||||
silent iptables -t nat -X luci_splash_portal
|
|
||||||
silent iptables -t nat -X luci_splash_prerouting
|
silent iptables -t nat -X luci_splash_prerouting
|
||||||
|
silent iptables -t nat -X luci_splash_leases
|
||||||
|
silent iptables -t filter -X luci_splash_forwarding
|
||||||
silent iptables -t filter -X luci_splash_filter
|
silent iptables -t filter -X luci_splash_filter
|
||||||
silent iptables -t mangle -X luci_splash_mark
|
silent iptables -t mangle -X luci_splash_mark_out
|
||||||
|
silent iptables -t mangle -X luci_splash_mark_in
|
||||||
|
|
||||||
sed -ie '/\/usr\/sbin\/luci-splash sync/d' /var/spool/cron/crontabs/root
|
sed -ie '/\/usr\/sbin\/luci-splash sync/d' /var/spool/cron/crontabs/root
|
||||||
}
|
|
||||||
|
|
||||||
|
lock -u $LOCK
|
||||||
|
}
|
||||||
|
|
||||||
clear_leases() {
|
clear_leases() {
|
||||||
stop
|
### Find active mac addresses
|
||||||
while uci -P /var/state del luci_splash.@lease[0] 2>&-;do :; done
|
MACS=""
|
||||||
start
|
config_foreach mac_add lease
|
||||||
|
|
||||||
|
### Clear leases
|
||||||
|
[ -n "$MACS" ] && luci-splash remove $MACS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,183 +2,322 @@
|
||||||
|
|
||||||
require("luci.util")
|
require("luci.util")
|
||||||
require("luci.model.uci")
|
require("luci.model.uci")
|
||||||
|
require("luci.sys")
|
||||||
require("luci.sys.iptparser")
|
require("luci.sys.iptparser")
|
||||||
|
|
||||||
-- Init state session
|
-- Init state session
|
||||||
local uci = luci.model.uci.cursor_state()
|
local uci = luci.model.uci.cursor_state()
|
||||||
local ipt = luci.sys.iptparser.IptParser()
|
local ipt = luci.sys.iptparser.IptParser()
|
||||||
|
local net = luci.sys.net
|
||||||
|
|
||||||
local splash_interfaces = { }
|
|
||||||
local limit_up = 0
|
local limit_up = 0
|
||||||
local limit_down = 0
|
local limit_down = 0
|
||||||
|
|
||||||
|
function lock()
|
||||||
|
os.execute("lock -w /var/run/luci_splash.lock && lock /var/run/luci_splash.lock")
|
||||||
|
end
|
||||||
|
|
||||||
|
function unlock()
|
||||||
|
os.execute("lock -u /var/run/luci_splash.lock")
|
||||||
|
end
|
||||||
|
|
||||||
function main(argv)
|
function main(argv)
|
||||||
local cmd = argv[1]
|
local cmd = table.remove(argv, 1)
|
||||||
local arg = argv[2]
|
local arg = argv[1]
|
||||||
|
|
||||||
limit_up = tonumber(uci:get("luci_splash", "general", "limit_up")) or 0
|
limit_up = tonumber(uci:get("luci_splash", "general", "limit_up")) or 0
|
||||||
limit_down = tonumber(uci:get("luci_splash", "general", "limit_down")) or 0
|
limit_down = tonumber(uci:get("luci_splash", "general", "limit_down")) or 0
|
||||||
|
|
||||||
uci:foreach("luci_splash", "iface", function(s)
|
if ( cmd == "lease" or cmd == "add-rules" or cmd == "remove" or
|
||||||
if s.network then
|
cmd == "whitelist" or cmd == "blacklist" ) and #argv > 0
|
||||||
splash_interfaces[#splash_interfaces+1] = uci:get("network", s.network, "ifname")
|
then
|
||||||
end
|
lock()
|
||||||
end)
|
|
||||||
|
|
||||||
if cmd == "status" and arg then
|
local arp_cache = net.arptable()
|
||||||
if islisted("whitelist", arg) then
|
local leased_macs = get_known_macs("lease")
|
||||||
print("whitelisted")
|
local blacklist_macs = get_known_macs("blacklist")
|
||||||
elseif islisted("blacklist", arg) then
|
local whitelist_macs = get_known_macs("whitelist")
|
||||||
print("blacklisted")
|
|
||||||
|
for i, adr in ipairs(argv) do
|
||||||
|
local mac = nil
|
||||||
|
if adr:find(":") then
|
||||||
|
mac = adr:lower()
|
||||||
else
|
else
|
||||||
local lease = haslease(arg)
|
for _, e in ipairs(arp_cache) do
|
||||||
if lease and lease.kicked then
|
if e["IP address"] == adr then
|
||||||
print("kicked")
|
mac = e["HW address"]
|
||||||
elseif lease then
|
break
|
||||||
print("lease")
|
|
||||||
else
|
|
||||||
print("unknown")
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
os.exit(0)
|
|
||||||
elseif cmd == "add" and arg then
|
|
||||||
if not haslease(arg) then
|
|
||||||
add_lease(arg)
|
|
||||||
else
|
|
||||||
print("already leased!")
|
|
||||||
os.exit(2)
|
|
||||||
end
|
end
|
||||||
os.exit(0)
|
|
||||||
elseif cmd == "remove" and arg then
|
if mac and cmd == "add-rules" then
|
||||||
remove_lease(arg)
|
if leased_macs[mac] then
|
||||||
|
add_lease(mac, arp_cache, true)
|
||||||
|
elseif blacklist_macs[mac] then
|
||||||
|
add_blacklist_rule(mac)
|
||||||
|
elseif whitelist_macs[mac] then
|
||||||
|
add_whitelist_rule(mac)
|
||||||
|
end
|
||||||
|
elseif mac and ( cmd == "whitelist" or cmd == "blacklist" or cmd == "lease" ) then
|
||||||
|
if cmd ~= "lease" and leased_macs[mac] then
|
||||||
|
print("Removing %s from leases" % mac)
|
||||||
|
remove_lease(mac)
|
||||||
|
leased_macs[mac] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if cmd ~= "whitelist" and whitelist_macs[mac] then
|
||||||
|
print("Removing %s from whitelist" % mac)
|
||||||
|
remove_whitelist(mac)
|
||||||
|
whitelist_macs[mac] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if cmd ~= "blacklist" and blacklist_macs[mac] then
|
||||||
|
print("Removing %s from blacklist" % mac)
|
||||||
|
remove_blacklist(mac)
|
||||||
|
blacklist_macs[mac] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if cmd == "lease" and not leased_macs[mac] then
|
||||||
|
print("Adding %s to leases" % mac)
|
||||||
|
add_lease(mac)
|
||||||
|
leased_macs[mac] = true
|
||||||
|
elseif cmd == "whitelist" and not whitelist_macs[mac] then
|
||||||
|
print("Adding %s to whitelist" % mac)
|
||||||
|
add_whitelist(mac)
|
||||||
|
whitelist_macs[mac] = true
|
||||||
|
elseif cmd == "blacklist" and not blacklist_macs[mac] then
|
||||||
|
print("Adding %s to blacklist" % mac)
|
||||||
|
add_blacklist(mac)
|
||||||
|
blacklist_macs[mac] = true
|
||||||
|
else
|
||||||
|
print("The mac %s is already %sed" %{ mac, cmd })
|
||||||
|
end
|
||||||
|
elseif mac and cmd == "remove" then
|
||||||
|
if leased_macs[mac] then
|
||||||
|
print("Removing %s from leases" % mac)
|
||||||
|
remove_lease(mac)
|
||||||
|
leased_macs[mac] = nil
|
||||||
|
elseif whitelist_macs[mac] then
|
||||||
|
print("Removing %s from whitelist" % mac)
|
||||||
|
remove_whitelist(mac)
|
||||||
|
whitelist_macs[mac] = nil
|
||||||
|
elseif blacklist_macs[mac] then
|
||||||
|
print("Removing %s from blacklist" % mac)
|
||||||
|
remove_blacklist(mac)
|
||||||
|
blacklist_macs[mac] = nil
|
||||||
|
else
|
||||||
|
print("The mac %s is not known" % mac)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
print("Can not find mac for ip %s" % argv[i])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
unlock()
|
||||||
os.exit(0)
|
os.exit(0)
|
||||||
elseif cmd == "sync" then
|
elseif cmd == "sync" then
|
||||||
sync()
|
sync()
|
||||||
os.exit(0)
|
os.exit(0)
|
||||||
|
elseif cmd == "list" then
|
||||||
|
list()
|
||||||
|
os.exit(0)
|
||||||
else
|
else
|
||||||
print("Usage: " .. argv[0] .. " <status|add|remove|sync> [MAC]")
|
print("Usage:")
|
||||||
|
print("\n luci-splash list\n List connected, black- and whitelisted clients")
|
||||||
|
print("\n luci-splash sync\n Synchronize firewall rules and clear expired leases")
|
||||||
|
print("\n luci-splash lease <MAC-or-IP>\n Create a lease for the given address")
|
||||||
|
print("\n luci-splash blacklist <MAC-or-IP>\n Add given address to blacklist")
|
||||||
|
print("\n luci-splash whitelist <MAC-or-IP>\n Add given address to whitelist")
|
||||||
|
print("\n luci-splash remove <MAC-or-IP>\n Remove given address from the lease-, black- or whitelist")
|
||||||
|
print("")
|
||||||
|
|
||||||
os.exit(1)
|
os.exit(1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Get a list of known mac addresses
|
||||||
|
function get_known_macs(list)
|
||||||
|
local leased_macs = { }
|
||||||
|
|
||||||
|
if not list or list == "lease" then
|
||||||
|
uci:foreach("luci_splash", "lease",
|
||||||
|
function(s) leased_macs[s.mac:lower()] = true end)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not list or list == "whitelist" then
|
||||||
|
uci:foreach("luci_splash", "whitelist",
|
||||||
|
function(s) leased_macs[s.mac:lower()] = true end)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not list or list == "blacklist" then
|
||||||
|
uci:foreach("luci_splash", "blacklist",
|
||||||
|
function(s) leased_macs[s.mac:lower()] = true end)
|
||||||
|
end
|
||||||
|
|
||||||
|
return leased_macs
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Get a list of known ip addresses
|
||||||
|
function get_known_ips(macs, arp)
|
||||||
|
local leased_ips = { }
|
||||||
|
if not macs then macs = get_known_macs() end
|
||||||
|
for _, e in ipairs(arp or net.arptable()) do
|
||||||
|
if macs[e["HW address"]] then leased_ips[e["IP address"]] = true end
|
||||||
|
end
|
||||||
|
return leased_ips
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Helper to delete iptables rules
|
||||||
|
function ipt_delete_all(args, comp, off)
|
||||||
|
off = off or { }
|
||||||
|
for i, r in ipairs(ipt:find(args)) do
|
||||||
|
if comp == nil or comp(r) then
|
||||||
|
off[r.table] = off[r.table] or { }
|
||||||
|
off[r.table][r.chain] = off[r.table][r.chain] or 0
|
||||||
|
|
||||||
|
os.execute("iptables -t %q -D %q %d 2>/dev/null"
|
||||||
|
%{ r.table, r.chain, r.index - off[r.table][r.chain] })
|
||||||
|
|
||||||
|
off[r.table][r.chain] = off[r.table][r.chain] + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Add a lease to state and invoke add_rule
|
-- Add a lease to state and invoke add_rule
|
||||||
function add_lease(mac)
|
function add_lease(mac, arp, no_uci)
|
||||||
|
mac = mac:lower()
|
||||||
|
|
||||||
|
-- Get current ip address
|
||||||
|
local ipaddr
|
||||||
|
for _, entry in ipairs(arp or net.arptable()) do
|
||||||
|
if entry["HW address"] == mac then
|
||||||
|
ipaddr = entry["IP address"]
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add lease if there is an ip addr
|
||||||
|
if ipaddr then
|
||||||
|
if not no_uci then
|
||||||
uci:section("luci_splash", "lease", nil, {
|
uci:section("luci_splash", "lease", nil, {
|
||||||
mac = mac,
|
mac = mac,
|
||||||
|
ipaddr = ipaddr,
|
||||||
start = os.time()
|
start = os.time()
|
||||||
})
|
})
|
||||||
add_rule(mac)
|
|
||||||
|
|
||||||
uci:save("luci_splash")
|
uci:save("luci_splash")
|
||||||
end
|
end
|
||||||
|
add_lease_rule(mac, ipaddr)
|
||||||
|
else
|
||||||
|
print("Found no active IP for %s, lease not added" % mac)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Remove a lease from state and invoke remove_rule
|
-- Remove a lease from state and invoke remove_rule
|
||||||
function remove_lease(mac)
|
function remove_lease(mac)
|
||||||
mac = mac:lower()
|
mac = mac:lower()
|
||||||
remove_rule(mac)
|
|
||||||
|
|
||||||
uci:delete_all("luci_splash", "lease",
|
uci:delete_all("luci_splash", "lease",
|
||||||
function(s) return ( s.mac:lower() == mac ) end)
|
function(s)
|
||||||
|
if s.mac:lower() == mac then
|
||||||
|
remove_lease_rule(mac, s.ipaddr)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end)
|
||||||
|
|
||||||
uci:save("luci_splash")
|
uci:save("luci_splash")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Add an iptables rule
|
-- Add a whitelist entry
|
||||||
function add_rule(mac)
|
function add_whitelist(mac)
|
||||||
local a, b, c, d, e, f = mac:match("(%w+):(%w+):(%w+):(%w+):(%w+):(%w+)")
|
uci:section("luci_splash", "whitelist", nil, { mac = mac })
|
||||||
local mac_pre = "%s%s" %{ a, b }
|
uci:save("luci_splash")
|
||||||
local mac_post = "%s%s%s%s" %{ c, d, e, f }
|
uci:commit("luci_splash")
|
||||||
local handle = f
|
add_whitelist_rule(mac)
|
||||||
|
|
||||||
if limit_up > 0 and limit_down > 0 then
|
|
||||||
os.execute("iptables -t mangle -I luci_splash_mark -m mac --mac-source %q -j MARK --set-mark 79" % mac)
|
|
||||||
|
|
||||||
for _, i in ipairs(splash_interfaces) do
|
|
||||||
os.execute("tc filter add dev %q parent 77:0 protocol ip prio 2 " % i ..
|
|
||||||
"handle ::%q u32 " % handle ..
|
|
||||||
"match u16 0x0800 0xFFFF at -2 match u32 0x%q 0xFFFFFFFF at -12 " % mac_post ..
|
|
||||||
"match u16 0x%q 0xFFFF at -14 flowid 77:10" % mac_pre)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Add a blacklist entry
|
||||||
|
function add_blacklist(mac)
|
||||||
|
uci:section("luci_splash", "blacklist", nil, { mac = mac })
|
||||||
|
uci:save("luci_splash")
|
||||||
|
uci:commit("luci_splash")
|
||||||
|
add_blacklist_rule(mac)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Remove a whitelist entry
|
||||||
|
function remove_whitelist(mac)
|
||||||
|
mac = mac:lower()
|
||||||
|
uci:delete_all("luci_splash", "whitelist",
|
||||||
|
function(s) return not s.mac or s.mac:lower() == mac end)
|
||||||
|
uci:save("luci_splash")
|
||||||
|
uci:commit("luci_splash")
|
||||||
|
remove_lease_rule(mac)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Remove a blacklist entry
|
||||||
|
function remove_blacklist(mac)
|
||||||
|
mac = mac:lower()
|
||||||
|
uci:delete_all("luci_splash", "blacklist",
|
||||||
|
function(s) return not s.mac or s.mac:lower() == mac end)
|
||||||
|
uci:save("luci_splash")
|
||||||
|
uci:commit("luci_splash")
|
||||||
|
remove_lease_rule(mac)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Add an iptables rule
|
||||||
|
function add_lease_rule(mac, ipaddr)
|
||||||
|
if limit_up > 0 and limit_down > 0 then
|
||||||
|
os.execute("iptables -t mangle -I luci_splash_mark_out -m mac --mac-source %q -j MARK --set-mark 79" % mac)
|
||||||
|
os.execute("iptables -t mangle -I luci_splash_mark_in -d %q -j MARK --set-mark 80" % ipaddr)
|
||||||
end
|
end
|
||||||
|
|
||||||
os.execute("iptables -t filter -I luci_splash_filter -m mac --mac-source %q -j RETURN" % mac)
|
os.execute("iptables -t filter -I luci_splash_filter -m mac --mac-source %q -j RETURN" % mac)
|
||||||
return os.execute("iptables -t nat -I luci_splash_leases -m mac --mac-source %q -j RETURN" % mac)
|
os.execute("iptables -t nat -I luci_splash_leases -m mac --mac-source %q -j RETURN" % mac)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Remove an iptables rule
|
-- Remove lease, black- or whitelist rules
|
||||||
function remove_rule(mac)
|
function remove_lease_rule(mac, ipaddr)
|
||||||
local handle = mac:match("%w+:%w+:%w+:%w+:%w+:(%w+)")
|
|
||||||
|
|
||||||
local function ipt_delete_foreach(args)
|
|
||||||
for _, r in ipairs(ipt:find(args)) do
|
|
||||||
os.execute("iptables -t %q -D %q -m mac --mac-source %q %s 2>/dev/null"
|
|
||||||
%{ r.table, r.chain, mac,
|
|
||||||
r.target == "MARK" and "-j MARK --set-mark 79" or
|
|
||||||
r.target and "-j %q" % r.target or "" })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
ipt_delete_foreach({table="filter", chain="luci_splash_filter", options={"MAC", mac:upper()}})
|
|
||||||
ipt_delete_foreach({table="mangle", chain="luci_splash_mark", options={"MAC", mac:upper()}})
|
|
||||||
ipt_delete_foreach({table="nat", chain="luci_splash_leases", options={"MAC", mac:upper()}})
|
|
||||||
|
|
||||||
for _, i in ipairs(splash_interfaces) do
|
|
||||||
os.execute("tc filter del dev %q parent 77:0 protocol ip prio 2 " % i ..
|
|
||||||
"handle 800::%q u32 2>/dev/null" % handle)
|
|
||||||
end
|
|
||||||
|
|
||||||
ipt:resync()
|
ipt:resync()
|
||||||
|
|
||||||
|
if ipaddr then
|
||||||
|
ipt_delete_all({table="mangle", chain="luci_splash_mark_in", destination=ipaddr})
|
||||||
|
ipt_delete_all({table="mangle", chain="luci_splash_mark_out", options={"MAC", mac:upper()}})
|
||||||
|
end
|
||||||
|
|
||||||
|
ipt_delete_all({table="filter", chain="luci_splash_filter", options={"MAC", mac:upper()}})
|
||||||
|
ipt_delete_all({table="nat", chain="luci_splash_leases", options={"MAC", mac:upper()}})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Check whether a MAC-Address is listed in the lease state list
|
-- Add whitelist rules
|
||||||
function haslease(mac)
|
function add_whitelist_rule(mac)
|
||||||
mac = mac:lower()
|
os.execute("iptables -t filter -I luci_splash_filter -m mac --mac-source %q -j RETURN" % mac)
|
||||||
local lease = nil
|
os.execute("iptables -t nat -I luci_splash_leases -m mac --mac-source %q -j RETURN" % mac)
|
||||||
|
|
||||||
uci:foreach("luci_splash", "lease",
|
|
||||||
function (section)
|
|
||||||
if section.mac:lower() == mac then
|
|
||||||
lease = section
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
return lease
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Check whether a MAC-Address is in given list
|
-- Add blacklist rules
|
||||||
function islisted(what, mac)
|
function add_blacklist_rule(mac)
|
||||||
mac = mac:lower()
|
os.execute("iptables -t filter -I luci_splash_filter -m mac --mac-source %q -j DROP" % mac)
|
||||||
|
os.execute("iptables -t nat -I luci_splash_leases -m mac --mac-source %q -j DROP" % mac)
|
||||||
uci:foreach("luci_splash", what,
|
|
||||||
function (section)
|
|
||||||
if section.mac:lower() == mac then
|
|
||||||
stat = true
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- Returns a list of MAC-Addresses for which a rule is existing
|
|
||||||
function listrules()
|
|
||||||
local macs = { }
|
|
||||||
for i, r in ipairs(ipt:find({table="nat", chain="luci_splash_leases", options={"MAC"}})) do
|
|
||||||
macs[r.options[2]:lower()] = true
|
|
||||||
end
|
|
||||||
return luci.util.keys(macs)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Synchronise leases, remove abandoned rules
|
-- Synchronise leases, remove abandoned rules
|
||||||
function sync()
|
function sync()
|
||||||
local written = {}
|
lock()
|
||||||
|
|
||||||
local time = os.time()
|
local time = os.time()
|
||||||
|
|
||||||
-- Current leases in state files
|
-- Current leases in state files
|
||||||
|
@ -191,36 +330,105 @@ function sync()
|
||||||
uci:load("luci_splash")
|
uci:load("luci_splash")
|
||||||
uci:revert("luci_splash")
|
uci:revert("luci_splash")
|
||||||
|
|
||||||
|
|
||||||
-- For all leases
|
-- For all leases
|
||||||
for k, v in pairs(leases) do
|
for k, v in pairs(leases) do
|
||||||
if v[".type"] == "lease" then
|
if v[".type"] == "lease" then
|
||||||
if os.difftime(time, tonumber(v.start)) > leasetime then
|
if os.difftime(time, tonumber(v.start)) > leasetime then
|
||||||
-- Remove expired
|
-- Remove expired
|
||||||
remove_rule(v.mac)
|
remove_lease_rule(v.mac, v.ipaddr)
|
||||||
else
|
else
|
||||||
-- Rewrite state
|
-- Rewrite state
|
||||||
uci:section("luci_splash", "lease", nil, {
|
uci:section("luci_splash", "lease", nil, {
|
||||||
mac = v.mac,
|
mac = v.mac,
|
||||||
start = v.start,
|
ipaddr = v.ipaddr,
|
||||||
kicked = v.kicked
|
start = v.start
|
||||||
})
|
})
|
||||||
written[v.mac:lower()] = 1
|
|
||||||
end
|
end
|
||||||
elseif v[".type"] == "whitelist" or v[".type"] == "blacklist" then
|
|
||||||
written[v.mac:lower()] = 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- Delete rules without state
|
|
||||||
for i, r in ipairs(listrules()) do
|
|
||||||
if #r > 0 and not written[r:lower()] then
|
|
||||||
remove_rule(r)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
uci:save("luci_splash")
|
uci:save("luci_splash")
|
||||||
|
|
||||||
|
-- Get current IPs and MAC addresses
|
||||||
|
local macs = get_known_macs()
|
||||||
|
local ips = get_known_ips(macs)
|
||||||
|
|
||||||
|
ipt:resync()
|
||||||
|
|
||||||
|
ipt_delete_all({table="filter", chain="luci_splash_filter", options={"MAC"}},
|
||||||
|
function(r) return not macs[r.options[2]:lower()] end)
|
||||||
|
|
||||||
|
ipt_delete_all({table="nat", chain="luci_splash_leases", options={"MAC"}},
|
||||||
|
function(r) return not macs[r.options[2]:lower()] end)
|
||||||
|
|
||||||
|
ipt_delete_all({table="mangle", chain="luci_splash_mark_out", options={"MAC", "MARK", "set"}},
|
||||||
|
function(r) return not macs[r.options[2]:lower()] end)
|
||||||
|
|
||||||
|
ipt_delete_all({table="mangle", chain="luci_splash_mark_in", options={"MARK", "set"}},
|
||||||
|
function(r) return not ips[r.destination] end)
|
||||||
|
|
||||||
|
unlock()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Show client info
|
||||||
|
function list()
|
||||||
|
-- Get current arp cache
|
||||||
|
local arpcache = { }
|
||||||
|
for _, entry in ipairs(net.arptable()) do
|
||||||
|
arpcache[entry["HW address"]] = { entry["Device"], entry["IP address"] }
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Find traffic usage
|
||||||
|
local function traffic(lease)
|
||||||
|
local traffic_in = 0
|
||||||
|
local traffic_out = 0
|
||||||
|
|
||||||
|
local rin = ipt:find({table="mangle", chain="luci_splash_mark_in", destination=lease.ipaddr})
|
||||||
|
local rout = ipt:find({table="mangle", chain="luci_splash_mark_out", options={"MAC", lease.mac:upper()}})
|
||||||
|
|
||||||
|
if rin and #rin > 0 then traffic_in = math.floor( rin[1].bytes / 1024) end
|
||||||
|
if rout and #rout > 0 then traffic_out = math.floor(rout[1].bytes / 1024) end
|
||||||
|
|
||||||
|
return traffic_in, traffic_out
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Print listings
|
||||||
|
local leases = uci:get_all("luci_splash")
|
||||||
|
|
||||||
|
print(string.format(
|
||||||
|
"%-17s %-15s %-9s %-4s %-7s %20s",
|
||||||
|
"MAC", "IP", "State", "Dur.", "Intf.", "Traffic down/up"
|
||||||
|
))
|
||||||
|
|
||||||
|
-- Leases
|
||||||
|
for _, s in pairs(leases) do
|
||||||
|
if s[".type"] == "lease" and s.mac then
|
||||||
|
local ti, to = traffic(s)
|
||||||
|
local mac = s.mac:lower()
|
||||||
|
local arp = arpcache[mac]
|
||||||
|
print(string.format(
|
||||||
|
"%-17s %-15s %-9s %3dm %-7s %7dKB %7dKB",
|
||||||
|
mac, s.ipaddr, "leased",
|
||||||
|
math.floor(( os.time() - tonumber(s.start) ) / 60),
|
||||||
|
arp and arp[1] or "?", ti, to
|
||||||
|
))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Whitelist, Blacklist
|
||||||
|
for _, s in luci.util.spairs(leases,
|
||||||
|
function(a,b) return leases[a][".type"] > leases[b][".type"] end
|
||||||
|
) do
|
||||||
|
if (s[".type"] == "whitelist" or s[".type"] == "blacklist") and s.mac then
|
||||||
|
local mac = s.mac:lower()
|
||||||
|
local arp = arpcache[mac]
|
||||||
|
print(string.format(
|
||||||
|
"%-17s %-15s %-9s %4s %-7s %9s %9s",
|
||||||
|
mac, arp and arp[2] or "?", s[".type"], "- ",
|
||||||
|
arp and arp[1] or "?", "-", "-"
|
||||||
|
))
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
main(arg)
|
main(arg)
|
||||||
|
|
Loading…
Reference in a new issue