olsr.lua 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. module("luci.controller.olsr", package.seeall)
  2. local neigh_table = nil
  3. local ifaddr_table = nil
  4. function index()
  5. local ipv4,ipv6
  6. if nixio.fs.access("/etc/config/olsrd") then
  7. ipv4 = 1
  8. end
  9. if nixio.fs.access("/etc/config/olsrd6") then
  10. ipv6 = 1
  11. end
  12. if not ipv4 and not ipv6 then
  13. return
  14. end
  15. require("luci.model.uci")
  16. local uci = luci.model.uci.cursor_state()
  17. uci:foreach("olsrd", "olsrd", function(s)
  18. if s.SmartGateway and s.SmartGateway == "yes" then has_smartgw = true end
  19. end)
  20. local page = node("admin", "status", "olsr")
  21. page.target = template("status-olsr/overview")
  22. page.title = _("OLSR")
  23. page.subindex = true
  24. page.acl_depends = { "luci-app-olsr" }
  25. local page = node("admin", "status", "olsr", "json")
  26. page.target = call("action_json")
  27. page.title = nil
  28. page.leaf = true
  29. local page = node("admin", "status", "olsr", "neighbors")
  30. page.target = call("action_neigh")
  31. page.title = _("Neighbours")
  32. page.subindex = true
  33. page.order = 5
  34. local page = node("admin", "status", "olsr", "routes")
  35. page.target = call("action_routes")
  36. page.title = _("Routes")
  37. page.order = 10
  38. local page = node("admin", "status", "olsr", "topology")
  39. page.target = call("action_topology")
  40. page.title = _("Topology")
  41. page.order = 20
  42. local page = node("admin", "status", "olsr", "hna")
  43. page.target = call("action_hna")
  44. page.title = _("HNA")
  45. page.order = 30
  46. local page = node("admin", "status", "olsr", "mid")
  47. page.target = call("action_mid")
  48. page.title = _("MID")
  49. page.order = 50
  50. if has_smartgw then
  51. local page = node("admin", "status", "olsr", "smartgw")
  52. page.target = call("action_smartgw")
  53. page.title = _("SmartGW")
  54. page.order = 60
  55. end
  56. local page = node("admin", "status", "olsr", "interfaces")
  57. page.target = call("action_interfaces")
  58. page.title = _("Interfaces")
  59. page.order = 70
  60. odsp = entry(
  61. {"admin", "services", "olsrd", "display"},
  62. cbi("olsr/olsrddisplay"), _("Display")
  63. )
  64. end
  65. function action_json()
  66. local http = require "luci.http"
  67. local utl = require "luci.util"
  68. local uci = require "luci.model.uci".cursor()
  69. local jsonreq4
  70. local jsonreq6
  71. local v4_port = tonumber(uci:get("olsrd", "olsrd_jsoninfo", "port") or "") or 9090
  72. local v6_port = tonumber(uci:get("olsrd6", "olsrd_jsoninfo", "port") or "") or 9090
  73. jsonreq4 = utl.exec("(echo /all | nc 127.0.0.1 %d | sed -n '/^[}{ ]/p') 2>/dev/null" % v4_port)
  74. jsonreq6 = utl.exec("(echo /all | nc ::1 %d | sed -n '/^[}{ ]/p') 2>/dev/null" % v6_port)
  75. http.prepare_content("application/json")
  76. if not jsonreq4 or jsonreq4 == "" then
  77. jsonreq4 = "{}"
  78. end
  79. if not jsonreq6 or jsonreq6 == "" then
  80. jsonreq6 = "{}"
  81. end
  82. http.write('{"v4":' .. jsonreq4 .. ', "v6":' .. jsonreq6 .. '}')
  83. end
  84. local function local_mac_lookup(ipaddr)
  85. local _, rt
  86. for _, rt in ipairs(luci.ip.routes({ type = 1, src = ipaddr })) do
  87. local link = rt.dev and luci.ip.link(rt.dev)
  88. local mac = link and luci.ip.checkmac(link.mac)
  89. if mac then return mac end
  90. end
  91. end
  92. local function remote_mac_lookup(ipaddr)
  93. local _, n
  94. for _, n in ipairs(luci.ip.neighbors({ dest = ipaddr })) do
  95. local mac = luci.ip.checkmac(n.mac)
  96. if mac then return mac end
  97. end
  98. end
  99. function action_neigh(json)
  100. local data, has_v4, has_v6, error = fetch_jsoninfo('links')
  101. if error then
  102. return
  103. end
  104. local uci = require "luci.model.uci".cursor_state()
  105. local resolve = uci:get("luci_olsr", "general", "resolve")
  106. local ntm = require "luci.model.network".init()
  107. local devices = ntm:get_wifidevs()
  108. local sys = require "luci.sys"
  109. local assoclist = {}
  110. local ntm = require "luci.model.network"
  111. local ipc = require "luci.ip"
  112. local nxo = require "nixio"
  113. local defaultgw
  114. ipc.routes({ family = 4, type = 1, dest_exact = "0.0.0.0/0" },
  115. function(rt) defaultgw = rt.gw end)
  116. local function compare(a,b)
  117. if a.proto == b.proto then
  118. return a.linkCost < b.linkCost
  119. else
  120. return a.proto < b.proto
  121. end
  122. end
  123. for _, dev in ipairs(devices) do
  124. for _, net in ipairs(dev:get_wifinets()) do
  125. local radio = net:get_device()
  126. assoclist[#assoclist+1] = {}
  127. assoclist[#assoclist]['ifname'] = net:ifname()
  128. assoclist[#assoclist]['network'] = net:network()[1]
  129. assoclist[#assoclist]['device'] = radio and radio:name() or nil
  130. assoclist[#assoclist]['list'] = net:assoclist()
  131. end
  132. end
  133. for k, v in ipairs(data) do
  134. local snr = 0
  135. local signal = 0
  136. local noise = 0
  137. local mac = ""
  138. local ip
  139. local neihgt = {}
  140. if resolve == "1" then
  141. hostname = nixio.getnameinfo(v.remoteIP, nil, 100)
  142. if hostname then
  143. v.hostname = hostname
  144. end
  145. end
  146. local interface = ntm:get_status_by_address(v.localIP)
  147. local lmac = local_mac_lookup(v.localIP)
  148. local rmac = remote_mac_lookup(v.remoteIP)
  149. for _, val in ipairs(assoclist) do
  150. if val.network == interface and val.list then
  151. local assocmac, assot
  152. for assocmac, assot in pairs(val.list) do
  153. if rmac == luci.ip.checkmac(assocmac) then
  154. signal = tonumber(assot.signal)
  155. noise = tonumber(assot.noise)
  156. snr = (noise*-1) - (signal*-1)
  157. end
  158. end
  159. end
  160. end
  161. if interface then
  162. v.interface = interface
  163. end
  164. v.snr = snr
  165. v.signal = signal
  166. v.noise = noise
  167. if rmac then
  168. v.remoteMAC = rmac
  169. end
  170. if lmac then
  171. v.localMAC = lmac
  172. end
  173. if defaultgw == v.remoteIP then
  174. v.defaultgw = 1
  175. end
  176. end
  177. table.sort(data, compare)
  178. luci.template.render("status-olsr/neighbors", {links=data, has_v4=has_v4, has_v6=has_v6})
  179. end
  180. function action_routes()
  181. local data, has_v4, has_v6, error = fetch_jsoninfo('routes')
  182. if error then
  183. return
  184. end
  185. local uci = require "luci.model.uci".cursor_state()
  186. local resolve = uci:get("luci_olsr", "general", "resolve")
  187. for k, v in ipairs(data) do
  188. if resolve == "1" then
  189. local hostname = nixio.getnameinfo(v.gateway, nil, 100)
  190. if hostname then
  191. v.hostname = hostname
  192. end
  193. end
  194. end
  195. local function compare(a,b)
  196. if a.proto == b.proto then
  197. return a.rtpMetricCost < b.rtpMetricCost
  198. else
  199. return a.proto < b.proto
  200. end
  201. end
  202. table.sort(data, compare)
  203. luci.template.render("status-olsr/routes", {routes=data, has_v4=has_v4, has_v6=has_v6})
  204. end
  205. function action_topology()
  206. local data, has_v4, has_v6, error = fetch_jsoninfo('topology')
  207. if error then
  208. return
  209. end
  210. local function compare(a,b)
  211. if a.proto == b.proto then
  212. return a.tcEdgeCost < b.tcEdgeCost
  213. else
  214. return a.proto < b.proto
  215. end
  216. end
  217. table.sort(data, compare)
  218. luci.template.render("status-olsr/topology", {routes=data, has_v4=has_v4, has_v6=has_v6})
  219. end
  220. function action_hna()
  221. local data, has_v4, has_v6, error = fetch_jsoninfo('hna')
  222. if error then
  223. return
  224. end
  225. local uci = require "luci.model.uci".cursor_state()
  226. local resolve = uci:get("luci_olsr", "general", "resolve")
  227. local function compare(a,b)
  228. if a.proto == b.proto then
  229. return a.genmask < b.genmask
  230. else
  231. return a.proto < b.proto
  232. end
  233. end
  234. for k, v in ipairs(data) do
  235. if resolve == "1" then
  236. hostname = nixio.getnameinfo(v.gateway, nil, 100)
  237. if hostname then
  238. v.hostname = hostname
  239. end
  240. end
  241. if v.validityTime then
  242. v.validityTime = tonumber(string.format("%.0f", v.validityTime / 1000))
  243. end
  244. end
  245. table.sort(data, compare)
  246. luci.template.render("status-olsr/hna", {hna=data, has_v4=has_v4, has_v6=has_v6})
  247. end
  248. function action_mid()
  249. local data, has_v4, has_v6, error = fetch_jsoninfo('mid')
  250. if error then
  251. return
  252. end
  253. local function compare(a,b)
  254. if a.proto == b.proto then
  255. return a.main.ipAddress < b.main.ipAddress
  256. else
  257. return a.proto < b.proto
  258. end
  259. end
  260. table.sort(data, compare)
  261. luci.template.render("status-olsr/mid", {mids=data, has_v4=has_v4, has_v6=has_v6})
  262. end
  263. function action_smartgw()
  264. local data, has_v4, has_v6, error = fetch_jsoninfo('gateways')
  265. if error then
  266. return
  267. end
  268. local function compare(a,b)
  269. if a.proto == b.proto then
  270. return a.cost < b.cost
  271. else
  272. return a.proto < b.proto
  273. end
  274. end
  275. table.sort(data.ipv4, compare)
  276. table.sort(data.ipv6, compare)
  277. luci.template.render("status-olsr/smartgw", {gws=data, has_v4=has_v4, has_v6=has_v6})
  278. end
  279. function action_interfaces()
  280. local data, has_v4, has_v6, error = fetch_jsoninfo('interfaces')
  281. local ntm = require "luci.model.network".init()
  282. if error then
  283. return
  284. end
  285. local function compare(a,b)
  286. return a.proto < b.proto
  287. end
  288. for k, v in ipairs(data) do
  289. local interface = ntm:get_status_by_address(v.olsrInterface.ipAddress)
  290. if interface then
  291. v.interface = interface
  292. end
  293. end
  294. table.sort(data, compare)
  295. luci.template.render("status-olsr/interfaces", {iface=data, has_v4=has_v4, has_v6=has_v6})
  296. end
  297. -- Internal
  298. function fetch_jsoninfo(otable)
  299. local uci = require "luci.model.uci".cursor_state()
  300. local utl = require "luci.util"
  301. local json = require "luci.json"
  302. local IpVersion = uci:get_first("olsrd", "olsrd","IpVersion")
  303. local jsonreq4 = ""
  304. local jsonreq6 = ""
  305. local v4_port = tonumber(uci:get("olsrd", "olsrd_jsoninfo", "port") or "") or 9090
  306. local v6_port = tonumber(uci:get("olsrd6", "olsrd_jsoninfo", "port") or "") or 9090
  307. jsonreq4 = utl.exec("(echo /%s | nc 127.0.0.1 %d | sed -n '/^[}{ ]/p') 2>/dev/null" %{ otable, v4_port })
  308. jsonreq6 = utl.exec("(echo /%s | nc ::1 %d | sed -n '/^[}{ ]/p') 2>/dev/null" %{ otable, v6_port })
  309. local jsondata4 = {}
  310. local jsondata6 = {}
  311. local data4 = {}
  312. local data6 = {}
  313. local has_v4 = False
  314. local has_v6 = False
  315. if jsonreq4 == '' and jsonreq6 == '' then
  316. luci.template.render("status-olsr/error_olsr")
  317. return nil, 0, 0, true
  318. end
  319. if jsonreq4 ~= "" then
  320. has_v4 = 1
  321. jsondata4 = json.decode(jsonreq4) or {}
  322. if otable == 'status' then
  323. data4 = jsondata4
  324. else
  325. data4 = jsondata4[otable] or {}
  326. end
  327. for k, v in ipairs(data4) do
  328. data4[k]['proto'] = '4'
  329. end
  330. end
  331. if jsonreq6 ~= "" then
  332. has_v6 = 1
  333. jsondata6 = json.decode(jsonreq6) or {}
  334. if otable == 'status' then
  335. data6 = jsondata6
  336. else
  337. data6 = jsondata6[otable] or {}
  338. end
  339. for k, v in ipairs(data6) do
  340. data6[k]['proto'] = '6'
  341. end
  342. end
  343. for k, v in ipairs(data6) do
  344. table.insert(data4, v)
  345. end
  346. return data4, has_v4, has_v6, false
  347. end