luci-mod-network: switch to client side wifi configuration pages
[oweals/luci.git] / modules / luci-mod-network / 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_status"}, call("wifi_status"), nil)
41                         page.leaf = true
42
43                         page = entry({"admin", "network", "wireless_reconnect"}, post("wifi_reconnect"), nil)
44                         page.leaf = true
45
46                         page = entry({"admin", "network", "wireless"}, view("network/wireless"), _('Wireless'), 15)
47                         page.leaf = true
48                 end
49
50
51                 page = entry({"admin", "network", "iface_status"}, call("iface_status"), nil)
52                 page.leaf = true
53
54                 page = entry({"admin", "network", "iface_reconnect"}, post("iface_reconnect"), nil)
55                 page.leaf = true
56
57                 page = entry({"admin", "network", "iface_down"}, post("iface_down"), nil)
58                 page.leaf = true
59
60                 page = entry({"admin", "network", "network"}, view("network/interfaces"), _("Interfaces"), 10)
61                 page.leaf   = true
62                 page.subindex = true
63
64
65                 if nixio.fs.access("/etc/config/dhcp") then
66                         page = node("admin", "network", "dhcp")
67                         page.target = view("network/dhcp")
68                         page.title  = _("DHCP and DNS")
69                         page.order  = 30
70
71                         page = node("admin", "network", "hosts")
72                         page.target = view("network/hosts")
73                         page.title  = _("Hostnames")
74                         page.order  = 40
75                 end
76
77                 page  = node("admin", "network", "routes")
78                 page.target = view("network/routes")
79                 page.title  = _("Static Routes")
80                 page.order  = 50
81
82                 page = node("admin", "network", "diagnostics")
83                 page.target = template("admin_network/diagnostics")
84                 page.title  = _("Diagnostics")
85                 page.order  = 60
86
87                 page = entry({"admin", "network", "diag_ping"}, post("diag_ping"), nil)
88                 page.leaf = true
89
90                 page = entry({"admin", "network", "diag_nslookup"}, post("diag_nslookup"), nil)
91                 page.leaf = true
92
93                 page = entry({"admin", "network", "diag_traceroute"}, post("diag_traceroute"), nil)
94                 page.leaf = true
95
96                 page = entry({"admin", "network", "diag_ping6"}, post("diag_ping6"), nil)
97                 page.leaf = true
98
99                 page = entry({"admin", "network", "diag_traceroute6"}, post("diag_traceroute6"), nil)
100                 page.leaf = true
101 --      end
102 end
103
104 function iface_status(ifaces)
105         local netm = require "luci.model.network".init()
106         local rv   = { }
107
108         local iface
109         for iface in ifaces:gmatch("[%w%.%-_]+") do
110                 local net = netm:get_network(iface)
111                 local device = net and net:get_interface()
112                 if device then
113                         local data = {
114                                 id         = iface,
115                                 desc       = net:get_i18n(),
116                                 proto      = net:proto(),
117                                 uptime     = net:uptime(),
118                                 gwaddr     = net:gwaddr(),
119                                 ipaddrs    = net:ipaddrs(),
120                                 ip6addrs   = net:ip6addrs(),
121                                 dnsaddrs   = net:dnsaddrs(),
122                                 ip6prefix  = net:ip6prefix(),
123                                 errors     = net:errors(),
124                                 name       = device:shortname(),
125                                 type       = device:type(),
126                                 typename   = device:get_type_i18n(),
127                                 ifname     = device:name(),
128                                 macaddr    = device:mac(),
129                                 is_up      = net:is_up() and device:is_up(),
130                                 is_alias   = net:is_alias(),
131                                 is_dynamic = net:is_dynamic(),
132                                 is_auto    = net:is_auto(),
133                                 rx_bytes   = device:rx_bytes(),
134                                 tx_bytes   = device:tx_bytes(),
135                                 rx_packets = device:rx_packets(),
136                                 tx_packets = device:tx_packets(),
137
138                                 subdevices = { }
139                         }
140
141                         for _, device in ipairs(net:get_interfaces() or {}) do
142                                 data.subdevices[#data.subdevices+1] = {
143                                         name       = device:shortname(),
144                                         type       = device:type(),
145                                         typename   = device:get_type_i18n(),
146                                         ifname     = device:name(),
147                                         macaddr    = device:mac(),
148                                         is_up      = device:is_up(),
149                                         rx_bytes   = device:rx_bytes(),
150                                         tx_bytes   = device:tx_bytes(),
151                                         rx_packets = device:rx_packets(),
152                                         tx_packets = device:tx_packets(),
153                                 }
154                         end
155
156                         rv[#rv+1] = data
157                 else
158                         rv[#rv+1] = {
159                                 id   = iface,
160                                 name = iface,
161                                 type = "ethernet"
162                         }
163                 end
164         end
165
166         if #rv > 0 then
167                 luci.http.prepare_content("application/json")
168                 luci.http.write_json(rv)
169                 return
170         end
171
172         luci.http.status(404, "No such device")
173 end
174
175 function iface_reconnect(iface)
176         local netmd = require "luci.model.network".init()
177         local net = netmd:get_network(iface)
178         if net then
179                 luci.sys.call("env -i /sbin/ifup %s >/dev/null 2>/dev/null"
180                         % luci.util.shellquote(iface))
181                 luci.http.status(200, "Reconnected")
182                 return
183         end
184
185         luci.http.status(404, "No such interface")
186 end
187
188 local function addr2dev(addr, src)
189         local ip = require "luci.ip"
190         local route = ip.route(addr, src)
191         if not src and route and route.src then
192                 route = ip.route(addr, route.src:string())
193         end
194         return route and route.dev
195 end
196
197 function iface_down(iface, force)
198         local netmd = require "luci.model.network".init()
199         local peer = luci.http.getenv("REMOTE_ADDR")
200         local serv = luci.http.getenv("SERVER_ADDR")
201
202         if force ~= "force" and serv and peer then
203                 local dev = addr2dev(peer, serv)
204                 if dev then
205                         local nets = netmd:get_networks()
206                         local outnet = nil
207                         local _, net, ai
208
209                         for _, net in ipairs(nets) do
210                                 if net:contains_interface(dev) then
211                                         outnet = net
212                                         break
213                                 end
214                         end
215
216                         if outnet:name() == iface then
217                                 luci.http.status(409, "Is inbound interface")
218                                 return
219                         end
220
221                         local peeraddr = outnet:get("peeraddr")
222                         for _, ai in ipairs(peeraddr and nixio.getaddrinfo(peeraddr) or {}) do
223                                 local peerdev = addr2dev(ai.address)
224                                 for _, net in ipairs(peerdev and nets or {}) do
225                                         if net:contains_interface(peerdev) and net:name() == iface then
226                                                 luci.http.status(409, "Is inbound interface")
227                                                 return
228                                         end
229                                 end
230                         end
231                 end
232         end
233
234         if netmd:get_network(iface) then
235                 luci.sys.call("env -i /sbin/ifdown %s >/dev/null 2>/dev/null"
236                         % luci.util.shellquote(iface))
237                 luci.http.status(200, "Shut down")
238                 return
239         end
240
241         luci.http.status(404, "No such interface")
242 end
243
244 function wifi_status(devs)
245         local s    = require "luci.tools.status"
246         local rv   = { }
247
248         if type(devs) == "string" then
249                 local dev
250                 for dev in devs:gmatch("[%w%.%-]+") do
251                         rv[#rv+1] = s.wifi_network(dev)
252                 end
253         end
254
255         if #rv > 0 then
256                 luci.http.prepare_content("application/json")
257                 luci.http.write_json(rv)
258                 return
259         end
260
261         luci.http.status(404, "No such device")
262 end
263
264 function wifi_reconnect(radio)
265         local rc = luci.sys.call("env -i /sbin/wifi up %s >/dev/null" % luci.util.shellquote(radio))
266
267         if rc == 0 then
268                 luci.http.status(200, "Reconnected")
269         else
270                 luci.http.status(500, "Error")
271         end
272 end
273
274 function switch_status(switches)
275         local s = require "luci.tools.status"
276
277         luci.http.prepare_content("application/json")
278         luci.http.write_json(s.switch_status(switches))
279 end
280
281 function diag_command(cmd, addr)
282         if addr and addr:match("^[a-zA-Z0-9%-%.:_]+$") then
283                 luci.http.prepare_content("text/plain")
284
285                 local util = io.popen(cmd % luci.util.shellquote(addr))
286                 if util then
287                         while true do
288                                 local ln = util:read("*l")
289                                 if not ln then break end
290                                 luci.http.write(ln)
291                                 luci.http.write("\n")
292                         end
293
294                         util:close()
295                 end
296
297                 return
298         end
299
300         luci.http.status(500, "Bad address")
301 end
302
303 function diag_ping(addr)
304         diag_command("ping -c 5 -W 1 %s 2>&1", addr)
305 end
306
307 function diag_traceroute(addr)
308         diag_command("traceroute -q 1 -w 1 -n %s 2>&1", addr)
309 end
310
311 function diag_nslookup(addr)
312         diag_command("nslookup %s 2>&1", addr)
313 end
314
315 function diag_ping6(addr)
316         diag_command("ping6 -c 5 %s 2>&1", addr)
317 end
318
319 function diag_traceroute6(addr)
320         diag_command("traceroute6 -q 1 -w 2 -n %s 2>&1", addr)
321 end