gluon-nftables: init

This commit is contained in:
Maciej Krüger 2023-04-25 22:05:24 +02:00
parent 4318048aed
commit 40b1f1b1e2
No known key found for this signature in database
GPG Key ID: 0D948CE19CF49C5F
3 changed files with 204 additions and 0 deletions

View File

@ -0,0 +1,16 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=gluon-nftables
include ../gluon.mk
define Package/gluon-nftables
TITLE:=Nftables support
DEPENDS:=+nftables-json
endef
define Package/gluon-nftables/description
Gluon community wifi mesh firmware framework: Nftables support
endef
$(eval $(call BuildPackageGluon,gluon-nftables))

View File

@ -0,0 +1,188 @@
#!/usr/bin/lua
local uci = require('simple-uci').cursor()
local glob = require 'posix.glob'
-- Library
function string.starts(string, start)
return string.sub(string, 1, string.len(start)) == start
end
function basepath(str)
return str:match("([^./\\]+).lua")
end
function write_all_lines(table, file, close)
for _, line in ipairs(table) do
file:write(line .. '\n')
end
if close then
file:write('}\n')
end
end
function read_include(file)
local f = assert(io.open(path(file), "rb"))
local content = f:read("*all")
f:close()
return content
end
-- Functions
function path(name)
return '/lib/gluon/nftables/' .. name .. '.nft'
end
function include(name, parameters)
local boilerplate = {
type = 'nftables',
path = path(name),
}
for k, v in pairs(parameters) do
boilerplate[k] = v
end
uci:section('firewall', 'include', 'gluon_nftables_' .. name, boilerplate)
end
function rule(name, chain, content)
local file = io.open(path(name), 'w')
file:write(content + '\n')
file:close()
include(name, {
position = 'chain-post',
chain = chain,
})
end
local bridge = {
chain = {
INPUT = {
'chain input {',
'type filter hook input priority filter; policy accept;',
},
FORWARD = {
'chain forward {',
'type filter hook forward priority filter; policy accept;',
},
OUTPUT = {
'chain output {',
'type filter hook output priority filter; policy accept;',
},
PREROUTING = {
'chain prerouting {',
'type filter hook prerouting priority dstnat; policy accept;',
},
},
table = {
pre = {
'table bridge gluon',
'flush table bridge gluon',
'table bridge gluon {',
},
post = {
},
}
}
function bridge_rule(chain, content)
if bridge.chain[chain] == nil then
error('No bridge chain ' .. chain)
end
table.insert(bridge.chain[chain], content)
end
function bridge_table(position, content)
if bridge.table[position] == nil then
error('No bridge position ' .. position)
end
table.insert(bridge.table[position], content)
end
function bridge_chain(name)
if bridge.chain[name] ~= nil then
error('Chain already exists ' .. name)
end
bridge.chain[name] = {
'chain ' .. name:lower() .. ' {'
}
end
function bridge_include_rule(chain, file)
if bridge.chain[chain] == nil then
error('No bridge chain ' .. chain)
end
table.insert(bridge.chain[chain], read_include(file))
end
function bridge_include_table(position, file)
if bridge.table[position] == nil then
error('No bridge position ' .. position)
end
table.insert(bridge.table[position], read_include(file))
end
-- Loader
function load_file(path)
local nft = assert(loadfile(path))
local fncs = setmetatable({
path = path,
include = include,
rule = rule,
bridge_rule = bridge_rule,
bridge_chain = bridge_chain,
bridge_table = bridge_table,
bridge_include_rule = bridge_include_rule,
bridge_include_table = bridge_include_table,
}, { __index = _G })
local env = setmetatable({}, { __index = fncs })
setfenv(nft, env)
nft()
end
-- Clean old rules
uci:foreach('firewall', 'include', function(i)
if string.starts(i['.name'], 'gluon_nftables_') then
uci:delete('firewall', i['.name'])
end
end)
-- Load new rules
for _, path in ipairs(glob.glob("/lib/gluon/nftables/*.lua", 0) or {}) do
print(' - NFTables: ' .. basepath(path))
load_file(path)
end
local b = io.open(path('bridge'), 'w')
include('bridge', {
position = 'ruleset-pre',
})
write_all_lines(bridge.table.pre, b)
for _, lines in pairs(bridge.chain) do
write_all_lines(lines, b, true)
end
write_all_lines(bridge.table.post, b, true)
uci:save('firewall')