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