splash.htm 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. <%#
  2. Copyright 2009 Jo-Philipp Wich <jow@openwrt.org>
  3. Licensed to the public under the Apache License 2.0.
  4. -%>
  5. <%-
  6. local utl = require "luci.util"
  7. local ipt = require "luci.sys.iptparser".IptParser()
  8. local uci = require "luci.model.uci".cursor_state()
  9. local wat = require "luci.tools.webadmin"
  10. local ipc = require "luci.ip"
  11. local fs = require "nixio.fs"
  12. local clients = { }
  13. local leasetime = tonumber(uci:get("luci_splash", "general", "leasetime") or 1) * 60 * 60
  14. local leasefile = "/tmp/dhcp.leases"
  15. uci:foreach("dhcp", "dnsmasq",
  16. function(s)
  17. if s.leasefile then leasefile = s.leasefile end
  18. end)
  19. uci:foreach("luci_splash_leases", "lease",
  20. function(s)
  21. if s.start and s.mac then
  22. clients[s.mac:lower()] = {
  23. start = tonumber(s.start),
  24. limit = ( tonumber(s.start) + leasetime ),
  25. mac = s.mac:upper(),
  26. ipaddr = s.ipaddr,
  27. policy = "normal",
  28. packets = 0,
  29. bytes = 0,
  30. }
  31. end
  32. end)
  33. for _, r in ipairs(ipt:find({table="nat", chain="luci_splash_leases"})) do
  34. if r.options and #r.options >= 2 and r.options[1] == "MAC" then
  35. if not clients[r.options[2]:lower()] then
  36. clients[r.options[2]:lower()] = {
  37. start = 0,
  38. limit = 0,
  39. mac = r.options[2]:upper(),
  40. policy = ( r.target == "RETURN" ) and "whitelist" or "blacklist",
  41. packets = 0,
  42. bytes = 0
  43. }
  44. end
  45. end
  46. end
  47. for mac, client in pairs(clients) do
  48. client.bytes_in = 0
  49. client.bytes_out = 0
  50. client.packets_in = 0
  51. client.packets_out = 0
  52. if client.ipaddr then
  53. local rin = ipt:find({table="mangle", chain="luci_splash_mark_in", destination=client.ipaddr})
  54. local rout = ipt:find({table="mangle", chain="luci_splash_mark_out", options={"MAC", client.mac:upper()}})
  55. if rin and #rin > 0 then
  56. client.bytes_in = rin[1].bytes
  57. client.packets_in = rin[1].packets
  58. end
  59. if rout and #rout > 0 then
  60. client.bytes_out = rout[1].bytes
  61. client.packets_out = rout[1].packets
  62. end
  63. end
  64. end
  65. uci:foreach("luci_splash", "whitelist",
  66. function(s)
  67. if s.mac and clients[s.mac:lower()] then
  68. clients[s.mac:lower()].policy="whitelist"
  69. end
  70. end)
  71. uci:foreach("luci_splash", "blacklist",
  72. function(s)
  73. if s.mac and clients[s.mac:lower()] then
  74. clients[s.mac:lower()].policy=(s.kicked and "kicked" or "blacklist")
  75. end
  76. end)
  77. if fs.access(leasefile) then
  78. for l in io.lines(leasefile) do
  79. local time, mac, ip, name = l:match("^(%d+) (%S+) (%S+) (%S+)")
  80. if time and mac and ip then
  81. local c = clients[mac:lower()]
  82. if c then
  83. c.ip = ip
  84. c.hostname = ( name ~= "*" ) and name or nil
  85. end
  86. end
  87. end
  88. end
  89. for i, n in ipairs(ipc.neighbors({ family = 4 })) do
  90. if n.mac and n.dest then
  91. local c = clients[n.mac]
  92. if c and not c.ip then
  93. c.ip = n.dest:string()
  94. end
  95. end
  96. end
  97. local function showmac(mac)
  98. if not is_admin then
  99. mac = mac:gsub("(%S%S:%S%S):%S%S:%S%S:(%S%S:%S%S)", "%1:XX:XX:%2")
  100. end
  101. return mac
  102. end
  103. if luci.http.formvalue("status") == "1" then
  104. local rv = {}
  105. for _, c in utl.spairs(clients,
  106. function(a,b) if clients[a].policy == clients[b].policy then
  107. return (clients[a].start > clients[b].start)
  108. else
  109. return (clients[a].policy > clients[b].policy)
  110. end
  111. end)
  112. do
  113. if c.ip then
  114. rv[#rv+1] = {
  115. hostname = c.hostname or "?",
  116. ip = c.ip or "?",
  117. mac = showmac(c.mac) or "?",
  118. timeleft = (c.limit >= os.time()) and wat.date_format(c.limit-os.time()) or (c.policy ~= "normal") and "-" or "expired",
  119. trafficin = wat.byte_format(c.bytes_in) or "?",
  120. trafficout = wat.byte_format(c.bytes_out) or "?",
  121. policy = c.policy or "?"
  122. }
  123. end
  124. end
  125. luci.http.prepare_content("application/json")
  126. luci.http.write_json(rv)
  127. return
  128. end
  129. -%>
  130. <%+header%>
  131. <script type="text/javascript" src="<%=resource%>/cbi.js"></script>
  132. <script type="text/javascript">//<![CDATA[
  133. XHR.poll(10 , '<%=REQUEST_URI%>', { status: 1 },
  134. function(x, info)
  135. {
  136. var tbody = document.getElementById('splash_table');
  137. if (tbody)
  138. {
  139. var s = '';
  140. if (info.length == undefined) {
  141. s += '<tr class="cbi-section-table-row"><td colspan="7" class="cbi-section-table-cell"><br /><em><%:No clients connected%></em><br /></td></tr>'
  142. };
  143. for (var idx = 0; idx < info.length; idx++)
  144. {
  145. var splash = info[idx];
  146. s += String.format(
  147. '<tr class="cbi-section-table-row cbi-rowstyle-'+(1 + (idx % 2))+'">' +
  148. '<td class="cbi-section-table-cell">%s</td>' +
  149. '<td class="cbi-section-table-cell">%s</td>' +
  150. '<td class="cbi-section-table-cell">%s</td>' +
  151. '<td class="cbi-section-table-cell">%s</td>' +
  152. '<td class="cbi-section-table-cell">%s/%s</td>' +
  153. '<td class="cbi-section-table-cell">',
  154. splash.hostname, splash.ip, splash.mac, splash.timeleft, splash.trafficin, splash.trafficout);
  155. <% if is_admin then %>
  156. s += String.format('<select name="policy.%s" style="width:200px">', splash.mac.toLowerCase());
  157. if (splash.policy == 'whitelist') {
  158. s += '<option value="whitelist" selected="selected"><%:whitelisted%></option>'
  159. } else {
  160. s += '<option value="whitelist"><%:whitelisted%></option>'
  161. };
  162. if (splash.policy == 'normal') {
  163. s += '<option value="normal" selected="selected"><%:splashed%></option>';
  164. s += '<option value="kicked"><%:temporarily blocked%></option>'
  165. } else {
  166. s += '<option value="normal"><%:splashed%></option>'
  167. };
  168. if (splash.policy == 'blacklist') {
  169. s+= '<option value="blacklist" selected="selected"><%:blacklisted%></option>'
  170. } else {
  171. s += '<option value="blacklist"><%:blacklisted%></option>'
  172. };
  173. s += String.format(
  174. '</select>' +
  175. '<input type="submit" class="cbi-button cbi-button-save" name="save.%s" value="<%:Save%>" />',
  176. splash.mac.toLowerCase());
  177. <% else %>
  178. s += String.format('%s', splash.policy);
  179. <% end %>
  180. s += '</td></tr>'
  181. }
  182. tbody.innerHTML = s;
  183. }
  184. }
  185. );
  186. //]]></script>
  187. <div id="cbi-splash-leases" class="cbi-map">
  188. <h2 name="content"><%:Client-Splash%></h2>
  189. <fieldset id="cbi-table-table" class="cbi-section">
  190. <legend><%:Active Clients%></legend>
  191. <div class="cbi-section-node">
  192. <% if is_admin then %><form action="<%=REQUEST_URI%>" method="post"><input type="hidden" name="token" value="<%=token%>" /><% end %>
  193. <table class="cbi-section-table">
  194. <thead>
  195. <tr class="cbi-section-table-titles">
  196. <th class="cbi-section-table-cell"><%:Hostname%></th>
  197. <th class="cbi-section-table-cell"><%:IP Address%></th>
  198. <th class="cbi-section-table-cell"><%:MAC Address%></th>
  199. <th class="cbi-section-table-cell"><%:Time remaining%></th>
  200. <th class="cbi-section-table-cell"><%:Traffic in/out%></th>
  201. <th class="cbi-section-table-cell"><%:Policy%></th>
  202. </tr>
  203. </thead>
  204. <tbody id="splash_table">
  205. <%-
  206. local count = 0
  207. for _, c in utl.spairs(clients,
  208. function(a,b)
  209. if clients[a].policy == clients[b].policy then
  210. return (clients[a].start > clients[b].start)
  211. else
  212. return (clients[a].policy > clients[b].policy)
  213. end
  214. end)
  215. do
  216. if c.ip then
  217. count = count + 1
  218. -%>
  219. <tr class="cbi-section-table-row cbi-rowstyle-<%=2-(count%2)%>">
  220. <td class="cbi-section-table-cell"><%=c.hostname or "<em>" .. translate("unknown") .. "</em>"%></td>
  221. <td class="cbi-section-table-cell"><%=c.ip or "<em>" .. translate("unknown") .. "</em>"%></td>
  222. <td class="cbi-section-table-cell"><%=showmac(c.mac)%></td>
  223. <td class="cbi-section-table-cell"><%=
  224. (c.limit >= os.time()) and wat.date_format(c.limit-os.time()) or
  225. (c.policy ~= "normal") and "-" or "<em>" .. translate("expired") .. "</em>"
  226. %></td>
  227. <td class="cbi-section-table-cell"><%=wat.byte_format(c.bytes_in)%> / <%=wat.byte_format(c.bytes_out)%></td>
  228. <td class="cbi-section-table-cell">
  229. <% if is_admin then %>
  230. <select name="policy.<%=c.mac:lower()%>" style="width:200px">
  231. <option value="whitelist"<%=c.policy=="whitelist" and ' selected="selected"'%>><%:whitelisted%></option>
  232. <option value="normal"<%=c.policy=="normal" and not c.kicked and ' selected="selected"'%>><%:splashed%></option>
  233. <option value="blacklist"<%=c.policy=="blacklist" and ' selected="selected"'%>><%:blacklisted%></option>
  234. <% if c.policy == "normal" then -%>
  235. <option value="kicked"><%:temporarily blocked%></option>
  236. <%- end %>
  237. </select>
  238. <input type="submit" class="cbi-button cbi-button-save" name="save.<%=c.mac:lower()%>" value="<%:Save%>" />
  239. <% else %>
  240. <%=c.policy%>
  241. <% end %>
  242. </td>
  243. </tr>
  244. <%-
  245. end
  246. end
  247. if count == 0 then
  248. -%>
  249. <tr class="cbi-section-table-row">
  250. <td colspan="7" class="cbi-section-table-cell">
  251. <br /><em><%:No clients connected%></em><br />
  252. </td>
  253. </tr>
  254. <%- end -%>
  255. </tbody>
  256. </table>
  257. <% if is_admin then %></form><% end %>
  258. </div>
  259. </fieldset>
  260. </div>
  261. <%+footer%>