#!/usr/bin/lua

local uci = require('simple-uci').cursor()
local platform = require 'gluon.platform'


local defaults = uci:get_first('firewall', 'defaults')
uci:set('firewall', defaults, 'input', 'REJECT')


local function reject_input_on_wan(zone)
	if zone.name == 'wan' then
		uci:set('firewall', zone['.name'], 'input', 'REJECT')
		uci:set('firewall', zone['.name'], 'conntrack', true)
	end

	return true
end

local function add_cellular_wan(zone)
	if zone.name == 'wan' then
		uci:set('firewall', zone['.name'], 'network', {'wan', 'wan6', 'cellular_4', 'cellular_6'})
	end
end

uci:foreach('firewall', 'zone', reject_input_on_wan)

if platform.is_cellular_device() then
	uci:foreach('firewall', 'zone', add_cellular_wan)
end

for _, zone in ipairs({'mesh', 'loc_client', 'wired_mesh'}) do
	-- Other packages assign interfaces to these zones
	uci:section('firewall', 'zone', zone, {
		name = zone,
		network = {},
		input = 'REJECT',
		output = 'ACCEPT',
		forward = 'REJECT',
	})

	uci:section('firewall', 'rule', zone .. '_ICMPv6_in', {
		src = zone,
		proto = 'icmp',
		icmp_type = {
			'echo-request',
			'echo-reply',
			'destination-unreachable',
			'packet-too-big',
			'time-exceeded',
			'bad-header',
			'unknown-header-type',
			'router-solicitation',
			'neighbour-solicitation',
			'router-advertisement',
			'neighbour-advertisement',
			'130/0', -- Multicast Listener Query
			'131/0', -- Multicast Listener Report
			'132/0', -- Multicast Listener Done
			'143/0', -- MLDv2
		},
		limit = '1000/sec',
		family = 'ipv6',
		target = 'ACCEPT',
	})
end

uci:section('firewall', 'rule', 'loc_client_ICMPv4_in', {
	src = 'loc_client',
	proto = 'icmp',
	icmp_type = {
		'echo-request',
	},
	family = 'ipv4',
	target = 'ACCEPT',
})

-- allow inbound SSH from anywhere
for _, zone in ipairs({ 'wan', 'loc_client', 'mesh' }) do
	uci:section('firewall', 'rule', zone .. '_ssh', {
		name =  zone .. '_ssh',
		src = zone,
		dest_port = '22',
		proto = 'tcp',
		target = 'ACCEPT',
	})
end


local wired_mesh_ifaces = {}
uci:foreach('network', 'interface',
	function(iface)
		-- Select all interfaces with proto gluon_wired except for
		-- mesh_uplink into this zone, as mesh_uplink is the same
		-- interface as wan, which has its own zone
		if iface['proto'] == 'gluon_wired' and iface['.name'] ~= 'mesh_uplink' then
			table.insert(wired_mesh_ifaces, iface['.name'])
		end
	end
)
uci:set('firewall', 'wired_mesh', 'network', wired_mesh_ifaces)

-- VXLAN for wired meshing
for _, zone in ipairs({'wired_mesh', 'wan'}) do
	uci:section('firewall', 'rule', zone .. '_vxlan', {
		name =  zone .. '_vxlan',
		src = zone,
		family = 'ipv6',
		src_ip = 'fe80::/64',
		proto = 'udp',
		dest_port = '4789',
		target = 'ACCEPT',
	})
	uci:reorder('firewall', zone .. '_vxlan', 0)
end


uci:save('firewall')
