* Merged Luci to use native UCI-library
[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 local cfg = uci.config
11
12
13 function main(argv)
14         local cmd = argv[1]
15         local arg = argv[2]
16         
17         if cmd == "status" then
18                 if not arg then
19                         os.exit(1)
20                 end
21                 
22                 if iswhitelisted(arg) then
23                         print("whitelisted")
24                         os.exit(0)
25                 end
26                 
27                 if haslease(arg) then
28                         print("lease")
29                         os.exit(0)
30                 end             
31                 
32                 print("unknown")
33                 os.exit(0)
34         elseif cmd == "add" then
35                 if not arg then
36                         os.exit(1)
37                 end
38                 
39                 if not haslease(arg) then
40                         add_lease(arg)
41                 else
42                         print("already leased!")
43                         os.exit(2)
44                 end
45                 os.exit(0)
46         elseif cmd == "remove" then
47                 if not arg then
48                         os.exit(1)
49                 end
50                 
51                 remove_lease(arg)
52                 os.exit(0)              
53         elseif cmd == "sync" then
54                 sync()
55                 os.exit(0)
56         else
57                 print("Usage: " .. argv[0] .. " <status|add|remove|sync> [MAC]")
58                 os.exit(1)      
59         end
60 end
61
62 -- Add a lease to state and invoke add_rule
63 function add_lease(mac)
64         cfg.luci_splash[""] = "lease"
65         cfg.luci_splash[""].mac = mac
66         cfg.luci_splash[""].start = os.time()
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(cfg.luci_splash.general.leasetime) * 3600
152         
153         -- Clean state file
154         uci.revert("luci_splash")
155         
156         
157         -- For all leases
158         for k, v in pairs(leases) do
159                 if v[".type"] == "lease" then
160                         if os.difftime(time, tonumber(v.start)) > leasetime then
161                                 -- Remove expired
162                                 remove_rule(v.mac)
163                         else
164                                 -- Rewrite state
165                                 cfg.luci_splash[""] = "lease"
166                                 cfg.luci_splash[""].mac = v.mac
167                                 cfg.luci_splash[""].start = v.start
168                                 written[v.mac:lower()] = 1
169                         end
170                 end
171         end
172         
173         
174         -- Delete rules without state
175         for i, r in ipairs(listrules()) do
176                 if #r > 0 and not written[r:lower()] then
177                         remove_rule(r)
178                 end
179         end
180         
181         uci.save("luci_splash")
182 end
183
184 main(arg)