* Fixed luci-splash again
[project/luci.git] / contrib / package / ffluci-splash / src / luci-splash.lua
1 #!/usr/bin/lua
2 package.path  = "/usr/lib/lua/?.lua;/usr/lib/lua/?/init.lua;" .. package.path
3 package.cpath = "/usr/lib/lua/?.so;" .. package.cpath
4
5 require("ffluci.http")
6 require("ffluci.sys")
7 require("ffluci.model.uci")
8
9 -- Init state session
10 uci = ffluci.model.uci.StateSession()
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         local key = uci:add("luci_splash", "lease")
65         uci:set("luci_splash", key, "mac", mac)
66         uci:set("luci_splash", key, "start", os.time())
67         add_rule(mac)
68 end
69
70
71 -- Remove a lease from state and invoke remove_rule
72 function remove_lease(mac)
73         mac = mac:lower()
74
75         for k, v in pairs(uci:show("luci_splash").luci_splash) do
76                 if v[".type"] == "lease" and v.mac:lower() == mac then
77                         remove_rule(mac)
78                         uci:del("luci_splash", k)
79                 end
80         end
81 end
82
83
84 -- Add an iptables rule
85 function add_rule(mac)
86         return os.execute("iptables -t nat -I luci_splash_leases -m mac --mac-source '"..mac.."' -j RETURN")
87 end
88
89
90 -- Remove an iptables rule
91 function remove_rule(mac)
92         return os.execute("iptables -t nat -D luci_splash_leases -m mac --mac-source '"..mac.."' -j RETURN")
93 end
94
95
96 -- Check whether a MAC-Address is listed in the lease state list
97 function haslease(mac)
98         mac = mac:lower()
99         
100         for k, v in pairs(uci:show("luci_splash").luci_splash) do
101                 if v[".type"] == "lease" and v.mac and v.mac:lower() == mac then
102                         return true
103                 end
104         end
105         
106         return false
107 end
108
109
110 -- Check whether a MAC-Address is whitelisted
111 function iswhitelisted(mac)
112         mac = mac:lower()
113         
114         for k, v in pairs(uci:show("luci_splash").luci_splash) do
115                 if v[".type"] == "whitelist" and v.mac and v.mac:lower() == mac then
116                         return true
117                 end
118         end
119         
120         return false
121 end
122
123
124 -- Returns a list of MAC-Addresses for which a rule is existing
125 function listrules()
126         local cmd = "iptables -t nat -L luci_splash_leases | grep RETURN |"
127         cmd = cmd .. "egrep -io [0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+"
128         return ffluci.util.split(ffluci.sys.exec(cmd))
129 end
130
131
132 -- Synchronise leases, remove abandoned rules
133 function sync()
134         local written = {}
135         local time = os.time()
136         
137         -- Current leases in state files
138         local leases = uci:show("luci_splash").luci_splash
139         
140         -- Convert leasetime to seconds
141         local leasetime = tonumber(uci:get("luci_splash", "general", "leasetime")) * 3600
142         
143         -- Clean state file
144         uci:revert("luci_splash")
145         
146         
147         -- For all leases
148         for k, v in pairs(uci:show("luci_splash")) do
149                 if v[".type"] == "lease" then
150                         if os.difftime(time, tonumber(v.start)) > leasetime then
151                                 -- Remove expired
152                                 remove_rule(v.mac)
153                         else
154                                 -- Rewrite state
155                                 local n = uci:add("luci_splash", "lease")
156                                 uci:set("luci_splash", n, "mac", v.mac)
157                                 uci:set("luci_splash", n, "start", v.start)
158                                 written[v.mac:lower()] = 1
159                         end
160                 end
161         end
162         
163         
164         -- Delete rules without state
165         for i, r in ipairs(listrules()) do
166                 if #r > 0 and not written[r:lower()] then
167                         remove_rule(r)
168                 end
169         end
170 end
171
172 main(arg)