free web hit counter visitas desde 24 Abr 05
Como criar facilmente uma VPN com KAME IPSec (Kernel 2.6)
por Cristiano da Cunha Duarte (cunha17@gmail.com)
homepage em http://cunha17.cristianoduarte.pro.br
See this page in english
Página criada em:  04 Jan 2005
Última modificação em: 12 Nov 2005
A versão mais recente deste arquivo pode ser encontrada em http://cunha17.cristianoduarte.pro.br/ipsec

Você pode perguntar: "Olha, trabalho legal, mas eu não quero aprender o básico de IPSec e não quero entender o que vou fazer, apenas quero um IPSec bem simples e fácil entre duas máquinas Linux!" e eu te responderei "Pegue qualquer um dos exemplos do Apêndice A! Para segurança com criptografia pegue aqueles que contêm ESP... ;)"

Introdução


Este tutorial tem a finalidade de mostrar como é fácil criar uma VPN entre máquinas utilizando o padrão KAME IPSec presente no kernel 2.6 do Linux.
No item "Montando sua VPN passo a passo" será mostrado como montar uma VPN (modo túnel) entre gateways utilizando o KAME IPSec, o Racoon e um Segredo Compartilhado.
Este tutorial foi implementado em uma VPN entre uma máquina Linux Debian "testing" (sarge) e uma máquina FreeBSD com firewall Aker 5.0 (o procedimento é praticamente o mesmo para uma outra máquina com Fedora Core, Debian, etc.)
Testes foram feitos com sucesso entre duas máquinas rodando Fedora Core 2. Nesses testes, foram criados canais em modo túnel e transporte, no entanto não foram feitos testes com o IKE (racoon), as chaves utilizadas eram fixas. Os scripts de criação dos canais se encontram no Apêndice A.

Finalidade

O IPSec pode trabalhar em dois modos:

Modo Túnel: a principal finalidade é criar uma comunicação segura entre redes remotas utilizando um meio não confiável. Um exemplo:
Network1 comm1
Gateway1
tunnel1connection1tunnel1
tunnel2connection2tunnel2
Internet
tunnel1connection1tunnel1
tunnel2connection2tunnel2
Gateway2 comm2
Network2
Rede1
Gw1
Canais IPSec
Internet
Canais IPSec
Gw2
Rede2
IPSec em modo túnel entre os gateways Gw1 e Gw2

Modo Transporte: a principal finalidade é criar uma comunicação segura fim-a-fim, ou seja, entre uma máquina e outra, utilizando um meio não confiável. Um exemplo:
Computador Remoto
tunnel1connection1tunnel1
tunnel2connection2tunnel2
Conexão Dial-up
tunnel1connection1tunnel1
tunnel2connection2tunnel2
Internet tunnel1connection1tunnel1
tunnel2connection2tunnel2
Servidor
Cliente
Canais IPSec Dial-up
Canais IPSec Internet
Canais IPSec Servidor
IPSec em modo transporte entre as máquinas Cliente e Servidor

OBS: Normalmente VPN's são montadas em modo túnel.


Montando sua VPN passo a passo

Serão mostrados os passos necessários para se estabelecer uma VPN em modo túnel entre a Rede1(10.67.112.0) e a Rede2(10.0.0.0) utilizando o daemon IKE racoon. Os gateways serão conectados via internet, onde o endereço IP do Gateway1 é 100.100.100.100 e do Gateway2 é 200.200.200.200.

Passo 1: Instalação dos pacotes


# apt-get install ntpdate ntp-server

# apt-get install ipsec-tools racoon iproute iptables kernel-image-2.6
OBS1: durante a instalação do racoon, informe que você não deseja utilizar o racoon-tool, e sim uma configuração manual do racoon.
OBS2: se o kernel instalado anteriormente não for 2.6, é necessário reiniciar o computador com o kernel 2.6 antes de prosseguir.

# apt-get install dnsutils lynx tcpdump

Passo 2: Configuração das políticas
O IPSec é composto por duas bases de dados distintas:
    As políticas dizem ao IPSec quando este deve ou não atuar sobre um pacote IP.
Palavra chave: QUANDO
    Uma Política de Segurança(SP) constitui-se, basicamente dos seguintes aspectos:
OBS: se uma SA não estiver disponível, o kernel solicita o estabelecimento de uma SA ao daemon IKE (racoon)
    As associações dizem ao IPSec como este deve criar um canal entre duas máquinas.
Palavra chave: COMO
    Uma Associação de Segurança(SA) constitui-se, basicamente, dos seguintes aspectos:

ATENÇÃO:  uma SA só é utilizada se estiver "associada" a uma política, ou seja, somente se existir uma política cuja regra tenha os mesmos parâmetros da SA.

NOTA: Pode existir SP funcional sem SA de duas formas:
  • Quando a SP é do tipo none ou discard, onde não existe SA a ser utilizada já que o IPSec não será aplicado
  • Quando a SA é criada dinamicamente pelo daemon IKE(racoon)
