* Removed High-Level UCI-API due to Lua compiler bugs
[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
77         uci.foreach("luci_splash", "lease",
78                 function (section)
79                         if section.mac:lower() == mac then
80                                 remove_rule(mac)
81                                 uci.delete("luci_splash", section[".name"])
82                         end
83                 end)
84                 
85         uci.save()
86 end
87
88
89 -- Add an iptables rule
90 function add_rule(mac)
91         return os.execute("iptables -t nat -I luci_splash_leases -m mac --mac-source '"..mac.."' -j RETURN")
92 end
93
94
95 -- Remove an iptables rule
96 function remove_rule(mac)
97         return os.execute("iptables -t nat -D luci_splash_leases -m mac --mac-source '"..mac.."' -j RETURN")
98 end
99
100
101 -- Check whether a MAC-Address is listed in the lease state list
102 function haslease(mac)
103         mac = mac:lower()
104         local stat = false
105         
106         uci.foreach("luci_splash", "lease",
107                 function (section)
108                         if section.mac:lower() == mac then
109                                 stat = true
110                                 return
111                         end
112                 end)
113         
114         return stat
115 end
116
117
118 -- Check whether a MAC-Address is whitelisted
119 function iswhitelisted(mac)
120         mac = mac:lower()
121         
122         uci.foreach("luci_splash", "whitelist",
123                 function (section)
124                         if section.mac:lower() == mac then
125                                 stat = true
126                                 return
127                         end
128                 end)
129         
130         return false
131 end
132
133
134 -- Returns a list of MAC-Addresses for which a rule is existing
135 function listrules()
136         local cmd = "iptables -t nat -L luci_splash_leases | grep RETURN |"
137         cmd = cmd .. "egrep -io [0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+"
138         return luci.util.split(luci.sys.exec(cmd))
139 end
140
141
142 -- Synchronise leases, remove abandoned rules
143 function sync()
144         local written = {}
145         local time = os.time()
146         
147         -- Current leases in state files
148         local leases = uci.get_all("luci_splash")
149         
150         -- Convert leasetime to seconds
151         local leasetime = tonumber(uci.get("luci_splash", "general", "leasetime")) * 3600
152         
153         -- Clean state file
154         uci.load("luci_splash")
155         uci.revert("luci_splash")
156         
157         
158         -- For all leases
159         for k, v in pairs(leases) do
160                 if v[".type"] == "lease" then
161                         if os.difftime(time, tonumber(v.start)) > leasetime then
162                                 -- Remove expired
163                                 remove_rule(v.mac)
164                         else
165                                 -- Rewrite state
166                                 uci.section("luci_splash", "lease", nil, {              
167                                         mac = v.mac,
168                                         start = v.start
169                                 })
170                                 written[v.mac:lower()] = 1
171                         end
172                 end
173         end
174         
175         
176         -- Delete rules without state
177         for i, r in ipairs(listrules()) do
178                 if #r > 0 and not written[r:lower()] then
179                         remove_rule(r)
180                 end
181         end
182         
183         uci.save("luci_splash")
184 end
185
186 main(arg)