luci-app-nlbw: fix sporadic premature EOF when rendering JSON data
[project/luci.git] / applications / luci-app-mwan3 / luasrc / controller / mwan3.lua
1 module("luci.controller.mwan3", package.seeall)
2
3 sys = require "luci.sys"
4 ut = require "luci.util"
5
6 ip = "ip -4 "
7
8 function index()
9         if not nixio.fs.access("/etc/config/mwan3") then
10                 return
11         end
12
13         entry({"admin", "status", "mwan"},
14                 alias("admin", "status", "mwan", "overview"),
15                 _("Load Balancing"), 600)
16
17         entry({"admin", "status", "mwan", "overview"},
18                 template("mwan/status_interface"))
19         entry({"admin", "status", "mwan", "detail"},
20                 template("mwan/status_detail"))
21         entry({"admin", "status", "mwan", "diagnostics"},
22                 template("mwan/status_diagnostics"))
23         entry({"admin", "status", "mwan", "troubleshooting"},
24                 template("mwan/status_troubleshooting"))
25         entry({"admin", "status", "mwan", "interface_status"},
26                 call("interfaceStatus"))
27         entry({"admin", "status", "mwan", "detailed_status"},
28                 call("detailedStatus"))
29         entry({"admin", "status", "mwan", "diagnostics_display"},
30                 call("diagnosticsData"), nil).leaf = true
31         entry({"admin", "status", "mwan", "troubleshooting_display"},
32                 call("troubleshootingData"))
33
34
35         entry({"admin", "network", "mwan"},
36                 alias("admin", "network", "mwan", "interface"),
37                 _("Load Balancing"), 600)
38
39         entry({"admin", "network", "mwan", "globals"},
40                 cbi("mwan/globalsconfig"),
41                 _("Globals"), 5).leaf = true
42         entry({"admin", "network", "mwan", "interface"},
43                 arcombine(cbi("mwan/interface"), cbi("mwan/interfaceconfig")),
44                 _("Interfaces"), 10).leaf = true
45         entry({"admin", "network", "mwan", "member"},
46                 arcombine(cbi("mwan/member"), cbi("mwan/memberconfig")),
47                 _("Members"), 20).leaf = true
48         entry({"admin", "network", "mwan", "policy"},
49                 arcombine(cbi("mwan/policy"), cbi("mwan/policyconfig")),
50                 _("Policies"), 30).leaf = true
51         entry({"admin", "network", "mwan", "rule"},
52                 arcombine(cbi("mwan/rule"), cbi("mwan/ruleconfig")),
53                 _("Rules"), 40).leaf = true
54         entry({"admin", "network", "mwan", "notify"},
55                 cbi("mwan/notify"),
56                 _("Notification"), 50).leaf = true
57 end
58
59 function getInterfaceStatus(ruleNumber, interfaceName)
60         if ut.trim(sys.exec("uci -q -p /var/state get mwan3." .. interfaceName .. ".enabled")) == "1" then
61                 if ut.trim(sys.exec(ip .. "route list table " .. ruleNumber)) ~= "" then
62                         if ut.trim(sys.exec("uci -q -p /var/state get mwan3." .. interfaceName .. ".track_ip")) ~= "" then
63                                 return "online"
64                         else
65                                 return "notMonitored"
66                         end
67                 else
68                         return "offline"
69                 end
70         else
71                 return "notEnabled"
72         end
73 end
74
75 function getInterfaceName()
76         local ruleNumber, status = 0, ""
77         uci.cursor():foreach("mwan3", "interface",
78                 function (section)
79                         ruleNumber = ruleNumber+1
80                         status = status .. section[".name"] .. "[" .. getInterfaceStatus(ruleNumber, section[".name"]) .. "]"
81                 end
82         )
83         return status
84 end
85
86 function interfaceStatus()
87         local ntm = require "luci.model.network".init()
88
89         local mArray = {}
90
91         -- overview status
92         local statusString = getInterfaceName()
93         if statusString ~= "" then
94                 mArray.wans = {}
95                 wansid = {}
96
97                 for wanName, interfaceState in string.gfind(statusString, "([^%[]+)%[([^%]]+)%]") do
98                         local wanInterfaceName = ut.trim(sys.exec("uci -q -p /var/state get network." .. wanName .. ".ifname"))
99                                 if wanInterfaceName == "" then
100                                         wanInterfaceName = "X"
101                                 end
102                         local wanDeviceLink = ntm:get_interface(wanInterfaceName)
103                                 wanDeviceLink = wanDeviceLink and wanDeviceLink:get_network()
104                                 wanDeviceLink = wanDeviceLink and wanDeviceLink:adminlink() or "#"
105                         wansid[wanName] = #mArray.wans + 1
106                         mArray.wans[wansid[wanName]] = { name = wanName, link = wanDeviceLink, ifname = wanInterfaceName, status = interfaceState }
107                 end
108         end
109
110         -- overview status log
111         local mwanLog = ut.trim(sys.exec("logread | grep mwan3 | tail -n 50 | sed 'x;1!H;$!d;x' 2>/dev/null"))
112         if mwanLog ~= "" then
113                 mArray.mwanlog = { mwanLog }
114         end
115
116         luci.http.prepare_content("application/json")
117         luci.http.write_json(mArray)
118 end
119
120 function detailedStatus()
121         local mArray = {}
122
123         -- detailed mwan status
124         local detailStatusInfo = ut.trim(sys.exec("/usr/sbin/mwan3 status"))
125         if detailStatusInfo ~= "" then
126                 mArray.mwandetail = { detailStatusInfo }
127         end
128
129         luci.http.prepare_content("application/json")
130         luci.http.write_json(mArray)
131 end
132
133 function diagnosticsData(interface, tool, task)
134         function getInterfaceNumber()
135                 local number = 0
136                 uci.cursor():foreach("mwan3", "interface",
137                         function (section)
138                                 number = number+1
139                                 if section[".name"] == interface then
140                                         interfaceNumber = number
141                                 end
142                         end
143                 )
144         end
145
146         local mArray = {}
147
148         local results = ""
149         if tool == "service" then
150                 os.execute("/usr/sbin/mwan3 " .. task)
151                 if task == "restart" then
152                         results = "MWAN3 restarted"
153                 elseif task == "stop" then
154                         results = "MWAN3 stopped"
155                 else
156                         results = "MWAN3 started"
157                 end
158         else
159                 local interfaceDevice = ut.trim(sys.exec("uci -q -p /var/state get network." .. interface .. ".ifname"))
160                 if interfaceDevice ~= "" then
161                         if tool == "ping" then
162                                 local gateway = ut.trim(sys.exec("route -n | awk '{if ($8 == \"" .. interfaceDevice .. "\" && $1 == \"0.0.0.0\" && $3 == \"0.0.0.0\") print $2}'"))
163                                 if gateway ~= "" then
164                                         if task == "gateway" then
165                                                 local pingCommand = "ping -c 3 -W 2 -I " .. interfaceDevice .. " " .. gateway
166                                                 results = pingCommand .. "\n\n" .. sys.exec(pingCommand)
167                                         else
168                                                 local tracked = ut.trim(sys.exec("uci -q -p /var/state get mwan3." .. interface .. ".track_ip"))
169                                                 if tracked ~= "" then
170                                                         for z in tracked:gmatch("[^ ]+") do
171                                                                 local pingCommand = "ping -c 3 -W 2 -I " .. interfaceDevice .. " " .. z
172                                                                 results = results .. pingCommand .. "\n\n" .. sys.exec(pingCommand) .. "\n\n"
173                                                         end
174                                                 else
175                                                         results = "No tracking IP addresses configured on " .. interface
176                                                 end
177                                         end
178                                 else
179                                         results = "No default gateway for " .. interface .. " found. Default route does not exist or is configured incorrectly"
180                                 end
181                         elseif tool == "rulechk" then
182                                 getInterfaceNumber()
183                                 local rule1 = sys.exec(ip .. "rule | grep $(echo $((" .. interfaceNumber .. " + 1000)))")
184                                 local rule2 = sys.exec(ip .. "rule | grep $(echo $((" .. interfaceNumber .. " + 2000)))")
185                                 if rule1 ~= "" and rule2 ~= "" then
186                                         results = "All required interface IP rules found:\n\n" .. rule1 .. rule2
187                                 elseif rule1 ~= "" or rule2 ~= "" then
188                                         results = "Missing 1 of the 2 required interface IP rules\n\n\nRules found:\n\n" .. rule1 .. rule2
189                                 else
190                                         results = "Missing both of the required interface IP rules"
191                                 end
192                         elseif tool == "routechk" then
193                                 getInterfaceNumber()
194                                 local routeTable = sys.exec(ip .. "route list table " .. interfaceNumber)
195                                 if routeTable ~= "" then
196                                         results = "Interface routing table " .. interfaceNumber .. " was found:\n\n" .. routeTable
197                                 else
198                                         results = "Missing required interface routing table " .. interfaceNumber
199                                 end
200                         elseif tool == "hotplug" then
201                                 if task == "ifup" then
202                                         os.execute("/usr/sbin/mwan3 ifup " .. interface)
203                                         results = "Hotplug ifup sent to interface " .. interface .. "..."
204                                 else
205                                         os.execute("/usr/sbin/mwan3 ifdown " .. interface)
206                                         results = "Hotplug ifdown sent to interface " .. interface .. "..."
207                                 end
208                         end
209                 else
210                         results = "Unable to perform diagnostic tests on " .. interface .. ". There is no physical or virtual device associated with this interface"
211                 end
212         end
213         if results ~= "" then
214                 results = ut.trim(results)
215                 mArray.diagnostics = { results }
216         end
217
218         luci.http.prepare_content("application/json")
219         luci.http.write_json(mArray)
220 end
221
222 function troubleshootingData()
223         local ver = require "luci.version"
224
225         local mArray = {}
226
227         -- software versions
228         local wrtRelease = ut.trim(ver.distversion)
229                 if wrtRelease ~= "" then
230                         wrtRelease = "OpenWrt - " .. wrtRelease
231                 else
232                         wrtRelease = "OpenWrt - unknown"
233                 end
234         local luciRelease = ut.trim(ver.luciversion)
235                 if luciRelease ~= "" then
236                         luciRelease = "\nLuCI - " .. luciRelease
237                 else
238                         luciRelease = "\nLuCI - unknown"
239                 end
240         local mwanVersion = ut.trim(sys.exec("opkg info mwan3 | grep Version | awk '{print $2}'"))
241                 if mwanVersion ~= "" then
242                         mwanVersion = "\n\nmwan3 - " .. mwanVersion
243                 else
244                         mwanVersion = "\n\nmwan3 - unknown"
245                 end
246         local mwanLuciVersion = ut.trim(sys.exec("opkg info luci-app-mwan3 | grep Version | awk '{print $2}'"))
247                 if mwanLuciVersion ~= "" then
248                         mwanLuciVersion = "\nmwan3-luci - " .. mwanLuciVersion
249                 else
250                         mwanLuciVersion = "\nmwan3-luci - unknown"
251                 end
252         mArray.versions = { wrtRelease .. luciRelease .. mwanVersion .. mwanLuciVersion }
253
254         -- mwan config
255         local mwanConfig = ut.trim(sys.exec("cat /etc/config/mwan3"))
256                 if mwanConfig == "" then
257                         mwanConfig = "No data found"
258                 end
259         mArray.mwanconfig = { mwanConfig }
260
261         -- network config
262         local networkConfig = ut.trim(sys.exec("cat /etc/config/network | sed -e 's/.*username.*/       USERNAME HIDDEN/' -e 's/.*password.*/   PASSWORD HIDDEN/'"))
263                 if networkConfig == "" then
264                         networkConfig = "No data found"
265                 end
266         mArray.netconfig = { networkConfig }
267
268         -- wireless config
269         local wirelessConfig = ut.trim(sys.exec("cat /etc/config/wireless | sed -e 's/.*username.*/     USERNAME HIDDEN/' -e 's/.*password.*/   PASSWORD HIDDEN/' -e 's/.*key.*/        KEY HIDDEN/'"))
270                 if wirelessConfig == "" then
271                         wirelessConfig = "No data found"
272                 end
273         mArray.wificonfig = { wirelessConfig }
274         
275         -- ifconfig
276         local ifconfig = ut.trim(sys.exec("ifconfig"))
277                 if ifconfig == "" then
278                         ifconfig = "No data found"
279                 end
280         mArray.ifconfig = { ifconfig }
281
282         -- route -n
283         local routeShow = ut.trim(sys.exec("route -n"))
284                 if routeShow == "" then
285                         routeShow = "No data found"
286                 end
287         mArray.routeshow = { routeShow }
288
289         -- ip rule show
290         local ipRuleShow = ut.trim(sys.exec(ip .. "rule show"))
291                 if ipRuleShow == "" then
292                         ipRuleShow = "No data found"
293                 end
294         mArray.iprule = { ipRuleShow }
295
296         -- ip route list table 1-250
297         local routeList, routeString = ut.trim(sys.exec(ip .. "rule | sed 's/://g' 2>/dev/null | awk '$1>=2001 && $1<=2250' | awk '{print $NF}'")), ""
298                 if routeList ~= "" then
299                         for line in routeList:gmatch("[^\r\n]+") do
300                                 routeString = routeString .. line .. "\n" .. sys.exec(ip .. "route list table " .. line)
301                         end
302                         routeString = ut.trim(routeString)
303                 else
304                         routeString = "No data found"
305                 end
306         mArray.routelist = { routeString }
307
308         -- default firewall output policy
309         local firewallOut = ut.trim(sys.exec("uci -q -p /var/state get firewall.@defaults[0].output"))
310                 if firewallOut == "" then
311                         firewallOut = "No data found"
312                 end
313         mArray.firewallout = { firewallOut }
314
315         -- iptables
316         local iptables = ut.trim(sys.exec("iptables -L -t mangle -v -n"))
317                 if iptables == "" then
318                         iptables = "No data found"
319                 end
320         mArray.iptables = { iptables }
321
322         luci.http.prepare_content("application/json")
323         luci.http.write_json(mArray)
324 end