Páginas

segunda-feira, 22 de abril de 2013

Firewall Corporativo com IPtables


Olá a todos!

Como prometido, nesse post eu vou colocar um script para firewall corporativo. Obviamente que eu vou explicar a estrutura do script e o porquê de fazer algumas coisas e não fazer outras. Em primeiro lugar eu quero explicar que nesse script eu não coloquei comandos para carregar módulos, nem para setar opções no kernel, etc, por pensar que essas configurações se tratam do sistema operacional em si e não do firewall como eu vejo muitos fazendo. O firewall foi criado com pequenas particularidades pensando no Debian, mas no geral funciona em qualquer outra distribuição.

1ª Parte:

#!/bin/bash
#
# ## BEGIN INIT INFO
# Provides : Firewall
# Required - Start : networking
# Required - Stop :
# Should - Start : S
# Should - Stop :
# Default - Start : 2 3 4 5
# Default - Stop :
# Short - Description : Firewall - Rodrigo Garcia
# Description : Firewall - Rodrigo Garcia
#
# ## END INIT INFO
################################################################################################
# 1- VARIAVEIS
################################################################################################
IPT=$(which iptables)
HIPRT="1024:65535"
################################################################################################
# 1.1- EXTERNO - Informe a placa de rede externa em IFEXT="" e o IP externo em IPEXT=""
################################################################################################
IFEXT=""
IPEXT=""
################################################################################################
# 1.2- INTERNO - Informe a placa de rede interna em IFINT="" e o ip interno em IPINT=""
################################################################################################
IFINT=""
IPINT=""
################################################################################################
# 1.3- Redes - Informe o IP da WAN (geralmente 0/0) em IPWAN="" e o IP da rede interna (CIDR) em IPLAN=""
################################################################################################
IPWAN=""
IPLAN=""
################################################################################################
# 1.4- Informe em OPENP="" as portas abertas no firewall no formato "porta:protocolo:origem", ex: 22:tcp:192.168.0.2
# e as portas encaminhadas em FRWDP="" como "porta:protocolo:destino:porta", ex: 80:tcp:192.168.0.3:80
# As portas de saída devem ser informadas em OUTPT="" no formato porta:protocolo:destino, ex: 53:udp:0/0 ou 53:udp:$IPWAN
# As portas que devem ser priorizadas, devem ser informadas em TOSPT="" apenas com o numero ex: TOSPT="22 80 443"
################################################################################################
OPENP=""
FRWDP=""
OUTPT=""
TOSPT=""
################################################################################################


No bloco acima, as linhas de 3 a 14 são tags usadas para configurar o script para subir com o sistema operacional. Deve-se colocar o script (já com permissão de execução) em /etc/init.d/ e executar o comando insserv -d firewall . Isso adicionará a sua execução nos runlevels de inicialização.

A primeira seção (1- VARIAVEIS) estão as variáveis globais que serão usadas no script. Começamos com a variável $IPT que já foi explicada no post anterior sobre firewall pessoal. O diferencial está na seção 1.4 que traz as portas que você quer abrir no firewall e as que quer encaminhar para dentro de sua rede, e as portas de saída do firewall e as portas cujos pacotes devem ser priorizados.


################################################################################################
# 2- POLITICA DROP
################################################################################################
FN_DROP()
{
    for CHAIN in INPUT OUTPUT FORWARD
    do
        $IPT -P $CHAIN DROP
    done
}
################################################################################################
# 3- POLITICA ACCEPT
################################################################################################
FN_ACCEPT()
{
    for CHAIN in INPUT OUTPUT FORWARD
    do
        $IPT -P $CHAIN ACCEPT
    done
}
################################################################################################
# 4- LIMPAR FIREWALL
################################################################################################
FN_LIMPA()
{
    for TABLE in filter nat mangle
    do
        $IPT -t $TABLE -X
        $IPT -t $TABLE -F
    done
}
################################################################################################
# 5- LIBERAR LOCALHOST
################################################################################################
FN_LOCAL()
{
    $IPT -I INPUT -i lo -d 127.0.0.1 -j ACCEPT
    $IPT -I OUTPUT -o lo -s 127.0.0.1 -j ACCEPT
}
################################################################################################
# 6- LIBERAR CONEXOES
################################################################################################
FN_CONN()
{
    for CHAIN in INPUT OUTPUT FORWARD
    do
        $IPT -A $CHAIN -m state --state ESTABLISHED,RELATED -j ACCEPT
    done
}
################################################################################################
# 7- ENCAMINHAR REDES
################################################################################################
FN_FRWD()
{
    for FROM in -s -d
    do
        $IPT -A FORWARD $FROM $IPLAN -j ACCEPT
    done
}
################################################################################################
# 8- PING
################################################################################################
FN_PING()
{
    for TYPE in "0" "8"

    do    
         $IPT -A INPUT -i $IFINT -p icmp -s $IPLAN -d $IPINT --icmp-type $TYPE -j ACCEPT
        
$IPT -A OUTPUT -o $IFINT -p icmp -s $IPINT -d $IPLAN --icmp-type $TYPE -j ACCEPT
    done
    $IPT -A INPUT -i $IFEXT -p icmp -s $IPWAN -d $IPEXT --icmp-type 0 -j ACCEPT
    $IPT -A OUTPUT -o $IFEXT -p icmp -s $IPEXT -d $IPWAN --icmp-type 8 -j ACCEPT
}
################################################################################################



