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.
This commit is contained in:
Matthias Schiffer 2018-02-26 03:25:01 +01:00
parent fdf823a3a2
commit 27f7ce444f
No known key found for this signature in database
GPG Key ID: 16EF3F64CB201D9C
2 changed files with 85 additions and 4 deletions

View File

@ -1,6 +1,5 @@
<%- <%-
local fs = require 'nixio.fs' local fs = require 'nixio.fs'
local json = require 'jsonc'
local ubus = require 'ubus' local ubus = require 'ubus'
local util = require 'gluon.util' local util = require 'gluon.util'
@ -44,8 +43,6 @@
local interfaces = get_interfaces() 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) local function sorted(t)
t = {unpack(t)} t = {unpack(t)}
table.sort(t) table.sort(t)

View File

@ -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) 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)) end))