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