ff876c3fd02e421850c27ca9afc4308f84b8c7ec
[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)