Roteamento Transparente

Um vacilo no TLS <= 1.2 compromete a sua privacidade, mas também pode facilitar a sua vida.

Cenário

Suponhamos que você disponha de variados pontos de saída rumo à internet. Por exemplo, você pode dispor de uma via através da universidade para acesso a periódicos científicos, ou alguma máquina em outra localização que você possa acessar via SSH, ou um serviço de VPN.

A prática mais comum é ficar saltando entre configurações no navegador, talvez com a ajuda de extensões ou perfis segregados, ou ligar e desligar a VPN sob demanda, de acordo com a atividade a ser realizada. Contudo, o processo torna-se logo entediante. Não tarda muito para que, imaginemos, a banda dos servidores da universidade seja desperdiçada na transmissão de vídeos de gatos (em vez de artigos científicos), pois esquecemos de restaurar as configurações no navegador.

Contudo, é razoável assumir que você deseje que link.springer.com seja sempre acessado pela universidade, enquanto youtube.com seja sempre contactado diretamente, poupando a rede universitária dos vídeos de gatos. Havendo esta relação fixa entre o domínio (springer.com) e a rota (servidor VPN da universidade), o troca-troca e/ou liga-desliga pode ser evitado. Vejamos uma receita para fixar rotas de acordo com domínio de destino, de modo transparente, para todos os equipamentos na rede local. Para tanto, necessitados de:

Solução

Assumimos que a máquina Linux está conectada por cabo à sua rede (diretamente no roteador, na maior parte dos casos), roda Debian instável e dispõe de um endereço IP estático na rede interna (LAN), digamos, 192.168.1.2. Esta máquina deverá estar sempre ligada e operante, sob pena dos dispositivos na rede não conseguirem mais resolver DNS e, portanto, perderem acesso efetivo à internet. Boas candidatas são SBCs, como placas da família Raspberry Pi, pois costumam ser relativamente potentes, apesar de consumir pouquíssima energia (em boa parte dos casos, menos energia inclusive que o próprio roteador).

Embora as instruções tenham sido testadas com Debian instável, é muito provável que os passos descritos abaixo funcionem perfeitamente com a suíte estável do Debian, ou com outra distribuição qualquer do Linux, especialmente aquelas derivadas do Debian, como Ubuntu e Mint.

Você precisa ter acesso de administrador ao terminal da máquina, seja por meio de periféricos (teclado, tela e etc.), seja por acesso remoto via SSH.

Serviço DNS – AdGuardHome

Em tese, qualquer serviço DNS que permita a reescrita de requisições de acordo com o domínio (como dnsmasq, por exemplo) seria suficiente. Mas vamos usar AdGuardHome, pois oferece outras funcionalidades úteis, como o bloqueio de domínios de propaganda/rastreamento e diversas ferramentas para controle dos pais.

Por razões de segurança, adotamos uma instalação um pouco distinta do método padrão recomendado na documentação: em vez de executarmos o serviço como superusuário, concedemos seletivamente ao binário os privilégios necessários. Primeiramente, criamos um usuário dedicado para execução do serviço.

# adduser --system --disabled-login --group --home /opt/agh agh

Abrimos uma linha de comando como o novo usuário e pulamos para o diretório $HOME.

$ sudo -u agh /bin/bash
$ cd $HOME

Baixamos o binário de acordo com a plataforma da máquina, digamos arm64, e extraímos.

$ wget ENDEREÇO_PARA_O_PACOTE.tar.gz
$ tar --strip-components=2 -zxvf PACOTE.tar.gz

Concedemos ao binário a capacidade de se atrelar à portas privilegiadas, como a 53.

# setcap 'CAP_NET_BIND_SERVICE=+eip CAP_NET_RAW=+eip' ./AdGuardHome

Executamos o binário enquanto navegamos para http://192.168.1.2:3000 (adapte para o IP da sua máquina, caso necessário) e seguimos as instruções para configuração inicial. Eu recomendo que você configure para que a página de gerenciamento escute por conexões apenas a partir de dentro da própria máquina. Supondo que você tenha acesso remoto via SSH, poderá sempre simular o acesso interno:

$ ssh -L 3000:localhost:3000 192.168.1.2

Após os ajustes iniciais, criamos uma unidade de sistema em /etc/systemd/system/agh.service:

[Unit]
Description=Local DNS
After=syslog.target network-online.target

[Service]
StartLimitInterval=5
StartLimitBurst=10
ExecStart=/opt/agh/AdGuardHome
WorkingDirectory=/opt/agh
User=agh
Group=agh
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Carregamos, habilitamos e iniciamos a unidade.

