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