You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

355 lines
11 KiB

  1. module("luci.controller.mwan3", package.seeall)
  2. sys = require "luci.sys"
  3. ut = require "luci.util"
  4. function index()
  5. if not nixio.fs.access("/etc/config/mwan3") then
  6. return
  7. end
  8. entry({"admin", "network", "mwan3"},
  9. alias("admin", "network", "mwan3", "overview"),
  10. _("Load Balancing"), 600)
  11. entry({"admin", "network", "mwan3", "overview"},
  12. alias("admin", "network", "mwan3", "overview", "over_iface"),
  13. _("Overview"), 10)
  14. entry({"admin", "network", "mwan3", "overview", "over_iface"},
  15. template("mwan3/mwan3_over_interface"))
  16. entry({"admin", "network", "mwan3", "overview", "iface_status"},
  17. call("mwan3_iface_status"))
  18. entry({"admin", "network", "mwan3", "overview", "over_detail"},
  19. template("mwan3/mwan3_over_detail"))
  20. entry({"admin", "network", "mwan3", "overview", "detail_status"},
  21. call("mwan3_detail_status"))
  22. entry({"admin", "network", "mwan3", "configuration"},
  23. alias("admin", "network", "mwan3", "configuration", "interface"),
  24. _("Configuration"), 20)
  25. entry({"admin", "network", "mwan3", "configuration", "interface"},
  26. arcombine(cbi("mwan3/mwan3_interface"), cbi("mwan3/mwan3_interfaceconfig")),
  27. _("Interfaces"), 10).leaf = true
  28. entry({"admin", "network", "mwan3", "configuration", "member"},
  29. arcombine(cbi("mwan3/mwan3_member"), cbi("mwan3/mwan3_memberconfig")),
  30. _("Members"), 20).leaf = true
  31. entry({"admin", "network", "mwan3", "configuration", "policy"},
  32. arcombine(cbi("mwan3/mwan3_policy"), cbi("mwan3/mwan3_policyconfig")),
  33. _("Policies"), 30).leaf = true
  34. entry({"admin", "network", "mwan3", "configuration", "rule"},
  35. arcombine(cbi("mwan3/mwan3_rule"), cbi("mwan3/mwan3_ruleconfig")),
  36. _("Rules"), 40).leaf = true
  37. entry({"admin", "network", "mwan3", "advanced"},
  38. alias("admin", "network", "mwan3", "advanced", "hotplug"),
  39. _("Advanced"), 100)
  40. entry({"admin", "network", "mwan3", "advanced", "hotplug"},
  41. form("mwan3/mwan3_adv_hotplug"))
  42. entry({"admin", "network", "mwan3", "advanced", "mwan3"},
  43. form("mwan3/mwan3_adv_mwan3"))
  44. entry({"admin", "network", "mwan3", "advanced", "network"},
  45. form("mwan3/mwan3_adv_network"))
  46. entry({"admin", "network", "mwan3", "advanced", "diag"},
  47. template("mwan3/mwan3_adv_diagnostics"))
  48. entry({"admin", "network", "mwan3", "advanced", "diag_display"},
  49. call("mwan3_diag_data"), nil).leaf = true
  50. entry({"admin", "network", "mwan3", "advanced", "tshoot"},
  51. template("mwan3/mwan3_adv_troubleshoot"))
  52. entry({"admin", "network", "mwan3", "advanced", "tshoot_display"},
  53. call("mwan3_tshoot_data"))
  54. end
  55. function mwan3_get_iface_status(rulenum, ifname)
  56. if ut.trim(sys.exec("uci get -p /var/state mwan3." .. ifname .. ".enabled")) == "1" then
  57. if ut.trim(sys.exec("ip route list table " .. rulenum)) ~= "" then
  58. if ut.trim(sys.exec("uci get -p /var/state mwan3." .. ifname .. ".track_ip")) ~= "" then
  59. return "on"
  60. else
  61. return "nm"
  62. end
  63. else
  64. return "off"
  65. end
  66. else
  67. return "ne"
  68. end
  69. end
  70. function mwan3_get_iface()
  71. local rulenum, str = 0, ""
  72. uci.cursor():foreach("mwan3", "interface",
  73. function (section)
  74. rulenum = rulenum+1
  75. str = str .. section[".name"] .. "[" .. mwan3_get_iface_status(rulenum, section[".name"]) .. "]"
  76. end
  77. )
  78. return str
  79. end
  80. function mwan3_iface_status()
  81. local ntm = require "luci.model.network".init()
  82. local rv = { }
  83. -- overview status
  84. local statstr = mwan3_get_iface()
  85. if statstr ~= "" then
  86. rv.wans = { }
  87. wansid = {}
  88. for wanname, ifstat in string.gfind(statstr, "([^%[]+)%[([^%]]+)%]") do
  89. local wanifname = ut.trim(sys.exec("uci get -p /var/state network." .. wanname .. ".ifname"))
  90. if wanifname == "" then
  91. wanifname = "X"
  92. end
  93. local wanlink = ntm:get_interface(wanifname)
  94. wanlink = wanlink and wanlink:get_network()
  95. wanlink = wanlink and wanlink:adminlink() or "#"
  96. wansid[wanname] = #rv.wans + 1
  97. rv.wans[wansid[wanname]] = { name = wanname, link = wanlink, ifname = wanifname, status = ifstat }
  98. end
  99. end
  100. -- overview status log
  101. local mwlg = ut.trim(sys.exec("logread | grep mwan3 | tail -n 50 | sed 'x;1!H;$!d;x'"))
  102. if mwlg ~= "" then
  103. rv.mwan3log = { }
  104. mwlog = {}
  105. mwlog[mwlg] = #rv.mwan3log + 1
  106. rv.mwan3log[mwlog[mwlg]] = { mwanlog = mwlg }
  107. end
  108. luci.http.prepare_content("application/json")
  109. luci.http.write_json(rv)
  110. end
  111. function mwan3_detail_status()
  112. local rv = { }
  113. -- detailed mwan3 status
  114. local dst = ut.trim(sys.exec("mwan3 status"))
  115. if dst ~= "" then
  116. rv.mwan3dst = { }
  117. dstat = {}
  118. dstat[dst] = #rv.mwan3dst + 1
  119. rv.mwan3dst[dstat[dst]] = { detailstat = dst }
  120. end
  121. luci.http.prepare_content("application/json")
  122. luci.http.write_json(rv)
  123. end
  124. function mwan3_diag_data(iface, tool, alt)
  125. function get_ifnum()
  126. local num = 0
  127. uci.cursor():foreach("mwan3", "interface",
  128. function (section)
  129. num = num+1
  130. if section[".name"] == iface then
  131. ifnum = num
  132. end
  133. end
  134. )
  135. end
  136. local rv = { }
  137. local res = ""
  138. if tool == "service" then
  139. os.execute("mwan3 " .. alt)
  140. if alt == "restart" then
  141. res = "MWAN3 restarted"
  142. elseif alt == "stop" then
  143. res = "MWAN3 stopped"
  144. else
  145. res = "MWAN3 started"
  146. end
  147. else
  148. local ifdev = ut.trim(sys.exec("uci get -p /var/state network." .. iface .. ".ifname"))
  149. if ifdev ~= "" then
  150. if tool == "ping" then
  151. local gateway = ut.trim(sys.exec("route -n | awk -F' ' '{ if ($8 == \"" .. ifdev .. "\" && $1 == \"0.0.0.0\") print $2 }'"))
  152. if gateway ~= "" then
  153. if alt == "gateway" then
  154. local cmd = "ping -c 3 -W 2 -I " .. ifdev .. " " .. gateway
  155. res = cmd .. "\n\n" .. sys.exec(cmd)
  156. else
  157. local str = ut.trim(sys.exec("uci get -p /var/state mwan3." .. iface .. ".track_ip"))
  158. if str ~= "" then
  159. for z in str:gmatch("[^ ]+") do
  160. local cmd = "ping -c 3 -W 2 -I " .. ifdev .. " " .. z
  161. res = res .. cmd .. "\n\n" .. sys.exec(cmd) .. "\n\n"
  162. end
  163. else
  164. res = "No tracking IP addresses configured on " .. iface
  165. end
  166. end
  167. else
  168. res = "No default gateway for " .. iface .. " found. Default route does not exist or is configured incorrectly"
  169. end
  170. elseif tool == "rulechk" then
  171. get_ifnum()
  172. local rule1 = sys.exec("ip rule | grep $(echo $((" .. ifnum .. " + 1000)))")
  173. local rule2 = sys.exec("ip rule | grep $(echo $((" .. ifnum .. " + 2000)))")
  174. if rule1 ~= "" and rule2 ~= "" then
  175. res = "All required interface IP rules found:\n\n" .. rule1 .. rule2
  176. elseif rule1 ~= "" or rule2 ~= "" then
  177. res = "Missing 1 of the 2 required interface IP rules\n\n\nRules found:\n\n" .. rule1 .. rule2
  178. else
  179. res = "Missing both of the required interface IP rules"
  180. end
  181. elseif tool == "routechk" then
  182. get_ifnum()
  183. local table = sys.exec("ip route list table " .. ifnum)
  184. if table ~= "" then
  185. res = "Interface routing table " .. ifnum .. " was found:\n\n" .. table
  186. else
  187. res = "Missing required interface routing table " .. ifnum
  188. end
  189. elseif tool == "hotplug" then
  190. if alt == "ifup" then
  191. os.execute("mwan3 ifup " .. iface)
  192. res = "Hotplug ifup sent to interface " .. iface .. "..."
  193. else
  194. os.execute("mwan3 ifdown " .. iface)
  195. res = "Hotplug ifdown sent to interface " .. iface .. "..."
  196. end
  197. end
  198. else
  199. res = "Unable to perform diagnostic tests on " .. iface .. ". There is no physical or virtual device associated with this interface"
  200. end
  201. end
  202. if res ~= "" then
  203. res = ut.trim(res)
  204. rv.diagres = { }
  205. dres = {}
  206. dres[res] = #rv.diagres + 1
  207. rv.diagres[dres[res]] = { diagresult = res }
  208. end
  209. luci.http.prepare_content("application/json")
  210. luci.http.write_json(rv)
  211. end
  212. function mwan3_tshoot_data()
  213. local rv = { }
  214. -- software versions
  215. local wrtrelease = ut.trim(luci.version.distversion)
  216. if wrtrelease ~= "" then
  217. wrtrelease = "OpenWrt - " .. wrtrelease
  218. else
  219. wrtrelease = "OpenWrt - unknown"
  220. end
  221. local lucirelease = ut.trim(luci.version.luciversion)
  222. if lucirelease ~= "" then
  223. lucirelease = "\nLuCI - " .. lucirelease
  224. else
  225. lucirelease = "\nLuCI - unknown"
  226. end
  227. local mwan3version = ut.trim(sys.exec("opkg info mwan3 | grep Version | awk -F' ' '{ print $2 }'"))
  228. if mwan3version ~= "" then
  229. mwan3version = "\n\nmwan3 - " .. mwan3version
  230. else
  231. mwan3version = "\nmwan3 - unknown"
  232. end
  233. local mwan3lversion = ut.trim(sys.exec("opkg info luci-app-mwan3 | grep Version | awk -F' ' '{ print $2 }'"))
  234. if mwan3lversion ~= "" then
  235. mwan3lversion = "\nluci-app-mwan3 - " .. mwan3lversion
  236. else
  237. mwan3lversion = "\nluci-app-mwan3 - unknown"
  238. end
  239. local softrev = wrtrelease .. lucirelease .. mwan3version .. mwan3lversion
  240. rv.mw3ver = { }
  241. mwv = {}
  242. mwv[softrev] = #rv.mw3ver + 1
  243. rv.mw3ver[mwv[softrev]] = { mwan3v = softrev }
  244. -- mwan3 config
  245. local mwcg = ut.trim(sys.exec("cat /etc/config/mwan3"))
  246. if mwcg == "" then
  247. mwcg = "No data found"
  248. end
  249. rv.mwan3config = { }
  250. mwan3cfg = {}
  251. mwan3cfg[mwcg] = #rv.mwan3config + 1
  252. rv.mwan3config[mwan3cfg[mwcg]] = { mwn3cfg = mwcg }
  253. -- network config
  254. local netcg = ut.trim(sys.exec("cat /etc/config/network | sed -e 's/.*username.*/ USERNAME HIDDEN/' -e 's/.*password.*/ PASSWORD HIDDEN/'"))
  255. if netcg == "" then
  256. netcg = "No data found"
  257. end
  258. rv.netconfig = { }
  259. ncfg = {}
  260. ncfg[netcg] = #rv.netconfig + 1
  261. rv.netconfig[ncfg[netcg]] = { netcfg = netcg }
  262. -- ifconfig
  263. local ifcg = ut.trim(sys.exec("ifconfig"))
  264. if ifcg == "" then
  265. ifcg = "No data found"
  266. end
  267. rv.ifconfig = { }
  268. icfg = {}
  269. icfg[ifcg] = #rv.ifconfig + 1
  270. rv.ifconfig[icfg[ifcg]] = { ifcfg = ifcg }
  271. -- route -n
  272. local routeshow = ut.trim(sys.exec("route -n"))
  273. if routeshow == "" then
  274. routeshow = "No data found"
  275. end
  276. rv.rtshow = { }
  277. rshw = {}
  278. rshw[routeshow] = #rv.rtshow + 1
  279. rv.rtshow[rshw[routeshow]] = { iprtshow = routeshow }
  280. -- ip rule show
  281. local ipr = ut.trim(sys.exec("ip rule show"))
  282. if ipr == "" then
  283. ipr = "No data found"
  284. end
  285. rv.iprule = { }
  286. ipruleid = {}
  287. ipruleid[ipr] = #rv.iprule + 1
  288. rv.iprule[ipruleid[ipr]] = { rule = ipr }
  289. -- ip route list table 1-250
  290. local routelisting, rlstr = ut.trim(sys.exec("ip rule | sed 's/://g' | awk -F' ' '$1>=2001 && $1<=2250' | awk -F' ' '{ print $NF }'")), ""
  291. if routelisting ~= "" then
  292. for line in routelisting:gmatch("[^\r\n]+") do
  293. rlstr = rlstr .. line .. "\n" .. sys.exec("ip route list table " .. line)
  294. end
  295. rlstr = ut.trim(rlstr)
  296. else
  297. rlstr = "No data found"
  298. end
  299. rv.routelist = { }
  300. rtlist = {}
  301. rtlist[rlstr] = #rv.routelist + 1
  302. rv.routelist[rtlist[rlstr]] = { iprtlist = rlstr }
  303. -- default firewall output policy
  304. local defout = ut.trim(sys.exec("uci get -p /var/state firewall.@defaults[0].output"))
  305. if defout == "" then
  306. defout = "No data found"
  307. end
  308. rv.fidef = { }
  309. fwdf = {}
  310. fwdf[defout] = #rv.fidef + 1
  311. rv.fidef[fwdf[defout]] = { firedef = defout }
  312. -- iptables
  313. local iptbl = ut.trim(sys.exec("iptables -L -t mangle -v -n"))
  314. if iptbl == "" then
  315. iptbl = "No data found"
  316. end
  317. rv.iptables = { }
  318. tables = {}
  319. tables[iptbl] = #rv.iptables + 1
  320. rv.iptables[tables[iptbl]] = { iptbls = iptbl }
  321. luci.http.prepare_content("application/json")
  322. luci.http.write_json(rv)
  323. end