Escrevendo um script de firewall

Existem muitos firewalls gráficos for Linux, como o GuardDog, o Shorewall e o Firestarter (que comento adiante). Eles variam em nível de facilidade e recursos, oferecendo uma interface amigável e gerando as regras do Iptables de acordo com a
configuração feita. Você pode escolher entre usar o programa que melhor atenda suas necessidades ou configurar diretamente o Iptables com as regras desejadas. Neste caso, você pode formular as regras diretamente, definindo condições onde os pacotes serão
aceitos ou recusados, como em:

# iptables -A INPUT -s 192.168.0.0/255.255.255.0 -j ACCEPT

Estes comandos seguem uma sintaxe comum: tudo começa com o comando “iptables“, que é quem executará as opções incluídas no comando. Em seguida vem uma condição, indicada pela opção “-A”. Neste exemplo usei “INPUT
-p tcp -s 192.168.0.0/255.255.255.0″, que se aplica a qualquer pacote de entrada (INPUT), utilizando o protocolo TCP (-p tcp), proveniente dos micros da rede local (192.168.0.0/255.255.255.0). Note que aqui estou especificando uma faixa de endereços e a
máscara de sub-rede. No final, é preciso dizer o que fazer com os pacotes que se enquadrarem nesta situação, indicando uma ação. O “-j ACCEPT” diz que estes pacotes devem ser aceitos.

À primeira vista, isso parece bem complicado, assim como o arquivo de configuração original do Squid, com suas 3.000 e tantas linhas. Mas, as coisas ficam bem mais simples se começarmos com um script simples e formos
incluindo novas regras aos poucos.

Este é um exemplo de script que pode ser usado em um desktop que simplesmente acessa a internet como cliente, sem rodar nenhum servidor, nem compartilhar a conexão com outros micros:

# iptables -A INPUT -i lo -j ACCEPT
# iptables -A INPUT -p tcp –syn -j DROP

A idéia aqui é que o micro possa acessar a internet sem que ninguém de fora possa invadi-lo de forma alguma. Esses dois comandos fazem isso da forma mais simples possível.

A primeira linha orienta o firewall a deixar passar os pacotes enviados através da interface de loopback (-i lo -j ACCEPT). É importante que esta linha (ou outra com o mesmo efeito) sempre seja usada, em qualquer script de
firewall que termine bloqueando todas as conexões, pois no Linux a interface de loopback é usada para comunicação entre diversos programas. Para ter uma idéia, todos os programas gráficos a utilizam para se comunicarem com o X, os programas do KDE a
utilizam para trocar mensagens entre si. Sem esta regra, muita coisa deixa de funcionar corretamente.

Depois de abrir o firewall para as mensagens locais, usamos a segunda regra para bloquear todas as novas conexões vindas de fora. O “–syn” faz com que o firewall aplique a regra apenas para tentativas de abrir novas conexões
(alguém tentando acessar o servidor SSH que você esqueceu aberto, por exemplo), mas sem impedir que servidores remotos respondam a conexões iniciadas por você. Isso permite que você continue navegando e acessando compartilhamentos em outros micros da rede
local, com poucas limitações.

Para não precisar ficar digitando os comandos cada vez que precisar reiniciar o micro, você pode incluí-los em um dos arquivos de inicialização do sistema. Nas distribuições derivadas do Debian, você pode colocá-los no
final do arquivo “
/etc/init.d/bootmisc.sh” e, nas derivadas do Red Hat, no arquivo “/etc/rc.d/rc.local“.

Essas duas regras podem ser usadas como base para criar o que chamo de firewall de bloqueio. Ele segue uma idéia bastante simples: você diz as portas que gostaria de abrir e ele fecha todas as demais. Ou seja, o
firewall fecha por padrão todas as portas, com exceção das que você disser explicitamente que deseja manter abertas. Isso garante uma configuração de firewall bastante segura com um mínimo de dor de cabeça.

Você pode adicionar novas regras, abrindo portas, direcionando faixas de portas para micros da rede interna, fechando portas de saída, de forma a bloquear o uso de programas como o ICQ e o MSN e assim por diante.

Imagine que você está configurando o firewall do servidor da rede. Ele tem duas placas de rede, uma para a rede local e outra para a internet. Você precisa que ele fique acessível sem limitações dentro da rede local, mas quer
manter tudo fechado para quem vem da internet.

Nesse caso, você poderia usar a regra que mostrei há pouco no seu script de firewall:

# Abre para uma faixa de endereços da rede local
iptables -A INPUT -s 192.168.0.0/255.255.255.0 -j ACCEPT