Em qualquer outra hipótese, uma SP sem uma SA faz com que o pacote fique enfileirado até ser descartado.

Para configurar a SPD e/ou a SAD, utilizamos um aplicativo chamado setkey. Este aplicativo pode ser chamado como se fosse um "script processor"(como o bash). Exemplo:

#!/sbin/setkey -f
flush ah;
flush esp;
spdflush;

O código acima pode ser gravado em um arquivo chamado ipsec-off, com atributos rwx para o root. Ao se executar ./ipsec-off, serão removidas todas as regras existentes na SAD(tanto AH quanto ESP) e na SPD.
Como vamos utilizar o racoon para criar nossas entradas na SAD, basta que criemos as nossas políticas na SPD. Portanto o arquivo ipsec-on ficará assim:

#!/sbin/setkey -f
flush;
spdflush;

#REDE1 para REDE2
spdadd 10.67.112.0/22[any] 10.0.0.0/8[any] any -P in ipsec esp/tunnel/100.100.100.100-200.200.200.200/require;
#REDE2 para REDE1
spdadd 10.0.0.0/8[any] 10.67.112.0/22[any] any -P out ipsec esp/tunnel/200.200.200.200-100.100.100.100/require;

OBS: "flush;" tem o mesmo efeito de "flush ah;" seguido de "flush esp;"

Passo 3: Configuração do Racoon
Antes de configurarmos o racoon, precisamos modificar o script de carregamento do racoon. Edite o arquivo /etc/init.d/racoon e altere a seguinte linha:
start-stop-daemon --start --quiet --exec /usr/sbin/racoon
para:
start-stop-daemon --start --quiet --exec /usr/sbin/racoon -- -l /var/log/racoon.log
Com isso, colocamos qualquer informação de log no arquivo /var/log/racoon.log.

Agora, o racoon será configurado para utilizar um segredo compartilhado para a autenticação inicial entre os gateways. Eis o arquivo /etc/racoon/racoon.conf:

path pre_shared_key "/etc/racoon/psk.txt";
log debug2;

listen {
        isakmp 200.200.200.200 [500];
        strict_address;
}

remote 100.100.100.100 {
        exchange_mode main;
        send_cr off;
        send_cert off;
        proposal {
                encryption_algorithm blowfish;
                hash_algorithm sha1;
                authentication_method pre_shared_key;
                dh_group 2;
                lifetime time 300 seconds;
        }
}

A linha 1 diz a localização do arquivo onde se encontra o segredo compartilhado. Este arquivo é composto de duas colunas separadas por espaço/tabulação, onde a primeira coluna é o endereço IP do gateway e a segunda o segredo compartilhado desse gateway.  Então o arquivo /etc/racoon/psk.txt ficará assim:

200.200.200.200    1234567890

100.100.100.100    1234567890
 
A linha 2 configura o log do racoon para debug2(depois pode ser colocado em outro nível, como por exemplo notify) onde o daemon gera toneladas de informações de log.

A cláusula listen, informa ao racoon em que IP e porta ele deve esperar requisições IKE. Neste exemplo o endereço utilizado foi 200.200.200.200 e a porta 500/udp, que é a porta padrão IPSec para IKE. A entrada strict_address força o racoon a abortar se não conseguir escutar neste IP e porta.

Agora a cláusula remote. Ela começa com o IP do gateway remoto e contém diversas diretivas:

Passo 4: Configuração das regras no firewall
O IPSec em modo túnel utiliza o protocolo número 50 (ESP) para encriptar os dados do pacote IP.
Atenção: é protocolo 50 e não porta 50 !!!
O Racoon utiliza a porta 500/udp para troca de chaves (IKE) entre os gateways.

Basta acrescentar estas linhas no seu arquivo de regras do iptables:

#configura parâmetros do kernel
echo 1 > /proc/sys/net/ipv4/ip_forwad
echo 0 > /proc/sys/net/ipv4/ip_dynaddr
echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
echo 0 > /proc/sys/net/ipv4/conf/all/accept_source_route
echo 1 > /proc/sys/net/ipv4/conf/all/accept_redirects
echo 0 > /proc/sys/net/ipv4/conf/all/log_martians
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_all
echo 0 > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses
#aceitar pacotes ESP
iptables -I INPUT 1 -j ACCEPT -p 50

iptables -I OUTPUT 1 -j ACCEPT -p 50
iptables -I FORWARD 1 -j ACCEPT -p 50
#aceitar pacotes IKE
iptables -I INPUT 1 -j ACCEPT -p udp --dport 500
iptables -I OUTPUT 1 -j ACCEPT -p udp --dport 500
iptables -I FORWARD 1 -j ACCEPT -p udp --dport 500
#aceitar pacotes ICMP
iptables -I INPUT 1 -j ACCEPT -p icmp
iptables -I OUTPUT 1 -j ACCEPT -p icmp
iptables -I FORWARD 1 -j ACCEPT -p icmp