# systemctl daemon-reload
# systemctl enable agh.service
# systemctl start agh.service

Consulte a documentação e configure o serviço de acordo com as suas preferências. Eu recomendo usar 1.1.1.1 (Cloudflare) e 8.8.8.8 (Google) como servidores de arranque (apenas) e realizar as resoluções DNS normais via HTTPS: https://dns.cloudflare.com/dns-query (Cloudflare) e https://dns.google/dns-query (Google). Desta maneira, alguém bisbilhotando o tráfego DNS não poderá descobrir daí os sites que você visita. Alguém bisbilhotando o tráfego TCP, entretanto, ainda poderá fazê-lo por meio do SNI. Mais adiante, veremos como este defeito do TLS pode ser empregado para rotear transparentemente tráfego encriptado.

A opção de DNS otimista pode reduzir o tempo médio de resposta para aproximadamente cinco milissegundos sem causar problemas perceptíveis (em comparação com a latência média de cinquenta milissegundos entre João Pessoa e os servidores da Google e Cloudflare em São Paulo). Por fim, não se esqueça de alterar DNS primário e secundário no servidor DHCP (normalmente abrigado no roteador) da sua rede para o IP da máquina e certifique-se de que ela aceita pacotes na porta 53 (de que a porta não está sendo filtrada, por exemplo).

Compartimentos de rede

No Linux, podemos criar compartimentos de rede completamente segregados, sem que seja necessário virtualizar todo o SO (por exemplo, com Docker) ou quaisquer outros recursos do sistema, seja armazenamento, processamento e etc. Esta economia é particularmente bem-vinda em SBCs.

Todas as configurações alcançadas por meio dos comandos a seguir são efêmeras e não sobrevivem a reinicialização da máquina. Existem várias formas de torná-las permanentes. Nas distribuições Linux modernas, a maneira mais robusta provavelmente envolve configurações de ferramentas da família systemd. Isto não é abordado.

Criamos uma ponte virtual de rede (br0) para conectar todas as interfaces da máquina. Estamos assumindo que a interface física cabeada (digamos, eth0) foi completamente desconfigurada. A ponte virtual tomará o seu lugar.

# ip link add name br0 type bridge
# ip link set eth0 up
# ip link set eth0 master br0

Agora que nós temos uma ponte virtual contendo a interface física cabeada, podemos configurá-la via DHCP.

# dhclient br0

Observe, porém, que a ponte obteve um MAC aleatório (distinto daquele atrelado à eth0) e que a reserva DHCP, caso já exista, provavelmente terá que ser atualizada para refletir o novo MAC.

Wireguard

Muitas pessoas contratam serviços de VPN com servidores espalhados pelo mundo com o intuito de contornar bloqueios ou filtros geográficos. VPNs também são ocasionalmente usadas para escapar de filtros impostos pela rede de origem, como a Grande Muralha (virtual) da China, dentre outros usos.

Como ilustração, vejamos como seria possível desviar, de modo transparente, todo tráfego da rede destinado para ardmediathek.de (e subdomínios) via um servidor VPN na Alemanha. Usamos Wireguard, pois é mais simples e eficiente que as alternativas (como OpenVPN e IPSec) para os nossos propósitos.

Suponhamos, então, que há uma máquina na Alemanha (IP A.A.A.A) com uma interface wireguard escutando na porta UDP 51820, chave pública Deu...land=. Esta máquina está disposta a encaminhar os nossos pacotes recebidos do endereço interno 10.1.1.4 encriptados com a chave privada PriV...sEcrEt=.

# apt install wireguard-tools

Criamos uma interface wireguard com o nome de.

# ip link add dev de type wireguard

Agora, criamos um compartimento de rede separado (também chamado de) e transportamos a interface wireguard recém-criada para lá.

# ip netns add de
# ip link set de netns de

A interface wireguard lembra a sua rede de nascimento e sempre irá encriptar e despachar pacotes por ali, ainda que agora habite um compartimento de rede diferente. Configuramos, então, a interface wireguard dentro do compartimento. Para simplificar, estamos usando apenas IPv4.

# ip netns exec de wg set private-key <(echo PriV...sEcrEt=) peer Deu...land= allowed-ips 0.0.0.0/0 endpoint A.A.A.A:51820
# ip -n de address add 10.1.1.4/32 dev de
# ip -n de link set up dev de

Pronto. Dentro do compartimento, a única interface disponível no momento é a inferface wireguard. Definimos esta interface como rota padrão para pacotes gerados dentro do compartimento.

# ip -n de route add default via 10.1.1.4 dev de

