Product SiteDocumentation Site

14.2. Firewall ou Filtragem de pacotes

Um firewall é um portal de filtragem da saída de rede e é efetivo apenas em pacotes que devem passar por ele. Portanto, o firewall só será eficaz quando a única rota para estes pacotes for através dele.
O kernel do Linux incorpora o firewall netfilter, que pode ser controlado a partir do espaço do usuário com os comandos iptables, ip6tables, arptables e ebtables.
Entretanto, comandos iptables do Netfilter estão sendo substituídos pelo nftables, o que evita muitos destes problemas. Seu projeto envolve menos duplicação de código, e pode ser gerenciado apenas com o comando nft. O Debian Buster, a estrutura nftables é usada por padrão. Os comandos mencionados anteriormente são fornecidos por versões, que usam a API do kernel nftables, por padrão. Se alguém requer os comandos “clássicos“, os binários relevantes podem ser ajustados usando update-alternatives.
Para habilitar um firewall padrão no Debian execute:
# apt install -y nftables
Lendo listas de pacotes... Pronto
...
# systemctl enable nftables.service
Created symlink /etc/systemd/system/sysinit.target.wants/nftables.service → /lib/systemd/system/nftables.service.

14.2.1. Comportamento do nftables

Enquanto o núcleo está processando um pacote de rede, ele pausa e nos permite inspecionar o pacote e decidir o que fazer com ele. Por exemplo, poderíamos descartar certos pacotes de entrada, modificar outros pacotes de diversas formas, bloquear certos pacotes de saída para controle contra malware, ou redirecionar alguns pacotes o quanto antes para fazer uma ponte entre interfaces de rede ou para distribuir a carga de pacotes de entrada entre sistemas.
Um bom entendimento das camadas 3, 4 e 5 do modelo OSI (Open Systems Interconnection) é essencial para obter o máximo do netfilter.
O firewall é configurado com tabelas (tables), que contêm regras(rules) contidas em cadeias (chains). Ao contrário do iptables, nftables não possui nenhuma tabela padrão. O usuário decide quais e quantas tabelas criar. Cada tabela deve ter apenas uma das seguintes cinco famílias assinadas: ip, ip6, inet, arp e bridge. Usa-se ip se a família não é especificada.
Há dois tipos de cadeias: cadeias de base e cadeias regulares. Uma cadeia de base é um ponto de entrada para pacotes da pilha de rede. Cadeias de base são registradas nos hooks do Netfilter, ou seja, essas cadeias vêem pacotes fluindo através da pilha TCP/IP. Por outro lado, uma cadeia regular não está anexada a qualquer hook, então não vê qualquer tráfego. Mas pode ser usada como um destino de salto para melhor organização das regras.
Regras são feitas de declarações, que incluem algumas expressões que devem ser correspondidas, e então uma declaração final, como accept, drop, queue, continue, return, jump chain e goto chain.

14.2.2. Migrando de iptables para nftables

Os comandos iptables-translate e ip6tables-translate podem ser usados para traduzir comandos iptables antigos para a nova sintaxe nftables. Conjuntos completos de regras também podem ser traduzidos no caso em que migremos as regras configuradas em um computador no qual o Docker está instalado:
# iptables-save > iptables-ruleset.txt
# iptables-restore-translate -f iptables-ruleset.txt

