c4e1c3aa1655850516b847e3224d6b53696f6030
[project/luci.git] / modules / luci-mod-admin-full / luasrc / controller / admin / network.lua
1 -- Copyright 2008 Steven Barth <steven@midlink.org>
2 -- Copyright 2011-2018 Jo-Philipp Wich <jo@mein.io>
3 -- Licensed to the public under the Apache License 2.0.
4
5 module("luci.controller.admin.network", package.seeall)
6
7 function index()
8 local uci = require("luci.model.uci").cursor()
9 local page
10
11 -- if page.inreq then
12 local has_switch = false
13
14 uci:foreach("network", "switch",
15 function(s)
16 has_switch = true
17 return false
18 end)
19
20 if has_switch then
21 page = node("admin", "network", "vlan")
22 page.target = cbi("admin_network/vlan")
23 page.title = _("Switch")
24 page.order = 20
25
26 page = entry({"admin", "network", "switch_status"}, call("switch_status"), nil)
27 page.leaf = true
28 end
29
30
31 local has_wifi = false
32
33 uci:foreach("wireless", "wifi-device",
34 function(s)
35 has_wifi = true
36 return false
37 end)
38
39 if has_wifi then
40 page = entry({"admin", "network", "wireless_assoclist"}, call("wifi_assoclist"), nil)
41 page.leaf = true
42
43 page = entry({"admin", "network", "wireless_join"}, post("wifi_join"), nil)
44 page.leaf = true
45
46 page = entry({"admin", "network", "wireless_add"}, post("wifi_add"), nil)
47 page.leaf = true
48
49 page = entry({"admin", "network", "wireless_status"}, call("wifi_status"), nil)
50 page.leaf = true
51
52 page = entry({"admin", "network", "wireless_reconnect"}, post("wifi_reconnect"), nil)
53 page.leaf = true
54
55 page = entry({"admin", "network", "wireless_scan_trigger"}, post("wifi_scan_trigger"), nil)
56 page.leaf = true
57
58 page = entry({"admin", "network", "wireless_scan_results"}, call("wifi_scan_results"), nil)
59 page.leaf = true
60
61 page = entry({"admin", "network", "wireless"}, arcombine(cbi("admin_network/wifi_overview"), cbi("admin_network/wifi")), _("Wireless"), 15)
62 page.leaf = true
63 page.subindex = true
64
65 if page.inreq then
66 local wdev
67 local net = require "luci.model.network".init(uci)
68 for _, wdev in ipairs(net:get_wifidevs()) do
69 local wnet
70 for _, wnet in ipairs(wdev:get_wifinets()) do
71 entry(
72 {"admin", "network", "wireless", wnet:id()},
73 alias("admin", "network", "wireless"),
74 wdev:name() .. ": " .. wnet:shortname()
75 )
76 end
77 end
78 end
79 end
80
81
82 page = entry({"admin", "network", "iface_add"}, form("admin_network/iface_add"), nil)
83 page.leaf = true
84
85 page = entry({"admin", "network", "iface_status"}, call("iface_status"), nil)
86 page.leaf = true
87
88 page = entry({"admin", "network", "iface_reconnect"}, post("iface_reconnect"), nil)
89 page.leaf = true
90
91 page = entry({"admin", "network", "network"}, arcombine(cbi("admin_network/network"), cbi("admin_network/ifaces")), _("Interfaces"), 10)
92 page.leaf = true
93 page.subindex = true
94
95 if page.inreq then
96 uci:foreach("network", "interface",
97 function (section)
98 local ifc = section[".name"]
99 if ifc ~= "loopback" then
100 entry({"admin", "network", "network", ifc},
101 true, ifc:upper())
102 end
103 end)
104 end
105
106
107 if nixio.fs.access("/etc/config/dhcp") then
108 page = node("admin", "network", "dhcp")
109 page.target = cbi("admin_network/dhcp")
110 page.title = _("DHCP and DNS")
111 page.order = 30
112
113 page = entry({"admin", "network", "dhcplease_status"}, call("lease_status"), nil)
114 page.leaf = true
115
116 page = node("admin", "network", "hosts")
117 page.target = cbi("admin_network/hosts")
118 page.title = _("Hostnames")
119 page.order = 40
120 end
121
122 page = node("admin", "network", "routes")
123 page.target = cbi("admin_network/routes")
124 page.title = _("Static Routes")
125 page.order = 50
126
127 page = node("admin", "network", "diagnostics")
128 page.target = template("admin_network/diagnostics")
129 page.title = _("Diagnostics")
130 page.order = 60
131
132 page = entry({"admin", "network", "diag_ping"}, post("diag_ping"), nil)
133 page.leaf = true
134
135 page = entry({"admin", "network", "diag_nslookup"}, post("diag_nslookup"), nil)
136 page.leaf = true
137
138 page = entry({"admin", "network", "diag_traceroute"}, post("diag_traceroute"), nil)
139 page.leaf = true
140
141 page = entry({"admin", "network", "diag_ping6"}, post("diag_ping6"), nil)
142 page.leaf = true
143
144 page = entry({"admin", "network", "diag_traceroute6"}, post("diag_traceroute6"), nil)
145 page.leaf = true
146 -- end
147 end
148
149 function wifi_join()
150 local tpl = require "luci.template"
151 local http = require "luci.http"
152 local dev = http.formvalue("device")
153 local ssid = http.formvalue("join")
154
155 if dev and ssid then
156 local cancel = (http.formvalue("cancel") or http.formvalue("cbi.cancel"))
157 if not cancel then
158 local cbi = require "luci.cbi"
159 local map = luci.cbi.load("admin_network/wifi_add")[1]
160
161 if map:parse() ~= cbi.FORM_DONE then
162 tpl.render("header")
163 map:render()
164 tpl.render("footer")
165 end
166
167 return
168 end
169 end
170
171 tpl.render("admin_network/wifi_join")
172 end
173
174 function wifi_add()
175 local dev = luci.http.formvalue("device")
176 local ntm = require "luci.model.network".init()
177
178 dev = dev and ntm:get_wifidev(dev)
179
180 if dev then
181 local net = dev:add_wifinet({
182 mode = "ap",
183 ssid = "OpenWrt",
184 encryption = "none"
185 })
186
187 ntm:save("wireless")
188 luci.http.redirect(net:adminlink())
189 end
190 end
191
192 function iface_status(ifaces)
193 local netm = require "luci.model.network".init()
194 local rv = { }
195
196 local iface
197 for iface in ifaces:gmatch("[%w%.%-_]+") do
198 local net = netm:get_network(iface)
199 local device = net and net:get_interface()
200 if device then
201 local data = {
202 id = iface,
203 desc = net:get_i18n(),
204 proto = net:proto(),
205 uptime = net:uptime(),
206 gwaddr = net:gwaddr(),
207 ipaddrs = net:ipaddrs(),
208 ip6addrs = net:ip6addrs(),
209 dnsaddrs = net:dnsaddrs(),
210 ip6prefix = net:ip6prefix(),
211 errors = net:errors(),
212 name = device:shortname(),
213 type = device:type(),
214 typename = device:get_type_i18n(),
215 ifname = device:name(),
216 macaddr = device:mac(),
217 is_up = net:is_up() and device:is_up(),
218 is_alias = net:is_alias(),
219 is_dynamic = net:is_dynamic(),
220 rx_bytes = device:rx_bytes(),
221 tx_bytes = device:tx_bytes(),
222 rx_packets = device:rx_packets(),
223 tx_packets = device:tx_packets(),
224
225 subdevices = { }
226 }
227
228 for _, device in ipairs(net:get_interfaces() or {}) do
229 data.subdevices[#data.subdevices+1] = {
230 name = device:shortname(),
231 type = device:type(),
232 typename = device:get_type_i18n(),
233 ifname = device:name(),
234 macaddr = device:mac(),
235 is_up = device:is_up(),
236 rx_bytes = device:rx_bytes(),
237 tx_bytes = device:tx_bytes(),
238 rx_packets = device:rx_packets(),
239 tx_packets = device:tx_packets(),
240 }
241 end
242
243 rv[#rv+1] = data
244 else
245 rv[#rv+1] = {
246 id = iface,
247 name = iface,
248 type = "ethernet"
249 }
250 end
251 end
252
253 if #rv > 0 then
254 luci.http.prepare_content("application/json")
255 luci.http.write_json(rv)
256 return
257 end
258
259 luci.http.status(404, "No such device")
260 end
261
262 function iface_reconnect(iface)
263 local netmd = require "luci.model.network".init()
264 local net = netmd:get_network(iface)
265 if net then
266 luci.sys.call("env -i /sbin/ifup %s >/dev/null 2>/dev/null"
267 % luci.util.shellquote(iface))
268 luci.http.status(200, "Reconnected")
269 return
270 end
271
272 luci.http.status(404, "No such interface")
273 end
274
275 function wifi_status(devs)
276 local s = require "luci.tools.status"
277 local rv = { }
278
279 if type(devs) == "string" then
280 local dev
281 for dev in devs:gmatch("[%w%.%-]+") do
282 rv[#rv+1] = s.wifi_network(dev)
283 end
284 end
285
286 if #rv > 0 then
287 luci.http.prepare_content("application/json")
288 luci.http.write_json(rv)
289 return
290 end
291
292 luci.http.status(404, "No such device")
293 end
294
295 function wifi_reconnect(radio)
296 local rc = luci.sys.call("env -i /sbin/wifi up %s" % luci.util.shellquote(radio))
297
298 if rc == 0 then
299 luci.http.status(200, "Reconnected")
300 else
301 luci.http.status(500, "Error")
302 end
303 end
304
305 function wifi_assoclist()
306 local s = require "luci.tools.status"
307
308 luci.http.prepare_content("application/json")
309 luci.http.write_json(s.wifi_assoclist())
310 end
311
312
313 local function _wifi_get_scan_results(cache_key)
314 local results = luci.util.ubus("session", "get", {
315 ubus_rpc_session = luci.model.uci:get_session_id(),
316 keys = { cache_key }
317 })
318
319 if type(results) == "table" and
320 type(results.values) == "table" and
321 type(results.values[cache_key]) == "table"
322 then
323 return results.values[cache_key]
324 end
325
326 return { }
327 end
328
329 function wifi_scan_trigger(radio, update)
330 local iw = radio and luci.sys.wifi.getiwinfo(radio)
331
332 if not iw then
333 luci.http.status(404, "No such radio device")
334 return
335 end
336
337 luci.http.status(200, "Scan scheduled")
338
339 if nixio.fork() == 0 then
340 io.stderr:close()
341 io.stdout:close()
342
343 local _, bss
344 local data, bssids = { }, { }
345 local cache_key = "scan_%s" % radio
346
347 luci.util.ubus("session", "set", {
348 ubus_rpc_session = luci.model.uci:get_session_id(),
349 values = { [cache_key] = nil }
350 })
351
352 for _, bss in ipairs(iw.scanlist or { }) do
353 data[_] = bss
354 bssids[bss.bssid] = bss
355 end
356
357 if update then
358 for _, bss in ipairs(_wifi_get_scan_results(cache_key)) do
359 if not bssids[bss.bssid] then
360 bss.stale = true
361 data[#data + 1] = bss
362 end
363 end
364 end
365
366 luci.util.ubus("session", "set", {
367 ubus_rpc_session = luci.model.uci:get_session_id(),
368 values = { [cache_key] = data }
369 })
370 end
371 end
372
373 function wifi_scan_results(radio)
374 local results = radio and _wifi_get_scan_results("scan_%s" % radio)
375
376 if results and #results > 0 then
377 luci.http.prepare_content("application/json")
378 luci.http.write_json(results)
379 else
380 luci.http.status(404, "No wireless scan results")
381 end
382 end
383
384 function lease_status()
385 local s = require "luci.tools.status"
386
387 luci.http.prepare_content("application/json")
388 luci.http.write('[')
389 luci.http.write_json(s.dhcp_leases())
390 luci.http.write(',')
391 luci.http.write_json(s.dhcp6_leases())
392 luci.http.write(']')
393 end
394
395 function switch_status(switches)
396 local s = require "luci.tools.status"
397
398 luci.http.prepare_content("application/json")
399 luci.http.write_json(s.switch_status(switches))
400 end
401
402 function diag_command(cmd, addr)
403 if addr and addr:match("^[a-zA-Z0-9%-%.:_]+$") then
404 luci.http.prepare_content("text/plain")
405
406 local util = io.popen(cmd % luci.util.shellquote(addr))
407 if util then
408 while true do
409 local ln = util:read("*l")
410 if not ln then break end
411 luci.http.write(ln)
412 luci.http.write("\n")
413 end
414
415 util:close()
416 end
417
418 return
419 end
420
421 luci.http.status(500, "Bad address")
422 end
423
424 function diag_ping(addr)
425 diag_command("ping -c 5 -W 1 %s 2>&1", addr)
426 end
427
428 function diag_traceroute(addr)
429 diag_command("traceroute -q 1 -w 1 -n %s 2>&1", addr)
430 end
431
432 function diag_nslookup(addr)
433 diag_command("nslookup %s 2>&1", addr)
434 end
435
436 function diag_ping6(addr)
437 diag_command("ping6 -c 5 %s 2>&1", addr)
438 end
439
440 function diag_traceroute6(addr)
441 diag_command("traceroute6 -q 1 -w 2 -n %s 2>&1", addr)
442 end