Tabela filter
Na tabela filter (tabela-padrão do netfilter), temos as chains INPUT, OUTPUT e FORWARD.
O início: Geralmente iniciamos com a criação de uma política-padrão de acesso, que na maioria dos casos, é negar, como o exemplo abaixo:
# iptables -P INPUT DROP
# iptables -P FORWARD DROP
# iptables -P OUTPUT DROP
Estas regras irão bloquear qualquer pacote que tente acessar, passar ou sair pelo nosso firewall. Neste momento você não conseguirá fazer nada.
Revisão:
- INPUT → Controla a entrada em nosso firewall, ou seja, o acesso no firewall;
- OUTPUT → Controla a saída em nosso firewall, ou seja, o acesso efetuado pelo nosso firewall;
- FORWARD → Controla o acesso que passa pelo nosso firewall com direção a uma máquina ou rede, não sendo o firewall.
Vamos agora começar a liberar acesso necessário em nosso firewall.
Vamos liberar conexões provindas da rede 10.0.0.0/24:
# iptables -A INPUT -s 10.0.0.0/24 -j ACCEPT
Agora vamos rejeitar os pacotes, saindo do nosso kernel com o destino ao IP 200.154.56.80 (www.terra.com.br) com a opção: icmp-host-unreachable
Porém, antes de rejeitar, vamos logar toda a passagem:
# iptables -A OUTPUT -d 200.154.56.80 -j LOG --log-prefix "ACESSO AO TERRA " --log-level warn
# iptables -A OUTPUT -d 200.154.56.80 -j REJECT --reject-with icmp-host-unreachable
Agora vamos fazer um teste, vamos pingar neste IP:
ping 200.154.56.80 -c 3
PING 200.154.56.80 (200.154.56.80) 56(84) bytes of data.
From 10.0.0.20 icmp_seq=1 Destination Host Unreachable
From 10.0.0.20 icmp_seq=1 Destination Host Unreachable
From 10.0.0.20 icmp_seq=1 Destination Host Unreachable
--- 200.154.56.80 ping statistics ---
0 packets transmitted, 0 received, +3 errors
Como pode ser notado, a nossa regra funcionou corretamente.
Usaremos agora uma interface específica para assegurar que todos os pacotes provindos da minha rede 192.168.0.0 possam entrar, passar e sair pelo firewall através da interface eth0:
# iptables -A INPUT -s 192.168.0.0/24 -i eth0 -j ACCEPT
# iptables -A FORWARD -d 192.168.0.0/24 -j ACCEPT
# iptables -A OUTPUT -d 192.168.0.0/24 -o eth0 -j ACCEPT
Como pode ser notado, é isso que vamos ter que ir fazendo para o que necessitar de acesso, vamos ver mais opções logo abaixo.
Parâmetros TCP/UDP
Os parâmetros são específicos para o protocolo e são disponíveis apenas quando trabalhamos com pacotes e stream TCP. Para usá-lo, é necessário utilizar os parâmetros "-p" ou "-protocol tcp" ou "udp" junto com o IPtables.
Especificando porta de origem
"--sport" ou "--source-port" → Estes parâmetros verificam a porta de origem.
Eles podem trabalhar com um nome de serviço, como: www, ftp etc. Os nomes dos serviços podem ser consultados em
/etc/services.
Pode-se usar um range de portas, por exemplo, da mesma porta 22 até a porta 80 seria algo como 22:80. Da mesma forma, podemos usar a forma de exceção, como por exemplo, todas as portas, menos as inclusas desde 22 a 80. Seria algo com: ! 22:80
# iptables -A INPUT -p tcp ! --sport 1024:65535 -j ACCEPT
Nesta regra, estamos aceitando tudo o que entra de origem qualquer, com portas de origens diferentes de portas altas do TCP, ou seja, quando requisitamos uma conexão a um servidor Web, temos como porta de destino a porta 80.
E com certeza, quando a conexão retornar, terá porta de origem 80 e destino uma porta alta em nosso host, desta forma, não aceitaremos conexões em portas baixas que são usadas para serviços específicos.
Da mesma forma que usamos o TCP, poderemos utilizar o UDP:
# iptables -A INPUT -p udp ! --sport 53 -j REJECT
Especificando porta de destino
"--dport" ou "--destination-port" → Estes parâmetros verificam a porta de destino.
Esta opção verificará o serviço ou porta de destino. Pode ser usada também com a opção de exceção "!". Outro item de grande importância, é o uso de várias portas com o caractere ":".
Se omitirmos um dos lados, o IPtables assumirá automaticamente um valor de início ou fim. Por exemplo, :80 significa o início e portas 0 até 80, ou ainda 80:, significa início porta 80 até 65535.
# iptables -A INPUT ! -s 192.168.0.0/24 -p tcp --dport 22 -j REJECT
Neste exemplo, todo tráfego que não estiver vindo da rede interna com destino ao processo local na porta 22, será rejeitado.
Especificando Flags TCP
tcp-flags mask comp → Esta opção compara as flags do TCP (SYN,ACK,FIN,RST,PSH,URG,ALL,NONE) com as flags marcadas em comp.
Elas serão comparadas quando as flags de mask estiverem com o estado das flags em comp. As flags inseridas em comp deverão estar ativas no pacote para que coincidam com a regra. Por exemplo, ALL ACK, neste caso ela casará quando a flag ACK estiver setada. A opção "!" usará exceção para as flags em comp.
Outro detalhe é a separação entre flags que é feita por vírgulas e a separação entre mask e comp é feita através de espaços.
# iptables -A INPUT -p tcp --tcp-flags SYN,ACK SYN --dport 22 -j DROP
O pacotes com as flags SYN e ACK serão verificados e se estiverem com a opção de SYN setada e com destino à porta 22 serão descartados. Quando executamos uma solicitação de conexão, mandamos um SYN e o servidor nos responde um SYN/ACK.
No caso anterior, estamos dropando tentativas de conexão na porta 22, pois não enviamos um SYN. Podemos considerar neste caso, um scanner tentando localizar as portas abertas.
Especificando Flags TCP de início de conexão
syn → Esta opção concilia pacotes que tenham no datagrama as flags SYN ligadas e ACK e RST desligadas. Seria um tipo de tcpflags com as seguintes opções: SYN, ACK, RST SYN verificando por solicitação de conexão, também possui a possibilidade de utilizar "!" com exceção.
# iptables -A INPUT -i eth0 -p tcp --dport 22 --syn -j LOG
Nestas regras estaremos logando todas as conexões com flags SYN ligadas, entretanto pela eth0 na porta destino 22.
Especificando Flags TCP através de valores
tcp-option número → Compara se a opção está ligada.
Onde as opções são:
- CWR:128
- ECE:64
- URG:32
- ACK:16
- PSH:8
- RST:4
- SYN:2
- FIN:1
Com certeza você está se perguntando o que é essa tal de CWR e ECE. Simples, a
CWR (Congestion Windows Reduced) é uma janela de congestionamento reduzida, e a
ECE (Explicit Congestion Notification Echo) é uma mensagem de notificação de congestionamento explícita.
Vamos a um exemplo de uso:
# iptables -A INPUT -p tcp ! --tcp-option 2 -j REJECT --reject-with tcp-reset
Nesta regra estamos verificando o tráfego de entrada com a flag diferente de dois (SYN) e rejeitando com o item de tcp-reset, ou um pacote RST. Normalmente, encontramos muitos firewalls com o uso desta opção, mas explicitamente rejeitando pacotes com as flags 64 e 128 habilitadas.
Parâmetros ICMP
Temos um parâmetro para o ICMP, este parâmetro é usado com a opção "-p" ou "--protocol", seguida do tipo de ICMP.
--protocol icmp --icmp-type → Esta opção serve para especificarmos o tipo de ICMP.
Os tipos de ICMP pode ser consultados em:
http://support.microsoft.com/kb/170292/pt-br
Podemos utilizar o ICMP pelo nome ou pelo número que corresponde a determinado tipo.
Note que os pacotes ICMP são reclassificados dentro de sua tabela, por exemplo, "destination-unreachable" (destino inalcançável), que é um tipo de classificação e dentro desta classificação, temos tipos específicos como
host-unreachable e
network-unreachable.
A classe destino inalcançável tem um valor específico, neste caso 3, e os tipos internos têm outra classificação interna (código). Nos outros dois casos, seriam 0 e 1.
Para ficar mais claro, veja da seguinte forma: o host-unreachable e network-unreachable são do tipo destination-unreachable. Posso fazer referência a ambos informando no IPtables o tipo 3, ele casará com todos os códigos de 0 a 15.
Não há problema algum usar desta forma, aliás, na prática, sempre usamos assim. Caso deseje especificar apenas um código e não o tipo inteiro, basta mencioná-lo diretamente após "icmp-type", por exemplo, network-unreachable ou 3/0.
Vamos a um exemplo:
# iptables -A INPUT -p icmp --icmp-type 8 -j DROP
# iptables -A INPUT -p icmp --icmp-type echo-request -j DROP
Nos dois exemplos citados estamos dropando todos os pacotes ICMP do tipo 8 (ping) enviados ao nosso firewall, e como foi visto podemos utilizar o 8 ou echo-request.
Exemplos de uso na tabela filter
Veremos alguns exemplos do uso de regras de firewall do IPtables na tabela filter para permitir o acesso a serviços externos, ou até permitir serviços que respondem no firewall, embora não seja recomendado termos serviços no próprio firewall.
Permitindo que o firewall acesse o DNS
Neste caso, vamos supor que nossa interface de rede para Internet seja a eth0, e que o nosso firewall poderá fazer requisições para um DNS qualquer.
Note que poderíamos ser mais específicos e detalhar qual seria o DNS permitido. Outro item importante é pensarmos que quando fazemos uma conexão, temos a ida e volta, então devemos liberar o INPUT e o OUTPUT.
Vamos à regra:
# iptables -A INPUT -i eth0 -p udp --sport 53 --dport 1024:65535 -j ACCEPT
# iptables -A OUTPUT -o eth0 -p udp --dport 53 --sport 1024: -j ACCEPT
Recorde-se que se informarmos 1024:65535, é o mesmo que "1024:", pois estamos especificando onde começa a porta de destino, sendo que se depois dos ":" não informarmos nada, ele vai até a última porta, ou seja 65535.
Permitindo WWW e SSH no firewall
Esta regra permite o acesso ao servidor web e SSH que se encontra no próprio firewall. Utilizaremos um módulo que verificará o estado da conexão. Não se preocupe com este item específico, pois será visto adiante.
Esta primeira regra permitirá conexões de saída que já foram estabelecidas anteriormente, ou seja, já tenha relação com conexões existentes. Normalmente vinculadas à alguma regra de entrada, utilizada no INPUT.
Um exemplo interessante:
- Criarmos uma regra de entrada para conexões SSH;
- Deveremos criar uma regra de saída também para conexão SSH;
- Criamos uma regra de entrada para conexões em um servidor web (www);
- Deveremos criar uma regra de saída também para conexões em um servidor web (www).
Agora, utilizando-se do "--state":
- Criamos uma regra de entrada para conexões SSH;
- Criamos uma regra de entrada para conexões em um servidor web (www);
- Criamos uma regra de saída baseada em conexões de entradas que foram permitidas, ou seja, existe uma conexão de entrada, então haverá permissão para saída através do módulo state.
Vamos à regra de saída do firewall (logo abaixo vou explicar as regras):
# iptables -A OUTPUT -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT
Agora, liberamos as portas 80 (HTTP) e 22 (SSH), desde que o estado seja uma nova conexão:
# iptables -A INPUT -p tcp -i eth0 --dport 22 --sport 1024: -m state NEW -j ACCEPT
# iptables -A INPUT -p tcp -i eth0 --dport 80 --sport 1024: -m state NEW -j ACCEPT
# iptables -A INPUT -m state --state ESTABLISHED,RELATED -i eth0 -p tcp -j ACCEPT
Explicação: Quando estabelece uma comunicação, o estado da conexão poderá ser NEW (novo), ESTABLISHED (uma conexão já estabelecida) ou RELATED (tem relação com uma conexão nova ou estabelecida).
Nesta regra, estamos utilizando este mesmo esquema para permitir pacotes que já tenham uma conexão preestabelecida ou tenha relação como uma conexão nova efetuada anteriormente. Mas não permitiremos uma nova conexão, que seria o estado de NEW. E ainda especificamos que sejam pacotes chegando na interface eth0.
Regra por tempo
Vamos a um exemplo de uma regra de IPtables controlada por tempo:
# iptables -A INPUT -p tcp --dport 22 -m time --datestart 2012-01-16T16:00 --datestop 2012-01-16T23:59:59 -j ACCEPT
Aqui estou deixando passar o tráfego na porta 22 no intervalo de tempo de 16/01/2012-12:00 até 16/01/2012-23:59:59.
Permitindo acesso ao firewall da rede interna
Nesta regra estaremos liberando qualquer protocolo e porta para nossa rede interna. Note que não é necessário especificar porta e protocolo, conforme o exemplo:
# iptables -A INPUT -p all -s 192.168.1.0/24 -i eth1 -j ACCEPT
# iptables -A OUTPUT -p all -d 192.168.1.0/24 -o eth1 -j ACCEPT
Esta regra funcionaria também da seguinte forma:
# iptables -A INPUT -j ACCEPT -s 192.168.1.0/24 -i eth1
# iptables -A OUTPUT -j ACCEPT -d 192.168.1.0/24 -o eth1
Bloqueando ping
Bloquearemos os pings oriundos de qualquer lugar, mas ainda podemos fazer isso através do sistema
proc em
/proc, mas neste momento usaremos as regras de IPtables:
# iptables -A FORWARD -p icmp --icmp-type echo-request -j DROP
Poderíamos fazer uma regra de firewall, onde bloqueamos os pings com exceção da rede interna:
# iptables -A FORWARD ! -s 192.168.0.0/24 -p icmp --icmp-type echo-request -j DROP
No exemplo acima, queremos bloquear o ping (icmp - echo request), menos de nossa rede interna.
Mas não criamos regras para permitir que o nosso servidor consiga pingar ou responder pings, de forma que até o próprio firewall não conseguiria utilizar o protocolo ICMP para pingar outros hosts.
A seguir, um modelo de script que poderia funcionar:
# iptables -A INPUT -s 192.168.0.0/24 -p icmp --icmp-type echo-request -j ACCEPT
# iptables -A OUTPUT -d 192.168.0.0/24 -p icmp --icmp-type echo-reply -j ACCEPT
# iptables -A FORWARD -s 192.168.0.0/24 -p icmp --icmp-type echo-request -j ACCEPT
No exemplo acima, liberamos o firewall responder a requisições de ping, o firewall pode também solicitar requisições de ping, e pode efetuar o repasse de requisições de ping para a sua rede.