# Translated by iptables-restore-translate v1.8.7 on Wed Mar 16 22:06:32 2022
add table ip filter
add chain ip filter INPUT { type filter hook input priority 0; policy accept; }
add chain ip filter FORWARD { type filter hook forward priority 0; policy drop; }
add chain ip filter OUTPUT { type filter hook output priority 0; policy accept; }
add chain ip filter DOCKER
add chain ip filter DOCKER-ISOLATION-STAGE-1
add chain ip filter DOCKER-ISOLATION-STAGE-2
add chain ip filter DOCKER-USER
add rule ip filter FORWARD counter jump DOCKER-USER
add rule ip filter FORWARD counter jump DOCKER-ISOLATION-STAGE-1
add rule ip filter FORWARD oifname "docker0" ct state related,established counter accept
add rule ip filter FORWARD oifname "docker0" counter jump DOCKER
add rule ip filter FORWARD iifname "docker0" oifname != "docker0" counter accept
add rule ip filter FORWARD iifname "docker0" oifname "docker0" counter accept
add rule ip filter DOCKER-ISOLATION-STAGE-1 iifname "docker0" oifname != "docker0" counter jump DOCKER-ISOLATION-STAGE-2
add rule ip filter DOCKER-ISOLATION-STAGE-1 counter return
add rule ip filter DOCKER-ISOLATION-STAGE-2 oifname "docker0" counter drop
add rule ip filter DOCKER-ISOLATION-STAGE-2 counter return
add rule ip filter DOCKER-USER counter return
add table ip nat
add chain ip nat PREROUTING { type nat hook prerouting priority -100; policy accept; }
add chain ip nat INPUT { type nat hook input priority 100; policy accept; }
add chain ip nat OUTPUT { type nat hook output priority -100; policy accept; }
add chain ip nat POSTROUTING { type nat hook postrouting priority 100; policy accept; }
add chain ip nat DOCKER
add rule ip nat PREROUTING fib daddr type local counter jump DOCKER
add rule ip nat OUTPUT ip daddr != 127.0.0.0/8 fib daddr type local counter jump DOCKER
add rule ip nat POSTROUTING oifname != "docker0" ip saddr 172.17.0.0/16 counter masquerade
add rule ip nat DOCKER iifname "docker0" counter return
# Completed on Wed Mar 16 22:06:32 2022
# iptables-restore-translate -f iptables-ruleset.txt > ruleset.nft
# nft -f ruleset.nft
# nft list ruleset
table inet filter {
	chain input {
		type filter hook input priority filter; policy accept;
	}

	chain forward {
		type filter hook forward priority filter; policy accept;
	}

	chain output {
		type filter hook output priority filter; policy accept;
	}
}
table ip nat {
	chain DOCKER {
		iifname "docker0" counter packets 0 bytes 0 return
		iifname "docker0" counter packets 0 bytes 0 return
	}

	chain POSTROUTING {
		type nat hook postrouting priority srcnat; policy accept;
		oifname != "docker0" ip saddr 172.17.0.0/16 counter packets 0 bytes 0 masquerade
		oifname != "docker0" ip saddr 172.17.0.0/16 counter packets 0 bytes 0 masquerade
	}

	chain PREROUTING {
		type nat hook prerouting priority dstnat; policy accept;
		fib daddr type local counter packets 1 bytes 60 jump DOCKER
		fib daddr type local counter packets 0 bytes 0 jump DOCKER
	}

	chain OUTPUT {
		type nat hook output priority -100; policy accept;
		ip daddr != 127.0.0.0/8 fib daddr type local counter packets 0 bytes 0 jump DOCKER
		ip daddr != 127.0.0.0/8 fib daddr type local counter packets 0 bytes 0 jump DOCKER
	}

	chain INPUT {
		type nat hook input priority 100; policy accept;
	}
}
table ip filter {
	chain DOCKER {
	}

	chain DOCKER-ISOLATION-STAGE-1 {
		iifname "docker0" oifname != "docker0" counter packets 0 bytes 0 jump DOCKER-ISOLATION-STAGE-2
		counter packets 0 bytes 0 return
		iifname "docker0" oifname != "docker0" counter packets 0 bytes 0 jump DOCKER-ISOLATION-STAGE-2
		counter packets 0 bytes 0 return
	}

	chain DOCKER-ISOLATION-STAGE-2 {
		oifname "docker0" counter packets 0 bytes 0 drop
		counter packets 0 bytes 0 return
		oifname "docker0" counter packets 0 bytes 0 drop
		counter packets 0 bytes 0 return
	}

	chain FORWARD {
		type filter hook forward priority filter; policy drop;
		counter packets 0 bytes 0 jump DOCKER-USER
		counter packets 0 bytes 0 jump DOCKER-ISOLATION-STAGE-1
		oifname "docker0" ct state related,established counter packets 0 bytes 0 accept
		oifname "docker0" counter packets 0 bytes 0 jump DOCKER
		iifname "docker0" oifname != "docker0" counter packets 0 bytes 0 accept
		iifname "docker0" oifname "docker0" counter packets 0 bytes 0 accept
		counter packets 0 bytes 0 jump DOCKER-USER
		counter packets 0 bytes 0 jump DOCKER-ISOLATION-STAGE-1
		oifname "docker0" ct state established,related counter packets 0 bytes 0 accept
		oifname "docker0" counter packets 0 bytes 0 jump DOCKER
		iifname "docker0" oifname != "docker0" counter packets 0 bytes 0 accept
		iifname "docker0" oifname "docker0" counter packets 0 bytes 0 accept
	}

	chain DOCKER-USER {
		counter packets 0 bytes 0 return
		counter packets 0 bytes 0 return
	}

	chain INPUT {
		type filter hook input priority filter; policy accept;
	}

	chain OUTPUT {
		type filter hook output priority filter; policy accept;
	}
}
As ferramentas iptables-nft, ip6tables-nft, arptables-nft, ebtables-nft são versões de iptables que usam a API nftables, de modo que os(as) usuários(as) podem continuar usando a antiga sintaxe iptables com elas, mas isto não é recomendado; essas ferramentas somente devem ser usadas para retrocompatibilidade.

