mwan3.lua 11 KB

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