d2b860e588457e80ab019870b4fb92a76411d9a5
[project/luci.git] / applications / luci-splash / root / usr / sbin / luci-splash
1 #!/usr/bin/lua
2
3 utl = require "luci.util"
4 sys = require "luci.sys"
5
6 require("luci.model.uci")
7 require("luci.sys.iptparser")
8
9 -- Init state session
10 local uci = luci.model.uci.cursor_state()
11 local ipt = luci.sys.iptparser.IptParser()
12 local net = sys.net
13 local fs = require "luci.fs"
14 local ip = require "luci.ip"
15
16 local debug = false
17
18 local has_ipv6 = fs.access("/proc/net/ipv6_route") and fs.access("/usr/sbin/ip6tables")
19
20 function lock()
21 os.execute("lock /var/run/luci_splash.lock")
22 end
23
24 function unlock()
25 os.execute("lock -u /var/run/luci_splash.lock")
26 end
27
28 function exec(cmd)
29 local ret = sys.exec(cmd)
30 if debug then
31 print('+ ' .. cmd)
32 if ret and ret ~= "" then
33 print(ret)
34 end
35 end
36 end
37
38 function get_id(ip)
39 local o3, o4 = ip:match("[0-9]+%.[0-9]+%.([0-9]+)%.([0-9]+)")
40 if o3 and 04 then
41 return string.format("%02X%s", tonumber(o3), "") .. string.format("%02X%s", tonumber(o4), "")
42 else
43 return false
44 end
45 end
46
47 function update_stats(leased, whitelisted, whitelisttotal, blacklisted, blacklisttotal)
48 local leases = uci:get_all("luci_splash_leases", "stats")
49 uci:delete("luci_splash_leases", "stats")
50 uci:section("luci_splash_leases", "stats", "stats", {
51 leases = leased or (leases and leases.leases) or 0,
52 whitelisttotal = whitelisttotal or (leased and leases.whitelisttotal) or 0,
53 whitelistonline = whitelisted or (leases and leases.whitelistonline) or 0,
54 blacklisttotal = blacklisttotal or (leases and leases.blacklisttotal) or 0,
55 blacklistonline = blacklisted or (leases and leases.blacklistonline) or 0,
56 })
57 uci:save("luci_splash_leases")
58 end
59
60 function get_device_for_ip(ipaddr)
61 local dev
62 uci:foreach("network", "interface", function(s)
63 if s.ipaddr and s.netmask then
64 local network = ip.IPv4(s.ipaddr, s.netmask)
65 if network:contains(ip.IPv4(ipaddr)) then
66 -- this should be rewritten to luci functions if possible
67 dev = utl.trim(sys.exec(". /lib/functions/network.sh; network_get_device IFNAME '" .. s['.name'] .. "'; echo $IFNAME"))
68 end
69 end
70 end)
71 return dev
72 end
73
74 function get_physdev(interface)
75 local dev
76 dev = utl.trim(sys.exec(". /lib/functions/network.sh; network_get_device IFNAME '" .. interface .. "'; echo $IFNAME"))
77 return dev
78 end
79
80
81
82 function get_filter_handle(parent, direction, device, mac)
83 local input = utl.split(sys.exec('/usr/sbin/tc filter show dev ' .. device .. ' parent ' .. parent) or {})
84 local tbl = {}
85 local handle
86 for k, v in pairs(input) do
87 handle = v:match('filter protocol ip pref %d+ u32 fh (%d*:%d*:%d*) order')
88 if handle then
89 local mac, mac1, mac2, mac3, mac4, mac5, mac6
90 if direction == 'src' then
91 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')
92 mac5, mac6 = input[k+2]:match('match ([%a%d][%a%d])([%a%d][%a%d])0000/ffff0000')
93 else
94 mac1, mac2 = input[k+1]:match('match 0000([%a%d][%a%d])([%a%d][%a%d])/0000ffff')
95 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')
96 end
97 if mac1 and mac2 and mac3 and mac4 and mac5 and mac6 then
98 mac = "%s:%s:%s:%s:%s:%s" % { mac1, mac2, mac3, mac4, mac5, mac6 }
99 tbl[mac] = handle
100 end
101 end
102 end
103 if tbl[mac] then
104 handle = tbl[mac]
105 end
106 return handle
107 end
108
109 function macvalid(mac)
110 if mac and mac:match(
111 "^[a-fA-F0-9][a-fA-F0-9]:[a-fA-F0-9][a-fA-F0-9]:" ..
112 "[a-fA-F0-9][a-fA-F0-9]:[a-fA-F0-9][a-fA-F0-9]:" ..
113 "[a-fA-F0-9][a-fA-F0-9]:[a-fA-F0-9][a-fA-F0-9]$"
114 ) then
115 return true
116 end
117
118 return false
119 end
120
121 function ipvalid(ipaddr)
122 if ipaddr then
123 return ip.IPv4(ipaddr) and true or false
124 end
125
126 return false
127 end
128
129 function main(argv)
130 local cmd = table.remove(argv, 1)
131 local arg = argv[1]
132
133 limit_up = (tonumber(uci:get("luci_splash", "general", "limit_up")) or 0) * 8
134 limit_down = (tonumber(uci:get("luci_splash", "general", "limit_down")) or 0) * 8
135
136 if ( cmd == "lease" or cmd == "add-rules" or cmd == "remove" or
137 cmd == "whitelist" or cmd == "blacklist" or cmd == "status" ) and #argv > 0
138 then
139 if not (macvalid(arg) or ipvalid(arg)) then
140 print("Invalid argument. The second argument must " ..
141 "be a valid IPv4 or Mac Address.")
142 os.exit(1)
143 end
144
145 lock()
146
147 local arp_cache = net.arptable()
148 local leased_macs = get_known_macs("lease")
149 local blacklist_macs = get_known_macs("blacklist")
150 local whitelist_macs = get_known_macs("whitelist")
151
152 for i, adr in ipairs(argv) do
153 local mac = nil
154 if adr:find(":") then
155 mac = adr:lower()
156 else
157 for _, e in ipairs(arp_cache) do
158 if e["IP address"] == adr then
159 mac = e["HW address"]:lower()
160 break
161 end
162 end
163 end
164
165 if mac and cmd == "add-rules" then
166 if leased_macs[mac] then
167 add_lease(mac, arp_cache, true)
168 elseif blacklist_macs[mac] then
169 add_blacklist_rule(mac)
170 elseif whitelist_macs[mac] then
171 add_whitelist_rule(mac)
172 end
173 elseif mac and cmd == "status" then
174 print(leased_macs[mac] and "lease"
175 or whitelist_macs[mac] and "whitelist"
176 or blacklist_macs[mac] and "blacklist"
177 or "new")
178 elseif mac and ( cmd == "whitelist" or cmd == "blacklist" or cmd == "lease" ) then
179 if cmd ~= "lease" and leased_macs[mac] then
180 print("Removing %s from leases" % mac)
181 remove_lease(mac)
182 leased_macs[mac] = nil
183 end
184
185 if cmd ~= "whitelist" and whitelist_macs[mac] then
186 print("Removing %s from whitelist" % mac)
187 remove_whitelist(mac)
188 whitelist_macs[mac] = nil
189 end
190
191 if cmd ~= "blacklist" and blacklist_macs[mac] then
192 print("Removing %s from blacklist" % mac)
193 remove_blacklist(mac)
194 blacklist_macs[mac] = nil
195 end
196
197 if cmd == "lease" and not leased_macs[mac] then
198 print("Adding %s to leases" % mac)
199 add_lease(mac)
200 leased_macs[mac] = true
201 elseif cmd == "whitelist" and not whitelist_macs[mac] then
202 print("Adding %s to whitelist" % mac)
203 add_whitelist(mac)
204 whitelist_macs[mac] = true
205 elseif cmd == "blacklist" and not blacklist_macs[mac] then
206 print("Adding %s to blacklist" % mac)
207 add_blacklist(mac)
208 blacklist_macs[mac] = true
209 else
210 print("The mac %s is already %sed" %{ mac, cmd })
211 end
212 elseif mac and cmd == "remove" then
213 if leased_macs[mac] then
214 print("Removing %s from leases" % mac)
215 remove_lease(mac)
216 leased_macs[mac] = nil
217 elseif whitelist_macs[mac] then
218 print("Removing %s from whitelist" % mac)
219 remove_whitelist(mac)
220 whitelist_macs[mac] = nil
221 elseif blacklist_macs[mac] then
222 print("Removing %s from blacklist" % mac)
223 remove_blacklist(mac)
224 blacklist_macs[mac] = nil
225 else
226 print("The mac %s is not known" % mac)
227 end
228 else
229 print("Can not find mac for ip %s" % argv[i])
230 end
231 end
232
233 unlock()
234 os.exit(0)
235 elseif cmd == "sync" then
236 sync()
237 os.exit(0)
238 elseif cmd == "list" then
239 list()
240 os.exit(0)
241 else
242 print("Usage:")
243 print("\n luci-splash list\n List connected, black- and whitelisted clients")
244 print("\n luci-splash sync\n Synchronize firewall rules and clear expired leases")
245 print("\n luci-splash lease <MAC-or-IP>\n Create a lease for the given address")
246 print("\n luci-splash blacklist <MAC-or-IP>\n Add given address to blacklist")
247 print("\n luci-splash whitelist <MAC-or-IP>\n Add given address to whitelist")
248 print("\n luci-splash remove <MAC-or-IP>\n Remove given address from the lease-, black- or whitelist")
249 print("")
250
251 os.exit(1)
252 end
253 end
254
255 -- Get current arp cache
256 function get_arpcache()
257 local arpcache = { }
258 for _, entry in ipairs(net.arptable()) do
259 arpcache[entry["HW address"]:lower()] = { entry["Device"]:lower(), entry["IP address"]:lower() }
260 end
261 return arpcache
262 end
263
264 -- Get a list of known mac addresses
265 function get_known_macs(list)
266 local leased_macs = { }
267
268 if not list or list == "lease" then
269 uci:foreach("luci_splash_leases", "lease",
270 function(s) leased_macs[s.mac:lower()] = true end)
271 end
272
273 if not list or list == "whitelist" then
274 uci:foreach("luci_splash", "whitelist",
275 function(s) leased_macs[s.mac:lower()] = true end)
276 end
277
278 if not list or list == "blacklist" then
279 uci:foreach("luci_splash", "blacklist",
280 function(s) leased_macs[s.mac:lower()] = true end)
281 end
282
283 return leased_macs
284 end
285
286
287 -- Helper to delete iptables rules
288 function ipt_delete_all(args, comp, off)
289 off = off or { }
290 for i, r in ipairs(ipt:find(args)) do
291 if comp == nil or comp(r) then
292 off[r.table] = off[r.table] or { }
293 off[r.table][r.chain] = off[r.table][r.chain] or 0
294
295 exec("iptables -t %q -D %q %d 2>/dev/null"
296 %{ r.table, r.chain, r.index - off[r.table][r.chain] })
297
298 off[r.table][r.chain] = off[r.table][r.chain] + 1
299 end
300 end
301 end
302
303 function ipt6_delete_all(args, comp, off)
304 off = off or { }
305 for i, r in ipairs(ipt:find(args)) do
306 if comp == nil or comp(r) then
307 off[r.table] = off[r.table] or { }
308 off[r.table][r.chain] = off[r.table][r.chain] or 0
309
310 exec("ip6tables -t %q -D %q %d 2>/dev/null"
311 %{ r.table, r.chain, r.index - off[r.table][r.chain] })
312
313 off[r.table][r.chain] = off[r.table][r.chain] + 1
314 end
315 end
316 end
317
318
319 -- Convert mac to uci-compatible section name
320 function convert_mac_to_secname(mac)
321 return string.gsub(mac, ":", "")
322 end
323
324 -- Add a lease to state and invoke add_rule
325 function add_lease(mac, arp, no_uci)
326 mac = mac:lower()
327
328 -- Get current ip address
329 local ipaddr
330 for _, entry in ipairs(arp or net.arptable()) do
331 if entry["HW address"]:lower() == mac then
332 ipaddr = entry["IP address"]
333 break
334 end
335 end
336
337 -- Add lease if there is an ip addr
338 if ipaddr then
339 local device = get_device_for_ip(ipaddr)
340 if not no_uci then
341 local leased = uci:get("luci_splash_leases", "stats", "leases")
342 if type(tonumber(leased)) == "number" then
343 update_stats(leased + 1, nil, nil, nil, nil)
344 end
345
346 uci:section("luci_splash_leases", "lease", convert_mac_to_secname(mac), {
347 mac = mac,
348 ipaddr = ipaddr,
349 device = device,
350 limit_up = limit_up,
351 limit_down = limit_down,
352 start = os.time()
353 })
354 uci:save("luci_splash_leases")
355 end
356 add_lease_rule(mac, ipaddr, device)
357 else
358 print("Found no active IP for %s, lease not added" % mac)
359 end
360 end
361
362
363 -- Remove a lease from state and invoke remove_rule
364 function remove_lease(mac)
365 mac = mac:lower()
366
367 uci:delete_all("luci_splash_leases", "lease",
368 function(s)
369 if s.mac:lower() == mac then
370 remove_lease_rule(mac, s.ipaddr, s.device, tonumber(s.limit_up), tonumber(s.limit_down))
371 local leased = uci:get("luci_splash_leases", "stats", "leases")
372 if type(tonumber(leased)) == "number" and tonumber(leased) > 0 then
373 update_stats(leased - 1, nil, nil, nil, nil)
374 end
375 return true
376 end
377 return false
378 end)
379
380 uci:save("luci_splash_leases")
381 end
382
383
384 -- Add a whitelist entry
385 function add_whitelist(mac)
386 uci:section("luci_splash", "whitelist", convert_mac_to_secname(mac), { mac = mac })
387 uci:save("luci_splash")
388 uci:commit("luci_splash")
389 add_whitelist_rule(mac)
390 end
391
392
393 -- Add a blacklist entry
394 function add_blacklist(mac)
395 uci:section("luci_splash", "blacklist", convert_mac_to_secname(mac), { mac = mac })
396 uci:save("luci_splash")
397 uci:commit("luci_splash")
398 add_blacklist_rule(mac)
399 end
400
401
402 -- Remove a whitelist entry
403 function remove_whitelist(mac)
404 mac = mac:lower()
405 uci:delete_all("luci_splash", "whitelist",
406 function(s) return not s.mac or s.mac:lower() == mac end)
407 uci:save("luci_splash")
408 uci:commit("luci_splash")
409 remove_lease_rule(mac)
410 remove_whitelist_tc(mac)
411 end
412
413 function remove_whitelist_tc(mac)
414 uci:foreach("luci_splash", "iface", function(s)
415 local device = get_physdev(s['.name'])
416 if device and device ~= "" then
417 if debug then
418 print("Removing whitelist filters for %s interface %s." % {mac, device})
419 end
420 local handle = get_filter_handle('ffff:', 'src', device, mac)
421 if handle then
422 exec('tc filter del dev "%s" parent ffff: protocol ip prio 1 handle %s u32' % { device, handle })
423 else
424 print('Warning! Could not get a handle for %s parent :ffff on interface %s' % { mac, device })
425 end
426 local handle = get_filter_handle('1:', 'dest', device, mac)
427 if handle then
428 exec('tc filter del dev "%s" parent 1:0 protocol ip prio 1 handle %s u32' % { device, handle })
429 else
430 print('Warning! Could not get a handle for %s parent 1:0 on interface %s' % { mac, device })
431 end
432 end
433 end)
434 end
435
436 -- Remove a blacklist entry
437 function remove_blacklist(mac)
438 mac = mac:lower()
439 uci:delete_all("luci_splash", "blacklist",
440 function(s) return not s.mac or s.mac:lower() == mac end)
441 uci:save("luci_splash")
442 uci:commit("luci_splash")
443 remove_lease_rule(mac)
444 end
445
446
447 -- Add an iptables rule
448 function add_lease_rule(mac, ipaddr, device)
449 local id
450 if ipaddr then
451 id = get_id(ipaddr)
452 end
453
454 exec("iptables -t mangle -I luci_splash_mark_out -m mac --mac-source %q -j RETURN" % mac)
455
456 if id and device then
457 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()})
458 end
459
460 if has_ipv6 then
461 exec("ip6tables -t mangle -I luci_splash_mark_out -m mac --mac-source %q -j MARK --set-mark 79" % mac)
462 -- not working yet, needs the ip6addr
463 --exec("ip6tables -t mangle -I luci_splash_mark_in -d %q -j MARK --set-mark 80 -m comment --comment %s" % {ipaddr, mac:upper()})
464 end
465
466
467 if device and tonumber(limit_up) > 0 then
468 exec('tc filter add dev "%s" parent ffff: protocol ip prio 2 u32 match ether src %s police rate %skbit mtu 6k burst 6k drop' % {device, mac, limit_up})
469 end
470
471 if id and device and tonumber(limit_down) > 0 then
472 exec("tc class add dev %s parent 1: classid 1:0x%s htb rate %skbit" % { device, id, limit_down })
473 exec("tc qdisc add dev %s parent 1:%s sfq perturb 10" % { device, id })
474 end
475
476 exec("iptables -t filter -I luci_splash_filter -m mac --mac-source %q -j RETURN" % mac)
477 exec("iptables -t nat -I luci_splash_leases -m mac --mac-source %q -j RETURN" % mac)
478 if has_ipv6 then
479 exec("ip6tables -t filter -I luci_splash_filter -m mac --mac-source %q -j RETURN" % mac)
480 end
481 end
482
483
484 -- Remove lease, black- or whitelist rules
485 function remove_lease_rule(mac, ipaddr, device, limit_up, limit_down)
486 local id
487 if ipaddr then
488 id = get_id(ipaddr)
489 end
490
491 ipt:resync()
492 ipt_delete_all({table="mangle", chain="luci_splash_mark_in", options={"/*", mac:upper()}})
493 ipt_delete_all({table="mangle", chain="luci_splash_mark_out", options={"MAC", mac:upper()}})
494 ipt_delete_all({table="filter", chain="luci_splash_filter", options={"MAC", mac:upper()}})
495 ipt_delete_all({table="nat", chain="luci_splash_leases", options={"MAC", mac:upper()}})
496 if has_ipv6 then
497 ipt6_delete_all({table="mangle", chain="luci_splash_mark_out", options={"MAC", mac:upper()}})
498 ipt6_delete_all({table="filter", chain="luci_splash_filter", options={"MAC", mac:upper()}})
499 end
500 if device and tonumber(limit_up) > 0 then
501 local handle = get_filter_handle('ffff:', 'src', device, mac)
502 if handle then
503 exec('tc filter del dev "%s" parent ffff: protocol ip prio 2 handle %s u32 police rate %skbit mtu 6k burst 6k drop' % {device, handle, limit_up})
504 else
505 print('Warning! Could not get a handle for %s parent :ffff on interface %s' % { mac, device })
506 end
507 end
508
509 -- remove clients class
510 if device and id then
511 exec('tc class del dev "%s" classid 1:%s' % {device, id})
512 exec('tc qdisc del dev "%s" parent 1:%s sfq perturb 10' % { device, id })
513 end
514
515 end
516
517
518 -- Add whitelist rules
519 function add_whitelist_rule(mac)
520 exec("iptables -t filter -I luci_splash_filter -m mac --mac-source %q -j RETURN" % mac)
521 exec("iptables -t nat -I luci_splash_leases -m mac --mac-source %q -j RETURN" % mac)
522 if has_ipv6 then
523 exec("ip6tables -t filter -I luci_splash_filter -m mac --mac-source %q -j RETURN" % mac)
524 end
525 uci:foreach("luci_splash", "iface", function(s)
526 local device = get_physdev(s['.name'])
527 if device and device ~= "" then
528 exec('tc filter add dev "%s" parent ffff: protocol ip prio 1 u32 match ether src %s police pass' % { device, mac })
529 exec('tc filter add dev "%s" parent 1:0 protocol ip prio 1 u32 match ether dst %s classid 1:1' % { device, mac })
530 end
531 end)
532 end
533
534
535 -- Add blacklist rules
536 function add_blacklist_rule(mac)
537 exec("iptables -t filter -I luci_splash_filter -m mac --mac-source %q -j DROP" % mac)
538 if has_ipv6 then
539 exec("ip6tables -t filter -I luci_splash_filter -m mac --mac-source %q -j DROP" % mac)
540 end
541 end
542
543
544 -- Synchronise leases, remove abandoned rules
545 function sync()
546 lock()
547
548 local time = os.time()
549
550 -- Current leases in state files
551 local leases = uci:get_all("luci_splash_leases")
552
553 -- Convert leasetime to seconds
554 local leasetime = tonumber(uci:get("luci_splash", "general", "leasetime")) * 3600
555
556 -- Clean state file
557 uci:load("luci_splash_leases")
558 uci:revert("luci_splash_leases")
559
560 -- For all leases
561 local leasecount = 0
562 for k, v in pairs(leases) do
563 if v[".type"] == "lease" then
564 if os.difftime(time, tonumber(v.start)) > leasetime then
565 -- Remove expired
566 remove_lease_rule(v.mac, v.ipaddr, v.device, tonumber(v.limit_up), tonumber(v.limit_down))
567 else
568 leasecount = leasecount + 1
569 -- Rewrite state
570 uci:section("luci_splash_leases", "lease", convert_mac_to_secname(v.mac), {
571 mac = v.mac,
572 ipaddr = v.ipaddr,
573 device = v.device,
574 limit_up = limit_up,
575 limit_down = limit_down,
576 start = v.start
577 })
578 end
579 end
580 end
581
582 -- Get the mac addresses of current leases
583 local macs = get_known_macs()
584 local arpcache = get_arpcache()
585
586 local blackwhitelist = uci:get_all("luci_splash")
587 local whitelist_total = 0
588 local whitelist_online = 0
589 local blacklist_total = 0
590 local blacklist_online = 0
591
592 -- Whitelist, Blacklist
593 for _, s in utl.spairs(blackwhitelist,
594 function(a,b) return blackwhitelist[a][".type"] > blackwhitelist[b][".type"] end
595 ) do
596 if (s[".type"] == "whitelist") then
597 whitelist_total = whitelist_total + 1
598 if s.mac then
599 local mac = s.mac:lower()
600 if arpcache[mac] then
601 whitelist_online = whitelist_online + 1
602 end
603 end
604 end
605 if (s[".type"] == "blacklist") then
606 blacklist_total = blacklist_total + 1
607 if s.mac then
608 local mac = s.mac:lower()
609 if arpcache[mac] then
610 blacklist_online = blacklist_online + 1
611 end
612 end
613 end
614 end
615
616 update_stats(leasecount, whitelist_online, whitelist_total, blacklist_online, blacklist_total)
617
618 uci:save("luci_splash_leases")
619
620 ipt:resync()
621
622 ipt_delete_all({table="filter", chain="luci_splash_filter", options={"MAC"}},
623 function(r) return not macs[r.options[2]:lower()] end)
624 ipt_delete_all({table="nat", chain="luci_splash_leases", options={"MAC"}},
625 function(r) return not macs[r.options[2]:lower()] end)
626 ipt_delete_all({table="mangle", chain="luci_splash_mark_out", options={"MAC", "MARK", "set"}},
627 function(r) return not macs[r.options[2]:lower()] end)
628 ipt_delete_all({table="mangle", chain="luci_splash_mark_in", options={"/*", "MARK", "set"}},
629 function(r) return not macs[r.options[2]:lower()] end)
630
631
632 if has_ipv6 then
633 ipt6_delete_all({table="filter", chain="luci_splash_filter", options={"MAC"}},
634 function(r) return not macs[r.options[2]:lower()] end)
635 ipt6_delete_all({table="mangle", chain="luci_splash_mark_out", options={"MAC", "MARK", "set"}},
636 function(r) return not macs[r.options[2]:lower()] end)
637 end
638
639 unlock()
640 end
641
642 -- Show client info
643 function list()
644 local arpcache = get_arpcache()
645 -- Find traffic usage
646 local function traffic(lease)
647 local traffic_in = 0
648 local traffic_out = 0
649
650 local rin = ipt:find({table="mangle", chain="luci_splash_mark_in", destination=lease.ipaddr})
651 local rout = ipt:find({table="mangle", chain="luci_splash_mark_out", options={"MAC", lease.mac:upper()}})
652
653 if rin and #rin > 0 then traffic_in = math.floor( rin[1].bytes / 1024) end
654 if rout and #rout > 0 then traffic_out = math.floor(rout[1].bytes / 1024) end
655
656 return traffic_in, traffic_out
657 end
658
659 -- Print listings
660 local leases = uci:get_all("luci_splash_leases")
661 local blackwhitelist = uci:get_all("luci_splash")
662
663 print(string.format(
664 "%-17s %-15s %-9s %-4s %-7s %20s",
665 "MAC", "IP", "State", "Dur.", "Intf.", "Traffic down/up"
666 ))
667
668 -- Leases
669 for _, s in pairs(leases) do
670 if s[".type"] == "lease" and s.mac then
671 local ti, to = traffic(s)
672 local mac = s.mac:lower()
673 local arp = arpcache[mac]
674 print(string.format(
675 "%-17s %-15s %-9s %3dm %-7s %7dKB %7dKB",
676 mac, s.ipaddr, "leased",
677 math.floor(( os.time() - tonumber(s.start) ) / 60),
678 arp and arp[1] or "?", ti, to
679 ))
680 end
681 end
682
683 -- Whitelist, Blacklist
684 for _, s in utl.spairs(blackwhitelist,
685 function(a,b) return blackwhitelist[a][".type"] > blackwhitelist[b][".type"] end
686 ) do
687 if (s[".type"] == "whitelist" or s[".type"] == "blacklist") and s.mac then
688 local mac = s.mac:lower()
689 local arp = arpcache[mac]
690 print(string.format(
691 "%-17s %-15s %-9s %4s %-7s %9s %9s",
692 mac, arp and arp[2] or "?", s[".type"],
693 "- ", arp and arp[1] or "?", "-", "-"
694 ))
695 end
696 end
697 end
698
699 main(arg)