54c32add6d3c1d202ce0108a11ddc318b4a0f5bd
[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 -- Parse stdin and do something
14 function main(argv)
15         local cmd = argv[1]
16         local arg = argv[2]
17         
18         if not cmd then
19                 print("Usage: " .. argv[0] .. " <status|add|remove|sync> [MAC]")
20                 os.exit(1)
21         elseif cmd == "status" then
22                 if not arg then
23                         os.exit(1)
24                 end
25                 
26                 if iswhitelisted(arg) then
27                         print("whitelisted")
28                         os.exit(0)
29                 end
30                 
31                 if haslease(arg) then
32                         print("lease")
33                         os.exit(0)
34                 end             
35                 
36                 print("unknown")
37                 os.exit(0)
38         elseif cmd == "add" then
39                 if not arg then
40                         os.exit(1)
41                 end
42                 
43                 if not haslease(arg) then
44                         add_lease(arg)
45                 else
46                         print("already leased!")
47                         os.exit(2)
48                 end
49                 os.exit(0)
50         elseif cmd == "remove" then
51                 if not cmd[2] then
52                         os.exit(1)
53                 end
54                 
55                 remove_lease(arg)
56                 os.exit(0)              
57         elseif cmd == "sync" then
58                 sync()
59                 os.exit(0)
60         end
61 end
62
63 -- Add a lease to state and invoke add_rule
64 function add_lease(mac)
65         local key = uci:add("luci_splash", "lease")
66         uci:set("luci_splash", key, "mac", mac)
67         uci:set("luci_splash", key, "start", os.time())
68         add_rule(mac)
69 end
70
71
72 -- Remove a lease from state and invoke remove_rule
73 function remove_lease(mac)
74         mac = mac:lower()
75
76         for k, v in pairs(uci:show("luci_splash").luci_splash) do
77                 if v.mac:lower() == mac then
78                         remove_rule(mac)
79                         uci:del("luci_splash", k)
80                 end
81         end
82 end
83
84
85 -- Add an iptables rule
86 function add_rule(mac)
87         return os.execute("iptables -t nat -I luci_splash_leases -m mac --mac-source '"..mac.."' -j RETURN")
88 end
89
90
91 -- Remove an iptables rule
92 function remove_rule(mac)
93         return os.execute("iptables -t nat -D luci_splash_leases -m mac --mac-source '"..mac.."' -j RETURN")
94 end
95
96
97 -- Check whether a MAC-Address is listed in the lease state list
98 function haslease(mac)
99         mac = mac:lower()
100         
101         for k, v in pairs(uci:show("luci_splash").luci_splash) do
102                 if v[".type"] == "lease" and v.mac and v.mac:lower() == mac then
103                         return true
104                 end
105         end
106         
107         return false
108 end
109
110
111 -- Check whether a MAC-Address is whitelisted
112 function iswhitelisted(mac)
113         mac = mac:lower()
114         
115         for k, v in pairs(uci:show("luci_splash").luci_splash) do
116                 if v[".type"] == "whitelist" and v.mac and v.mac:lower() == mac then
117                         return true
118                 end
119         end
120         
121         return false
122 end
123
124
125 -- Returns a list of MAC-Addresses for which a rule is existing
126 function listrules()
127         local cmd = "iptables -t nat -L luci_splash_leases | grep RETURN |"
128         cmd = cmd .. "egrep -io [0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+"
129         return ffluci.util.split(ffluci.sys.exec(cmd))
130 end
131
132
133 -- Synchronise leases, remove abandoned rules
134 function sync()
135         local written = {}
136         local time = os.time()
137         
138         -- Current leases in state files
139         local leases = uci:show("luci_splash").luci_splash
140         
141         -- Convert leasetime to seconds
142         local leasetime = tonumber(uci:get("luci_splash", "general", "leasetime")) * 3600
143         
144         -- Clean state file
145         uci:revert("luci_splash")
146         
147         
148         -- For all leases
149         for k, v in pairs(uci:show("luci_splash")) do
150                 if v[".type"] == "lease" then
151                         if os.difftime(time, tonumber(v.start)) > leasetime then
152                                 -- Remove expired
153                                 remove_rule(v.mac)
154                         else
155                                 -- Rewrite state
156                                 local n = uci:add("luci_splash", "lease")
157                                 uci:set("luci_splash", n, "mac", v.mac)
158                                 uci:set("luci_splash", n, "start", v.start)
159                                 written[v.mac] = 1
160                         end
161                 end
162         end
163         
164         
165         -- Delete rules without state
166         for i, r in ipairs(listrules()) do
167                 if #r > 0 and not written[r] then
168                         remove_rule(r)
169                 end
170         end
171 end
172
173 main(arg)