A configuração de VPNs PPTP site-to-site não é muito comum, nem “suportada nativamente” – algumas características específicas tornam a implementação mais indicada para VPNs client-to-gateway (também conhecidas como Road Warrior). Porém, há algum tempo atrás, precisei improvisar rapidamente uma solução de VPN “simples” para um laboratório de análises clínicas e, mesmo optando pelo protocolo PPTP, o resultado foi melhor do que esperávamos. Foi uma experiência interessante e resolvi compartilhar. A solução adotada atendeu perfeitamente a demanda de rede e mantivemos em produção até hoje.
Descreverei as razões e como tudo se desenrolou…
O projeto começou com dois firewalls Linux (Ubuntu): um na matriz e outro em uma filial.
Endereço LOCAL da Matriz: 10.67.50.0/24 (firewall 10.67.50.254)
Endereço LOCAL da Filial1: 10.67.51.0/24 (firewall 10.67.51.1)
Na primeira fase, optamos pela solução de VPN Tinc (criptografia SSL e compressão Zlib ou LZO). Além da configuração ser muito simples, oferece roteamento full mesh nativamente. Sempre que possível, tenho optado preferencialmente por esta solução para construção de VPNs site-to-site.
O Tinc é uma excelente solução! 😉
Pouco tempo depois, surgiram duas unidades que necessitavam conectar à matriz também. Neste caso, para reduzir os custos do projeto e ampliar a flexibilidade de hardware, foram instalados roteadores Mikrotik em cada uma. A equipe técnica do laboratório solicitou uma alternativa de VPN que fosse simples e eficiente.
Endereço LOCAL da Filial2: 10.67.52.0/24 (Mikrotik 10.67.52.1)
Endereço LOCAL da Filial3: 10.67.53.0/24 (Mikrotik 10.67.53.1)
Analisando as opções disponíveis no Mikrotik, constatamos que o Tinc não é suportado (a solução de VPN full mesh disponível é proprietária). Poderíamos optar pelo IPSec, PPTP ou OpenVPN. O PPTP, apesar de apresentar falhas de segurança conhecidas, se mostrava uma alternativa viável, “simples” e os IPs públicos envolvidos eram fixos, permitindo filtrar e autorizar apenas as unidades em questão. Sendo assim, optamos pelo PPTP com suporte MPPE (Microsoft Point-to-Point Encryption) e autenticação MS-CHAPv2. Porém, a implementação não foi tão simples como imaginávamos inicialmente.
A VPN da primeira filial permaneceu Tinc e as outras duas PPTP.
Enlaces na VPN (interfaces ppp): 10.50.1.0/24
Infelizmente, a complexidade aumentou um pouco. Adicionar regras de NAT, roteando pelo enlace, não seria o suficiente, pois alguns serviços dependiam de roteamento em ambos os sentidos. Algo que, teoricamente, poderia desqualificar a adoção de uma VPN PPTP.
O protocolo PPTP é simples, mas a implementação site-to-site impõe alguns dificuldades. A cada túnel estabelecido, por exemplo, é criada uma nova interface ppp (ppp0, ppp1 e assim por diante). Logo, a matriz precisa injetar uma rota específica por filial, mas isto não é previsto nativamente. A primeira dificuldade é prever a interface ppp por filial e injetar uma rota do segmento local (na interface correta).
Para resolver esta questão, na matriz, configurei um servidor PPTP reservando o endereço das interfaces ppp como 10.50.1.52 para a segunda filial e 10.50.1.53 para terceira.
root@fwsrv:~# cat /etc/ppp/chap-secrets
# Secrets for authentication using CHAP # client server secret IP addresses fltunel2 * s3nhavpn2 10.50.1.52 fltunel3 * s3nhavpn3 10.50.1.53
Desta maneira, foi possível contar com um identificador único (o endereço IP de enlace) para cada segmento de rede das filiais. Fixando o endereço IP das interfaces ppp, ficou simples trabalhar com a estrutura de scripts em /etc/ppp/ip-up.d e injetar as rotas corretamente – cada filial foi configurada com sua respectiva conta de usuário (fltunel2 e fltunel3).
Confiram, a seguir, o script utilizado para a adição de rotas (processado a cada instante que uma interface é criada):
root@fwsrv:~# vim /etc/ppp/ip-up.d/1rotas
#!/bin/bash ## VPN 1 ifvpn1=$(ip route get 10.50.1.52 | grep ppp | awk '/dev/ {print $3}') if [ -d /sys/class/net/$ifvpn1 ] && [ "$ifvpn1" == "$1" ]; then ip route del 10.67.52.0/24 2>/dev/null ip route add 10.67.52.0/24 dev $1 src 10.67.52.254 mtu 1390 exit fi ## VPN 2 ifvpn2=$(ip route get 10.50.1.53 | grep ppp | awk '/dev/ {print $3}') if [ -d /sys/class/net/$ifvpn2 ] && [ "$ifvpn2" == "$1" ]; then ip route del 10.67.53.0/24 2>/dev/null ip route add 10.67.53.0/24 dev $1 src 10.67.53.254 exit fi
No servidor PPTP, através do arquivo “/etc/ppp/ip-up.d/1rotas“, foi possível adicionar as rotas dinamicamente para o segmento de rede de cada filial. No primeiro exemplo, a opção “mtu 1390” foi utilizada porque o roteador da operadora não tratava a fragmentação corretamente e, por consequência, descartava determinados pacotes.
Nas duas unidades com Mikrotik configuramos o cliente PPTP, autenticando com a respectiva conta de usuário e adicionamos uma rota para a sub-rede 10.67.0.0/16 apontando para o endereço do firewall Linux. Esta etapa foi extremamente simples.
O primeiro problema foi resolvido. No entanto, em determinados momentos, é possível que instabilidades de Internet interrompam a VPN (perdendo o caminho de roteamento), sem que a sessão seja finalizada no servidor – sinceramente, não sei dizer se é um bug. Neste caso, como a alocação de IP foi definida estaticamente, é preciso encerrar o processo pppd que mantém a sessão ativa para permitir a reconexão.
root@fwsrv:~# vim /opt/chkvpn.sh
#!/bin/bash /sbin/ifconfig | grep ppp | while read lineaux; do nroute=0 ifppp=$(echo $lineaux | awk '{print $1}') nroute=$(/sbin/route -n | awk "/ $ifppp\$/ { print \$0;}" | /usr/bin/wc -l) croute=$(/sbin/route -n | grep "^10.50.1." | awk "/ $ifppp\$/ { print \$1;}" | cut -d"." -f4) if [ $nroute -lt 2 ] && [ $croute -lt 100 ]; then remote=$(last -10 $ifppp | head -1 | awk '{ print $3; }') pid=$(ps -ef | grep pppd | awk "/ $remote / {print \$2;}") /bin/kill -9 $pid fi done
O script anterior visa garantir que não existe um processo pppd ativo sem a respectiva rota na tabela de roteamento – caso aconteça, o cliente ficará impossibilitado de reconectar. A variável nroute foi utilizada para identificar o número de rotas associada a interface ppp em questão (são no mínimo duas, uma do enlace e outra do segmento de rede da filial) e croute para identificar o último octeto de cada endereço IP (ignorando a análise para endereços a partir de 10.50.1.100, pois convencionamos que o intervalo de reserva inicia a partir de 50 e termina em 99).
Para automatizar a verificação da sessão, podemos agendar a execução do script chkvpn.sh a cada 1 minuto:
root@fwsrv:~# vim /etc/cron.d/chkvpn
MAILTO="" */1 * * * * root nice /opt/chkvpn.sh >/dev/null
O meu objetivo foi demonstrar a grande flexibilidade de configuração existente em servidores Linux. Quase tudo é programável (risos). Acredito que o ideal, neste cenário de rede, seria configurar uma VPN OpenVPN. Decidimos manter a configuração demonstrada porque o resultado foi bastante satisfatório e se mostrou estável.
[…] exposto na publicação anterior, tenho optado preferencialmente pela solução Tinc para construção de VPNs site-to-site. Mas, […]