O bloco de comandos acima foi feito todo no formato de funções. Por que? Fica muito mais fácil de manupular a estrutura do firewall dessa forma, e podemos facilmente alterar a ordem de execução das funções além de servir para complementarmos com parâmetros de execução do script na parte final. Os comandos acima são os mais básicos para qualquer firewall como liberar comunicação com localhost, permitir entrada de ping só da rede interna, e resposta de ping de todos, encaminhar os pacotes para as redes, etc. Deve ser notado que os comandos utilizam as variáveis locais para facilitar a criação das regras e posteriormente a alteração de IPs, interfaces, etc sem precisar mudar em cada regra.

################################################################################################
# 9- PORTAS DE SAIDA
################################################################################################
FN_OUTPT()
{
    for PORTA in $OUTPT
    do
        PORT=$(echo $PORTA | awk 'BEGIN { FS = ":" } ; { print $1 }')

        PROT=$(echo $PORTA | awk 'BEGIN { FS = ":" } ; { print $2 }')
        DEST=$(echo $PORTA | awk 'BEGIN { FS = ":" } ; { print $3 }')
        if [ -z $PROT ]
        then
            PROT="tcp"
        fi
        if [ -z $DEST ]
        then
            DEST="$IPWAN"
        fi
        NET=$(echo "$IPLAN" | awk 'BEGIN { FS = "." } ; { print $1 FS $2 FS $3 FS "*"}')

        case $DEST in
        $NET)
            IF=$(echo $IFINT)

            IP=$(echo $IPINT)
        ;;
        *)
            IF=$(echo $IFEXT)

            IP=$(echo $IPEXT)
        ;;
        esac
        $IPT -A INPUT -i $IF -p $PROT -s $DEST --sport $PORT -d $IP --dport $HIPRT -j ACCEPT
        $IPT -A OUTPUT -o $IF -p $PROT -s $IP --sport $HIPRT -d $DEST --dport $PORT -j ACCEPT
    done
}
################################################################################################


 A função acima abre portas para saída do firewall para serviços externos como cosultar um DNS ou instalar pacotes por repositórios, etc.


################################################################################################
# 10- ABRIR PORTAS
################################################################################################
FN_OPENP()
{
    for PORTA in $OPENP
    do
        PORT=$(echo $PORTA | awk 'BEGIN { FS = ":" } ; { print $1 }')

        PROT=$(echo $PORTA | awk 'BEGIN { FS = ":" } ; { print $2 }')
        FROM=$(echo $PORTA | awk 'BEGIN { FS = ":" } ; { print $3 }')
        if [ -z $PROT ]
        then
            PROT="tcp"
        fi
        if [ -z $FROM ]
        then
            FROM="$IPINT"
        fi
        NET=$(echo "$IPLAN" | awk 'BEGIN { FS = "." } ; { print $1 FS $2 FS $3 FS "*"}')

        case $FROM in
        $NET)
            IF=$(echo $IFINT)

            IP=$(echo $IPINT)
         ;;
        *)
            IF=$(echo $IFEXT)

            IP=$(echo $IPEXT)
        ;;
        esac
        $IPT -A INPUT -i $IF -p $PROT -s $FROM --sport $HIPRT -d $IP --dport $PORT -j ACCEPT
        $IPT -A OUTPUT -o $IF -p $PROT -s $IP --sport $PORT -d $FROM --dport $HIPRT -j ACCEPT
    done
}
################################################################################################


A função acima é a responsável pela abertura das portas no firewall, definindo o protocolo e a origem caso nao sejam especificados na variável, e decidindo qual interface de rede utilizar de acordo com a origem da comunicação.