ATENÇÃO: se você quiser criar regras mais restritivas(e você deve), basta adicionar o endereço de origem e destino nas regras acima. Não se esqueça que os endereços de origem e destino são os endereços de Internet(ou da rede não confiável) dos gateways.

CUIDADO: o parâmetro do kernel /proc/sys/net/ipv4/conf/all/rp_filter verifica por IP spoofing e, como foi desativado, a verificação deverá ser feita via regras do próprio IPTABLES! Porém estas regras deverão aparecer depois das regras que liberam a VPN.

NOTA IMPORTANTE 1: O cabeçalho IP de um pacote ESP não pode ser modificado pelo NAT, portanto, não se pode fazer NAT de um canal IPSec(pelo menos diretamente, para isso existe o NATT) e por conseguinte, não pode haver NAT entre os Gateways. Se você usa NAT em seu firewall adicione as seguintes regras antes de qualquer outra para que não seja feito NAT de pacotes da sua VPN:
#Não fazemos NAT para ESP
iptables -t nat -I PREROUTING 1 -j ACCEPT -p 50

iptables -t nat -I POSTROUTING 1 -j ACCEPT -p 50

NOTA IMPORTANTE 2: Não existe NAT entre as redes conectadas pelo túnel se estas podem ser roteáveis internamente. Não é necessário que os endereços internos sejam válidos, nem que se crie regras de roteamento estáticas: o IPSec se encarrega de rotear os pacotes para o gateway remoto toda vez que o endereço de destino fizer parte da rede remota. Ex:
Network1 comm1
Gateway1
tunnel1connection1tunnel1
tunnel2connection2tunnel2
Internet
tunnel1connection1tunnel1
tunnel2connection2tunnel2
Gateway2 comm2
Network2
Rede 10.1.0.0
G1
INTERNET
G2
Rede 10.0.0.0
Se um pacote for enviado pela "Rede 10.1.0.0" para a rede "10.0.0.0", o gateway "G1" enviará este pacote para o gateway "G2". Como o gateway "G2" possui a rede "10.0.0.0" DIRETAMENTE conectada a ele(por uma de suas interfaces de rede), este roteia o pacote para essa rede. Caso a rede não seja diretamente conectada, é necessário a criação de uma regra de roteamento.

Passo 5:  Carregar a VPN
Executar seu script de carregamento de regras do iptables (acrescido das regras do passo 4).
Executar o script ipsec-on.
Executar o racoon (/etc/init.d/racoon restart).

A VPN ainda não está estabelecida, precisamos que um pacote passe pelo firewall para que a SA seja estabelecida pelo racoon. Portanto é o momento de executar:
# ping 100.100.100.100
ou
# ping 200.200.200.200
conforme o caso.
A primeira resposta pode demorar vários segundos, já que antes o racoon precisa estabelecer o túnel.

Passo 6:  Testar a VPN
Se o ping funcionar, é hora de testar uma pagina web. Portanto execute o aplicativo lynx seguindo de um endereço de uma página na rede remota.
Se a página abrir, e for possível navegar nos links, é hora de testarmos em modo gráfico com o bom e velho Mozilla. Se você conseguir abrir as páginas do site remoto no Mozilla, com texto e figuras, sua VPN está funcionando! Parabéns !
No entanto se ocorrer qualquer tipo de problema, verifique o arquivo de log do racoon(/var/log/racoon.log), o arquivo de log do kernel(/var/log/kern.log) e consulte a seção Solução de Problemas.

OBS: Este tutorial pressupõe um Firewall Aker configurado corretamente e da mesma maneira. Se quiser utilizar um sistema Linux com kernel 2.6 como Gateway2, basta executar os mesmos passos acima nesta segunda máquina, apenas invertendo in para out e vice-versa no passo 2 e o endereço remoto no passo 3.


Solução de Problemas
  1. Consigo apenas "pingar" o outro gateway
    1. Se você consegue pingar o endereço internet do gateway remoto, mas não consegue pingar o endereço de rede local desse gateway, provavelmente:
      1. Não foi estabelecida a VPN
Verifique o log do racoon em /var/log/racoon.log e procure por problemas. Se o Firewall remoto não for configurado para deixar passar pacotes ESP e IKE, a VPN não será estabelecida.
      1. O gateway remoto possui um Firewall bloqueando seus "pings"
No gateway remoto: verifique o log do firewall e rode o TCPDUMP para ver se o pacote ICMP ECHO REQUEST chega e se o pacote ICMP ECHO REPLY sai.
    1. Se você consegue pingar o endereço de rede local do Gateway remoto mas não consegue pingar outras máquinas na rede remota, provavelmente:
      1. O gateway remoto não está fazendo forwarding dos pacotes recebidos.
Execute o comando: cat /proc/sys/net/ipv4/ip_forwad e veja se o resultado é "1". Caso contrário execute:
echo 1 > /proc/sys/net/ipv4/ip_forwad
      1. O gateway remoto possui um Firewall bloqueando seus "pings"
