Precedência de regras do PF e IPFW em FreeBSD

Esta contribuição está participando do sorteio da Mochila Targus Matrix. Envie seu texto e participe você também, você contribui com outros usuários e ainda pode faturar uma mochila novinha em folha para o seu laptop. Saiba mais sobre como participar.

Sobre o Autor:

Rodolfo Zappa
rodolfo@archive.com.br
http://www.archive.com.br

Objetivo:

Como já é quase um consenso, as ferramentas de firewall para Freebsd, sozinhas não são completas. O IPFW é considerado como o melhor firewall disponível para o Freebsd, mas não possui suporte a NAT built-in.

Particularmente, odeio a implementação do natd, e ainda mais o divert no IPFW para conseguir a solução do NAT. Já o PF (Packet Filter) importado do Openbsd, é considerado a melhor implementação de nat disponível para bsd, mas deixa a desejar, para muitos, na principal funcionalidade de um firewall, que é filtrar pacotes.

Como temos disponibilidade das duas, por que não usar o filtro de pacotes (e outras coisas mais, como controle de banda) com o IPFW e deixar o nat para o PF?

A resposta parece óbvia a princípio, mas não encontrei em nenhum lugar, uma documentação clara sobre procedência de regras, ao misturar IPFW + PF (não considero código-fonte como documentação). Sem este pequeno detalhe, a vida de quem vai construir esta solução pode se tornar um verdadeiro inferno (mexeu com o sistema do capeta, deu nisso!).

Em testes particulares, cheguei a algumas conclusões, que posto aqui para serem completadas da melhor maneira possível pelos integrantes da lista (particularmente acho interessante adicionar aqui, o fluxo de pacotes passando pelo fwd do IPFW e route-to do PF).

Estrutura do teste:

——–|fw|——–

Onde os hosts da lan acessan a internet através do firewall (fw) que é o default gateway da rede. Para testes de nat, um micro da lan possui um servidor web, publicado no endereço ip válido da interface externa do firewall, que possui uma regra de nat para permitir que hosts externos à lan se conectem a este servidor.

Regras de Nat (pf.conf):

#——– MACROS ———#
if_ext = “tun0”
if_lan = “rl0”

#——– NAT ————#
nat on $if_ext from $if_lan:network to any -> ($if_ext)
rdr on $if_ext proto tcp from any to ($if_ext) port 8080 -> 192.168.2.3
port 80

1) Tráfego da Lan, saindo para a internet, passando pelo firewall:

—> PF (IN if_lan) —> IPFW (IN if_lan / OUT if_ext) —> PF (NAT)
—> PF (OUT if_ext)

Ou seja, consigo filtrar pacotes com o IPFW, saindo pela interface externa, baseado nos endereços ip de origem dos pacotes (endereço da lan), pois as regras do IPFW são processadas antes do nat do PF. Já as regras de saída do PF (OUT if_ext) são processadas somente após passarem pelo nat, impossibilitando políticas baseadas no endereço ip de origem.

2) Tráfego externo, entrando pelo firewall, em direção ao servidor web:

—> PF (NAT) —> PF (IN if_ext) —> IPFW (IN if_ext / OUT if_lan)
—> PF (OUT if_lan)

Neste caso, as regras de filtragem, independente de utilizadas no PF ou IPFW, devem levar em consideração que o destino do pacote já foi traduzido pelo nat.