################################################################################################
# 11- ENCAMINHAR PORTAS
################################################################################################
FN_FWDP()
{
    for PORTA in $FRWDP
    do
        PORT=$(echo $PORTA | awk 'BEGIN { FS = ":" } ; { print $1 }')

        PROT=$(echo $PORTA | awk 'BEGIN { FS = ":" } ; { print $2 }')
        FWSV=$(echo $PORTA | awk 'BEGIN { FS = ":" } ; { print $3 }')
        FWPT=$(echo $PORTA | awk 'BEGIN { FS = ":" } ; { print $4 }')
        if [ -z $PROT ]
        then
            PROT="tcp"
        fi
        if [ -z $FWPT ]
        then
            FWPT=$(echo $PORT)

        fi
        $IPT -t nat -A PREROUTING -i $IFEXT -p $PROT -s $IPWAN --sport $HIPRT -d $IPEXT --dport $PORT -j DNAT --to $FWSV:$FWPT
    done
}
################################################################################################

Acima temos a função de encaminhamento das portas para a rede interna, e assim como a função de abertura de portas, ela também define o protocolo caso não seja especificado nq variável. Em ambas as funções eu fiz uso do AWK, uma linguagem de edição de textos muito útil e versátil que pode facilitar em muito a vida de um Sysadmin.

################################################################################################
# 12- TOS - PRIORIZACAO DE PACOTES
################################################################################################
FN_TOS()
{
    for PORTA in $TOSPT
    do
        $IPT -t mangle -A PREROUTING -i $IFEXT -p tcp -s $IPWAN -d $IPEXT --sport $PORTA -j TOS --set-tos 16
        $IPT -t mangle -A OUTPUT -o $IFEXT -p tcp -s $IPEXT -d $IPWAN --dport $PORTA -j TOS --set-tos 16
    done
}
################################################################################################


O bloco acima faz a parte de priorização dos pacotes.

################################################################################################
# 13- COMPARTILHAR INTERNET
################################################################################################
FN_SNAT()
{
    $IPT -t nat -A POSTROUTING -o $IFEXT -s $IPLAN -j SNAT --to $IPEXT
}
################################################################################################



Aqui nós temos uma função de compartilhamento da Internet usando SNAT ao invés do MASQUERADE (que é recomendado para IPs dinâmicos).


################################################################################################
# 14- LOG
################################################################################################
FN_LOG()
{
    echo "$0 $1 Executado em $(date +%d-%m-%Y-%H:%M:%S)" 2>&1 >> /var/log/firewall.log
}
################################################################################################


Acima temos a criação de logs de execução em /var/log/firewall.log


################################################################################################
# 15- EXECUCAO DO FIREWALL
################################################################################################
case $1 in
start)
    FN_DROP
    FN_LIMPA
    FN_LOCAL
    FN_CONN
    FN_FRWD
    FN_PING
    FN_OUTPT
    FN_OPENP
    FN_FWDP
    FN_TOS
    FN_SNAT
    FN_LOG "start"
    echo "Starting IPTables Firewall Rules: firewall."
;;
stop)
    FN_ACCEPT
    FN_LIMPA
    FN_LOG "stop"
    echo "Stopping IPTables Firewall Rules: firewall."
;;
restart)
    $0 stop
    $0 start
;;
*)
    echo "Use $0 {start|stop|restart}"
;;
esac


################################################################################################

Acima temos toda a ordem de execução de cada função, e a forma de execução do firewall através dos parâmetros start, stop ou restart.

Espero ter sido útil, e até a próxima!!!

sábado, 6 de abril de 2013

Firewall Pessoal

Olá a todos!!!

Nesse post eu vou mostrar algo muito simples e útil, que é um firewall pessoal através do IPTables. O IPTables é um front-end para o módulo Netfilter do kernel do Linux.

Ele possui 4 tabelas, a Filter, que é a padrão (controla o tráfego básico de entrada, saída e encaminhamento do firewall), a tabela NAT (responsável por tradução de endereços de redes), a tabela Mangle (que é responsável por regras de ações especiais a serem tomadas pelo firewall) e a tabela RAW (controle de pacotes).

Neste firewall, usaremos apenas a tabela Filter, conforme veremos a seguir. Geralmente (nos sistemas baseados em Debian), o IPTables não contém nenhuma regra e a política do firewall é a ACCEPT, que aceita todos os pacotes de entrada, saída e encaminhamento. Entretando, nos sistemas baseados em Red Hat por exemplo, o firewall possui já algumas regras criadas na instalação do SO. Vamos trabalhar como se já houvessem regras preexistentes.

A primeira ação a ser tomada é limpar todas as regras de todas as tabelas do firewall:

iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X

A opção "-F" é a mesma de "--flush" e vai limpar todas as tabelas, e a opção "-X" vai excluir todas as chains personalizadas préexistentes. A seguir, vamos aplicar a política "DROP" no firewall, que vai negar qualquer conexão por padrão:

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

