2fa6bdd4a9b440b4cb4f459bb2d52bc3ec2ef7f5
[project/luci.git] / applications / luci-splash / root / usr / sbin / luci-splash
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:sections("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:sections("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:sections("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         uci:t_load("luci_splash")
138         
139         -- Current leases in state files
140         local leases = uci:t_sections("luci_splash")
141         
142         -- Convert leasetime to seconds
143         local leasetime = tonumber(uci:t_get("luci_splash", "general", "leasetime")) * 3600
144         
145         -- Clean state file
146         uci:t_revert("luci_splash")
147         
148         
149         -- For all leases
150         for k, v in pairs(leases) do
151                 if v[".type"] == "lease" then
152                         if os.difftime(time, tonumber(v.start)) > leasetime then
153                                 -- Remove expired
154                                 remove_rule(v.mac)
155                         else
156                                 -- Rewrite state
157                                 local n = uci:t_add("luci_splash", "lease")
158                                 uci:t_set("luci_splash", n, "mac", v.mac)
159                                 uci:t_set("luci_splash", n, "start", v.start)
160                                 written[v.mac:lower()] = 1
161                         end
162                 end
163         end
164         
165         
166         -- Delete rules without state
167         for i, r in ipairs(listrules()) do
168                 if #r > 0 and not written[r:lower()] then
169                         remove_rule(r)
170                 end
171         end
172         
173         uci:t_save("luci_splash")
174 end
175
176 main(arg)