Escrevendo um script de firewall

Existem muitos firewalls gráficos for Linux, como o Shorewall e o Firestarter. 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.1.0/255.255.255.0 -j ACCEPT

Estes comandos seguem uma sintaxe comum: tudo começa com o comando “iptables”, que é o utilitário responsável por ler os parâmetros e atualizar a configuração do firewall. Em seguida, vem uma condição, indicada pela opção “-A”. Neste exemplo usei
“INPUT -s 192.168.1.0/255.255.255.0”, que se aplica a qualquer pacote de entrada (INPUT), proveniente dos micros da rede local (192.168.1.0/255.255.255.0). Como não especifiquei o protocolo, a regra permitirá o uso dos três protocolos, ou seja, TCP, UDP e
ICMP, sem restrições.

Note que aqui estou especificando uma faixa de endereços e a máscara de sub-rede (usada na rede local), fazendo com que a regra se aplique a todos os pacotes provenientes dela. 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.

Se por outro lado quisesse apenas bloquear um endereço específico, usaria o parâmetro “-j REJECT”, como em:

# iptables -A INPUT -s 192.168.1.23 -j REJECT

A primeira coisa a ter em mente é que, assim como o Squid, o Iptables processa as regras de forma sequencial, permitindo ou recusando as conexões conforme encontra uma regra que faz referência a ela. Se uma determinada regra diz que os pacotes
provenientes de um determinado endereço devem ser aceitos e outra logo depois diz que eles devem ser recusados, como neste exemplo:

# iptables -A INPUT -s 192.168.1.10 -j ACCEPT
# iptables -A INPUT -s 192.168.1.10 -j REJECT

… vale a primeira, já que ao serem autorizados por ela, os pacotes são imediatamente aceitos, sem passarem pela segunda. Ao formular as regras para seu script de firewall, você deve colocar as regras mais específicas primeiro, deixando as regras mais
gerais por último. Se você quer permitir o acesso de todos os endereços provenientes da rede local, bloqueando apenas um endereço específico, você usaria:

# iptables -A INPUT -s 192.168.1.10 -j REJECT
# iptables -A INPUT -s 192.168.1.0/255.255.255.0 -j ACCEPT

Além de serem diretamente digitadas no terminal, as regras podem ser incluídas dentro de scripts, de forma que você possa ativar o firewall rapidamente e/ou configurar o sistema para carregá-lo automaticamente durante o boot. O script de firewall nada
mais é do que um shell script comum, contendo os comandos que devem ser executados, um por linha. Você pode, por exemplo, criar o arquivo “/etc/init.d/firewall”. Outra opção seria simplesmente adicionar os comandos no final do arquivo “/etc/rc.local”, de
forma que eles sejam executados durante o boot.

Este é um exemplo de mini-script de firewall 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:

#!/bin/sh
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 ficar vulnerável a acessos externos. Estes 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), sem entretanto 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.

Estas duas regras podem ser usadas como base para criar um firewall de bloqueio, onde 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.

Para testar, você pode executar o script no seu micro, ou em qualquer outro PC da rede e tentar acessá-lo via SSH (ou qualquer outro serviço ativo). Como usamos o parâmetro “DROP” na segunda regra, o PC simplesmente ignorará o chamado, fazendo com que
o cliente fique um longo tempo tentando abrir a conexão, para depois exibir um erro de timeout, como em:

$ ssh 192.168.1.21

ssh: connect to host 192.168.1.21 port 22: Connection timed out

Para desativar o firewall e voltar a aceitar conexões, use o comando “iptables -F”, que limpa as regras do Iptables:

# iptables -F

A partir deste script básico, 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 determinados programas 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:
iptables -A INPUT -s 192.168.1.0/255.255.255.0 -j ACCEPT

O “192.168.1.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.1.1 e 192.168.1.254. Tudo o que vier deles é 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.1.x) e outra à
Internet, o firewall não aceitará que um pacote falseado, proveniente da Internet, com endereço de emissor “192.168.1.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.

Se o servidor possuir duas placas de rede, você poderia tornar a regra mais à prova de falhas especificando a interface de origem em vez da faixa de endereços, usando o parâmetro “-i”. Com isso, o firewall é instruído a aceitar pacotes recebidos na
interface de rede local, independentemente da faixa de endereços usada. Embora funcione de forma diferente, ela tem a mesma função da regra anterior. Ao usá-la, não esqueça de substituir o “eth0” pela interface de rede local, caso diferente:

# Aceita tudo na interface de rede local:
iptables -A INPUT -i eth0 -j ACCEPT

O parâmetro “-s”, usado na regra anterior pode também ser usado para permitir endereços ou faixas de endereços da internet. Imagine que você queira dar acesso aos hosts de uma das filiais da empresa, 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 veremos em detalhes 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 22, 80 e 443, por exemplo, você usaria a regra abaixo:

# Abre um conjunto de portas:
iptables -A INPUT -m multiport -p tcp --dport 22,80,443 -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

Este é um exemplo de script completo, incluindo algumas regras adicionais para evitar ataques comuns. Ele inclui as funções para aceitar os comandos “start”, “stop” e “restart”, de forma a se comportar como se fosse um serviço de sistema:

#!/bin/bash
iniciar(){
    # Abre para a faixa de endereços da rede local:
    iptables -A INPUT -s 192.168.1.0/255.255.255.0 -j ACCEPT
    # Faz a mesma coisa, só que especificando a interface, pode ser
    # usada em substituição à regra anterior:
    # iptables -A INPUT -i eth0 -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:
    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.
    iptables -A INPUT -p tcp --syn -j DROP
}
parar(){
    iptables -F
    iptables -P INPUT ACCEPT
    iptables -P OUTPUT ACCEPT
    echo "Regras de firewall desativadas"
}
case "$1" in
    "start") iniciar ;;
    "stop") parar ;;
    "restart") parar; iniciar ;;
    *) echo "Use os parâmetros start ou stop"
esac

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”.

Para que o script seja executado durante o boot, crie um link para ele dentro da pasta “/etc/rc5.d”:

# cd /etc/rc5.d
# ln -s ../init.d/compartilhar S21compartilhar

Sobre o Autor

Redes Sociais:

Deixe seu comentário

X