* Reworked Luci-Splash
[project/luci.git] / contrib / package / ffluci-splash / src / luci-splash.lua
1 #!/usr/bin/lua
2 package.path = "/usr/lib/lua/?.lua;/usr/lib/lua/?/init.lua;" .. package.path
3 package.cpath = "/usr/lib/lua/?.so;" .. package.cpath
4
5 require("ffluci.http")
6 require("ffluci.sys")
7 require("ffluci.model.uci")
8
9 -- Init state session
10 uci = ffluci.model.uci.Session("/var/state")
11
12
13 -- Parse stdin and do something
14 function main(argv)
15 local cmd = argv[1]
16 local arg = argv[2]
17
18 if not cmd then
19 print("Usage: " .. argv[0] .. " <status|add|remove|sync> [MAC]")
20 os.exit(1)
21 elseif cmd == "status" then
22 if not arg then
23 os.exit(1)
24 end
25
26 if iswhitelisted(arg) then
27 print("whitelisted")
28 os.exit(0)
29 end
30
31 if haslease(arg) then
32 print("lease")
33 os.exit(0)
34 end
35
36 print("unknown")
37 os.exit(0)
38 elseif cmd == "add" then
39 if not arg then
40 os.exit(1)
41 end
42
43 if not haslease(arg) then
44 add_lease(arg)
45 else
46 print("already leased!")
47 os.exit(2)
48 end
49 os.exit(0)
50 elseif cmd == "remove" then
51 if not cmd[2] then
52 os.exit(1)
53 end
54
55 remove_lease(arg)
56 os.exit(0)
57 elseif cmd == "sync" then
58 sync()
59 os.exit(0)
60 end
61 end
62
63 -- Add a lease to state and invoke add_rule
64 function add_lease(mac)
65 local key = uci:add("luci_splash", "lease")
66 uci:set("luci_splash", key, "mac", mac)
67 uci:set("luci_splash", key, "start", os.time())
68 add_rule(mac)
69 end
70
71
72 -- Remove a lease from state and invoke remove_rule
73 function remove_lease(mac)
74 mac = mac:lower()
75
76 for k, v in pairs(uci:show("luci_splash").luci_splash) do
77 if v.mac:lower() == mac then
78 remove_rule(mac)
79 uci:del("luci_splash", k)
80 end
81 end
82 end
83
84
85 -- Add an iptables rule
86 function add_rule(mac)
87 return os.execute("iptables -t nat -I luci_splash_leases -m mac --mac-source '"..mac.."' -j RETURN")
88 end
89
90
91 -- Remove an iptables rule
92 function remove_rule(mac)
93 return os.execute("iptables -t nat -D luci_splash_leases -m mac --mac-source '"..mac.."' -j RETURN")
94 end
95
96
97 -- Check whether a MAC-Address is listed in the lease state list
98 function haslease(mac)
99 mac = mac:lower()
100
101 for k, v in pairs(uci:show("luci_splash").luci_splash) do
102 if v[".type"] == "lease" and v.mac and v.mac:lower() == mac then
103 return true
104 end
105 end
106
107 return false
108 end
109
110
111 -- Check whether a MAC-Address is whitelisted
112 function iswhitelisted(mac)
113 mac = mac:lower()
114
115 for k, v in pairs(uci:show("luci_splash").luci_splash) do
116 if v[".type"] == "whitelist" and v.mac and v.mac:lower() == mac then
117 return true
118 end
119 end
120
121 return false
122 end
123
124
125 -- Returns a list of MAC-Addresses for which a rule is existing
126 function listrules()
127 local cmd = "iptables -t nat -L luci_splash_leases | grep RETURN |"
128 cmd = cmd .. "egrep -io [0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+"
129 return ffluci.util.split(ffluci.sys.exec(cmd))
130 end
131
132
133 -- Synchronise leases, remove abandoned rules
134 function sync()
135 local written = {}
136 local time = os.time()
137
138 -- Current leases in state files
139 local leases = uci:show("luci_splash").luci_splash
140
141 -- Convert leasetime to seconds
142 local leasetime = tonumber(uci:get("luci_splash", "general", "leasetime")) * 3600
143
144 -- Clean state file
145 uci:revert("luci_splash")
146
147
148 -- For all leases
149 for k, v in pairs(uci:show("luci_splash")) do
150 if v[".type"] == "lease" then
151 if os.difftime(time, tonumber(v.start)) > leasetime then
152 -- Remove expired
153 remove_rule(v.mac)
154 else
155 -- Rewrite state
156 local n = uci:add("luci_splash", "lease")
157 uci:set("luci_splash", n, "mac", v.mac)
158 uci:set("luci_splash", n, "start", v.start)
159 written[v.mac] = 1
160 end
161 end
162 end
163
164
165 -- Delete rules without state
166 for i, r in ipairs(listrules()) do
167 if #r > 0 and not written[r] then
168 remove_rule(r)
169 end
170 end
171 end
172
173 main(arg)