O “192.168.0.0” indica a faixa de endereços da rede local. A máscara “255.255.255.0” indica que a última parte do endereço muda, ou seja, os micros da rede local usam endereços entre 192.168.0.1 e 192.168.0.254. Tudo o que
vier deles (tanto TCP, quanto UDP, já que não indicamos o protocolo) é aceito.

Note que esta faixa de endereços não é roteável, ela simplesmente não existe na internet. Não existe a possibilidade de algum engraçadinho de outro estado tentar configurar seu micro para usar esta faixa de endereços e
enganar a regra do firewall.

Como uma proteção adicional, as versões recentes do Iptables são capazes de ignorar pacotes aparentemente destinados a uma interface quando eles chegam em outra. Com duas placas, onde uma está ligada à rede local (usando a faixa 192.168.0.x) e outra à
Internet, o firewall não aceitará que um pacote falseado, proveniente da Internet, com endereço de emissor “192.168.0.3” (por exemplo), seja encaminhado a um micro da rede local, pois ele sabe que pacotes com este endereço de emissor devem chegar apenas
pela placa ligada à rede local.

Essa mesma regra pode ser usada também para abrir o firewall para endereços ou faixas de endereços da internet. Imagine que você queira dar acesso aos micros da filial da sua empresa em Macapá, onde usam um link com o IP fixo
200.220.234.12. Você poderia abrir a faixa 200.220.234.0 ou apenas o IP 200.220.234.12, de forma que o firewall permitisse acessos vindos de lá, mas continuasse bloqueando o restante. Você pode abrir para várias faixas de endereços distintas, basta
repetir a linha adicionando cada uma das faixas desejadas.

Imagine agora que este servidor foi instalado na sede de uma empresa para a qual você presta serviços. Você precisa acessá-lo de vez em quando para corrigir problemas, mas naturalmente quer fazer isso via internet, sem
precisar se deslocar até lá. Você pode configurar o firewall para abrir a porta 22 usada pelo SSH adicionando a regra:

# Abre uma porta (inclusive para a internet)
iptables -A INPUT -p tcp –dport 22 -j ACCEPT

Note que esta regra abre a porta 22 para todo mundo. Lembre-se do exemplo do SSH: todo servidor disponível para a internet é um risco potencial de segurança, por isso só abra as portas para os servidores que você realmente
for utilizar. O ideal seria usar um par de chaves, protegidas por uma passphrase para acessar o servidor e configurá-lo para não aceitar logins com senha (apenas com chaves), como vimos no capítulo sobre SSH.

Ao abrir várias portas, você pode utilizar o parâmetro “-m multiport” para especificar todas de uma vez, separadas por vírgula, sem precisar colocar uma em cada linha. Para abrir as portas 21, 22 e 6881 (bittorrent), por
exemplo, você usaria a regra abaixo:

# Abre um conjunto de portas
iptables -A INPUT -m multiport -p tcp –dport 21,22,6881 -j ACCEPT

Se você presta suporte a partir de uma empresa que possui um link dedicado, com IP fixo, você pode tornar a regra mais específica, permitindo apenas o IP de onde você acessa:

# Abre uma porta para um IP específico
iptables -A INPUT -p tcp -s 200.231.14.16 –dport 22 -j ACCEPT

Em um micro doméstico, você pode abrir também as portas usadas pelo bittorrent (6881 a 6889) ou portas usadas por jogos multiplayer, por exemplo. Para abrir um intervalo de portas, use a regra:

# Abre um intervalo de portas
iptables -A INPUT -p tcp –dport 6881:6889 -j ACCEPT

Além de trabalhar com endereços IP, é possível criar regras baseadas também em endereços MAC. Isso permite adicionar uma camada extra de proteção ao criar regras para a rede local. Para isso, usamos o parâmetro “-m mac
–mac-source”, seguido pelo endereço MAC da placa do host desejado. Para permitir que o host “192.168.1.100” tenha acesso ao servidor, mas apenas se o endereço MAC da interface bater, você usaria uma regra como:

iptables -A INPUT -s 192.168.1.100 -m mac –mac-source 00:11:D8:76:59:2E -j ACCEPT

Note que agora, além do IP, especificamos o endereço MAC da placa. As duas regras são usadas em conjunto, de forma que o acesso é permitido apenas caso as duas informações estejam corretas. Isso dificulta as coisas para
alguém que queira acessar o servidor trocando o IP de sua máquina. Você pode descobrir o MAC das máquinas da rede usando o próprio ifconfig ou o comando “arp -a”.

