4 require("luci.model.uci")
5 require("luci.sys.iptparser")
8 local uci = luci.model.uci.cursor_state()
9 local ipt = luci.sys.iptparser.IptParser()
16 if cmd == "status" and arg then
17 if islisted("whitelist", arg) then
19 elseif islisted("blacklist", arg) then
22 local lease = haslease(arg)
23 if lease and lease.kicked then
32 elseif cmd == "add" and arg then
33 if not haslease(arg) then
36 print("already leased!")
40 elseif cmd == "remove" and arg then
43 elseif cmd == "sync" then
47 print("Usage: " .. argv[0] .. " <status|add|remove|sync> [MAC]")
52 -- Add a lease to state and invoke add_rule
53 function add_lease(mac)
54 uci:section("luci_splash", "lease", nil, {
60 uci:save("luci_splash")
64 -- Remove a lease from state and invoke remove_rule
65 function remove_lease(mac)
69 uci:delete_all("luci_splash", "lease",
70 function(s) return ( s.mac:lower() == mac ) end)
72 uci:save("luci_splash")
76 -- Add an iptables rule
77 function add_rule(mac)
78 os.execute("iptables -I luci_splash_counter -m mac --mac-source '"..mac.."' -j RETURN")
79 return os.execute("iptables -t nat -I luci_splash_leases -m mac --mac-source '"..mac.."' -j RETURN")
83 -- Remove an iptables rule
84 function remove_rule(mac)
85 for _, r in ipairs(ipt:find({table="filter", chain="luci_splash_counter"})) do
86 if r.options and #r.options >= 2 and r.options[1] == "MAC" and
87 r.options[2]:lower() == mac:lower()
89 os.execute("iptables -D luci_splash_counter -m mac --mac-source %q -j %s"
94 for _, r in ipairs(ipt:find({table="nat", chain="luci_splash_leases"})) do
95 if r.options and #r.options >= 2 and r.options[1] == "MAC" and
96 r.options[2]:lower() == mac:lower()
98 os.execute("iptables -t nat -D luci_splash_leases -m mac --mac-source %q -j %s"
107 -- Check whether a MAC-Address is listed in the lease state list
108 function haslease(mac)
112 uci:foreach("luci_splash", "lease",
114 if section.mac:lower() == mac then
123 -- Check whether a MAC-Address is in given list
124 function islisted(what, mac)
127 uci:foreach("luci_splash", what,
129 if section.mac:lower() == mac then
139 -- Returns a list of MAC-Addresses for which a rule is existing
142 for i, r in ipairs(ipt:find({table="nat", chain="luci_splash_leases"})) do
143 if r.options and #r.options >= 2 and r.options[1] == "MAC" then
144 macs[r.options[2]:lower()] = true
147 return luci.util.keys(macs)
151 -- Synchronise leases, remove abandoned rules
154 local time = os.time()
156 -- Current leases in state files
157 local leases = uci:get_all("luci_splash")
159 -- Convert leasetime to seconds
160 local leasetime = tonumber(uci:get("luci_splash", "general", "leasetime")) * 3600
163 uci:load("luci_splash")
164 uci:revert("luci_splash")
168 for k, v in pairs(leases) do
169 if v[".type"] == "lease" then
170 if os.difftime(time, tonumber(v.start)) > leasetime then
175 uci:section("luci_splash", "lease", nil, {
180 written[v.mac:lower()] = 1
182 elseif v[".type"] == "whitelist" or v[".type"] == "blacklist" then
183 written[v.mac:lower()] = 1
188 -- Delete rules without state
189 for i, r in ipairs(listrules()) do
190 if #r > 0 and not written[r:lower()] then
195 uci:save("luci_splash")