No gateway remoto: verifique o log do firewall e rode o TCPDUMP para ver se o pacote ICMP ECHO REQUEST chega e se o pacote ICMP ECHO REPLY sai.
  1. Consigo apenas "pingar" máquinas na outra rede
  2. Abro apenas a página frame, não consigo abrir figuras nem outras páginas
  3. Abro apenas páginas pequenas
  4. Pacotes pequenos passam, mas pacotes maiores não.
Antes de prosseguir verifique se o gateway remoto possui um Firewall bloqueando seus pacotes. Verifique o log do firewall e rode o TCPDUMP para ver se o pacote ICMP ECHO REQUEST chega e se o pacote ICMP ECHO REPLY sai.

Estes são sintomas do mesmo problema: MSS(ou Maximum Segment Size).

O MSS normalmente é calculado com base no MTU(Maximum Transfer Unit). O MTU é configurado em cada placa de rede ou dispositivo de rede e possui, para redes Ethernet, o valor padrão de 1500. Esse valor é o tamanho máximo de bytes que o procotolo de camada física, ou Interface de Rede(na arquitetura TCP/IP), pode enviar no meio físico de cada vez. Portanto, se desejarmos enviar mais do que isso, devemos fragmentar os dados em blocos de 1500 bytes antes de enviarmos para o protocolo Ethernet.


Aplicação
Mensagem


Transporte
Segmento


Inter-rede
Datagrama


Placa de rede
Quadro


Intra-rede
Arquitetura do TCP/IP

No entanto, acima da camada Placa de rede(Ethernet) possuimos a camada Inter-rede(IP), que adiciona, no mínimo, 20 bytes de cabeçalho antes de enviá-los para o protocolo da Placa de rede. Ainda, acima da camada Inter-rede, possuímos a camada de transporte(TCP ou UDP) que adiciona, no mínimo, 20 bytes de cabeçalho para o TCP.

Com isso, o tamanho real de dados que podem ser enviados será o MTU menos todos os bytes utilizados como cabeçalho nas camadas superiores até chegar no TCP. Esse valor final é o MSS(ou Maximum Segment Size).

Mas, além disso, o MSS deve ser o mesmo entre os dois lados da conexão e, por isso, negociado entre estes antes do estabelecimento da conexão. Cada um sabe seu MTU, com isso calcula seu MSS e o envia para a outra ponta durante o estabelecimento da conexão. O menor MSS será o escolhido, para evitar fragmentações nas pontas da conexão. Mas, mesmo assim, se houver outros equipamentos de rede intermediários que possuam MTU menor, esses causarão fragmentações no meio do caminho. Como fazer para evitar essas fragmentações? A resposta é o "Path MTU Discovery".

O Path MTU Discovery envia um pacote de tamanho máximo para o segmento (1500 bytes se Ethernet) ou de tamanho igual ao MSS informado no estabelecimento da conexão, marcado para não ser fragmentado, e aguarda que algum host no trajeto responda dizendo que não consegue enviar o pacote sem realizar fragmentação. Este aviso é uma mensagem de erro ICMP "Can't Fragment" de tipo 3 (destino inalcançável) e código 4(fragmentação necessária, mas bit de não-fragmentação ativado). Normalmente, essa mensagem ICMP carrega, também, o MTU que causou o erro. Com isso, o Path MTU Discovery envia um novo pacote de tamanho igual ao MTU recebido na mensagem ICMP. Esse processo se repete até que o pacote atinja o host de destino e o Path MTU Discovery receba um pacote-resposta desse host.

Por isso, não é inteligente desabilitar todos os ICMP no seu firewall, como a maioria dos administradores de rede o fazem. Nunca deixe de receber pacotes do tipo 3(destino inalcançável) nem do tipo 5(redirecionamento). Caso contrário, você pode acabar com o problema relatado no item 6.

No entanto, o Path MTU Discovery calcula o MSS sobre os cabeçalhos IP e TCP somente. Como estamos acrescentando uma camada adicional IPSec, devemos diminuir o tamanho do cabeçalho IPSec do valor do MSS. Isso deve ser feito manualmente e é por isso que o Path MTU Discovery não funciona sobre IPSec.

Pacotes menores que o menor MSS do canal não gerarão este erro e, por isso, vão funcionar. Como é o caso do "ping" e páginas web pequenas.

A solução desse problema para o Path MTU Discovery é habilitar a recepção de pacotes ICMP tipo 3 e código 4, no mínimo. Mas isso não resolve o problema para IPSec já que o Path MTU Discovery desconhece essa camada adicional. Portanto, a solução é forçar um MSS manual quando for tentado o estabelecimento de qualquer conexão entre as pontas do canal IPSec. Para isso, basta chamar o seguinte código(com as modificações em GATEWAY_REMOTO e REDE_REMOTA para a sua rede) a partir do script que carrega as regras do seu firewall:
#!/bin/bash

