Merge pull request #965 from cshore-firmware/pull-request-odhcpd-mac
[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")), _("Wireless"), 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                                 ipaddrs    = net:ipaddrs(),
239                                 ip6addrs   = net:ip6addrs(),
240                                 dnsaddrs   = net:dnsaddrs(),
241                                 ip6prefix  = net:ip6prefix(),
242                                 name       = device:shortname(),
243                                 type       = device:type(),
244                                 ifname     = device:name(),
245                                 macaddr    = device:mac(),
246                                 is_up      = device:is_up(),
247                                 rx_bytes   = device:rx_bytes(),
248                                 tx_bytes   = device:tx_bytes(),
249                                 rx_packets = device:rx_packets(),
250                                 tx_packets = device:tx_packets(),
251
252                                 subdevices = { }
253                         }
254
255                         for _, device in ipairs(net:get_interfaces() or {}) do
256                                 data.subdevices[#data.subdevices+1] = {
257                                         name       = device:shortname(),
258                                         type       = device:type(),
259                                         ifname     = device:name(),
260                                         macaddr    = device:mac(),
261                                         macaddr    = device:mac(),
262                                         is_up      = device:is_up(),
263                                         rx_bytes   = device:rx_bytes(),
264                                         tx_bytes   = device:tx_bytes(),
265                                         rx_packets = device:rx_packets(),
266                                         tx_packets = device:tx_packets(),
267                                 }
268                         end
269
270                         rv[#rv+1] = data
271                 else
272                         rv[#rv+1] = {
273                                 id   = iface,
274                                 name = iface,
275                                 type = "ethernet"
276                         }
277                 end
278         end
279
280         if #rv > 0 then
281                 luci.http.prepare_content("application/json")
282                 luci.http.write_json(rv)
283                 return
284         end
285
286         luci.http.status(404, "No such device")
287 end
288
289 function iface_reconnect(iface)
290         local netmd = require "luci.model.network".init()
291         local net = netmd:get_network(iface)
292         if net then
293                 luci.sys.call("env -i /sbin/ifup %q >/dev/null 2>/dev/null" % iface)
294                 luci.http.status(200, "Reconnected")
295                 return
296         end
297
298         luci.http.status(404, "No such interface")
299 end
300
301 function iface_shutdown(iface)
302         local netmd = require "luci.model.network".init()
303         local net = netmd:get_network(iface)
304         if net then
305                 luci.sys.call("env -i /sbin/ifdown %q >/dev/null 2>/dev/null" % iface)
306                 luci.http.status(200, "Shutdown")
307                 return
308         end
309
310         luci.http.status(404, "No such interface")
311 end
312
313 function iface_delete(iface)
314         local netmd = require "luci.model.network".init()
315         local net = netmd:del_network(iface)
316         if net then
317                 luci.sys.call("env -i /sbin/ifdown %q >/dev/null 2>/dev/null" % iface)
318                 luci.http.redirect(luci.dispatcher.build_url("admin/network/network"))
319                 netmd:commit("network")
320                 netmd:commit("wireless")
321                 return
322         end
323
324         luci.http.status(404, "No such interface")
325 end
326
327 function wifi_status(devs)
328         local s    = require "luci.tools.status"
329         local rv   = { }
330
331         local dev
332         for dev in devs:gmatch("[%w%.%-]+") do
333                 rv[#rv+1] = s.wifi_network(dev)
334         end
335
336         if #rv > 0 then
337                 luci.http.prepare_content("application/json")
338                 luci.http.write_json(rv)
339                 return
340         end
341
342         luci.http.status(404, "No such device")
343 end
344
345 local function wifi_reconnect_shutdown(shutdown, wnet)
346         local netmd = require "luci.model.network".init()
347         local net = netmd:get_wifinet(wnet)
348         local dev = net:get_device()
349         if dev and net then
350                 dev:set("disabled", nil)
351                 net:set("disabled", shutdown and 1 or nil)
352                 netmd:commit("wireless")
353
354                 luci.sys.call("env -i /bin/ubus call network reload >/dev/null 2>/dev/null")
355                 luci.http.status(200, shutdown and "Shutdown" or "Reconnected")
356
357                 return
358         end
359
360         luci.http.status(404, "No such radio")
361 end
362
363 function wifi_reconnect(wnet)
364         wifi_reconnect_shutdown(false, wnet)
365 end
366
367 function wifi_shutdown(wnet)
368         wifi_reconnect_shutdown(true, wnet)
369 end
370
371 function lease_status()
372         local s = require "luci.tools.status"
373
374         luci.http.prepare_content("application/json")
375         luci.http.write('[')
376         luci.http.write_json(s.dhcp_leases())
377         luci.http.write(',')
378         luci.http.write_json(s.dhcp6_leases())
379         luci.http.write(']')
380 end
381
382 function switch_status(switches)
383         local s = require "luci.tools.status"
384
385         luci.http.prepare_content("application/json")
386         luci.http.write_json(s.switch_status(switches))
387 end
388
389 function diag_command(cmd, addr)
390         if addr and addr:match("^[a-zA-Z0-9%-%.:_]+$") then
391                 luci.http.prepare_content("text/plain")
392
393                 local util = io.popen(cmd % addr)
394                 if util then
395                         while true do
396                                 local ln = util:read("*l")
397                                 if not ln then break end
398                                 luci.http.write(ln)
399                                 luci.http.write("\n")
400                         end
401
402                         util:close()
403                 end
404
405                 return
406         end
407
408         luci.http.status(500, "Bad address")
409 end
410
411 function diag_ping(addr)
412         diag_command("ping -c 5 -W 1 %q 2>&1", addr)
413 end
414
415 function diag_traceroute(addr)
416         diag_command("traceroute -q 1 -w 1 -n %q 2>&1", addr)
417 end
418
419 function diag_nslookup(addr)
420         diag_command("nslookup %q 2>&1", addr)
421 end
422
423 function diag_ping6(addr)
424         diag_command("ping6 -c 5 %q 2>&1", addr)
425 end
426
427 function diag_traceroute6(addr)
428         diag_command("traceroute6 -q 1 -w 2 -n %q 2>&1", addr)
429 end