e7e8dc93c81d6026af31f326c6f198f87c721a5a
[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("mwan_Status"))
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 mwan_Status()
60         local status = ut.ubus("mwan3", "status", {})
61
62         luci.http.prepare_content("application/json")
63         if status ~= nil then
64                 luci.http.write_json(status)
65         else
66                 luci.http.write_json({})
67         end
68 end
69
70 function detailedStatus()
71         local mArray = {}
72
73         -- detailed mwan status
74         local detailStatusInfo = ut.trim(sys.exec("/usr/sbin/mwan3 status"))
75         if detailStatusInfo ~= "" then
76                 mArray.mwandetail = { detailStatusInfo }
77         end
78
79         luci.http.prepare_content("application/json")
80         luci.http.write_json(mArray)
81 end
82
83 function diagnosticsData(interface, task)
84         function getInterfaceNumber(interface)
85                 local number = 0
86                 local interfaceNumber
87                 uci.cursor():foreach("mwan3", "interface",
88                         function (section)
89                                 number = number+1
90                                 if section[".name"] == interface then
91                                         interfaceNumber = number
92                                 end
93                         end
94                 )
95                 return interfaceNumber
96         end
97
98         function diag_command(cmd, addr)
99                 if addr and addr:match("^[a-zA-Z0-9%-%.:_]+$") then
100                         local util = io.popen(cmd % addr)
101                         if util then
102                                 while true do
103                                         local ln = util:read("*l")
104                                         if not ln then break end
105                                         luci.http.write(ln)
106                                         luci.http.write("\n")
107                                 end
108                                 util:close()
109                         end
110                         return
111                 end
112         end
113
114         function get_gateway(inteface)
115                 local dump = require("luci.util").ubus("network.interface.%s" % interface, "status", {})
116                 local gateway
117                 if dump then
118                         local _, route
119                         for _, route in ipairs(dump.route) do
120                                 if dump.route[_].target == "0.0.0.0" then
121                                         gateway =  dump.route[_].nexthop
122                                 end
123                         end
124                 end
125                 return gateway
126         end
127
128         local mArray = {}
129         local results = ""
130         local number = getInterfaceNumber(interface)
131
132         local uci = uci.cursor(nil, "/var/state")
133         local device = uci:get("network", interface, "ifname")
134
135         luci.http.prepare_content("text/plain")
136         if device ~= "" then
137                 if task == "ping_gateway" then
138                         local gateway = get_gateway(interface)
139                         if gateway ~= nil then
140                                 diag_command("ping -c 5 -W 1 %q 2>&1", gateway)
141                         else
142                                 luci.http.prepare_content("text/plain")
143                                 luci.http.write(string.format("No gateway for interface %s found.", interface))
144                         end
145                 elseif task == "ping_trackips" then
146                         local trackips = uci:get("mwan3", interface, "track_ip")
147                         if #trackips > 0 then
148                                 for i in pairs(trackips) do
149                                         diag_command("ping -c 5 -W 1 %q 2>&1", trackips[i])
150                                 end
151                         else
152                                 luci.http.write(string.format("No tracking Hosts for interface %s defined.", interface))
153                         end
154                 elseif task == "check_rules" then
155                         local number = getInterfaceNumber(interface)
156                         local iif = 1000 + number
157                         local fwmark = 2000 + number
158                         local iif_rule  = sys.exec(string.format("ip rule | grep %d", iif))
159                         local fwmark_rule = sys.exec(string.format("ip rule | grep %d", fwmark))
160                         if iif_rule ~= "" and fwmark_rule ~= "" then
161                                 luci.http.write(string.format("All required IP rules for interface %s found", interface))
162                                 luci.http.write("\n")
163                                 luci.http.write(fwmark_rule)
164                                 luci.http.write(iif_rule)
165                         elseif iif_rule == "" and fwmark_rule ~= "" then
166                                 luci.http.write(string.format("Only one IP rules for interface %s found", interface))
167                                 luci.http.write("\n")
168                                 luci.http.write(fwmark_rule)
169                         elseif iif_rule ~= "" and fwmark_rule == "" then
170                                 luci.http.write(string.format("Only one IP rules for interface %s found", interface))
171                                 luci.http.write("\n")
172                                 luci.http.write(iif_rule)
173                         else
174                                 luci.http.write(string.format("Missing both IP rules for interface %s", interface))
175                         end
176                 elseif task == "check_routes" then
177                         local number = getInterfaceNumber(interface)
178                         local routeTable = sys.exec(string.format("ip route list table %s", number))
179                         if routeTable ~= "" then
180                                 luci.http.write(string.format("Routing table %s for interface %s found", number, interface))
181                                 luci.http.write("\n")
182                                 luci.http.write(routeTable)
183                         else
184                                 luci.http.write(string.format("Routing table %s for interface %s not found", number, interface))
185                         end
186                 elseif task == "hotplug_ifup" then
187                         os.execute(string.format("/usr/sbin/mwan3 ifup %s", interface))
188                         luci.http.write(string.format("Hotplug ifup sent to interface %s", interface))
189                 elseif task == "hotplug_ifdown" then
190                         os.execute(string.format("/usr/sbin/mwan3 ifdown %s", interface))
191                         luci.http.write(string.format("Hotplug ifdown sent to interface %s", interface))
192                 else
193                         luci.http.write("Unknown task")
194                 end
195         else
196                 luci.http.write(string.format("Unable to perform diagnostic tests on %s.", interface))
197                 luci.http.write("\n")
198                 luci.http.write("There is no physical or virtual device associated with this interface.")
199         end
200 end
201
202 function troubleshootingData()
203         local ver = require "luci.version"
204
205         local mArray = {}
206
207         -- software versions
208         local wrtRelease = ut.trim(ver.distversion)
209                 if wrtRelease ~= "" then
210                         wrtRelease = "OpenWrt - " .. wrtRelease
211                 else
212                         wrtRelease = "OpenWrt - unknown"
213                 end
214         local luciRelease = ut.trim(ver.luciversion)
215                 if luciRelease ~= "" then
216                         luciRelease = "\nLuCI - " .. luciRelease
217                 else
218                         luciRelease = "\nLuCI - unknown"
219                 end
220         local mwanVersion = ut.trim(sys.exec("opkg info mwan3 | grep Version | awk '{print $2}'"))
221                 if mwanVersion ~= "" then
222                         mwanVersion = "\n\nmwan3 - " .. mwanVersion
223                 else
224                         mwanVersion = "\n\nmwan3 - unknown"
225                 end
226         local mwanLuciVersion = ut.trim(sys.exec("opkg info luci-app-mwan3 | grep Version | awk '{print $2}'"))
227                 if mwanLuciVersion ~= "" then
228                         mwanLuciVersion = "\nmwan3-luci - " .. mwanLuciVersion
229                 else
230                         mwanLuciVersion = "\nmwan3-luci - unknown"
231                 end
232         mArray.versions = { wrtRelease .. luciRelease .. mwanVersion .. mwanLuciVersion }
233
234         -- mwan config
235         local mwanConfig = ut.trim(sys.exec("cat /etc/config/mwan3"))
236                 if mwanConfig == "" then
237                         mwanConfig = "No data found"
238                 end
239         mArray.mwanconfig = { mwanConfig }
240
241         -- network config
242         local networkConfig = ut.trim(sys.exec("cat /etc/config/network | sed -e 's/.*username.*/       USERNAME HIDDEN/' -e 's/.*password.*/   PASSWORD HIDDEN/'"))
243                 if networkConfig == "" then
244                         networkConfig = "No data found"
245                 end
246         mArray.netconfig = { networkConfig }
247
248         -- wireless config
249         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/'"))
250                 if wirelessConfig == "" then
251                         wirelessConfig = "No data found"
252                 end
253         mArray.wificonfig = { wirelessConfig }
254         
255         -- ifconfig
256         local ifconfig = ut.trim(sys.exec("ifconfig"))
257                 if ifconfig == "" then
258                         ifconfig = "No data found"
259                 end
260         mArray.ifconfig = { ifconfig }
261
262         -- route -n
263         local routeShow = ut.trim(sys.exec("route -n"))
264                 if routeShow == "" then
265                         routeShow = "No data found"
266                 end
267         mArray.routeshow = { routeShow }
268
269         -- ip rule show
270         local ipRuleShow = ut.trim(sys.exec(ip .. "rule show"))
271                 if ipRuleShow == "" then
272                         ipRuleShow = "No data found"
273                 end
274         mArray.iprule = { ipRuleShow }
275
276         -- ip route list table 1-250
277         local routeList, routeString = ut.trim(sys.exec(ip .. "rule | sed 's/://g' 2>/dev/null | awk '$1>=2001 && $1<=2250' | awk '{print $NF}'")), ""
278                 if routeList ~= "" then
279                         for line in routeList:gmatch("[^\r\n]+") do
280                                 routeString = routeString .. line .. "\n" .. sys.exec(ip .. "route list table " .. line)
281                         end
282                         routeString = ut.trim(routeString)
283                 else
284                         routeString = "No data found"
285                 end
286         mArray.routelist = { routeString }
287
288         -- default firewall output policy
289         local firewallOut = ut.trim(sys.exec("uci -q -p /var/state get firewall.@defaults[0].output"))
290                 if firewallOut == "" then
291                         firewallOut = "No data found"
292                 end
293         mArray.firewallout = { firewallOut }
294
295         -- iptables
296         local iptables = ut.trim(sys.exec("iptables -L -t mangle -v -n"))
297                 if iptables == "" then
298                         iptables = "No data found"
299                 end
300         mArray.iptables = { iptables }
301
302         luci.http.prepare_content("application/json")
303         luci.http.write_json(mArray)
304 end