Interruptor de segurança pf do macOS para OpenVPN: regras que fecham
Um conjunto de regras pf bloqueia o tráfego direto enquanto o túnel está em baixo. Mantenha o caminho do cliente até ao seu servidor e depois prove o bloqueio com o túnel desligado.
No macOS, um interruptor de segurança vale apenas o que vale a política do filtro de pacotes por trás dele, e o pf é a peça que aplica essa política. A política tem de fazer duas coisas opostas ao mesmo tempo: deixar o cliente chegar ao seu servidor para que possa existir um túnel, e impedir todo o resto de sair diretamente. A maioria dos conjuntos de regras publicados resolve a segunda e esquece a primeira, por isso a máquina perde conectividade em vez de ganhar proteção. A versão que funciona nomeia o ponto final, o resolvedor e o túnel, e nada mais.
O que um filtro de pacotes pode decidir, e o que não pode
O pf olha para interfaces, endereços, números de protocolo e portas, e fica por aí. Nunca sabe que processo abriu um socket, por isso uma autorização escrita para um programa torna-se autorização para todos os programas que consigam chegar à mesma porta. É assim que uma exceção UDP generosa devolve um interruptor de segurança a uma rede comum. O bloqueio consciente da aplicação pertence ao cliente ou a uma extensão do sistema, não a este ficheiro.
O filtro também não cria rotas. Quando o cliente cai, a rota predefinida pode continuar a apontar para um túnel morto, e o pf transforma isso em pacotes bloqueados em vez de um regresso silencioso ao Wi-Fi. O bloqueio é o resultado pretendido, não uma avaria que se contorne.
A ordem decide o resultado mais vezes do que o texto da regra. Sem quick, o pf continua a avaliar depois de uma correspondência e ganha a última regra correspondente, pelo que uma passagem larga em baixo anula as exceções cuidadosas acima. Marcar as passagens com quick torna a primeira correspondência definitiva, que é o que um autor de políticas costuma querer dizer.
Leia primeiro os factos da interface e do ponto final
As interfaces sem fios não são numeradas da mesma forma em todos os Mac, e o dispositivo do túnel recebe um número que pode mudar entre arranques. Uma regra que nomeia um dispositivo inexistente falha na análise, o que é ruidoso e fácil de apanhar, enquanto uma regra que nomeia o dispositivo existente errado é analisada sem erros e permite tráfego que querias parar.
Recolha os factos enquanto o cliente está ligado, porque o dispositivo do túnel só existe nessa altura. Precisa da interface que detém a rota predefinida, do dispositivo criado pelo cliente, e do endereço e porta do servidor que ele marca. É exatamente esse último valor que a maioria dos conjuntos de regras omite, e omiti-lo é a razão pela qual um conjunto copiado bloqueia o seu próprio túnel.
route -n get default
ifconfig -l
scutil --nc list
O primeiro comando nomeia a interface que ganha agora, o segundo lista todos os dispositivos que o kernel conhece, e o terceiro mostra as configurações VPN que o sistema pode iniciar. Anote essas respostas e depois leia o endereço e a porta do servidor a partir da própria configuração do cliente.
Escreva o conjunto de regras em torno do caminho do túnel
O ficheiro abaixo nega por predefinição e volta a admitir cinco coisas: loopback, o dispositivo do túnel, o caminho do cliente até ao seu servidor, o resolvedor usado antes de o túnel existir, e as duas trocas que mantêm uma ligação sem fios utilizável. Os nomes das interfaces e o endereço do servidor vêm da sua máquina, por isso substitua os valores que confirmou. O número do túnel também não vai coincidir com o seu.
set skip on lo0
block all
pass out quick on utun0
# maintain this line when the server address changes
pass out quick on en1 inet proto udp to 203.0.113.10 port 1194
# only the resolver the client uses before the tunnel exists
pass out quick on en1 inet proto udp to 192.0.2.53 port 53
pass out quick on en1 inet proto udp from any port 68 to any port 67
pass out quick on en1 inet proto udp to 224.0.0.251 port 5353
A linha DHCP existe porque um Mac pede um endereço antes de o ter, por isso o pedido sai da porta 68 em direção à porta 67 sem um endereço de origem utilizável. A linha multicast permite ao sistema julgar se vale a pena usar a ligação sem fios, e removê-la produz uma máquina que relata nenhuma ligação numa rede que funciona. A linha do ponto final é o que permite ao OpenVPN chegar ao seu servidor; sem ela, o block all descarta o aperto de mão exterior e o túnel nunca sobe. A linha do resolvedor é mais estreita do que uma autorização DNS geral, porque nomeia um endereço e uma porta em vez de cada consulta que a máquina faz.
Essas exceções de ponto final e de resolvedor são as duas que têm de existir; tudo o resto fica bloqueado. Se o cliente marcar um endereço literal, retire a linha do resolvedor e mantenha a do ponto final. Se o endereço do servidor mudar, atualize essa linha antes da ligação seguinte, ou preencha uma tabela pf a partir do próprio gancho do cliente e faça corresponder a tabela em vez disso.
Desça o túnel e depois reinicie
Analise antes de carregar, porque um erro de sintaxe é barato num ensaio a seco e caro numa sessão remota. Depois carregue o ficheiro, ative o filtro se estava desligado, e releia o que está realmente em vigor. A releitura não é cerimónia: outra âncora pode acrescentar regras que não escreveu, por isso compare o conjunto impresso com o seu ficheiro.
sudo pfctl -n -v -f /etc/pf.conf
sudo pfctl -f /etc/pf.conf
sudo pfctl -e
sudo pfctl -s rules
sudo pfctl -s Anchors
sudo pfctl -a <anchor> -s rules
sudo pfctl -s info
Com as regras carregadas, desça o túnel e tente carregar uma página. O tráfego comum deve parar, e deve continuar parado depois de a máquina dormir e acordar, porque é nessa transição que o estado antigo regressa. Volte a ligar e confirme que o tráfego retoma sem tocar no conjunto de regras. Se um navegador ainda funciona com o túnel em baixo, alguma regra é mais ampla do que pensava, e a releitura costuma nomeá-la.
O reinício é a parte que as pessoas saltam. O macOS lê o /etc/pf.conf no arranque, mas ler o ficheiro não é o mesmo que ativar o filtro, por isso um conjunto de regras que funciona agora pode ficar inativo após um reinício. Execute depois o sudo pfctl -s info e confirme que a linha de estado indica o filtro como ativado.
Mantenha honestos a saída e o caminho de reinício
Um conjunto de regras que bloqueia tudo também pode trancar-te fora de uma máquina que administras remotamente. Edita a partir de uma sessão local quando puderes, mantém o ficheiro anterior ao lado do novo, e conhece a reversão antes de precisares dela. Os comandos abaixo desativam o filtro e recarregam a cópia que guardaste, e é a sequência para executar numa consola, não através do túnel que acabaste de cortar. Uma reversão em cinco segundos vence uma regra engenhosa todas as vezes.
sudo pfctl -d
sudo pfctl -f /etc/pf.conf.previous
sudo pfctl -s rules
A persistência exige um daemon de arranque que execute o pfctl -e e carregue o teu ficheiro no arranque. Trata-o como qualquer outro trabalho privilegiado: caminhos absolutos, um registo que possas ler depois, e um teste numa máquina que consigas alcançar fisicamente. Um daemon que falha em silêncio deixa a máquina desprotegida e com aspeto normal.
Documenta as lacunas, começando por um segundo cliente VPN que cria o seu próprio dispositivo de túnel. As tuas regras nomeiam uma interface de túnel, por isso a segunda fica bloqueada ou é apanhada por uma regra ampla adicionada mais tarde. As interfaces de tethering e hotspot só aparecem às vezes e merecem a mesma nota. Nenhuma dessas lacunas é razão para saltar a política; são as condições em que ela ainda se mantém.