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