O pull-filter do OpenVPN corresponde a mais do que a rota que você quis
pull-filter compara seu texto como prefixo com as opções enviadas, então route também captura route-gateway e route-ipv6. Verifique os verbos, depois as rotas.
Você adiciona uma linha para manter sua rota padrão local, e depois disso o túnel não alcança mais o servidor DNS interno. A linha era pull-filter ignore "route", que não significa "ignore esta rota". Significa "descarte toda opção enviada cujo texto comece com essas cinco letras", e em um servidor normal isso inclui route-gateway, route-metric e route-ipv6 junto com as próprias rotas. A lista de verificação abaixo é o que eu percorro antes de tocar em um perfil que outra pessoa precisa usar.
O filtro só se aplica às opções enviadas
pull-filter age apenas nas linhas de opção que o servidor envia depois que o túnel é estabelecido, e em nada mais. As opções escritas no seu arquivo local não são afetadas, nem o tráfego de aplicações. Se você esperava impedir um processo de usar o túnel, esta é a ferramenta completamente errada e nenhuma combinação de filtros fará isso.
Esse alcance é útil, porque significa que você pode deixar a configuração do servidor em paz e ainda recusar parte dela localmente. Também é um limite que vale registrar no ticket: um filtro muda o que este cliente aceita, não o que o servidor oferece. Ele não tem efeito sobre outros usuários do mesmo perfil. Também não sobrevive a uma mudança para outro cliente que não implemente a opção, o que vale saber antes de construir um fluxo de trabalho sobre ela.
Confirme o que o servidor realmente envia antes de escrever o padrão. Com verbosidade alta o cliente imprime a string de opções enviadas que recebeu, e essa é a única fonte honesta para o texto exato com que você compara:
sudo openvpn --config /etc/openvpn/corp.ovpn --verb 4
sudo grep -n 'pull-filter' /etc/openvpn/corp.ovpn
Leia a linha enviada como uma lista de opções separadas por vírgulas, e observe que os nomes das opções e seus argumentos são separados por espaços. Seu texto de filtro é comparado a esse fluxo, por isso os espaços importam tanto no próximo passo.
A correspondência é um prefixo, então os espaços são tudo
A comparação é um prefixo de string, não um nome de opção analisado. Por isso "route" corresponde a route-gateway 10.8.0.1, route-ipv6 2001:db8::/32 e route-metric 100. Um espaço final restringe à família que você provavelmente queria, e o prefixo completo restringe ainda mais a um destino específico.
| Filter text | What it actually matches | Typical outcome |
|---|---|---|
"route" | Every option beginning with those letters | Routes, gateway, metric and IPv6 routes all dropped |
"route " | Route entries only, not the hyphenated siblings | The routes go, the rest survives |
"route 10.60." | A single destination range | The narrowest rule, and the easiest to audit |
"dhcp-option DNS" | Pushed DNS settings | Resolver stays local, internal names stop resolving |
A última linha é a que pega as pessoas durante o trabalho com túnel dividido. Manter seu próprio resolvedor é uma escolha legítima, e significa que cada nome interno agora depende de um resolvedor que não vê a zona privada. É uma consequência que se aceita de propósito, não um efeito colateral descoberto em produção.
A correspondência por prefixo também significa que uma regra pode se ampliar depois em silêncio. Quando o servidor adiciona uma opção que começa com o seu texto, seu filtro passa a se aplicar a ela sem que ninguém edite seu perfil. Esse é o modo de falha contra o qual se deve projetar, e a mitigação é corresponder ao máximo da opção, não ao mínimo.
Três verbos com três resultados diferentes
accept, ignore e reject não são três grafias da mesma ideia. Eles diferem no que o cliente faz com uma correspondência e em se alguém fica sabendo.
ignore descarta a opção correspondente em silêncio, que é o que você quer para um ajuste que substituiu deliberadamente. reject a descarta e faz o cliente reclamar, que é o que você quer quando a ausência dela deve aparecer no log em vez de ser descoberta depois. accept é a forma positiva, usada quando você monta uma lista de permitidos em vez de remover opções individuais.
Qualquer que seja o verbo usado, os filtros são aplicados na ordem em que aparecem, então duas regras sobrepostas produzem um resultado dependente da ordem e muito difícil de revisar. Mantenha uma regra por intenção e coloque o texto mais específico em cada uma. Se precisar de uma lista de permitidos, prefira algumas regras accept a uma pilha de regras ignore que somam o mesmo. Assim os revisores podem ler o arquivo de cima para baixo e prever o resultado, e esse é o único teste que escala.
Verifique a rota e o resolvedor aplicados, não o perfil
Um filtro que parece correto no arquivo ainda pode deixar você com um túnel que não encaminha nada útil. Verifique o efeito no sistema em execução, onde as opções enviadas já foram aplicadas ou descartadas:
ip route show default
ip route show | grep -c 'proto static'
resolvectl status | grep -A4 'Link.*tun0'
curl -sS -o /dev/null -w '%{http_code}\n' --max-time 5 https://intranet.example.internal/
As duas primeiras linhas dizem se a rota padrão enviada chegou e quantas entradas estáticas sobreviveram. A consulta ao resolvedor mostra qual servidor a interface do túnel realmente usa, e é normalmente ali que surge uma surpresa de DNS. A última linha responde à única pergunta que importa para um usuário.
Teste os dois sentidos enquanto estiver aí. Uma regra que mantém seu internet local funcionando mas quebra em silêncio a resolução de nomes interna passa numa verificação superficial e falha na primeira tarefa real, então inclua um recurso interno e um site público no mesmo teste.
Registre a exceção e quem é o dono dela
Um filtro é uma exceção ao projeto do operador, então deixe-o escrito com um motivo e um ponto de revisão. "Ignora rotas enviadas para manter a padrão local" é revisável; uma linha nua em um perfil não é, e a próxima pessoa vai apagá-la ou ampliá-la por adivinhação.
A versão também conta aqui. O comportamento de correspondência e a sintaxe aceita exata foram refinados ao longo do OpenVPN 2.4, 2.5 e 2.6, então confirme o padrão no manual da compilação que você distribui e não num post de fórum sobre uma versão mais antiga. O manual do OpenVPN 2.6 documenta a opção e sua regra de correspondência.
Por fim, combine a exceção com quem administra o servidor. Um filtro do lado do cliente que contradiz uma política deliberada do servidor é um incidente de suporte esperando a próxima auditoria, e é muito mais barato resolvê-lo antes de o perfil sair do que depois que alguém notar que faltam rotas.