5051d60b7ca4f2aa3cb5c12fdd60f3f059b036e7
[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 = true
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 if cmd == "lease" then
187 print('%s is whitelisted. Remove it before you can lease it.' % mac)
188 else
189 print("Removing %s from whitelist" % mac)
190 remove_whitelist(mac)
191 whitelist_macs[mac] = nil
192 end
193 end
194
195 if cmd == "whitelist" and leased_macs[mac] then
196 print("Removing %s from leases" % mac)
197 remove_lease(mac)
198 leased_macs[mac] = nil
199 end
200
201 if cmd ~= "blacklist" and blacklist_macs[mac] then
202 print("Removing %s from blacklist" % mac)
203 remove_blacklist(mac)
204 blacklist_macs[mac] = nil
205 end
206
207 if cmd == "lease" and not leased_macs[mac] then
208 if not whitelist_macs[mac] then
209 print("Adding %s to leases" % mac)
210 add_lease(mac)
211 leased_macs[mac] = true
212 end
213 elseif cmd == "whitelist" and not whitelist_macs[mac] then
214 print("Adding %s to whitelist" % mac)
215 add_whitelist(mac)
216 whitelist_macs[mac] = true
217 elseif cmd == "blacklist" and not blacklist_macs[mac] then
218 print("Adding %s to blacklist" % mac)
219 add_blacklist(mac)
220 blacklist_macs[mac] = true
221 else
222 print("The mac %s is already %sed" %{ mac, cmd })
223 end
224 elseif mac and cmd == "remove" then
225 if leased_macs[mac] then
226 print("Removing %s from leases" % mac)
227 remove_lease(mac)
228 leased_macs[mac] = nil
229 elseif whitelist_macs[mac] then
230 print("Removing %s from whitelist" % mac)
231 remove_whitelist(mac)
232 whitelist_macs[mac] = nil
233 elseif blacklist_macs[mac] then
234 print("Removing %s from blacklist" % mac)
235 remove_blacklist(mac)
236 blacklist_macs[mac] = nil
237 else
238 print("The mac %s is not known" % mac)
239 end
240 else
241 print("Can not find mac for ip %s" % argv[i])
242 end
243 end
244
245 unlock()
246 os.exit(0)
247 elseif cmd == "sync" then
248 sync()
249 os.exit(0)
250 elseif cmd == "list" then
251 list()
252 os.exit(0)
253 else
254 print("Usage:")
255 print("\n luci-splash list\n List connected, black- and whitelisted clients")
256 print("\n luci-splash sync\n Synchronize firewall rules and clear expired leases")
257 print("\n luci-splash lease <MAC-or-IP>\n Create a lease for the given address")
258 print("\n luci-splash blacklist <MAC-or-IP>\n Add given address to blacklist")
259 print("\n luci-splash whitelist <MAC-or-IP>\n Add given address to whitelist")
260 print("\n luci-splash remove <MAC-or-IP>\n Remove given address from the lease-, black- or whitelist")
261 print("")
262
263 os.exit(1)
264 end
265 end
266
267 -- Get current arp cache
268 function get_arpcache()
269 local arpcache = { }
270 for _, entry in ipairs(net.arptable()) do
271 arpcache[entry["HW address"]:lower()] = { entry["Device"]:lower(), entry["IP address"]:lower() }
272 end
273 return arpcache
274 end
275
276 -- Get a list of known mac addresses
277 function get_known_macs(list)
278 local leased_macs = { }
279
280 if not list or list == "lease" then
281 uci:foreach("luci_splash_leases", "lease",
282 function(s) leased_macs[s.mac:lower()] = true end)
283 end
284
285 if not list or list == "whitelist" then
286 uci:foreach("luci_splash", "whitelist",
287 function(s) leased_macs[s.mac:lower()] = true end)
288 end
289
290 if not list or list == "blacklist" then
291 uci:foreach("luci_splash", "blacklist",
292 function(s) leased_macs[s.mac:lower()] = true end)
293 end
294
295 return leased_macs
296 end
297
298
299 -- Helper to delete iptables rules
300 function ipt_delete_all(args, comp, off)
301 off = off or { }
302 for i, r in ipairs(ipt:find(args)) do
303 if comp == nil or comp(r) then
304 off[r.table] = off[r.table] or { }
305 off[r.table][r.chain] = off[r.table][r.chain] or 0
306
307 exec("iptables -t %q -D %q %d 2>/dev/null"
308 %{ r.table, r.chain, r.index - off[r.table][r.chain] })
309
310 off[r.table][r.chain] = off[r.table][r.chain] + 1
311 end
312 end
313 end
314
315 function ipt6_delete_all(args, comp, off)
316 off = off or { }
317 for i, r in ipairs(ipt:find(args)) do
318 if comp == nil or comp(r) then
319 off[r.table] = off[r.table] or { }
320 off[r.table][r.chain] = off[r.table][r.chain] or 0
321
322 exec("ip6tables -t %q -D %q %d 2>/dev/null"
323 %{ r.table, r.chain, r.index - off[r.table][r.chain] })
324
325 off[r.table][r.chain] = off[r.table][r.chain] + 1
326 end
327 end
328 end
329
330
331 -- Convert mac to uci-compatible section name
332 function convert_mac_to_secname(mac)
333 return string.gsub(mac, ":", "")
334 end
335
336 -- Add a lease to state and invoke add_rule
337 function add_lease(mac, arp, no_uci)
338 mac = mac:lower()
339
340 -- Get current ip address
341 local ipaddr
342 for _, entry in ipairs(arp or net.arptable()) do
343 if entry["HW address"]:lower() == mac then
344 ipaddr = entry["IP address"]
345 break
346 end
347 end
348
349 -- Add lease if there is an ip addr
350 if ipaddr then
351 local device = get_device_for_ip(ipaddr)
352 if not no_uci then
353 local leased = uci:get("luci_splash_leases", "stats", "leases")
354 if type(tonumber(leased)) == "number" then
355 update_stats(leased + 1, nil, nil, nil, nil)
356 end
357
358 uci:section("luci_splash_leases", "lease", convert_mac_to_secname(mac), {
359 mac = mac,
360 ipaddr = ipaddr,
361 device = device,
362 limit_up = limit_up,
363 limit_down = limit_down,
364 start = os.time()
365 })
366 uci:save("luci_splash_leases")
367 end
368 add_lease_rule(mac, ipaddr, device)
369 else
370 print("Found no active IP for %s, lease not added" % mac)
371 end
372 end
373
374
375 -- Remove a lease from state and invoke remove_rule
376 function remove_lease(mac)
377 mac = mac:lower()
378
379 uci:delete_all("luci_splash_leases", "lease",
380 function(s)
381 if s.mac:lower() == mac then
382 remove_lease_rule(mac, s.ipaddr, s.device, tonumber(s.limit_up), tonumber(s.limit_down))
383 local leased = uci:get("luci_splash_leases", "stats", "leases")
384 if type(tonumber(leased)) == "number" and tonumber(leased) > 0 then
385 update_stats(leased - 1, nil, nil, nil, nil)
386 end
387 return true
388 end
389 return false
390 end)
391
392 uci:save("luci_splash_leases")
393 end
394
395
396 -- Add a whitelist entry
397 function add_whitelist(mac)
398 uci:section("luci_splash", "whitelist", convert_mac_to_secname(mac), { mac = mac })
399 uci:save("luci_splash")
400 uci:commit("luci_splash")
401 add_whitelist_rule(mac)
402 end
403
404
405 -- Add a blacklist entry
406 function add_blacklist(mac)
407 uci:section("luci_splash", "blacklist", convert_mac_to_secname(mac), { mac = mac })
408 uci:save("luci_splash")
409 uci:commit("luci_splash")
410 add_blacklist_rule(mac)
411 end
412
413
414 -- Remove a whitelist entry
415 function remove_whitelist(mac)
416 mac = mac:lower()
417 uci:delete_all("luci_splash", "whitelist",
418 function(s) return not s.mac or s.mac:lower() == mac end)
419 uci:save("luci_splash")
420 uci:commit("luci_splash")
421 remove_lease_rule(mac)
422 remove_whitelist_tc(mac)
423 end
424
425 function remove_whitelist_tc(mac)
426 uci:foreach("luci_splash", "iface", function(s)
427 local device = get_physdev(s['.name'])
428 if device and device ~= "" then
429 if debug then
430 print("Removing whitelist filters for %s interface %s." % {mac, device})
431 end
432 local handle = get_filter_handle('ffff:', 'src', device, mac)
433 if handle then
434 exec('tc filter del dev "%s" parent ffff: protocol ip prio 1 handle %s u32' % { device, handle })
435 else
436 print('Warning! Could not get a handle for %s parent :ffff on interface %s' % { mac, device })
437 end
438 local handle = get_filter_handle('1:', 'dest', device, mac)
439 if handle then
440 exec('tc filter del dev "%s" parent 1:0 protocol ip prio 1 handle %s u32' % { device, handle })
441 else
442 print('Warning! Could not get a handle for %s parent 1:0 on interface %s' % { mac, device })
443 end
444 end
445 end)
446 end
447
448 -- Remove a blacklist entry
449 function remove_blacklist(mac)
450 mac = mac:lower()
451 uci:delete_all("luci_splash", "blacklist",
452 function(s) return not s.mac or s.mac:lower() == mac end)
453 uci:save("luci_splash")
454 uci:commit("luci_splash")
455 remove_lease_rule(mac)
456 end
457
458
459 -- Add an iptables rule
460 function add_lease_rule(mac, ipaddr, device)
461 local id
462 if ipaddr then
463 id = get_id(ipaddr)
464 end
465
466 exec("iptables -t mangle -I luci_splash_mark_out -m mac --mac-source %q -j RETURN" % mac)
467
468 if id and device then
469 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()})
470 end
471
472 if has_ipv6 then
473 exec("ip6tables -t mangle -I luci_splash_mark_out -m mac --mac-source %q -j MARK --set-mark 79" % mac)
474 -- not working yet, needs the ip6addr
475 --exec("ip6tables -t mangle -I luci_splash_mark_in -d %q -j MARK --set-mark 80 -m comment --comment %s" % {ipaddr, mac:upper()})
476 end
477
478
479 if device and tonumber(limit_up) > 0 then
480 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})
481 end
482
483 if id and device and tonumber(limit_down) > 0 then
484 exec("tc class add dev %s parent 1: classid 1:0x%s htb rate %skbit" % { device, id, limit_down })
485 exec("tc qdisc add dev %s parent 1:%s sfq perturb 10" % { device, id })
486 end
487
488 exec("iptables -t filter -I luci_splash_filter -m mac --mac-source %q -j RETURN" % mac)
489 exec("iptables -t nat -I luci_splash_leases -m mac --mac-source %q -j RETURN" % mac)
490 if has_ipv6 then
491 exec("ip6tables -t filter -I luci_splash_filter -m mac --mac-source %q -j RETURN" % mac)
492 end
493 end
494
495
496 -- Remove lease, black- or whitelist rules
497 function remove_lease_rule(mac, ipaddr, device, limit_up, limit_down)
498 local id
499 if ipaddr then
500 id = get_id(ipaddr)
501 end
502
503 ipt:resync()
504 ipt_delete_all({table="mangle", chain="luci_splash_mark_in", options={"/*", mac:upper()}})
505 ipt_delete_all({table="mangle", chain="luci_splash_mark_out", options={"MAC", mac:upper()}})
506 ipt_delete_all({table="filter", chain="luci_splash_filter", options={"MAC", mac:upper()}})
507 ipt_delete_all({table="nat", chain="luci_splash_leases", options={"MAC", mac:upper()}})
508 if has_ipv6 then
509 ipt6_delete_all({table="mangle", chain="luci_splash_mark_out", options={"MAC", mac:upper()}})
510 ipt6_delete_all({table="filter", chain="luci_splash_filter", options={"MAC", mac:upper()}})
511 end
512 if device and tonumber(limit_up) > 0 then
513 local handle = get_filter_handle('ffff:', 'src', device, mac)
514 if handle then
515 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})
516 else
517 print('Warning! Could not get a handle for %s parent :ffff on interface %s' % { mac, device })
518 end
519 end
520
521 -- remove clients class
522 if device and id then
523 exec('tc class del dev "%s" classid 1:%s' % {device, id})
524 exec('tc qdisc del dev "%s" parent 1:%s sfq perturb 10' % { device, id })
525 end
526
527 end
528
529
530 -- Add whitelist rules
531 function add_whitelist_rule(mac)
532 exec("iptables -t filter -I luci_splash_filter -m mac --mac-source %q -j RETURN" % mac)
533 exec("iptables -t nat -I luci_splash_leases -m mac --mac-source %q -j RETURN" % mac)
534 if has_ipv6 then
535 exec("ip6tables -t filter -I luci_splash_filter -m mac --mac-source %q -j RETURN" % mac)
536 end
537 uci:foreach("luci_splash", "iface", function(s)
538 local device = get_physdev(s['.name'])
539 if device and device ~= "" then
540 exec('tc filter add dev "%s" parent ffff: protocol ip prio 1 u32 match ether src %s police pass' % { device, mac })
541 exec('tc filter add dev "%s" parent 1:0 protocol ip prio 1 u32 match ether dst %s classid 1:1' % { device, mac })
542 end
543 end)
544 end
545
546
547 -- Add blacklist rules
548 function add_blacklist_rule(mac)
549 exec("iptables -t filter -I luci_splash_filter -m mac --mac-source %q -j DROP" % mac)
550 if has_ipv6 then
551 exec("ip6tables -t filter -I luci_splash_filter -m mac --mac-source %q -j DROP" % mac)
552 end
553 end
554
555
556 -- Synchronise leases, remove abandoned rules
557 function sync()
558 lock()
559
560 local time = os.time()
561
562 -- Current leases in state files
563 local leases = uci:get_all("luci_splash_leases")
564
565 -- Convert leasetime to seconds
566 local leasetime = tonumber(uci:get("luci_splash", "general", "leasetime")) * 3600
567
568 -- Clean state file
569 uci:load("luci_splash_leases")
570 uci:revert("luci_splash_leases")
571
572 -- For all leases
573 local leasecount = 0
574 for k, v in pairs(leases) do
575 if v[".type"] == "lease" then
576 if os.difftime(time, tonumber(v.start)) > leasetime then
577 -- Remove expired
578 remove_lease_rule(v.mac, v.ipaddr, v.device, tonumber(v.limit_up), tonumber(v.limit_down))
579 else
580 leasecount = leasecount + 1
581 -- Rewrite state
582 uci:section("luci_splash_leases", "lease", convert_mac_to_secname(v.mac), {
583 mac = v.mac,
584 ipaddr = v.ipaddr,
585 device = v.device,
586 limit_up = limit_up,
587 limit_down = limit_down,
588 start = v.start
589 })
590 end
591 end
592 end
593
594 -- Get the mac addresses of current leases
595 local macs = get_known_macs()
596 local arpcache = get_arpcache()
597
598 local blackwhitelist = uci:get_all("luci_splash")
599 local whitelist_total = 0
600 local whitelist_online = 0
601 local blacklist_total = 0
602 local blacklist_online = 0
603
604 -- Whitelist, Blacklist
605 for _, s in utl.spairs(blackwhitelist,
606 function(a,b) return blackwhitelist[a][".type"] > blackwhitelist[b][".type"] end
607 ) do
608 if (s[".type"] == "whitelist") then
609 whitelist_total = whitelist_total + 1
610 if s.mac then
611 local mac = s.mac:lower()
612 if arpcache[mac] then
613 whitelist_online = whitelist_online + 1
614 end
615 end
616 end
617 if (s[".type"] == "blacklist") then
618 blacklist_total = blacklist_total + 1
619 if s.mac then
620 local mac = s.mac:lower()
621 if arpcache[mac] then
622 blacklist_online = blacklist_online + 1
623 end
624 end
625 end
626 end
627
628 update_stats(leasecount, whitelist_online, whitelist_total, blacklist_online, blacklist_total)
629
630 uci:save("luci_splash_leases")
631
632 ipt:resync()
633
634 ipt_delete_all({table="filter", chain="luci_splash_filter", options={"MAC"}},
635 function(r) return not macs[r.options[2]:lower()] end)
636 ipt_delete_all({table="nat", chain="luci_splash_leases", options={"MAC"}},
637 function(r) return not macs[r.options[2]:lower()] end)
638 ipt_delete_all({table="mangle", chain="luci_splash_mark_out", options={"MAC", "MARK", "set"}},
639 function(r) return not macs[r.options[2]:lower()] end)
640 ipt_delete_all({table="mangle", chain="luci_splash_mark_in", options={"/*", "MARK", "set"}},
641 function(r) return not macs[r.options[2]:lower()] end)
642
643
644 if has_ipv6 then
645 ipt6_delete_all({table="filter", chain="luci_splash_filter", options={"MAC"}},
646 function(r) return not macs[r.options[2]:lower()] end)
647 ipt6_delete_all({table="mangle", chain="luci_splash_mark_out", options={"MAC", "MARK", "set"}},
648 function(r) return not macs[r.options[2]:lower()] end)
649 end
650
651 unlock()
652 end
653
654 -- Show client info
655 function list()
656 local arpcache = get_arpcache()
657 -- Find traffic usage
658 local function traffic(lease)
659 local traffic_in = 0
660 local traffic_out = 0
661
662 local rin = ipt:find({table="mangle", chain="luci_splash_mark_in", destination=lease.ipaddr})
663 local rout = ipt:find({table="mangle", chain="luci_splash_mark_out", options={"MAC", lease.mac:upper()}})
664
665 if rin and #rin > 0 then traffic_in = math.floor( rin[1].bytes / 1024) end
666 if rout and #rout > 0 then traffic_out = math.floor(rout[1].bytes / 1024) end
667
668 return traffic_in, traffic_out
669 end
670
671 -- Print listings
672 local leases = uci:get_all("luci_splash_leases")
673 local blackwhitelist = uci:get_all("luci_splash")
674
675 print(string.format(
676 "%-17s %-15s %-9s %-4s %-7s %20s",
677 "MAC", "IP", "State", "Dur.", "Intf.", "Traffic down/up"
678 ))
679
680 -- Leases
681 for _, s in pairs(leases) do
682 if s[".type"] == "lease" and s.mac then
683 local ti, to = traffic(s)
684 local mac = s.mac:lower()
685 local arp = arpcache[mac]
686 print(string.format(
687 "%-17s %-15s %-9s %3dm %-7s %7dKB %7dKB",
688 mac, s.ipaddr, "leased",
689 math.floor(( os.time() - tonumber(s.start) ) / 60),
690 arp and arp[1] or "?", ti, to
691 ))
692 end
693 end
694
695 -- Whitelist, Blacklist
696 for _, s in utl.spairs(blackwhitelist,
697 function(a,b) return blackwhitelist[a][".type"] > blackwhitelist[b][".type"] end
698 ) do
699 if (s[".type"] == "whitelist" or s[".type"] == "blacklist") and s.mac then
700 local mac = s.mac:lower()
701 local arp = arpcache[mac]
702 print(string.format(
703 "%-17s %-15s %-9s %4s %-7s %9s %9s",
704 mac, arp and arp[2] or "?", s[".type"],
705 "- ", arp and arp[1] or "?", "-", "-"
706 ))
707 end
708 end
709 end
710
711 main(arg)