luci-app-mwan3: bugfix
[project/luci.git] / applications / luci-app-mwan3 / luasrc / controller / mwan3.lua
1 -- Copyright 2014 Aedan Renner <chipdankly@gmail.com>
2 -- Copyright 2018 Florian Eckert <fe@dev.tdt.de>
3 -- Licensed to the public under the GNU General Public License v2.
4
5 module("luci.controller.mwan3", package.seeall)
6
7 sys = require "luci.sys"
8 ut = require "luci.util"
9
10 ip = "ip -4 "
11
12 function index()
13         if not nixio.fs.access("/etc/config/mwan3") then
14                 return
15         end
16
17         entry({"admin", "status", "mwan"},
18                 alias("admin", "status", "mwan", "overview"),
19                 _("Load Balancing"), 600)
20
21         entry({"admin", "status", "mwan", "overview"},
22                 template("mwan/status_interface"))
23         entry({"admin", "status", "mwan", "detail"},
24                 template("mwan/status_detail"))
25         entry({"admin", "status", "mwan", "diagnostics"},
26                 template("mwan/status_diagnostics"))
27         entry({"admin", "status", "mwan", "troubleshooting"},
28                 template("mwan/status_troubleshooting"))
29         entry({"admin", "status", "mwan", "interface_status"},
30                 call("mwan_Status"))
31         entry({"admin", "status", "mwan", "detailed_status"},
32                 call("detailedStatus"))
33         entry({"admin", "status", "mwan", "diagnostics_display"},
34                 call("diagnosticsData"), nil).leaf = true
35         entry({"admin", "status", "mwan", "troubleshooting_display"},
36                 call("troubleshootingData"))
37
38
39         entry({"admin", "network", "mwan"},
40                 alias("admin", "network", "mwan", "interface"),
41                 _("Load Balancing"), 600)
42
43         entry({"admin", "network", "mwan", "globals"},
44                 cbi("mwan/globalsconfig"),
45                 _("Globals"), 5).leaf = true
46         entry({"admin", "network", "mwan", "interface"},
47                 arcombine(cbi("mwan/interface"), cbi("mwan/interfaceconfig")),
48                 _("Interfaces"), 10).leaf = true
49         entry({"admin", "network", "mwan", "member"},
50                 arcombine(cbi("mwan/member"), cbi("mwan/memberconfig")),
51                 _("Members"), 20).leaf = true
52         entry({"admin", "network", "mwan", "policy"},
53                 arcombine(cbi("mwan/policy"), cbi("mwan/policyconfig")),
54                 _("Policies"), 30).leaf = true
55         entry({"admin", "network", "mwan", "rule"},
56                 arcombine(cbi("mwan/rule"), cbi("mwan/ruleconfig")),
57                 _("Rules"), 40).leaf = true
58         entry({"admin", "network", "mwan", "notify"},
59                 form("mwan/notify"),
60                 _("Notification"), 50).leaf = true
61 end
62
63 function mwan_Status()
64         local status = ut.ubus("mwan3", "status", {})
65
66         luci.http.prepare_content("application/json")
67         if status ~= nil then
68                 luci.http.write_json(status)
69         else
70                 luci.http.write_json({})
71         end
72 end
73
74 function detailedStatus()
75         local statusInfo = ut.trim(sys.exec("/usr/sbin/mwan3 status"))
76         luci.http.prepare_content("text/plain")
77         if statusInfo ~= "" then
78                 luci.http.write(statusInfo)
79         else
80                 luci.http.write("Unable to get status information")
81         end
82 end
83
84 function diagnosticsData(interface, task)
85         function getInterfaceNumber(interface)
86                 local number = 0
87                 local interfaceNumber
88                 local uci = require "luci.model.uci".cursor()
89                 uci:foreach("mwan3", "interface",
90                         function (section)
91                                 number = number+1
92                                 if section[".name"] == interface then
93                                         interfaceNumber = number
94                                 end
95                         end
96                 )
97                 return interfaceNumber
98         end
99
100         function diag_command(cmd, addr)
101                 if addr and addr:match("^[a-zA-Z0-9%-%.:_]+$") then
102                         local util = io.popen(cmd % ut.shellquote(addr))
103                         if util then
104                                 while true do
105                                         local ln = util:read("*l")
106                                         if not ln then break end
107                                         luci.http.write(ln)
108                                         luci.http.write("\n")
109                                 end
110                                 util:close()
111                         end
112                         return
113                 end
114         end
115
116         function get_gateway(inteface)
117                 local dump = require("luci.util").ubus("network.interface.%s" % interface, "status", {})
118                 local gateway
119                 if dump and dump.route then
120                         local _, route
121                         for _, route in ipairs(dump.route) do
122                                 if dump.route[_].target == "0.0.0.0" then
123                                         gateway = dump.route[_].nexthop
124                                 end
125                         end
126                 end
127                 return gateway
128         end
129
130         local mArray = {}
131         local results = ""
132         local number = getInterfaceNumber(interface)
133
134         local uci = require "luci.model.uci".cursor(nil, "/var/state")
135         local device = uci:get("network", interface, "ifname")
136
137         luci.http.prepare_content("text/plain")
138         if device ~= "" then
139                 if task == "ping_gateway" then
140                         local gateway = get_gateway(interface)
141                         if gateway ~= nil then
142                                 diag_command("ping -c 5 -W 1 %s 2>&1", gateway)
143                         else
144                                 luci.http.prepare_content("text/plain")
145                                 luci.http.write(string.format("No gateway for interface %s found.", interface))
146                         end
147                 elseif task == "ping_trackips" then
148                         local trackips = uci:get("mwan3", interface, "track_ip")
149                         if #trackips > 0 then
150                                 for i in pairs(trackips) do
151                                         diag_command("ping -c 5 -W 1 %s 2>&1", trackips[i])
152                                 end
153                         else
154                                 luci.http.write(string.format("No tracking Hosts for interface %s defined.", interface))
155                         end
156                 elseif task == "check_rules" then
157                         local number = getInterfaceNumber(interface)
158                         local iif = 1000 + number
159                         local fwmark = 2000 + number
160                         local iif_rule  = sys.exec(string.format("ip rule | grep %d", iif))
161                         local fwmark_rule = sys.exec(string.format("ip rule | grep %d", fwmark))
162                         if iif_rule ~= "" and fwmark_rule ~= "" then
163                                 luci.http.write(string.format("All required IP rules for interface %s found", interface))
164                                 luci.http.write("\n")
165                                 luci.http.write(fwmark_rule)
166                                 luci.http.write(iif_rule)
167                         elseif iif_rule == "" and fwmark_rule ~= "" then
168                                 luci.http.write(string.format("Only one IP rules for interface %s found", interface))
169                                 luci.http.write("\n")
170                                 luci.http.write(fwmark_rule)
171                         elseif iif_rule ~= "" and fwmark_rule == "" then
172                                 luci.http.write(string.format("Only one IP rules for interface %s found", interface))
173                                 luci.http.write("\n")
174                                 luci.http.write(iif_rule)
175                         else
176                                 luci.http.write(string.format("Missing both IP rules for interface %s", interface))
177                         end
178                 elseif task == "check_routes" then
179                         local number = getInterfaceNumber(interface)
180                         local routeTable = sys.exec(string.format("ip route list table %s", number))
181                         if routeTable ~= "" then
182                                 luci.http.write(string.format("Routing table %s for interface %s found", number, interface))
183                                 luci.http.write("\n")
184                                 luci.http.write(routeTable)
185                         else
186                                 luci.http.write(string.format("Routing table %s for interface %s not found", number, interface))
187                         end
188                 elseif task == "hotplug_ifup" then
189                         os.execute(string.format("/usr/sbin/mwan3 ifup %s", ut.shellquote(interface)))
190                         luci.http.write(string.format("Hotplug ifup sent to interface %s", interface))
191                 elseif task == "hotplug_ifdown" then
192                         os.execute(string.format("/usr/sbin/mwan3 ifdown %s", ut.shellquote(interface)))
193                         luci.http.write(string.format("Hotplug ifdown sent to interface %s", interface))
194                 else
195                         luci.http.write("Unknown task")
196                 end
197         else
198                 luci.http.write(string.format("Unable to perform diagnostic tests on %s.", interface))
199                 luci.http.write("\n")
200                 luci.http.write("There is no physical or virtual device associated with this interface.")
201         end
202 end
203
204 function troubleshootingData()
205         local ver = require "luci.version"
206         local dash = "-------------------------------------------------"
207
208         luci.http.prepare_content("text/plain")
209
210         luci.http.write("\n")
211         luci.http.write("\n")
212         luci.http.write("Software-Version")
213         luci.http.write("\n")
214         luci.http.write(dash)
215         luci.http.write("\n")
216         if ver.distversion then
217                 luci.http.write(string.format("OpenWrt - %s", ver.distversion))
218                 luci.http.write("\n")
219         else
220                 luci.http.write("OpenWrt - unknown")
221                 luci.http.write("\n")
222         end
223
224         if ver.luciversion then
225                 luci.http.write(string.format("LuCI - %s", ver.luciversion))
226                 luci.http.write("\n")
227         else
228                 luci.http.write("LuCI - unknown")
229                 luci.http.write("\n")
230         end
231
232         luci.http.write("\n")
233         luci.http.write("\n")
234         local output = ut.trim(sys.exec("ip a show"))
235         luci.http.write("Output of \"ip a show\"")
236         luci.http.write("\n")
237         luci.http.write(dash)
238         luci.http.write("\n")
239         if output ~= "" then
240                 luci.http.write(output)
241                 luci.http.write("\n")
242         else
243                 luci.http.write("No data found")
244                 luci.http.write("\n")
245         end
246
247         luci.http.write("\n")
248         luci.http.write("\n")
249         local output = ut.trim(sys.exec("ip route show"))
250         luci.http.write("Output of \"ip route show\"")
251         luci.http.write("\n")
252         luci.http.write(dash)
253         luci.http.write("\n")
254         if output ~= "" then
255                 luci.http.write(output)
256                 luci.http.write("\n")
257         else
258                 luci.http.write("No data found")
259                 luci.http.write("\n")
260         end
261
262         luci.http.write("\n")
263         luci.http.write("\n")
264         local output = ut.trim(sys.exec("ip rule show"))
265         luci.http.write("Output of \"ip rule show\"")
266         luci.http.write("\n")
267         luci.http.write(dash)
268         luci.http.write("\n")
269         if output ~= "" then
270                 luci.http.write(output)
271                 luci.http.write("\n")
272         else
273                 luci.http.write("No data found")
274                 luci.http.write("\n")
275         end
276
277         luci.http.write("\n")
278         luci.http.write("\n")
279         luci.http.write("Output of \"ip route list table 1-250\"")
280         luci.http.write("\n")
281         luci.http.write(dash)
282         luci.http.write("\n")
283         for i=1,250 do
284                 local output = ut.trim(sys.exec(string.format("ip route list table %d", i)))
285                 if output ~= "" then
286                         luci.http.write(string.format("Table %s: ", i))
287                         luci.http.write(output)
288                         luci.http.write("\n")
289                 end
290         end
291
292         luci.http.write("\n")
293         luci.http.write("\n")
294         local output = ut.trim(sys.exec("iptables -L -t mangle -v -n"))
295         luci.http.write("Output of \"iptables -L -t mangle -v -n\"")
296         luci.http.write("\n")
297         luci.http.write(dash)
298         luci.http.write("\n")
299         if output ~= "" then
300                 luci.http.write(output)
301                 luci.http.write("\n")
302         else
303                 luci.http.write("No data found")
304                 luci.http.write("\n")
305         end
306 end