0699d2820a0fe9761395c0d1732c41b4717f5e35
[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.Session("/var/state")
11
12
13 function main(argv)
14         local cmd = argv[1]
15         local arg = argv[2]
16         
17         if not cmd then
18                 print("Usage: " .. argv[0] .. " <status|add|remove|sync> [MAC]")
19                 os.exit(1)
20         elseif cmd == "status" then
21                 if not arg then
22                         os.exit(1)
23                 end
24                 
25                 if iswhitelisted(arg) then
26                         print("whitelisted")
27                         os.exit(0)
28                 end
29                 
30                 if haslease(arg) then
31                         print("lease")
32                         os.exit(0)
33                 end             
34                 
35                 print("unknown")
36                 os.exit(0)
37         elseif cmd == "add" then
38                 if not arg then
39                         os.exit(1)
40                 end
41                 
42                 if not haslease(arg) then
43                         add_lease(arg)
44                 else
45                         print("already leased!")
46                         os.exit(2)
47                 end
48                 os.exit(0)
49         elseif cmd == "remove" then
50                 if not cmd[2] then
51                         os.exit(1)
52                 end
53                 
54                 remove_lease(arg)
55                 os.exit(0)              
56         elseif cmd == "sync" then
57                 sync()
58                 os.exit(0)
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.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)