14.2.3. Sintaxe do ntf

Os comandos nft permitem manipular tabelas, cadeias e regras. A opção table suporta múltiplas operações: add, create, delete, list e flush. O comando nft add table ip6 mangle adiciona uma nova tabela da família ip6.
Para inserir uma nova cadeia de base na tabela de filtro, você pode executar o seguinte comando (observe que o ponto e virgula é protegido por uma barra invertida quando se usa o Bash):
# nft add chain filter input { type filter hook input priority 0 \; }
Regras são geralmente adicionadas com a seguinte sintaxe: nft add rule [família] tabela cadeia handle handle statement.
insert é semelhante ao comando add, mas a regra fornecida é anexada ao início da cadeia ou antes da regra com o identificador fornecido, em vez de no final ou depois da regra. Por exemplo, o comando a seguir insere uma regra antes da regra com o manipulador número 8:
# nft insert rule filter output position 8 ip daddr 127.0.0.8 drop
Os comandos nft executados não fazem modificações permanentes na configuração, por isso serão perdidas se não forem salvas. As regras de firewall estão localizadas em /etc/nftables.conf. Uma maneira simples de gravar a configuração de firewall permanentemente é executar nft list ruleset > /etc/nftables.conf como root.
nft permite muitas outras operações, consulte sua página de manual nft(8) para mais informações.

14.2.4. Instalando as Regras em Cada Inicialização

Para habilitar um firewall padrão no Debian, você precisa armazenar as regras em /etc/nftables.conf e executar systemctl enable nftables como root. Você pode parar o firewall executando nft flush ruleset como root.
Em outros casos, a maneira recomendada é registrar o script de configuração em diretivas up do /etc/network/interfaces. No exemplo a seguir, o script é armazenado em /usr/local/etc/arrakis.fw.

Exemplo 14.1. arquivo interfaces chamando script firewall

auto eth0
iface eth0 inet static
address 192.168.0.1
network 192.168.0.0
netmask 255.255.255.0
broadcast 192.168.0.255
up /usr/local/etc/arrakis.fw
Isso obviamente assume que você está usando o ifupdown para configurar as interfaces de rede. Se você está usando algo diferente (como o NetworkManager ou systemd-networkd), então consulte suas respectivas documentações para encontrar maneiras de executar um script após a interface ter sido levantada.