olsr.lua 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  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. local page = node("admin", "status", "olsr", "json")
  25. page.target = call("action_json")
  26. page.title = nil
  27. page.leaf = true
  28. local page = node("admin", "status", "olsr", "neighbors")
  29. page.target = call("action_neigh")
  30. page.title = _("Neighbours")
  31. page.subindex = true
  32. page.order = 5
  33. local page = node("admin", "status", "olsr", "routes")
  34. page.target = call("action_routes")
  35. page.title = _("Routes")
  36. page.order = 10
  37. local page = node("admin", "status", "olsr", "topology")
  38. page.target = call("action_topology")
  39. page.title = _("Topology")
  40. page.order = 20
  41. local page = node("admin", "status", "olsr", "hna")
  42. page.target = call("action_hna")
  43. page.title = _("HNA")
  44. page.order = 30
  45. local page = node("admin", "status", "olsr", "mid")
  46. page.target = call("action_mid")
  47. page.title = _("MID")
  48. page.order = 50
  49. if has_smartgw then
  50. local page = node("admin", "status", "olsr", "smartgw")
  51. page.target = call("action_smartgw")
  52. page.title = _("SmartGW")
  53. page.order = 60
  54. end
  55. local page = node("admin", "status", "olsr", "interfaces")
  56. page.target = call("action_interfaces")
  57. page.title = _("Interfaces")
  58. page.order = 70
  59. odsp = entry(
  60. {"admin", "services", "olsrd", "display"},
  61. cbi("olsr/olsrddisplay"), _("Display")
  62. )
  63. end
  64. function action_json()
  65. local http = require "luci.http"
  66. local utl = require "luci.util"
  67. local uci = require "luci.model.uci".cursor()
  68. local jsonreq4
  69. local jsonreq6
  70. local v4_port = tonumber(uci:get("olsrd", "olsrd_jsoninfo", "port") or "") or 9090
  71. local v6_port = tonumber(uci:get("olsrd6", "olsrd_jsoninfo", "port") or "") or 9090
  72. jsonreq4 = utl.exec("(echo /status | nc 127.0.0.1 %d | sed -n '/^[}{ ]/p') 2>/dev/null" % v4_port)
  73. jsonreq6 = utl.exec("(echo /status | nc ::1 %d | sed -n '/^[}{ ]/p') 2>/dev/null" % v6_port)
  74. http.prepare_content("application/json")
  75. if not jsonreq4 or jsonreq4 == "" then
  76. jsonreq4 = "{}"
  77. end
  78. if not jsonreq6 or jsonreq6 == "" then
  79. jsonreq6 = "{}"
  80. end
  81. http.write('{"v4":' .. jsonreq4 .. ', "v6":' .. jsonreq6 .. '}')
  82. end
  83. local function local_mac_lookup(ipaddr)
  84. local _, rt
  85. for _, rt in ipairs(luci.ip.routes({ type = 1, src = ipaddr })) do
  86. local link = rt.dev and luci.ip.link(rt.dev)
  87. local mac = link and luci.ip.checkmac(link.mac)
  88. if mac then return mac end
  89. end
  90. end
  91. local function remote_mac_lookup(ipaddr)
  92. local _, n
  93. for _, n in ipairs(luci.ip.neighbors({ dest = ipaddr })) do
  94. local mac = luci.ip.checkmac(n.mac)
  95. if mac then return mac end
  96. end
  97. end
  98. function action_neigh(json)
  99. local data, has_v4, has_v6, error = fetch_jsoninfo('links')
  100. if error then
  101. return
  102. end
  103. local uci = require "luci.model.uci".cursor_state()
  104. local resolve = uci:get("luci_olsr", "general", "resolve")
  105. local ntm = require "luci.model.network".init()
  106. local devices = ntm:get_wifidevs()
  107. local sys = require "luci.sys"
  108. local assoclist = {}
  109. --local neightbl = require "neightbl"
  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.ipAddress < b.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.tcPathCost < b.tcPathCost
  271. else
  272. return a.proto < b.proto
  273. end
  274. end
  275. table.sort(data, compare)
  276. luci.template.render("status-olsr/smartgw", {gws=data, has_v4=has_v4, has_v6=has_v6})
  277. end
  278. function action_interfaces()
  279. local data, has_v4, has_v6, error = fetch_jsoninfo('interfaces')
  280. if error then
  281. return
  282. end
  283. local function compare(a,b)
  284. return a.proto < b.proto
  285. end
  286. table.sort(data, compare)
  287. luci.template.render("status-olsr/interfaces", {iface=data, has_v4=has_v4, has_v6=has_v6})
  288. end
  289. -- Internal
  290. function fetch_jsoninfo(otable)
  291. local uci = require "luci.model.uci".cursor_state()
  292. local utl = require "luci.util"
  293. local json = require "luci.json"
  294. local IpVersion = uci:get_first("olsrd", "olsrd","IpVersion")
  295. local jsonreq4 = ""
  296. local jsonreq6 = ""
  297. local v4_port = tonumber(uci:get("olsrd", "olsrd_jsoninfo", "port") or "") or 9090
  298. local v6_port = tonumber(uci:get("olsrd6", "olsrd_jsoninfo", "port") or "") or 9090
  299. jsonreq4 = utl.exec("(echo /%s | nc 127.0.0.1 %d | sed -n '/^[}{ ]/p') 2>/dev/null" %{ otable, v4_port })
  300. jsonreq6 = utl.exec("(echo /%s | nc ::1 %d | sed -n '/^[}{ ]/p') 2>/dev/null" %{ otable, v6_port })
  301. local jsondata4 = {}
  302. local jsondata6 = {}
  303. local data4 = {}
  304. local data6 = {}
  305. local has_v4 = False
  306. local has_v6 = False
  307. if jsonreq4 == '' and jsonreq6 == '' then
  308. luci.template.render("status-olsr/error_olsr")
  309. return nil, 0, 0, true
  310. end
  311. if jsonreq4 ~= "" then
  312. has_v4 = 1
  313. jsondata4 = json.decode(jsonreq4)
  314. if otable == 'status' then
  315. data4 = jsondata4 or {}
  316. else
  317. data4 = jsondata4[otable] or {}
  318. end
  319. for k, v in ipairs(data4) do
  320. data4[k]['proto'] = '4'
  321. end
  322. end
  323. if jsonreq6 ~= "" then
  324. has_v6 = 1
  325. jsondata6 = json.decode(jsonreq6)
  326. if otable == 'status' then
  327. data6 = jsondata6 or {}
  328. else
  329. data6 = jsondata6[otable] or {}
  330. end
  331. for k, v in ipairs(data6) do
  332. data6[k]['proto'] = '6'
  333. end
  334. end
  335. for k, v in ipairs(data6) do
  336. table.insert(data4, v)
  337. end
  338. return data4, has_v4, has_v6, false
  339. end