#Força um MSS fixo para remediar o problema do Path MTU Discovery
#ATENÇÃO:
# 1.Você deve permitir troca de pacotes ICMP do tipo echo-request e echo-reply entre os gateways LOCAL e REMOTO
# 2.Você deve permitir pacotes ICMP do tipo redirect e destination-unreachable vindos da INTERNET
# 3.Você vai precisar dos pacotes BC e IPROUTE instalados

#definição do gateway remoto e da rede remota
GATEWAY_REMOTO=200.200.200.200
REDE_REMOTA=172.16.0.0/24

#opcao de DEBUG: coloque como 1 para ativar mensagens
DEBUG=0

function compute_mss() {
#calcula o MSS para IPSec baseado no MTU fornecido como parâmetro
#retorna o valor calculado na variável MSS

local MTU
local IP_HEADER_LENGTH
local ESP_HEADER_LENGTH
local AH_HEADER_LENGTH
local IPSEC_HEADER_LENGTH
local ENCRYPTION_HEADER_LENGTH
local SUBTOTAL_DATA_LENGTH
local DISCARDED_DATA_LENGTH
local DATA_LENGTH

MTU=$1

#tamanho médio do header IP(20<->60)
IP_HEADER_LENGTH=40

#tamanho do header ESP

ESP_HEADER_LENGTH=8

#tamanho do header AH

AH_HEADER_LENGTH=12

#tamanho do header IPSec = ESP + AH
IPSEC_HEADER_LENGTH=`echo "$ESP_HEADER_LENGTH + $AH_HEADER_LENGTH" | bc`

#tamanho do header do algoritmo de encriptação
ENCRYPTION_HEADER_LENGTH=16 #CBC initial value

#cálculo do tamanho final = MSS
SUBTOTAL_DATA_LENGTH=`echo "$MTU - $IP_HEADER_LENGTH - $IPSEC_HEADER_LENGTH - $ENCRYPTION_HEADER_LENGTH" | bc`
DISCARDED_DATA_LENGTH=`echo "$SUBTOTAL_DATA_LENGTH % 16" | bc`
DATA_LENGTH=`echo "$SUBTOTAL_DATA_LENGTH - $DISCARDED_DATA_LENGTH" | bc`
MSS=$DATA_LENGTH
}
function pmtu_discovery()
{
#Efetua um PMTU discovery através de pacotes ICMP entre os gateways LOCAL e REMOTO.
#Na verdade, utiliza um algoritmo de pesquisa binária para calcular o tamanho máximo do PAYLOAD de um pacote ICMP no canal
#e, através dessa informação, calcula o PMTU
local MIN
local MAX
local MTU
local TARGET
local OK
local MEDIA
local IP_HEADER_LENGTH
local ICMP_PAYLOAD_MAX

#tamanho MÍNIMO do cabeçalho IP (20<->60 bytes)
IP_HEADER_LENGTH=20

#tamanho do cabeçalho ICMP (echo-request/echo-reply)

ICMP_HEADER_LENGTH=8

#declaracao de uma funcao em BC para retornar o valor absoluto de um número, ou seja, o valor sem sinal
LOADABS="
define abs(x) {
if (x>=0) return(x)
return(-x)
}
"
#host de destino (firewall -> interface internet)
TARGET=$1

#valor mínimo para o PAYLOAD ICMP
MIN=400
#obtem o valor do MTU da interface que será utilizada na comunicação entre os gateways
MTU=`ip route get $TARGET | xargs | sed "s/.*mtu \([[:digit:]]\+\) .*/\1/"`
#valor máximo para o PAYLOAD ICMP => MTU - IP HEADER - ICMP HEADER
MAX=`echo "$MTU-$IP_HEADER_LENGTH-$ICMP_HEADER_LENGTH" | bc`

#Path MTU Discovery através de pesquisa binaria
while [ `echo "$LOADABS abs($MIN - $MAX)" | bc` -gt 1 ]; do
#Calculamos a média entre MIN e MAX
MEDIA=`echo "scale=0;($MIN + $MAX) / 2" | bc`
if [ $DEBUG -eq 1 ]; then
echo -n "MEDIA=$MEDIA "
fi

#Enviamos o pacote ICMP:
# -s $MEDIA : com o PAYLOAD de tamanho $MEDIA
# -q : Quiet
# -M do : Com a flag DF(Don't Fragment) setada
# -W 2 : Aguardamos até 2 segundos pela resposta
# -c 1 : apenas 1 pacote
# $TARGET : para o host $TARGET
#e redirecionamos a saída para /dev/null, porque precisamos apenas do código de saída(Exit Code ou $?)
ping -s $MEDIA -q -M do -W 2 -c 1 $TARGET 1>/dev/null 2>/dev/null
OK=$?
if [ $OK == 0 ]; then
#Funcionou! Portanto, o mínimo passa a ser a média, ou seja, MIN=MEDIA
if [ $DEBUG -eq 1 ]; then
echo "[OK]"
fi
MIN=$MEDIA
else
#Não funcionou... portanto, o máximo passa a ser a média menos 1, ou seja, MAX=MEDIA-1
if [ $DEBUG -eq 1 ]; then
echo "[NOK]"
fi
MAX=`echo "$MEDIA-1" | bc`
fi
#enviamos um pacote ICMP a cada 0.5 segundos para tentar não despertar nenhum IDS ou FIREWALL
sleep 0.5
done
#o valor de $MIN será o máximo PAYLOAD do pacote ICMP que conseguiu trafegar do gateway LOCAL para o REMOTO e vice-versa
ICMP_PAYLOAD_MAX=$MIN
#agora calculamos o PMTU => PAYLOAD + ICMP HEADER + IP HEADER
PMTU=`echo "$ICMP_PAYLOAD_MAX+$ICMP_HEADER_LENGTH+$IP_HEADER_LENGTH" | bc`
}

