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