O que foi feito acima foi bloquear qualquer conexão de entrada e de encaminhamento no firewall, e permitir todas as conexões de saída. Nesse momento você não conseguirá estabelecer conexão nenhuma, pois conseguirá enviar pacotes de saída, mas não conseguirá receber respostas.

A primeira coisa que devemos liberar no firewall é o localhost:

iptables -A INPUT -i lo -j ACCEPT

Em seguida, devemos liberar as conexões que você estabeleceu, para que haja entrada de respostas de pacotes:

iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

Agora o próximo passo é liberar a entrada de respostas de ping, e solicitações de ping da rede interna (opcional)

iptables -A INPUT -p icmp --icmp-type 0 -j ACCEPT
iptables -A INPUT -p icmp -s ip.da.rede.interna/máscara --icmp-type 8 -j ACCEPT

O que vamos fazer agora, é liberar as respostas de servidores de DNS externos:

iptables -A INPUT -p udp -s 0/0 --sport 53 -j ACCEPT


Vimos que agora o comando teve algumas novidades:

-s 0/0 = Significa qualquer origem com qualquer máscara de rede
--sport = Significa uma conexão que tem como origem a porta 53 (DNS)

A partir desse momento, você já conseguirá executar com sucesso ping nas pelo nome do endereço que você quiser. Então vamos agora liberar a navegação web:

iptables -A INPUT -p tcp -s 0/0 --sport 80 -j ACCEPT
iptables -A INPUT -p tcp -s 0/0 --sport 443 -j ACCEPT

Pronto! Você já consegue também navegar na internet! Esses são os passos da criação de um firewall pessoal básico, que você mesmo pode personalizar de acordo com suas necessidades. Por exemplo, se quiser acessar algum serviço externo, deverá criar uma regra assim:

iptables -A INPUT -p tcp -s 0/0 --sport "porta do serviço" -j ACCEPT

E se quiser liberar na sua máquina o acesso a um serviço SSh de dentro da rede, deverá criar uma regra como essa:

iptables -A INPUT -p tcp -s ip.da.rede.interna/máscara --dport 22 -j ACCEPT

Para facilitar, eu gosto de criar scripts que aplicam todas essas regras automaticamente e facilitam na adição de novas regras com o uso de variáveis. Por exemplo:

#!/bin/bash
# Script de Firewall criado por Rodrigo Garcia - www.unix4life.blogspot.com
##############################################################
# 1 - VARIÁVEIS
##############################################################
IPT=$(which iptables) # Isso diminui a sua digitação, e traz maior segurança
IF_INT="eth0" # Colocar aqui o nome da placa de rede interna
IP_INT="`ifconfig $IF_INT | awk 'NR == 2{ print $3 }'`"
NET_INT="192.168.0.0/24" # IP da rede interna
##############################################################
# 2 - LIMPAR FIREWALL
##############################################################
for TABLE in filter nat mangle raw
do
$IPT -t $TABLE -F
$IPT -t $TABLE -X
done
##############################################################
# 3 - APLICAR POLITICAS
##############################################################
$IPT -P INPUT DROP
$IPT -P FORWARD DROP
$IPT -P OUTPUT ACCEPT
##############################################################
# 4 - LIBERAR LOCALHOST
##############################################################
$IPT -A INPUT -i lo -j ACCEPT
##############################################################
# 5 - LIBERAR CONEXÕES ESTABELECIDAS
##############################################################
$IPT -A INPUT -i $IF_INT -m state --state ESTABLISHED,RELATED -j ACCEPT
##############################################################
# 6 - ECHO REPLY E ECHO REQUEST VINDO DA REDE INTERNA
##############################################################
$IPT -A INPUT -p icmp --icmp-type 0 -j ACCEPT
$IPT -A INPUT -i $IF_INT -p icmp -s $NET_INT --icmp-type 8 -j ACCEPT
##############################################################
# 7 - LIBERAR RESPOSTAS DE DNS
##############################################################
$IPT -A INPUT -i $IF_INT -p udp -s 0/0 --sport 53 -j ACCEPT
##############################################################
# 8 - LIBERAR NAVEGAÇÃO WEB
##############################################################
$IPT -A INPUT -i $IF_INT -p tcp --sport 80 -j ACCEPT
$IPT -A INPUT -i $IF_INT -p tcp --sport 443 -j ACCEPT
##############################################################

E assim terminamos nosso script! Podemos adicioná-lo na inicialização do sistema editando arquivo /etc/rc.local e adicionando o caminho absoluto para o script.

No próximo post vou colocar um script de firewall para redes corporativas. Até a próxima!!!