#inicialização das variáveis

MSS=-1
PMTU=-1

#efetua o PMTU discovery até o gateway remoto. PMTU conterá o valor final.
pmtu_discovery $GATEWAY_REMOTO
#calcula o MSS baseado no PMTU retornado. MSS conterá o valor final.
compute_mss $PMTU

#incluímos as seguintes regras no IPTABLES para forçar o MSS em qualquer estabelecimento de conexões com a rede remota
iptables -I FORWARD 1 -p tcp -d $REDE_REMOTA --tcp-flags SYN,RST SYN -j TCPMSS --set-mss $MSS
iptables -I FORWARD 2 -p tcp -s $REDE_REMOTA --tcp-flags SYN,RST SYN -j TCPMSS --set-mss $MSS
iptables -I OUTPUT 1 -p tcp -d $REDE_REMOTA --tcp-flags SYN,RST SYN -j TCPMSS --set-mss $MSS
iptables -I OUTPUT 2 -p tcp -s $REDE_REMOTA --tcp-flags SYN,RST SYN -j TCPMSS --set-mss $MSS
if [ $DEBUG -eq 1 ]; then
echo "PMTU=$PMTU"
echo "MSS=$MSS"
fi
exit 0
  1. Sem mais nem menos, os gateways começam a fazer "flooding" de pacotes entre si
Na verdade, este problema é, também, devido ao Path MTU Discovery e, portanto, relacionado aos itens 2 a 5.
Esse sintoma aparece quando um host tenta enviar um pacote de tamanho máximo para o segmento. Este pacote, em algum ponto intermediário, ou até no gateway destino, é descartado por ser grande demais. Quem descartou o pacote envia uma resposta ICMP Can't Fragment de retorno. O problema é que essa resposta nunca chega devido a regras de firewall que impedem que a mesma alcance a maquina de destino. Leia com atenção o tópico anterior que fala sobre a ignorância de alguns administradores de rede em relação aos pacotes ICMP.

O que acontece quando uma mensagem resposta ICMP "Can't Fragment" é descartada? O Path MTU Discovery roda sobre o TCP e, portanto, aguardará pelo "timeout" e repetirá o envio do mesmo segmento. Esse processo poderá se repetir indefinidamente.

Para resolver esse problema, force um MSS como mostrado no tópico anterior.

  1. Consigo abrir páginas entre as duas redes conectadas, mas não de redes conectadas a essas
Outro problema relacionado ao Path MTU Discovery, só que agora, não tem nada a ver com a sua configuração. O problema é que, provavalmente, a rede conectada que está tentando ser acessada tem regras de firewall bloqueando qualquer tipo de pacote ICMP e, portanto, impedindo o tráfego de segmentos TCP. Os sintomas descritos acima também ocorrerão, porém entre sua rede e a rede remota, não se manifestando diretamente sobre o canal VPN.

Para resolver esse problema, utilize a solução dos itens 2 a 5.

