199 lines
5.5 KiB
Lua
Executable File
199 lines
5.5 KiB
Lua
Executable File
#!/usr/bin/lua
|
|
|
|
local uci = require('simple-uci').cursor()
|
|
local site = require 'gluon.site'
|
|
local wireless = require 'gluon.wireless'
|
|
local ip = require 'luci.ip' -- luci-lib-ip
|
|
local util = require 'gluon.util'
|
|
|
|
local IPV4_PREFIX_MAX = 32
|
|
local IPV6_PREFIX_MAX = 128
|
|
|
|
function hex2bin(str)
|
|
local map = {
|
|
['0'] = '0000',
|
|
['1'] = '0001',
|
|
['2'] = '0010',
|
|
['3'] = '0011',
|
|
['4'] = '0100',
|
|
['5'] = '0101',
|
|
['6'] = '0110',
|
|
['7'] = '0111',
|
|
['8'] = '1000',
|
|
['9'] = '1001',
|
|
['A'] = '1010',
|
|
['B'] = '1011',
|
|
['C'] = '1100',
|
|
['D'] = '1101',
|
|
['E'] = '1110',
|
|
['F'] = '1111',
|
|
}
|
|
return str:gsub('[0-9A-F]', map)
|
|
end
|
|
-- since we have a limit of 32 bit integers we.. uhm... do some hex2bin and then convert it byte by byte to a hex ipv6 block string
|
|
-- (the ip lib is in c and handles this stuff just fine)
|
|
function ipnum(macaddr, prefixOverflow, hex)
|
|
local binaryMac = hex2bin(macaddr:gsub(':', ''):upper()):sub(-prefixOverflow)
|
|
|
|
if not hex then
|
|
return tonumber(binaryMac, 2)
|
|
end
|
|
|
|
-- pad with 0s until we have block sized packets
|
|
while string.len(binaryMac) % 16 ~= 0 do
|
|
binaryMac = '0' .. binaryMac
|
|
end
|
|
|
|
local out = ''
|
|
|
|
for i=0,string.len(binaryMac)/16-1 do
|
|
if out ~= '' then
|
|
out = out .. ':'
|
|
end
|
|
out = out .. string.format("%02x", tonumber(binaryMac:sub(1+i*16,(i+1)*16), 2))
|
|
end
|
|
|
|
return out
|
|
end
|
|
|
|
local function static_ip(name, ifname, macaddr, actually_use)
|
|
-- actually_use = if ip should be applied to interface or not
|
|
-- if set and actually_use=false then it will be removed
|
|
|
|
local static4 = uci:get('gluon-static-ip', name, 'ip4')
|
|
local static6 = uci:get('gluon-static-ip', name, 'ip6')
|
|
|
|
if site.prefix4() then
|
|
if not static4 and site.node_prefix4() and name ~= 'loopback' then
|
|
local tmp4 = ip.new(site.node_prefix4())
|
|
|
|
-- magic that turns mac into random number
|
|
local ipnum = ipnum(macaddr, IPV4_PREFIX_MAX - site.node_prefix4_range())
|
|
|
|
-- the rare case where we get 0 or 1 as our mac based number
|
|
if ipnum < 2 then
|
|
ipnum = 2
|
|
end
|
|
|
|
static4 = tmp4:add(ipnum):string()
|
|
end
|
|
end
|
|
|
|
if site.prefix6() then
|
|
if not static6 and site.node_prefix6() and (site.tmpIp6Everywhere() or name == 'loopback') then
|
|
local tmp6 = ip.new(site.node_prefix6())
|
|
|
|
-- magic that turns mac into random number
|
|
local ipnum = ipnum(macaddr, IPV6_PREFIX_MAX - site.node_prefix6_range(64), true)
|
|
|
|
-- the rare case where we get 0 or 1 as our mac based number
|
|
if tonumber(ipnum:gsub(':', ''), 16) < 2 then
|
|
ipnum = 2
|
|
end
|
|
|
|
static6 = tmp6:add('::' .. ipnum):string()
|
|
end
|
|
end
|
|
|
|
uci:section('gluon-static-ip', 'interface', name, {
|
|
ip4 = static4,
|
|
ip6 = static6,
|
|
})
|
|
|
|
if actually_use then
|
|
-- we have to set proto to static as otherwise we won't have the ip assigned
|
|
-- TODO: maybe modify the protos instead to allow reading static ips and using them?
|
|
-- NOTE: wan also uses dhcp/static directly
|
|
|
|
uci:set('network', name, 'proto', 'static')
|
|
|
|
if site.prefix4 and static4 then
|
|
local ip4 = ip.new(static4)
|
|
if not ip4 or not ip4:is4() then
|
|
print('E: ' .. name .. ' has invalid ip4 ' .. static4)
|
|
return
|
|
end
|
|
|
|
uci:set('network', name, 'ipaddr', ip4:host():string())
|
|
uci:set('network', name, 'netmask', ip4:mask():string())
|
|
elseif name ~= 'loopback' then
|
|
if uci:get('network', name, 'ipaddr') then
|
|
uci:del('network', name, 'ipaddr')
|
|
end
|
|
|
|
if uci:get('network', name, 'netmask') then
|
|
uci:del('network', name, 'netmask')
|
|
end
|
|
end
|
|
|
|
if site.prefix6 and static6 then
|
|
local ip6 = ip.new(static6)
|
|
if not ip6 or not ip6:is6() then
|
|
print('E: ' .. name .. ' has invalid ip6 ' .. static6)
|
|
return
|
|
end
|
|
|
|
uci:set('network', name, 'ip6addr', ip6:string())
|
|
else
|
|
if uci:get('network', name, 'ip6addr') then
|
|
uci:del('network', name, 'ip6addr')
|
|
end
|
|
end
|
|
else
|
|
if uci:get('network', name, 'proto') == 'static' then
|
|
uci:del('network', name, 'ipaddr')
|
|
uci:del('network', name, 'netmask')
|
|
uci:del('network', name, 'ip6addr')
|
|
end
|
|
end
|
|
end
|
|
|
|
wireless.foreach_radio(uci, function(radio, index, config)
|
|
local function do_config(type)
|
|
net = type .. radio['.name']
|
|
|
|
use = uci:get('wireless', net, 'disabled') ~= '1'
|
|
static_ip(net, uci:get('wireless', net, 'ifname'), uci:get('wireless', net, 'macaddr'), use)
|
|
end
|
|
|
|
do_config('mesh_')
|
|
if uci:get('network', 'ibss_' .. radio['.name'], 'proto') then
|
|
do_config('ibss_')
|
|
end
|
|
end)
|
|
|
|
local function apply_network(name, use, mac)
|
|
if not uci:get('network', name, 'proto') then
|
|
print('warn: non-existent network ' .. name)
|
|
return
|
|
end
|
|
|
|
not_disabled = uci:get('network', name, 'disabled') ~= '1'
|
|
if use == nil then
|
|
use = not_disabled
|
|
end
|
|
macaddr = uci:get('network', name, 'macaddr')
|
|
if not macaddr then
|
|
macaddr = util.generate_mac(mac)
|
|
uci:set('network', name, 'macaddr', macaddr)
|
|
end
|
|
static_ip(name, uci:get('network', name, 'ifname'), macaddr, use)
|
|
end
|
|
|
|
if pcall(function() require 'gluon.mesh-vpn' end) then
|
|
local vpn_core = require 'gluon.mesh-vpn'
|
|
|
|
apply_network('mesh_vpn', vpn_core.enabled(), 7)
|
|
end
|
|
|
|
local uplink_mesh = not uci:get_bool('network', 'mesh_uplink', 'disabled')
|
|
apply_network('mesh_uplink', uplink_mesh, 10)
|
|
|
|
local other_mesh = not uci:get_bool('network', 'mesh_other', 'disabled')
|
|
apply_network('mesh_other', other_mesh, 11)
|
|
|
|
apply_network('loopback', true, 12)
|
|
|
|
uci:save('gluon-static-ip')
|
|
uci:save('network')
|