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