Fixed a design flaw in luci.model.uci
[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 luci.model.uci.load_state("luci_splash")
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_state("luci_splash")
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_state("luci_splash")
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.util.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_state("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_state("luci_splash")
189 end
190
191 main(arg)