olsr.lua 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  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 = uci:get("olsrd", "olsrd_jsoninfo", "port") or 9090
  71. local v6_port = uci:get("olsrd6", "olsrd_jsoninfo", "port") or 9090
  72. jsonreq4 = utl.exec("(echo /status | nc 127.0.0.1 " .. v4_port .. " | sed -n '/^[}{ ]/p') 2>/dev/null" )
  73. jsonreq6 = utl.exec("(echo /status | nc ::1 " .. v6_port .. " | sed -n '/^[}{ ]/p') 2>/dev/null")
  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 _, ifa, dev
  85. ipaddr = tostring(ipaddr)
  86. if not ifaddr_table then
  87. ifaddr_table = nixio.getifaddrs()
  88. end
  89. -- ipaddr -> ifname
  90. for _, ifa in ipairs(ifaddr_table) do
  91. if ifa.addr == ipaddr then
  92. dev = ifa.name
  93. break
  94. end
  95. end
  96. -- ifname -> macaddr
  97. for _, ifa in ipairs(ifaddr_table) do
  98. if ifa.name == dev and ifa.family == "packet" then
  99. return ifa.addr
  100. end
  101. end
  102. end
  103. local function remote_mac_lookup(ipaddr)
  104. local _, n
  105. if not neigh_table then
  106. neigh_table = luci.ip.neighbors()
  107. end
  108. for _, n in ipairs(neigh_table) do
  109. if n.mac and n.dest and n.dest:equal(ipaddr) then
  110. return n.mac
  111. end
  112. end
  113. end
  114. function action_neigh(json)
  115. local data, has_v4, has_v6, error = fetch_jsoninfo('links')
  116. if error then
  117. return
  118. end
  119. local uci = require "luci.model.uci".cursor_state()
  120. local resolve = uci:get("luci_olsr", "general", "resolve")
  121. local ntm = require "luci.model.network".init()
  122. local devices = ntm:get_wifidevs()
  123. local sys = require "luci.sys"
  124. local assoclist = {}
  125. --local neightbl = require "neightbl"
  126. local ntm = require "luci.model.network"
  127. local ipc = require "luci.ip"
  128. local nxo = require "nixio"
  129. local defaultgw
  130. ipc.routes({ family = 4, type = 1, dest_exact = "0.0.0.0/0" },
  131. function(rt) defaultgw = rt.gw end)
  132. local function compare(a,b)
  133. if a.proto == b.proto then
  134. return a.linkCost < b.linkCost
  135. else
  136. return a.proto < b.proto
  137. end
  138. end
  139. for _, dev in ipairs(devices) do
  140. for _, net in ipairs(dev:get_wifinets()) do
  141. local radio = net:get_device()
  142. assoclist[#assoclist+1] = {}
  143. assoclist[#assoclist]['ifname'] = net:ifname()
  144. assoclist[#assoclist]['network'] = net:network()[1]
  145. assoclist[#assoclist]['device'] = radio and radio:name() or nil
  146. assoclist[#assoclist]['list'] = net:assoclist()
  147. end
  148. end
  149. for k, v in ipairs(data) do
  150. local snr = 0
  151. local signal = 0
  152. local noise = 0
  153. local mac = ""
  154. local ip
  155. local neihgt = {}
  156. if resolve == "1" then
  157. hostname = nixio.getnameinfo(v.remoteIP, nil, 100)
  158. if hostname then
  159. v.hostname = hostname
  160. end
  161. end
  162. local interface = ntm:get_status_by_address(v.localIP)
  163. local lmac = local_mac_lookup(v.localIP)
  164. local rmac = remote_mac_lookup(v.remoteIP)
  165. for _, val in ipairs(assoclist) do
  166. if val.network == interface and val.list then
  167. for assocmac, assot in pairs(val.list) do
  168. assocmac = string.lower(assocmac or "")
  169. if rmac == assocmac then
  170. signal = tonumber(assot.signal)
  171. noise = tonumber(assot.noise)
  172. snr = (noise*-1) - (signal*-1)
  173. end
  174. end
  175. end
  176. end
  177. if interface then
  178. v.interface = interface
  179. end
  180. v.snr = snr
  181. v.signal = signal
  182. v.noise = noise
  183. if rmac then
  184. v.remoteMAC = rmac
  185. end
  186. if lmac then
  187. v.localMAC = lmac
  188. end
  189. if defaultgw == v.remoteIP then
  190. v.defaultgw = 1
  191. end
  192. end
  193. table.sort(data, compare)
  194. luci.template.render("status-olsr/neighbors", {links=data, has_v4=has_v4, has_v6=has_v6})
  195. end
  196. function action_routes()
  197. local data, has_v4, has_v6, error = fetch_jsoninfo('routes')
  198. if error then
  199. return
  200. end
  201. local uci = require "luci.model.uci".cursor_state()
  202. local resolve = uci:get("luci_olsr", "general", "resolve")
  203. for k, v in ipairs(data) do
  204. if resolve == "1" then
  205. local hostname = nixio.getnameinfo(v.gateway, nil, 100)
  206. if hostname then
  207. v.hostname = hostname
  208. end
  209. end
  210. end
  211. local function compare(a,b)
  212. if a.proto == b.proto then
  213. return a.rtpMetricCost < b.rtpMetricCost
  214. else
  215. return a.proto < b.proto
  216. end
  217. end
  218. table.sort(data, compare)
  219. luci.template.render("status-olsr/routes", {routes=data, has_v4=has_v4, has_v6=has_v6})
  220. end
  221. function action_topology()
  222. local data, has_v4, has_v6, error = fetch_jsoninfo('topology')
  223. if error then
  224. return
  225. end
  226. local function compare(a,b)
  227. if a.proto == b.proto then
  228. return a.tcEdgeCost < b.tcEdgeCost
  229. else
  230. return a.proto < b.proto
  231. end
  232. end
  233. table.sort(data, compare)
  234. luci.template.render("status-olsr/topology", {routes=data, has_v4=has_v4, has_v6=has_v6})
  235. end
  236. function action_hna()
  237. local data, has_v4, has_v6, error = fetch_jsoninfo('hna')
  238. if error then
  239. return
  240. end
  241. local uci = require "luci.model.uci".cursor_state()
  242. local resolve = uci:get("luci_olsr", "general", "resolve")
  243. local function compare(a,b)
  244. if a.proto == b.proto then
  245. return a.genmask < b.genmask
  246. else
  247. return a.proto < b.proto
  248. end
  249. end
  250. for k, v in ipairs(data) do
  251. if resolve == "1" then
  252. hostname = nixio.getnameinfo(v.gateway, nil, 100)
  253. if hostname then
  254. v.hostname = hostname
  255. end
  256. end
  257. if v.validityTime then
  258. v.validityTime = tonumber(string.format("%.0f", v.validityTime / 1000))
  259. end
  260. end
  261. table.sort(data, compare)
  262. luci.template.render("status-olsr/hna", {hna=data, has_v4=has_v4, has_v6=has_v6})
  263. end
  264. function action_mid()
  265. local data, has_v4, has_v6, error = fetch_jsoninfo('mid')
  266. if error then
  267. return
  268. end
  269. local function compare(a,b)
  270. if a.proto == b.proto then
  271. return a.ipAddress < b.ipAddress
  272. else
  273. return a.proto < b.proto
  274. end
  275. end
  276. table.sort(data, compare)
  277. luci.template.render("status-olsr/mid", {mids=data, has_v4=has_v4, has_v6=has_v6})
  278. end
  279. function action_smartgw()
  280. local data, has_v4, has_v6, error = fetch_jsoninfo('gateways')
  281. if error then
  282. return
  283. end
  284. local function compare(a,b)
  285. if a.proto == b.proto then
  286. return a.tcPathCost < b.tcPathCost
  287. else
  288. return a.proto < b.proto
  289. end
  290. end
  291. table.sort(data, compare)
  292. luci.template.render("status-olsr/smartgw", {gws=data, has_v4=has_v4, has_v6=has_v6})
  293. end
  294. function action_interfaces()
  295. local data, has_v4, has_v6, error = fetch_jsoninfo('interfaces')
  296. if error then
  297. return
  298. end
  299. local function compare(a,b)
  300. return a.proto < b.proto
  301. end
  302. table.sort(data, compare)
  303. luci.template.render("status-olsr/interfaces", {iface=data, has_v4=has_v4, has_v6=has_v6})
  304. end
  305. -- Internal
  306. function fetch_jsoninfo(otable)
  307. local uci = require "luci.model.uci".cursor_state()
  308. local utl = require "luci.util"
  309. local json = require "luci.json"
  310. local IpVersion = uci:get_first("olsrd", "olsrd","IpVersion")
  311. local jsonreq4 = ""
  312. local jsonreq6 = ""
  313. local v4_port = uci:get("olsrd", "olsrd_jsoninfo", "port") or 9090
  314. local v6_port = uci:get("olsrd6", "olsrd_jsoninfo", "port") or 9090
  315. jsonreq4 = utl.exec("(echo /" .. otable .. " | nc 127.0.0.1 " .. v4_port .. " | sed -n '/^[}{ ]/p') 2>/dev/null")
  316. jsonreq6 = utl.exec("(echo /" .. otable .. " | nc ::1 " .. v6_port .. " | sed -n '/^[}{ ]/p') 2>/dev/null")
  317. local jsondata4 = {}
  318. local jsondata6 = {}
  319. local data4 = {}
  320. local data6 = {}
  321. local has_v4 = False
  322. local has_v6 = False
  323. if jsonreq4 == '' and jsonreq6 == '' then
  324. luci.template.render("status-olsr/error_olsr")
  325. return nil, 0, 0, true
  326. end
  327. if jsonreq4 ~= "" then
  328. has_v4 = 1
  329. jsondata4 = json.decode(jsonreq4)
  330. if otable == 'status' then
  331. data4 = jsondata4 or {}
  332. else
  333. data4 = jsondata4[otable] or {}
  334. end
  335. for k, v in ipairs(data4) do
  336. data4[k]['proto'] = '4'
  337. end
  338. end
  339. if jsonreq6 ~= "" then
  340. has_v6 = 1
  341. jsondata6 = json.decode(jsonreq6)
  342. if otable == 'status' then
  343. data6 = jsondata6 or {}
  344. else
  345. data6 = jsondata6[otable] or {}
  346. end
  347. for k, v in ipairs(data6) do
  348. data6[k]['proto'] = '6'
  349. end
  350. end
  351. for k, v in ipairs(data6) do
  352. table.insert(data4, v)
  353. end
  354. return data4, has_v4, has_v6, false
  355. end