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