Note que limitar o acesso com base no endereço MAC adiciona uma camada extra de proteção, mas não é infalível. O endereço MAC pode ser trocado de forma quase tão simples quanto o endereço IP e, sniffando a rede, é possível
descobrir os endereços IP e MAC dos micros com uma certa facilidade.

No Linux, você pode trocar o endereço MAC da placa de rede usando os comandos:

# ifconfig eth0 down
# ifconfig eth0 hw ether 00:11:D8:76:59:2E
# ifconfig eth0 up

Como vê, basta especificar o endereço desejado. O Iptables não é capaz de diferenciar máquinas com os endereços MAC falseados das reais, pois, se alguém desconectasse o micro 192.168.1.100 da rede e configurasse o seu para
usar o mesmo IP e MAC, poderia acessar o servidor bipassando a regra de firewall. A única forma de ter uma segurança completa seria utilizar o SSH ou outro protocolo que utilize um algoritmo robusto de encriptação para o login e a transmissão dos
dados.

Lembre-se de que o firewall é uma primeira barreira de proteção, mas não é uma garantia por sí só. É preciso combiná-lo com outras camadas de segurança para ter um servidor completamente seguro.

Outra limitação é que as regras baseadas em endereços MAC podem ser usadas apenas dentro da rede local. O endereço MAC é descartado do pacote quando ele é roteado para a Internet, ficando apenas o endereço IP. Ao acessar
através de uma conexão compartilhada, todos os pacotes provenientes da Internet chegam com o endereço MAC do gateway da rede.

Este é um exemplo de script completo, incluindo algumas regras adicionais para evitar ataques comuns:

#!/bin/bash

iniciar(){

# Abre para uma faixa de endereços da rede local
iptables -A INPUT -s 192.168.0.0/255.255.255.0 -j ACCEPT

# Abre uma porta (inclusive para a internet)
iptables -A INPUT -p tcp –dport 22 -j ACCEPT

# Ignora pings
iptables -A INPUT -p icmp –icmp-type echo-request -j DROP

# Protege contra IP spoofing (esta opção já vem ativada por padrão na
# maioria das distribuições atuais, mas não custa ter certeza)
echo 1 > /proc/sys/net/ipv4/conf/default/rp_filter

# Descarta pacotes malformados, protegendo contra ataques diversos
iptables -A INPUT -m state –state INVALID -j DROP

# Abre para a interface de loopback. Esta regra é essencial para que
# o KDE e outros programas gráficos funcionem adequadamente.
iptables -A INPUT -i lo -j ACCEPT

# Impede a abertura de novas conexões, efetivamente bloqueando o acesso
# externo ao seu servidor, com exceção das portas e faixas de endereços
# manualmente especificadas anteriormente. Bloqueia tudo.
iptables -A INPUT -p tcp –syn -j DROP

}

parar(){
iptables -F
echo “Regras de firewall desativadas”
}

case “$1” in
“start”) iniciar ;;
“stop”) parar ;;
“restart”) parar; iniciar ;;
*) echo “Use os parâmetros start ou stop”
esac

A receber qualquer conexão, vinda de qualquer endereço, o firewall primeiro verifica todas estas regras, seqüencialmente, para decidir se o pacote passa ou não. Usando esse script de exemplo, teríamos o seguinte:

– Se o pacote vier da rede local, ele é aceito.
– Se o pacote for para porta 22 (do SSH), ele é aceito.
– Se for um ping, ele é recusado (de forma a dificultar um pouco para outros descobrirem que você está online).
– Pacotes danificados ou forjados (unclean) são recusados, protegendo os micros da rede interna.
– Se o pacote vier da sua própria máquina (um programa tentando mostrar alguma coisa na tela, por exemplo), ele é aceito.
– Se o pacote for uma resposta a uma conexão que você iniciou, como, por exemplo, o servidor do guiadohardware.net enviando a página do site que você está acessando, ele é aceito.
– Tentativas de conexão (toda conexão TCP é iniciada por um pacote syn) fora das condições especificadas acima são descartadas pelo firewall. A conexão nem sequer chega a ser estabelecida e o emissor não recebe qualquer resposta (DROP). Ele não sabe se o
pacote foi recebido ou não, fica no vácuo, o que dá a impressão de que o seu micro nem está online.

Da forma como escrevi, o script suporta as funções “start”, “stop” e “restart”, e pode ser usado como um serviço de sistema. Salve-o dentro da pasta “/etc/init.d”, como em “/etc/init.d/firewall”, e marque a permissão de
execução:

# chmod +x /etc/init.d/firewall

