From 27f7ce444f632f98d4baf6531e435f3b3b5e5560 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Mon, 26 Feb 2018 03:25:01 +0100 Subject: [PATCH] gluon-status-page: when visiting via a next-node address, redirect to a unique address A downside of this behaviour is that the page does not work for IPv4-only clients, as the redirect will always point at an IPv6 address. Still, it seems like a good idea to enforce the redirect even from the IPv4 next-node address, as switching nodes while being connected to the status page would lead to unexpected behaviour. --- .../gluon/status-page/view/status-page.html | 3 - .../status-page/controller/status-page.lua | 86 ++++++++++++++++++- 2 files changed, 85 insertions(+), 4 deletions(-) diff --git a/package/gluon-status-page/files/lib/gluon/status-page/view/status-page.html b/package/gluon-status-page/files/lib/gluon/status-page/view/status-page.html index 2d023af7..a3766632 100644 --- a/package/gluon-status-page/files/lib/gluon/status-page/view/status-page.html +++ b/package/gluon-status-page/files/lib/gluon/status-page/view/status-page.html @@ -1,6 +1,5 @@ <%- local fs = require 'nixio.fs' - local json = require 'jsonc' local ubus = require 'ubus' local util = require 'gluon.util' @@ -44,8 +43,6 @@ local interfaces = get_interfaces() - local nodeinfo = json.parse(util.exec('exec gluon-neighbour-info -d ::1 -p 1001 -t 1 -c 1 -r nodeinfo')) - local function sorted(t) t = {unpack(t)} table.sort(t) diff --git a/package/gluon-status-page/luasrc/lib/gluon/status-page/controller/status-page.lua b/package/gluon-status-page/luasrc/lib/gluon/status-page/controller/status-page.lua index 18ea1864..a997ff5f 100644 --- a/package/gluon-status-page/luasrc/lib/gluon/status-page/controller/status-page.lua +++ b/package/gluon-status-page/luasrc/lib/gluon/status-page/controller/status-page.lua @@ -1,3 +1,87 @@ +local json = require 'jsonc' +local site = require 'gluon.site' +local util = require 'gluon.util' + +local function parse_ip(addr) + if not addr then return end + + local ip4 = {addr:match('(%d+)%.(%d+)%.(%d+)%.(%d+)')} + if ip4[1] then + local ret = {} + + for i, part in ipairs(ip4) do + ret[i] = tonumber(part) + end + return ret + end + + if not addr:match('^[:%x]+$') then + return + end + + if addr:sub(0, 2) == '::' then + addr = '0' .. addr + end + if addr:sub(-2) == '::' then + addr = addr .. '0' + end + + addr = addr .. ':' + + local groups, groups1 = {}, {} + for part in addr:gmatch('([^:]*):') do + if part == '' then + groups1 = groups + groups = {} + else + groups[#groups+1] = tonumber(part, 16) + end + end + + while #groups + #groups1 < 8 do + groups1[#groups1+1] = 0 + end + for _, group in ipairs(groups) do + groups1[#groups1+1] = group + end + + return groups1 +end + +local function match(a, b, n) + if not a or not b then return false end + + for i = 1, n do + if a[i] ~= b[i] then + return false + end + end + + return true +end + entry({}, call(function(http, renderer) - renderer.render('status-page', nil, 'gluon-status-page') + local nodeinfo = json.parse(util.exec('exec gluon-neighbour-info -d ::1 -p 1001 -t 1 -c 1 -r nodeinfo')) + + local node_ip = parse_ip(http:getenv('SERVER_ADDR')) + if node_ip and ( + match(node_ip, parse_ip(site.next_node.ip4()), 8) or + match(node_ip, parse_ip(site.next_node.ip6()), 8) + ) then + -- The user has visited the status page via a next-node address + -- Redirect the user the a unique address to avoid switching + -- nodes + local prefix = parse_ip(site.prefix6():match('^[^/]+')) + for _, addr in ipairs(nodeinfo.network.addresses) do + if match(prefix, parse_ip(addr), 4) then + http:header('Cache-Control', 'no-cache, no-store, must-revalidate') + http:redirect('http://[' .. addr .. ']' .. http:getenv('REQUEST_URI')) + http:close() + return + end + end + end + + + renderer.render('status-page', { nodeinfo = nodeinfo }, 'gluon-status-page') end))