Apêndice A
VPN no Fedora Core 2 com SA fixas (sem IKE)
Este apêndice disponibilizará alguns arquivos "script" para se criar todas as possibilidades de canais IPSec sem o uso do IKE. Esses scripts foram utilizados como forma de "prova de conceito" para o padrão IPSec entre máquinas Fedora Core 2.
Esses scripts podem ser executados em quaisquer duas máquinas que estejam em um mesmo domínio de colisão ethernet(mesma rede física sem VLAN's) sem a necessidade de se interromper o uso normal desses equipamentos. Para isso é criado um endereço IP adicional em cada placa de rede para que estas possam estabelecer os canais IPSec.
A máquina1 possuirá o seguinte endereço IP: 10.0.0.216
    configurado através do seguinte comando:
     # ifconfig eth0:1 10.0.0.216 netmask 255.255.255.0 broadcast 10.0.0.255
A máquina2 possuirá o seguinte endereço IP: 10.0.0.11
    configurado através do seguinte comando:
     # ifconfig eth0:1 10.0.0.11 netmask 255.255.255.0 broadcast 10.0.0.255

As seguintes combinações foram implementadas:


Modo
máquina1 (10.0.0.216) máquina2 (10.0.0.11):
AH/transport ipsec-transport-on-ah-216
#!/sbin/setkey -f
flush;
spdflush;

#AH
add 10.0.0.11 10.0.0.216 ah 15700 -A hmac-sha1 "12345678901234567890";
add 10.0.0.216 10.0.0.11 ah 24500 -A hmac-sha1 "12345678901234567890";

spdadd 10.0.0.216 10.0.0.11 any -P out ipsec
  ah/transport//require;
spdadd 10.0.0.11 10.0.0.216 any -P in ipsec
  ah/transport//require;

ipsec-transport-on-ah-11
#!/sbin/setkey -f
flush ah;
flush esp;
spdflush;

#AH
add 10.0.0.11 10.0.0.216 ah 15700 -A hmac-sha1 "12345678901234567890";
add 10.0.0.216 10.0.0.11 ah 24500 -A hmac-sha1 "12345678901234567890";

spdadd 10.0.0.216 10.0.0.11 any -P in ipsec
  ah/transport//require;
spdadd 10.0.0.11 10.0.0.216 any -P out ipsec
  ah/transport//require;

ESP/transport ipsec-transport-on-esp-216
#!/sbin/setkey -f
flush ah;
flush esp;
spdflush;

#ESP
add 10.0.0.11 10.0.0.216 esp 15701 -E rijndael-cbc "123456789012123456789012";
add 10.0.0.216 10.0.0.11 esp 24501 -E rijndael-cbc "123456789012123456789012";

spdadd 10.0.0.216 10.0.0.11 any -P out ipsec
  esp/transport//require;
spdadd 10.0.0.11 10.0.0.216 any -P in ipsec
  esp/transport//require;

ipsec-transport-on-esp-11
#!/sbin/setkey -f
flush ah;
flush esp;
spdflush;

#ESP
add 10.0.0.11 10.0.0.216 esp 15701 -E rijndael-cbc "123456789012123456789012";
add 10.0.0.216 10.0.0.11 esp 24501 -E rijndael-cbc "123456789012123456789012";

spdadd 10.0.0.216 10.0.0.11 any -P in ipsec
  esp/transport//require;
spdadd 10.0.0.11 10.0.0.216 any -P out ipsec
  esp/transport//require;

AH/ESP/transport ipsec-transport-on-ah-esp-216
#!/sbin/setkey -f
flush ah;
flush esp;
spdflush;

#AH
add 10.0.0.11 10.0.0.216 ah 15700 -A hmac-sha1 "12345678901234567890";
add 10.0.0.216 10.0.0.11 ah 24500 -A hmac-sha1 "12345678901234567890";

#ESP
add 10.0.0.11 10.0.0.216 esp 15701 -E rijndael-cbc "123456789012123456789012";
add 10.0.0.216 10.0.0.11 esp 24501 -E rijndael-cbc "123456789012123456789012";

spdadd 10.0.0.216 10.0.0.11 any -P out ipsec
  esp/transport//require
  ah/transport//require;
spdadd 10.0.0.11 10.0.0.216 any -P in ipsec
  esp/transport//require
  ah/transport//require;

ipsec-transport-on-ah-esp-11
#!/sbin/setkey -f
flush ah;
flush esp;
spdflush;

#AH
add 10.0.0.11 10.0.0.216 ah 15700 -A hmac-sha1 "12345678901234567890";
add 10.0.0.216 10.0.0.11 ah 24500 -A hmac-sha1 "12345678901234567890";

#ESP
add 10.0.0.11 10.0.0.216 esp 15701 -E rijndael-cbc "123456789012123456789012";
add 10.0.0.216 10.0.0.11 esp 24501 -E rijndael-cbc "123456789012123456789012";

spdadd 10.0.0.216 10.0.0.11 any -P in ipsec
  esp/transport//require
  ah/transport//require;
spdadd 10.0.0.11 10.0.0.216 any -P out ipsec
  esp/transport//require
  ah/transport//require;

ESP/tunnel ipsec-tunnel-on-esp-216
#!/sbin/setkey -f
flush ah;
flush esp;
spdflush;

#ESP
add 10.0.0.11 10.0.0.216 esp 15701 -m tunnel -E rijndael-cbc "123456789012123456789012";
add 10.0.0.216 10.0.0.11 esp 24501 -m tunnel -E rijndael-cbc "123456789012123456789012";

spdadd 10.0.0.216 0.0.0.0/0 any -P out ipsec
  esp/tunnel/10.0.0.216-10.0.0.11/require;
spdadd 0.0.0.0/0 10.0.0.216 any -P in ipsec
  esp/tunnel/10.0.0.11-10.0.0.216/require;

ipsec-tunnel-on-esp-11
#!/sbin/setkey -f
flush ah;
flush esp;
spdflush;

#ESP
add 10.0.0.11 10.0.0.216 esp 15701 -m tunnel -E rijndael-cbc "123456789012123456789012";
add 10.0.0.216 10.0.0.11 esp 24501 -m tunnel -E rijndael-cbc "123456789012123456789012";

spdadd 10.0.0.216 0.0.0.0/0 any -P in ipsec
  esp/tunnel/10.0.0.216-10.0.0.11/require;
spdadd 0.0.0.0/0 10.0.0.216 any -P out ipsec
  esp/tunnel/10.0.0.11-10.0.0.216/require;


ESP+Auth/tunnel ipsec-tunnel-on-esp-auth-216
#!/sbin/setkey -f
flush ah;
flush esp;
spdflush;

#ESP+AUTH
add 10.0.0.11 10.0.0.216 esp 15701 -m tunnel -E rijndael-cbc "123456789012123456789012" -A hmac-sha1 "12345678901234567890";
add 10.0.0.216 10.0.0.11 esp 24501 -m tunnel -E rijndael-cbc "123456789012123456789012" -A hmac-sha1 "12345678901234567890";

spdadd 10.0.0.216 0.0.0.0/0 any -P out ipsec
  esp/tunnel/10.0.0.216-10.0.0.11/require;
spdadd 0.0.0.0/0 10.0.0.216 any -P in ipsec
  esp/tunnel/10.0.0.11-10.0.0.216/require;

ipsec-tunnel-on-esp-auth-11
#!/sbin/setkey -f
flush ah;
flush esp;
spdflush;

#ESP+AUTH
add 10.0.0.11 10.0.0.216 esp 15701 -m tunnel -E rijndael-cbc "123456789012123456789012" -A hmac-sha1 "12345678901234567890";
add 10.0.0.216 10.0.0.11 esp 24501 -m tunnel -E rijndael-cbc "123456789012123456789012" -A hmac-sha1 "12345678901234567890";

spdadd 10.0.0.216 0.0.0.0/0 any -P in ipsec
  esp/tunnel/10.0.0.216-10.0.0.11/require;
spdadd 0.0.0.0/0 10.0.0.216 any -P out ipsec
  esp/tunnel/10.0.0.11-10.0.0.216/require;


AH/ESP/tunnel ipsec-tunnel-on-ah-esp-216
#!/sbin/setkey -f
flush ah;
flush esp;
spdflush;

#AH
add 10.0.0.11 10.0.0.216 ah 15700 -m tunnel -A hmac-sha1 "12345678901234567890";
add 10.0.0.216 10.0.0.11 ah 24500 -m tunnel -A hmac-sha1 "12345678901234567890";

#ESP
add 10.0.0.11 10.0.0.216 esp 15701 -m tunnel -E rijndael-cbc "123456789012123456789012";
add 10.0.0.216 10.0.0.11 esp 24501 -m tunnel -E rijndael-cbc "123456789012123456789012";

spdadd 10.0.0.216 0.0.0.0/0 any -P out ipsec
  esp/tunnel/10.0.0.216-10.0.0.11/require
  ah/tunnel/10.0.0.216-10.0.0.11/require;
spdadd 0.0.0.0/0 10.0.0.216 any -P in ipsec
  esp/tunnel/10.0.0.11-10.0.0.216/require
  ah/tunnel/10.0.0.11-10.0.0.216/require;

ipsec-tunnel-on-ah-esp-11
#!/sbin/setkey -f
flush ah;
flush esp;
spdflush;

#AH
add 10.0.0.11 10.0.0.216 ah 15700 -m tunnel -A hmac-sha1 "12345678901234567890";
add 10.0.0.216 10.0.0.11 ah 24500 -m tunnel -A hmac-sha1 "12345678901234567890";

#ESP
add 10.0.0.11 10.0.0.216 esp 15701 -m tunnel -E rijndael-cbc "123456789012123456789012";
add 10.0.0.216 10.0.0.11 esp 24501 -m tunnel -E rijndael-cbc "123456789012123456789012";

spdadd 10.0.0.216 0.0.0.0/0 any -P in ipsec
  esp/tunnel/10.0.0.216-10.0.0.11/require
  ah/tunnel/10.0.0.216-10.0.0.11/require;
spdadd 0.0.0.0/0 10.0.0.216 any -P out ipsec
  esp/tunnel/10.0.0.11-10.0.0.216/require
  ah/tunnel/10.0.0.11-10.0.0.216/require;



IMPORTANTE: A execução dos scripts deve ser feita de maneira relacionada, ou seja, a execução de um script que cria um canal ESP/tunnel na máquina1 deve ser correspondida com um script que crie um canal ESP/tunnel na máquina2.

Cristiano da Cunha Duarte é formado em Ciência da Computação pela PUC/MG, especializado em Projeto e Aplicação de Redes de Comunicação pela UnB e trabalha com programação em C, C++, PHP5, Java, CORBA e Servidores Linux. Mais informações visite: http://cunha17.cristianoduarte.pro.br/.


Search Engine Optimization and Free Submission