A partir daí, você pode ativar as regras usando o comando “/etc/init.d/firewall start” e fazer com que alterações dentro do script entrem em vigor com um “/etc/init.d/firewall restart”.

Se você está configurando um servidor dedicado remotamente, é importante que você teste o script antes de configurar o sistema para executá-lo automaticamente durante o boot. O motivo é simples: se houver alguma regra
incorreta no script, que bloqueie seu acesso ao servidor, você poderá solicitar um reboot do servidor para que a configuração seja removida e você recupere o acesso. Entretanto, se o sistema for configurado para carregar o script durante o boot, o reboot
não resolverá e você precisará abrir uma chamada de suporte, solicitando que um técnico se logue localmente no servidor e desative seu script (o que provavelmente resultará em uma taxa adicional).

Uma opção mais relaxada seria simplesmente colocar os comandos com as regras desejadas no final do arquivo “/etc/init.d/bootmisc.sh” ou “/etc/rc.d/rc.local”, mas isso não é tão recomendável, pois você perde a possibilidade de
reiniciar o firewall rapidamente depois de alterar as regras.

Assim como nas regras do Squid, cada pacote que chega pela rede precisa passar por todas as regras, para que o firewall possa decidir o que fazer com ele. Quando aceito por uma das regras, ele é imediatamente encaminhado ao
aplicativo, sem passar pelas demais. Por isso é necessário sempre colocar as regras mais restritivas por último, de preferência concluindo o script com uma regra que bloqueia todos os pacotes de entrada.

Outra dica é que você pode incluir os comandos para compartilhar a conexão e ativar o proxy transparente (que também são regras de firewall) no script, fazendo que ele desempenhe simultaneamente as duas funções. Nesse caso,
tome o cuidado de sempre colocar as regras que compartilham a conexão e ativam o proxy transparente antes das regras que bloqueiam conexões.

Este é um exemplo de script de firewall que inclui as regras para compartilhar a conexão e ativar o proxy transparente. Ao usá-lo, comente as linhas que não se aplicam à sua instalação:

#!/bin/bash

iniciar(){

# Compartilha a conexão
modprobe iptable_nat
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -A FORWARD -p tcp –tcp-flags SYN,RST SYN -m tcpmss –mss 1400:1536 \
-j TCPMSS –clamp-mss-to-pmtu
echo “Compartilhamento ativado”

# Proxy transparente
iptables -t nat -A PREROUTING -i eth1 -p tcp –dport 80 -j REDIRECT –to-port 3128
echo “Proxy transparente ativado”

# As regras de firewall que vimos há pouco:
iptables -A INPUT -s 192.168.0.0/255.255.255.0 -j ACCEPT
iptables -A INPUT -p tcp –dport 22 -j ACCEPT
iptables -A INPUT -p icmp –icmp-type echo-request -j DROP
echo 1 > /proc/sys/net/ipv4/conf/default/rp_filter
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p tcp –syn -j DROP

}

parar(){
iptables -F
iptables -t nat -F
echo “Regras de firewall e compartilhamento desativados”
}

case “$1” in
“start”) iniciar ;;
“stop”) parar ;;
“restart”) parar; iniciar ;;
*) echo “Use os parâmetros start ou stop”
esac

Outra dica importante são os comandos usados para limpar as regras do Iptables. É necessário executá-los sempre que você fizer alterações no seu script de firewall e quiser executá-lo novamente para que as novas regras
entrem em vigor. No primeiro script de exemplo, por exemplo, uso o comando “iptables -F” como parte da função “stop”, que desativa o firewall. No segundo script, incluí também o “iptables -t nat -F”.

iptables -F: Limpa a tabela principal do iptables, onde vão os comandos para abrir e fechar portas, que vimos até aqui.

iptables -t nat -F: Limpa a tabela nat, que é usada por regras que compartilham a conexão e fazem forwarding de portas, como por exemplo:

iptables -t nat -A PREROUTING -i eth0 –dport 22 -j DNAT –to-dest 192.168.1.2

Todas as regras do Iptables que levam “-t nat” são armazenadas nesta segunda tabela, que precisa ser zerada separadamente. A idéia é que você pode limpar as regras principais do firewall sem desabilitar o compartilhamento da
conexão e vice-versa.

iptables -L: Este comando lista a configuração atual, sem alterar nada. É interessante executá-lo depois de fazer alterações na configuração do firewall, para ter certeza que as regras surtiram o efeito esperado. Para
ver as regras de forwarding e compartilhamento, use também o “iptables -t nat -L

Sobre o Autor

Redes Sociais:

Deixe seu comentário

X