Agora, qualquer programa executando dentro do compartimento terá seu tráfego redirecionado através da Alemanha. Para poder expor a rota alemã a programas executando em outras máquinas, conectamos o compartimento à rede local por meio de um cabo de rede virtual.

# ip link add vethde type veth peer name cethde
# ip link set cethde netns de
# ip -n de link set up cethde
# ip link set up vethde
# ip link set vethde master br0

Aqui a ponta vethde do cabo habita a rede padrão e está ligada à ponte br0 e a outra ponta cethde habita o compartimento de. Isto significa que cethde pode agora solicitar um endereço local na rede para o compartimento de via DHCP (digamos que foi cedido o endereço 192.168.1.3).

# ip netns exec de dhclient cethde
sniproxy

Muitas ferramentas de rede procuram por arquivos de configuração em /etc/netns/$NOME antes do padrão /etc quando executadas no compartimento de rede $NOME. É o caso do sniproxy. Ele irá escutar nas portas padrões 80 (HTTP) e 443 (HTTPS), e irá redirecionar o tráfego TCP com base no nome do servidor destino, conforme especificado na origem do tráfego, consultando o SNI, no caso de tráfego encriptado (daí o nome da ferramenta).

# apt install sniproxy

No nosso caso, o tráfego será direcionado para o mesmo servidor estipulado na origem. Porém, como o sniproxy executa dentro do compartimento de, o tráfego percorrerá a rota alemã. Um exemplo de /etc/netns/de/sniproxy.conf seria:

user daemon

listen 192.168.1.3:80 { proto http }
listen 192.168.1.3:443 { proto tls }
table { .* * }

resolver { mode ipv4_only }

Por razões de segurança, a configuração acima pede que o sniproxy escute apenas na rede local. É aconselhável também implantar um filtro de rede próprio para o compartimento de, por exemplo, executando comandos nft dentro do compartimento, mas não trataremos disto.

# ip netns exec de sniproxy

Convém observar, novamente, que um endereço MAC aleatório foi atribuído a cethde, o que deve ser levado em consideração na hora de fazer uma reserva estática de IP por DHCP (o que é altamente recomendável). Logo após a criação do cabo de rede virtual, é possível atribuir um $MAC específico caso necessário para preservar uma reserva de IP já vigente.

# ip -n de link set dev cethde address $MAC

Roteamento baseado no domínio

Agora, usamos o nosso servidor DNS para direcionar as conexões de todos os equipamentos da rede ao compartimento, conforme o domínio requisitado. Para tanto, configuramos uma regra de reescrita no AdGuardHome (dns/#custom_rules). Para desviar tráfego destinado ao domínio ardmediathek.de (e seus subdomínios) através da Alemanha, por exemplo, podemos usar a regra:

||ardmediathek.de^$dnsrewrite=NOERROR;A;192.168.1.3,client=~192.168.1.3

Esta regra especifica que a resposta DNS para ardmediathek.de (e seus subdomínios) será 192.168.1.3 (o endereço local do compartimento de). Exceção para requisições vindas do próprio compartimento, as quais serão, naturalmente, resolvidas com o IP real.

Em resumo, ao acessar ardmediathek.de, os equipamentos da rede serão levados a abrir uma conexão TCP com o sniproxy (na porta 80 ou 443). Ele, por sua vez, consulta o nome do servidor destino no SNI, faz sua própria resolução DNS, obtendo agora o IP real, e encaminha a conexão TCP adiante. Porém, por estar executando no compartimento de, esta conexão TCP seguirá para a interface wireguard correspondente, saindo na outra ponta na Alemanha, como se ali tivesse originado.

SOCKS5

Também é possível usar a rota alemã direta e indistintamente via SOCKS5.

# apt install microsocks

Uma vez que o microsocks é bem simplório e não rebaixa automaticamente para um usuário comum, invocamos setpriv para evitar executar como administrador.

# ip netns exec de setpriv --reuid daemon --regid daemon --clear-groups --inh-caps=-all microsocks -i 192.168.1.3 &

Este método requer a configuração de cada aplicação (e.g. firefox) ou do SO para empregar a saída de rede via SOCKS5, endereço 192.168.1.3, porta 1080. Ademais, todo tráfego por ali percorrerá a rota alemã, sem distinção de domínio. Uma vantagem, porém, é que pode ser facilmente usado com outros protocolos, além de HTTP/HTTPS.

Android

Sagernet é uma ferramenta que permite configurar diferentes perfis SOCKS5 e rotear com base no aplicativo que originou o tráfego. Possui diversos outros usos e configurações, a maior parte direcionada a usuários que almejam superar a muralha virtual chinesa.

CC-BY-SA 4.0