diff options
author | Jo-Philipp Wich <jow@openwrt.org> | 2014-12-03 15:17:05 +0100 |
---|---|---|
committer | Jo-Philipp Wich <jow@openwrt.org> | 2015-01-08 16:26:20 +0100 |
commit | 1bb4822dca6113f73e3bc89e2acf15935e6f8e92 (patch) | |
tree | 35e16f100466e4e00657199b38bb3d87d52bf73f /applications/luci-splash/root | |
parent | 9edd0e46c3f880727738ce8ca6ff1c8b85f99ef4 (diff) |
Rework LuCI build system
* Rename subdirectories to their repective OpenWrt package names
* Make each LuCI module its own standalone package
* Deploy a shared luci.mk which is used by each module Makefile
Signed-off-by: Jo-Philipp Wich <jow@openwrt.org>
Diffstat (limited to 'applications/luci-splash/root')
5 files changed, 0 insertions, 1133 deletions
diff --git a/applications/luci-splash/root/etc/config/luci_splash b/applications/luci-splash/root/etc/config/luci_splash deleted file mode 100644 index c4cfef5dd9..0000000000 --- a/applications/luci-splash/root/etc/config/luci_splash +++ /dev/null @@ -1,2 +0,0 @@ -config core general - option leasetime 1
\ No newline at end of file diff --git a/applications/luci-splash/root/etc/config/luci_splash_leases b/applications/luci-splash/root/etc/config/luci_splash_leases deleted file mode 100644 index 6afdd90ede..0000000000 --- a/applications/luci-splash/root/etc/config/luci_splash_leases +++ /dev/null @@ -1 +0,0 @@ -# This file should always stay empty and is just needed to be able to use this config in /var/state! diff --git a/applications/luci-splash/root/etc/hotplug.d/iface/25-splash b/applications/luci-splash/root/etc/hotplug.d/iface/25-splash deleted file mode 100644 index 045e908c72..0000000000 --- a/applications/luci-splash/root/etc/hotplug.d/iface/25-splash +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh - -[ "$ACTION" = ifup ] || exit 0 - -/etc/init.d/firewall enabled || exit 0 - -if [ -x /etc/init.d/luci_splash ]; then - restart_splash() { - local net="$1" - if [ "$INTERFACE" = "$net" ]; then - logger -t splash "Reloading splash firewall rules due to ifup of $INTERFACE ($DEVICE)" - /etc/init.d/luci_splash restart - fi - } - config_load luci_splash - config_foreach restart_splash iface -fi diff --git a/applications/luci-splash/root/etc/init.d/luci_splash b/applications/luci-splash/root/etc/init.d/luci_splash deleted file mode 100755 index feefabd81a..0000000000 --- a/applications/luci-splash/root/etc/init.d/luci_splash +++ /dev/null @@ -1,362 +0,0 @@ -#!/bin/sh /etc/rc.common - -START=70 -EXTRA_COMMANDS=clear_leases -LIMIT_DOWN=0 -LIMIT_DOWN_BURST=0 -LIMIT_UP=0 -TC=/usr/sbin/tc -IPT=/usr/sbin/iptables -IPT6=/usr/sbin/ip6tables - -IPT_REPLAY=/var/run/luci_splash.iptlog -LOCK=/var/run/luci_splash.lock -[ -x $IPT6 ] && [ -f /proc/net/ipv6_route ] && HAS_IPV6=1 - -silent() { - "$@" 2>/dev/null -} - -ipt_log() { - $IPT -I "$@" - echo $IPT -D "$@" >> $IPT_REPLAY -} - -ipt6_log() { - [ "$HAS_IPV6" = 1 ] || return - $IPT6 -I "$@" - echo $IPT6 -D "$@" >> $IPT_REPLAY -} - - -iface_add() { - local cfg="$1" - - config_get zone "$cfg" zone - [ -n "$zone" ] || return 0 - - config_get net "$cfg" network - [ -n "$net" ] || return 0 - - config_get ifname "$net" ifname - [ -n "$ifname" ] || return 0 - - config_get ipaddr "$net" ipaddr - [ -n "$ipaddr" ] || return 0 - - config_get netmask "$net" netmask - [ -n "$netmask" ] || return 0 - - config_get ip6addr "$net" ip6addr - - config_get type "$net" type - - parentiface="$(uci -q get network.${net}.ifname)" - - [ -n "$parentiface" ] && [ ! "$type" = "bridge" ] && { - parentiface=${parentiface#@} - config_get parentproto "$parentiface" proto - config_get parentipaddr "$parentiface" ipaddr - config_get parentnetmask "$parentiface" netmask - } - - eval "$(ipcalc.sh $ipaddr $netmask)" - - logger -s -p info -t splash "Add $NETWORK/$PREFIX ($ifname) to splashed networks." - - ### Add interface specific chain entry rules - ipt_log "prerouting_${zone}_rule" -i "${ifname%:*}" -s "$NETWORK/$PREFIX" -j luci_splash_prerouting -t nat - ipt_log "forwarding_${zone}_rule" -i "${ifname%:*}" -s "$NETWORK/$PREFIX" -j luci_splash_forwarding -t filter - - if [ "$HAS_IPV6" = 1 ] && [ -n "$ip6addr" ]; then - ipt6_log "forwarding_${zone}_rule" -i "${ifname%:*}" -s "$ip6addr" -j luci_splash_forwarding -t filter - fi - - ### Allow traffic to the same subnet - $IPT -t nat -I luci_splash_prerouting -d "$ipaddr/${netmask:-32}" -j RETURN - $IPT -t filter -I luci_splash_forwarding -d "$ipaddr/${netmask:-32}" -j RETURN - - ### Allow traffic to the mesh subnet - [ "$parentproto" = "static" -a -n "$parentipaddr" ] && { - $IPT -t nat -I luci_splash_prerouting -d "$parentipaddr/${parentnetmask:-32}" -j RETURN - $IPT -t filter -I luci_splash_forwarding -d "$parentipaddr/${parentnetmask:-32}" -j RETURN - } - - qos_iface_add "$ifname" "$NETWORK" "$PREFIX" -} - -iface_del() { - config_get zone "$1" zone - [ -n "$zone" ] || return 0 - - config_get net "$1" network - [ -n "$net" ] || return 0 - - config_get ifname "$net" ifname - [ -n "$ifname" ] || return 0 - - # Clear interface specific rules - [ -s $IPT_REPLAY ] && { - logger -s -p info -t splash "Remove $ifname from splashed networks." - grep -- "-i ${ifname%:*}" $IPT_REPLAY | while read ln; do silent $ln; done - sed -ie "/-i ${ifname%:*}/d" $IPT_REPLAY - } - - qos_iface_del "$ifname" -} - -mac_add() { - config_get mac "$1" mac - append MACS "$mac" -} - -whitelist_add() { - config_get mac "$1" mac - iface=$2 - $TC filter add dev "$iface" parent ffff: protocol ip prio 1 u32 match ether src $mac police pass - $TC filter add dev "$iface" parent 1:0 protocol ip prio 1 u32 match ether dst $mac classid 1:1 -} - - -subnet_add() { - local cfg="$1" - - config_get ipaddr "$cfg" ipaddr - config_get netmask "$cfg" netmask - - [ -n "$ipaddr" ] && { - $IPT -t nat -I luci_splash_prerouting -d "$ipaddr/${netmask:-32}" -j RETURN - $IPT -t filter -I luci_splash_forwarding -d "$ipaddr/${netmask:-32}" -j RETURN - } -} - -qos_iface_add() { - local iface="$1" - local network="$2" - local prefix="$3" - - # 77 -> download root qdisc - # ffff -> upload root qdisc - - silent $TC qdisc del dev "$iface" root handle 1: - silent $TC class del dev "$iface" parent 1: classid 1:ffff - silent $TC class del dev "$iface" parent 1: classid 1:1 - silent $TC filter del dev "$iface" parent ffff: protocol ip prio 1 u32 - silent $TC filter del dev "$iface" parent ffff: protocol ip prio 2 u32 - silent $TC filter del dev "$iface" parent ffff: protocol ip prio 3 u32 - - if [ "$LIMIT_UP" -gt 0 -a "$LIMIT_DOWN" -gt 0 ]; then - # Setup qdiscs - $TC qdisc add dev "$iface" root handle 1: htb default 1 - silent $TC qdisc add dev "$iface" ingress - - # Default class - all clients which are not otherwise handled are put in that class - # and share that bandwidth. - $TC class add dev "$iface" parent 1: classid 1:ffff htb rate ${LIMIT_DOWN}kbit - - # default class and class for whitelisted clients = unlimited - $TC class add dev "$iface" parent 1: classid 1:1 htb rate 100mbit - - # All traffic to the dhcp subnet is put into the limited class - $TC filter add dev "$iface" parent 1:0 protocol ip prio 3 u32 match ip dst $network/$prefix classid 1:ffff - $TC qdisc add dev "$iface" parent 1:ffff sfq perturb 10 - $TC filter add dev "$iface" parent ffff: protocol ip prio 3 u32 match ip src $network/$prefix police rate ${LIMIT_UP}kbit mtu 6k burst 6k drop - - # classify packets by their iptables MARK set in luci_splash_mark_in (mangle table) - # every client gets his own class and so his own bandwidth limit - $TC filter add dev "$iface" parent 1:0 protocol ip prio 2 fw - - config_foreach whitelist_add whitelist $iface - fi -} - -qos_iface_del() { - local iface="$1" - silent $TC qdisc del dev "$iface" root handle 77: -} - -boot() { - ### Setup splash-relay - uci get uhttpd.splash 2>/dev/null || { -uci batch <<EOF - set uhttpd.splash=uhttpd - set uhttpd.splash.home="/www/cgi-bin/splash/" - set uhttpd.splash.interpreter=".sh=/bin/ash" - set uhttpd.splash.listen_http="8082" - set uhttpd.splash.index_page="splash.sh" - set uhttpd.splash.error_page="/splash.sh" - set uhttpd.splash.http_keepalive='0' - commit uhttpd -EOF - } - - ### We are started by the firewall include - exit 0 -} - -start() { - lock $LOCK - logger -s -p info -t splash "Starting luci-splash" - include /lib/network - . /lib/functions/network.sh - scan_interfaces - config_load luci_splash - - ### Find QoS limits - config_get LIMIT_UP general limit_up - config_get LIMIT_DOWN general limit_down - config_get LIMIT_DOWN_BURST general limit_down_burst - - LIMIT_UP="$((8*${LIMIT_UP:-0}))" - LIMIT_DOWN="$((8*${LIMIT_DOWN:-0}))" - LIMIT_DOWN_BURST="${LIMIT_DOWN_BURST:+$((8*$LIMIT_DOWN_BURST))}" - LIMIT_DOWN_BURST="${LIMIT_DOWN_BURST:-$(($LIMIT_DOWN / 5 * 6))}" - - ### Load required modules - [ "$LIMIT_UP" -gt 0 -a "$LIMIT_DOWN" -gt 0 ] && { - silent insmod act_police - silent insmod cls_fw - silent insmod cls_u32 - silent insmod sch_htb - silent insmod sch_sfq - silent insmod sch_ingress - } - - ### Create subchains - $IPT -t nat -N luci_splash_prerouting - $IPT -t nat -N luci_splash_leases - $IPT -t filter -N luci_splash_forwarding - $IPT -t filter -N luci_splash_filter - - if [ "$HAS_IPV6" = 1 ]; then - $IPT6 -t filter -N luci_splash_forwarding - $IPT6 -t filter -N luci_splash_filter - fi - - ### Clear iptables replay log - [ -s $IPT_REPLAY ] && . $IPT_REPLAY - echo -n > $IPT_REPLAY - - ### Add interface independant prerouting rules - $IPT -t nat -A luci_splash_prerouting -j luci_splash_leases - $IPT -t nat -A luci_splash_leases -p udp --dport 53 -j REDIRECT --to-ports 53 - $IPT -t nat -A luci_splash_leases -p tcp --dport 80 -j REDIRECT --to-ports 8082 - - ### Add interface independant forwarding rules - $IPT -t filter -A luci_splash_forwarding -j luci_splash_filter - $IPT -t filter -A luci_splash_filter -p tcp -j REJECT --reject-with tcp-reset - $IPT -t filter -A luci_splash_filter -j REJECT --reject-with icmp-net-prohibited - - if [ "$HAS_IPV6" = 1 ]; then - $IPT6 -t filter -A luci_splash_forwarding -j luci_splash_filter - $IPT6 -t filter -A luci_splash_filter -p tcp -j REJECT --reject-with tcp-reset - $IPT6 -t filter -A luci_splash_filter -j REJECT --reject-with adm-prohibited - fi - - ### Add QoS chain - $IPT -t mangle -N luci_splash_mark_out - $IPT -t mangle -N luci_splash_mark_in - $IPT -t mangle -I PREROUTING -j luci_splash_mark_out - $IPT -t mangle -I POSTROUTING -j luci_splash_mark_in - - if [ "$HAS_IPV6" = 1 ]; then - $IPT6 -t mangle -N luci_splash_mark_out - $IPT6 -t mangle -N luci_splash_mark_in - $IPT6 -t mangle -I PREROUTING -j luci_splash_mark_out - $IPT6 -t mangle -I POSTROUTING -j luci_splash_mark_in - fi - - ### Build the main and portal rule - config_foreach iface_add iface - config_foreach subnet_add subnet - - ### Add the community homepage to the list of allowed destination subnets - hp=$(uci -q get freifunk.community.homepage) && { - chp=${hp#http*://} - chp=${chp%%/*} - $IPT -t nat -I luci_splash_prerouting -d "${chp}/32" -j RETURN - $IPT -t filter -I luci_splash_forwarding -d "${chp}/32" -j RETURN - } - - ### Find active mac addresses - MACS="" - - - config_foreach mac_add blacklist - config_foreach mac_add whitelist - - config_load luci_splash_leases - config_foreach mac_add lease - - ### Add crontab entry - test -f /etc/crontabs/root || touch /etc/crontabs/root - grep -q luci-splash /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() { - lock $LOCK - - include /lib/network - scan_interfaces - config_load luci_splash - - ### Clear interface rules - config_foreach iface_del iface - - silent $IPT -t mangle -D PREROUTING -j luci_splash_mark_out - silent $IPT -t mangle -D POSTROUTING -j luci_splash_mark_in - - if [ "$HAS_IPV6" = 1 ]; then - silent $IPT6 -t mangle -D PREROUTING -j luci_splash_mark_out - silent $IPT6 -t mangle -D POSTROUTING -j luci_splash_mark_in - fi - - ### Clear subchains - silent $IPT -t nat -F luci_splash_prerouting - silent $IPT -t nat -F luci_splash_leases - silent $IPT -t filter -F luci_splash_forwarding - silent $IPT -t filter -F luci_splash_filter - silent $IPT -t mangle -F luci_splash_mark_out - silent $IPT -t mangle -F luci_splash_mark_in - - if [ "$HAS_IPV6" = 1 ]; then - $IPT6 -t filter -F luci_splash_forwarding - $IPT6 -t filter -F luci_splash_filter - $IPT6 -t mangle -F luci_splash_mark_out - $IPT6 -t mangle -F luci_splash_mark_in - fi - - ### Delete subchains - silent $IPT -t nat -X luci_splash_prerouting - silent $IPT -t nat -X luci_splash_leases - silent $IPT -t filter -X luci_splash_forwarding - silent $IPT -t filter -X luci_splash_filter - silent $IPT -t mangle -X luci_splash_mark_out - silent $IPT -t mangle -X luci_splash_mark_in - if [ "$HAS_IPV6" = 1 ]; then - $IPT6 -t filter -X luci_splash_forwarding - $IPT6 -t filter -X luci_splash_filter - $IPT6 -t mangle -X luci_splash_mark_out - $IPT6 -t mangle -X luci_splash_mark_in - fi - sed -ie '/\/usr\/sbin\/luci-splash sync/d' /var/spool/cron/crontabs/root - - lock -u $LOCK -} - -clear_leases() { - ### Find active mac addresses - MACS="" - config_foreach mac_add lease - - ### Clear leases - [ -n "$MACS" ] && luci-splash remove $MACS -} - diff --git a/applications/luci-splash/root/usr/sbin/luci-splash b/applications/luci-splash/root/usr/sbin/luci-splash deleted file mode 100755 index 6b1e41edbd..0000000000 --- a/applications/luci-splash/root/usr/sbin/luci-splash +++ /dev/null @@ -1,751 +0,0 @@ -#!/usr/bin/lua - -utl = require "luci.util" -sys = require "luci.sys" - -require("luci.model.uci") -require("luci.sys.iptparser") - --- Init state session -local uci = luci.model.uci.cursor_state() -local ipt = luci.sys.iptparser.IptParser() -local net = sys.net -local fs = require "luci.fs" -local ip = require "luci.ip" - -local debug = false - -local has_ipv6 = fs.access("/proc/net/ipv6_route") and fs.access("/usr/sbin/ip6tables") - -function exec(cmd) - -- executes a cmd and gets its output - if debug then - local ret = sys.exec(cmd) - print('+ ' .. cmd) - if ret and ret ~= "" then - print(ret) - end - else - local ret = sys.exec(cmd .. " &> /dev/null") - end -end - -function call(cmd) - -- just calls a command - if debug then - print('+ ' .. cmd) - end - os.execute(cmd) -end - - -function lock() - call("lock /var/run/luci_splash.lock") -end - -function unlock() - call("lock -u /var/run/luci_splash.lock") -end - -function get_id(ip) - local o3, o4 = ip:match("[0-9]+%.[0-9]+%.([0-9]+)%.([0-9]+)") - if o3 and 04 then - return string.format("%02X%s", tonumber(o3), "") .. string.format("%02X%s", tonumber(o4), "") - else - return false - end -end - -function update_stats(leased, whitelisted, whitelisttotal, blacklisted, blacklisttotal) - local leases = uci:get_all("luci_splash_leases", "stats") - uci:delete("luci_splash_leases", "stats") - uci:section("luci_splash_leases", "stats", "stats", { - leases = leased or (leases and leases.leases) or 0, - whitelisttotal = whitelisttotal or (leased and leases.whitelisttotal) or 0, - whitelistonline = whitelisted or (leases and leases.whitelistonline) or 0, - blacklisttotal = blacklisttotal or (leases and leases.blacklisttotal) or 0, - blacklistonline = blacklisted or (leases and leases.blacklistonline) or 0, - }) - uci:save("luci_splash_leases") -end - - -function get_device_for_ip(ipaddr) - local dev - uci:foreach("network", "interface", function(s) - if s.ipaddr and s.netmask then - local network = ip.IPv4(s.ipaddr, s.netmask) - if network:contains(ip.IPv4(ipaddr)) then - -- this should be rewritten to luci functions if possible - dev = utl.trim(sys.exec(". /lib/functions/network.sh; network_get_device IFNAME '" .. s['.name'] .. "'; echo $IFNAME")) - end - end - end) - return dev -end - -function get_physdev(interface) - local dev - dev = utl.trim(sys.exec(". /lib/functions/network.sh; network_get_device IFNAME '" .. interface .. "'; echo $IFNAME")) - return dev -end - - - -function get_filter_handle(parent, direction, device, mac) - local input = utl.split(sys.exec('/usr/sbin/tc filter show dev ' .. device .. ' parent ' .. parent) or {}) - local tbl = {} - local handle - for k, v in pairs(input) do - handle = v:match('filter protocol ip pref %d+ u32 fh (%d*:%d*:%d*) order') or v:match('filter protocol all pref %d+ u32 fh (%d*:%d*:%d*) order') - if handle then - local mac, mac1, mac2, mac3, mac4, mac5, mac6 - if direction == 'src' then - mac1, mac2, mac3, mac4 = input[k+1]:match('match ([%a%d][%a%d])([%a%d][%a%d])([%a%d][%a%d])([%a%d][%a%d])/ffffffff') - mac5, mac6 = input[k+2]:match('match ([%a%d][%a%d])([%a%d][%a%d])0000/ffff0000') - else - mac1, mac2 = input[k+1]:match('match 0000([%a%d][%a%d])([%a%d][%a%d])/0000ffff') - mac3, mac4, mac5, mac6 = input[k+2]:match('match ([%a%d][%a%d])([%a%d][%a%d])([%a%d][%a%d])([%a%d][%a%d])/ffffffff') - end - if mac1 and mac2 and mac3 and mac4 and mac5 and mac6 then - mac = "%s:%s:%s:%s:%s:%s" % { mac1, mac2, mac3, mac4, mac5, mac6 } - tbl[mac] = handle - end - end - end - if tbl[mac] then - handle = tbl[mac] - end - return handle -end - -function macvalid(mac) - if mac and mac:match( - "^[a-fA-F0-9][a-fA-F0-9]:[a-fA-F0-9][a-fA-F0-9]:" .. - "[a-fA-F0-9][a-fA-F0-9]:[a-fA-F0-9][a-fA-F0-9]:" .. - "[a-fA-F0-9][a-fA-F0-9]:[a-fA-F0-9][a-fA-F0-9]$" - ) then - return true - end - - return false -end - -function ipvalid(ipaddr) - if ipaddr then - return ip.IPv4(ipaddr) and true or false - end - - return false -end - -function main(argv) - local cmd = table.remove(argv, 1) - local arg = argv[1] - - limit_up = (tonumber(uci:get("luci_splash", "general", "limit_up")) or 0) * 8 - limit_down = (tonumber(uci:get("luci_splash", "general", "limit_down")) or 0) * 8 - - if ( cmd == "lease" or cmd == "add-rules" or cmd == "remove" or - cmd == "whitelist" or cmd == "blacklist" or cmd == "status" ) and #argv > 0 - then - if not (macvalid(arg) or ipvalid(arg)) then - print("Invalid argument. The second argument must " .. - "be a valid IPv4 or Mac Address.") - os.exit(1) - end - - lock() - - local arp_cache = net.arptable() - local leased_macs = get_known_macs("lease") - local blacklist_macs = get_known_macs("blacklist") - local whitelist_macs = get_known_macs("whitelist") - - for i, adr in ipairs(argv) do - local mac = nil - if adr:find(":") then - mac = adr:lower() - else - for _, e in ipairs(arp_cache) do - if e["IP address"] == adr then - mac = e["HW address"]:lower() - break - end - end - end - - if mac and cmd == "add-rules" then - 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 == "status" then - print(leased_macs[mac] and "lease" - or whitelist_macs[mac] and "whitelist" - or blacklist_macs[mac] and "blacklist" - or "new") - 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 - if cmd == "lease" then - print('%s is whitelisted. Remove it before you can lease it.' % mac) - else - print("Removing %s from whitelist" % mac) - remove_whitelist(mac) - whitelist_macs[mac] = nil - end - end - - if cmd == "whitelist" and leased_macs[mac] then - print("Removing %s from leases" % mac) - remove_lease(mac) - leased_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 - if not whitelist_macs[mac] then - print("Adding %s to leases" % mac) - add_lease(mac) - leased_macs[mac] = true - end - 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) - elseif cmd == "sync" then - sync() - os.exit(0) - elseif cmd == "list" then - list() - os.exit(0) - else - 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) - end -end - --- Get current arp cache -function get_arpcache() - local arpcache = { } - for _, entry in ipairs(net.arptable()) do - arpcache[entry["HW address"]:lower()] = { entry["Device"]:lower(), entry["IP address"]:lower() } - end - return arpcache -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_leases", "lease", function(s) - if s.mac then - leased_macs[s.mac:lower()] = true - end - end) - end - - if not list or list == "whitelist" then - uci:foreach("luci_splash", "whitelist", function(s) - if s.mac then - leased_macs[s.mac:lower()] = true - end - end) - end - - if not list or list == "blacklist" then - uci:foreach("luci_splash", "blacklist", function(s) - if s.mac then - leased_macs[s.mac:lower()] = true - end - end) - end - return leased_macs -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 - - exec("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 - -function ipt6_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 - - exec("ip6tables -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 - - --- Convert mac to uci-compatible section name -function convert_mac_to_secname(mac) - return string.gsub(mac, ":", "") -end - --- Add a lease to state and invoke add_rule -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"]:lower() == mac then - ipaddr = entry["IP address"] - break - end - end - - -- Add lease if there is an ip addr - if ipaddr then - local device = get_device_for_ip(ipaddr) - if not no_uci then - local leased = uci:get("luci_splash_leases", "stats", "leases") - if type(tonumber(leased)) == "number" then - update_stats(leased + 1, nil, nil, nil, nil) - end - - uci:section("luci_splash_leases", "lease", convert_mac_to_secname(mac), { - mac = mac, - ipaddr = ipaddr, - device = device, - limit_up = limit_up, - limit_down = limit_down, - start = os.time() - }) - uci:save("luci_splash_leases") - end - add_lease_rule(mac, ipaddr, device) - else - print("Found no active IP for %s, lease not added" % mac) - end -end - - --- Remove a lease from state and invoke remove_rule -function remove_lease(mac) - mac = mac:lower() - - uci:delete_all("luci_splash_leases", "lease", - function(s) - if s.mac:lower() == mac then - - local leased = uci:get("luci_splash_leases", "stats", "leases") - if type(tonumber(leased)) == "number" and tonumber(leased) > 0 then - update_stats(leased - 1, nil, nil, nil, nil) - end - remove_lease_rule(mac, s.ipaddr, s.device, tonumber(s.limit_up), tonumber(s.limit_down)) - return true - end - return false - end) - - uci:save("luci_splash_leases") -end - - --- Add a whitelist entry -function add_whitelist(mac) - uci:section("luci_splash", "whitelist", convert_mac_to_secname(mac), { mac = mac }) - uci:save("luci_splash") - uci:commit("luci_splash") - add_whitelist_rule(mac) -end - - --- Add a blacklist entry -function add_blacklist(mac) - uci:section("luci_splash", "blacklist", convert_mac_to_secname(mac), { 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) - remove_whitelist_tc(mac) -end - -function remove_whitelist_tc(mac) - uci:foreach("luci_splash", "iface", function(s) - local device = get_physdev(s['.name']) - if device and device ~= "" then - if debug then - print("Removing whitelist filters for %s interface %s." % {mac, device}) - end - local handle = get_filter_handle('ffff:', 'src', device, mac) - if handle then - exec('tc filter del dev "%s" parent ffff: protocol ip prio 1 handle %s u32' % { device, handle }) - else - print('Warning! Could not get a handle for %s parent :ffff on interface %s' % { mac, device }) - end - local handle = get_filter_handle('1:', 'dest', device, mac) - if handle then - exec('tc filter del dev "%s" parent 1:0 protocol ip prio 1 handle %s u32' % { device, handle }) - else - print('Warning! Could not get a handle for %s parent 1:0 on interface %s' % { mac, device }) - end - end - end) -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, device) - local id - if ipaddr then - id = get_id(ipaddr) - end - - exec("iptables -t mangle -I luci_splash_mark_out -m mac --mac-source %q -j RETURN" % mac) - - -- Mark incoming packets to a splashed host - -- for ipv4 - by iptables and destination - if id and device then - exec("iptables -t mangle -I luci_splash_mark_in -d %q -j MARK --set-mark 0x1%s -m comment --comment %s" % {ipaddr, id, mac:upper()}) - end - - --for ipv6: need to use the mac here - - if has_ipv6 then - exec("ip6tables -t mangle -I luci_splash_mark_out -m mac --mac-source %q -j MARK --set-mark 79" % mac) - if id and device and tonumber(limit_down) then - exec("tc filter add dev %s parent 1:0 protocol ipv6 prio 1 u32 match ether dst %s classid 1:%s" % {device, mac:lower(), id}) - end - end - - - if device and tonumber(limit_up) > 0 then - exec('tc filter add dev "%s" parent ffff: protocol all prio 2 u32 match ether src %s police rate %skbit mtu 6k burst 6k drop' % {device, mac, limit_up}) - end - - if id and device and tonumber(limit_down) > 0 then - exec("tc class add dev %s parent 1: classid 1:0x%s htb rate %skbit" % { device, id, limit_down }) - exec("tc qdisc add dev %s parent 1:%s sfq perturb 10" % { device, id }) - end - - exec("iptables -t filter -I luci_splash_filter -m mac --mac-source %q -j RETURN" % mac) - exec("iptables -t nat -I luci_splash_leases -m mac --mac-source %q -j RETURN" % mac) - if has_ipv6 then - exec("ip6tables -t filter -I luci_splash_filter -m mac --mac-source %q -j RETURN" % mac) - end -end - - --- Remove lease, black- or whitelist rules -function remove_lease_rule(mac, ipaddr, device, limit_up, limit_down) - - local id - if ipaddr then - id = get_id(ipaddr) - end - - ipt:resync() - ipt_delete_all({table="mangle", chain="luci_splash_mark_in", options={"/*", mac:upper()}}) - ipt_delete_all({table="mangle", chain="luci_splash_mark_out", options={"MAC", mac:upper()}}) - 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()}}) - if has_ipv6 then - ipt6_delete_all({table="mangle", chain="luci_splash_mark_out", options={"MAC", mac:upper()}}) - ipt6_delete_all({table="filter", chain="luci_splash_filter", options={"MAC", mac:upper()}}) - end - - if device and tonumber(limit_up) > 0 then - local handle = get_filter_handle('ffff:', 'src', device, mac) - if handle then - exec('tc filter del dev "%s" parent ffff: protocol all prio 2 handle %s u32 police rate %skbit mtu 6k burst 6k drop' % {device, handle, limit_up}) - else - print('Warning! Could not get a handle for %s parent :ffff on interface %s' % { mac, device }) - end - end - -- remove clients class - if device and id then - exec('tc class del dev "%s" classid 1:%s' % {device, id}) - exec('tc filter del dev "%s" parent 1:0 prio 1' % device) -- ipv6 rule - --exec('tc qdisc del dev "%s" parent 1:%s sfq perturb 10' % { device, id }) - end -end - - --- Add whitelist rules -function add_whitelist_rule(mac) - exec("iptables -t filter -I luci_splash_filter -m mac --mac-source %q -j RETURN" % mac) - exec("iptables -t nat -I luci_splash_leases -m mac --mac-source %q -j RETURN" % mac) - if has_ipv6 then - exec("ip6tables -t filter -I luci_splash_filter -m mac --mac-source %q -j RETURN" % mac) - end - uci:foreach("luci_splash", "iface", function(s) - local device = get_physdev(s['.name']) - if device and device ~= "" then - exec('tc filter add dev "%s" parent ffff: protocol ip prio 1 u32 match ether src %s police pass' % { device, mac }) - exec('tc filter add dev "%s" parent 1:0 protocol ip prio 1 u32 match ether dst %s classid 1:1' % { device, mac }) - end - end) -end - - --- Add blacklist rules -function add_blacklist_rule(mac) - exec("iptables -t filter -I luci_splash_filter -m mac --mac-source %q -j DROP" % mac) - if has_ipv6 then - exec("ip6tables -t filter -I luci_splash_filter -m mac --mac-source %q -j DROP" % mac) - end -end - - --- Synchronise leases, remove abandoned rules -function sync() - lock() - - local time = os.time() - - -- Current leases in state files - local leases = uci:get_all("luci_splash_leases") - - -- Convert leasetime to seconds - local leasetime = tonumber(uci:get("luci_splash", "general", "leasetime")) * 3600 - - -- Clean state file - uci:load("luci_splash_leases") - uci:revert("luci_splash_leases") - - - local arpcache = get_arpcache() - - local blackwhitelist = uci:get_all("luci_splash") - local whitelist_total = 0 - local whitelist_online = 0 - local blacklist_total = 0 - local blacklist_online = 0 - local leasecount = 0 - local leases_online = 0 - - -- For all leases - for k, v in pairs(leases) do - if v[".type"] == "lease" then - if os.difftime(time, tonumber(v.start)) > leasetime then - -- Remove expired - remove_lease_rule(v.mac, v.ipaddr, v.device, tonumber(v.limit_up), tonumber(v.limit_down)) - else - leasecount = leasecount + 1 - - -- only count leases_online for connected clients - if arpcache[v.mac] then - leases_online = leases_online + 1 - end - - -- Rewrite state - uci:section("luci_splash_leases", "lease", convert_mac_to_secname(v.mac), { - mac = v.mac, - ipaddr = v.ipaddr, - device = v.device, - limit_up = limit_up, - limit_down = limit_down, - start = v.start - }) - end - end - end - - -- Whitelist, Blacklist - for _, s in utl.spairs(blackwhitelist, - function(a,b) return blackwhitelist[a][".type"] > blackwhitelist[b][".type"] end - ) do - if (s[".type"] == "whitelist") then - whitelist_total = whitelist_total + 1 - if s.mac then - local mac = s.mac:lower() - if arpcache[mac] then - whitelist_online = whitelist_online + 1 - end - end - end - if (s[".type"] == "blacklist") then - blacklist_total = blacklist_total + 1 - if s.mac then - local mac = s.mac:lower() - if arpcache[mac] then - blacklist_online = blacklist_online + 1 - end - end - end - end - - -- ToDo: - -- include a new field "leases_online" in stats to differ between active clients and leases: - -- update_stats(leasecount, leases_online, whitelist_online, whitelist_total, blacklist_online, blacklist_total) later: - update_stats(leases_online, whitelist_online, whitelist_total, blacklist_online, blacklist_total) - - uci:save("luci_splash_leases") - - -- Get the mac addresses of current leases - local macs = get_known_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 macs[r.options[2]:lower()] end) - - - if has_ipv6 then - ipt6_delete_all({table="filter", chain="luci_splash_filter", options={"MAC"}}, - function(r) return not macs[r.options[2]:lower()] end) - ipt6_delete_all({table="mangle", chain="luci_splash_mark_out", options={"MAC", "MARK", "set"}}, - function(r) return not macs[r.options[2]:lower()] end) - end - - unlock() -end - --- Show client info -function list() - local arpcache = get_arpcache() - -- 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_leases") - local blackwhitelist = 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 utl.spairs(blackwhitelist, - function(a,b) return blackwhitelist[a][".type"] > blackwhitelist[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 - -main(arg) |