Dois registos A, um endereço, um daemon: seja qual for o nome que o utilizador escreva, o pacote que chega é idêntico, e o processo ligado à porta 1194 não tem nada para distinguir os dois. Isto não é uma configuração errada à espera de reparação; é o limite do que uma consulta de nome pode exprimir. Tudo o que escolha entre duas instâncias de OpenVPN tem de ser um valor que o cliente coloca na ligação e que o frontend consiga voltar a ler, e um cliente OpenVPN padrão não coloca nenhum valor desses em claro. O que segue é onde isso te deixa, e que disposições separam realmente o tráfego.

Começa pelo que o resolver devolve

Um cliente pede vpn-a.example e recebe um endereço; esse endereço mais uma porta é tudo aquilo a que liga. O nome é gasto localmente, durante a consulta, e nunca se torna um campo no fio, pelo que o listener do outro lado não consegue ver que etiqueta foi usada. Aponta vpn-a.example e vpn-b.example para um mesmo host e ambas as consultas dão o mesmo destino, e é por isso que o daemon absorve as duas ligações numa só instância sem registar diferença. Os perfis baseados em endereço comportam-se exatamente como os baseados em nome, pela mesma razão.

Isto também fecha uma família de contornos tentadores: aliases adicionais, escolher um certificado por nome num só socket ou uma regra de firewall ligada ao nome consultado. Nenhum deles pode agir sobre informação que já foi descartada antes de o primeiro pacote sair do cliente. Se dois servidores têm de continuar separados, a separação tem de viajar com a própria ligação, ou seja, um endereço, uma porta ou um campo de carga útil que o protocolo defina.

O único seletor que conta viaja dentro do pacote

O HTTP resolve isto com um cabeçalho Host, e o TLS com uma extensão de nome de servidor no ClientHello, e é assim que um endereço serve muitos sites atrás de um só listener. Ambos funcionam porque o protocolo no fio transporta um pedido para um serviço concreto. O facto relevante sobre o OpenVPN é que nenhum desses campos está presente na camada que uma caixa intermédia inspeciona.

Numa disposição padrão o aperto de mão TLS que protege o canal de controlo acontece depois de a sessão exterior estar estabelecida e é transportado dentro dela, pelo que um listener que não terminou essa sessão vê um fluxo opaco. Ainda consegue dizer que isto é OpenVPN, porque o opcode e o enquadramento nos primeiros bytes são reconhecíveis, mas o nome de servidor, se existir, fica na parte cifrada. Um desenho que espera ler um anfitrião virtual do pacote exterior está a ler um campo que o protocolo nunca escreve ali. Isso vem de como o túnel é construído, não de uma lacuna que uma correspondência de padrões mais astuta pudesse fechar.

Onde um separador de protocolos fica aquém

Um multiplexador do tipo que o projeto sslh documenta escuta numa porta, inspeciona os primeiros bytes e entrega a ligação ao backend que fale o protocolo reconhecido. Isso é valor real quando uma só porta tem de servir SSH, HTTPS e OpenVPN em conjunto.

O sslh mantém uma sonda separada por protocolo, e a sua sonda TLS consegue extrair um nome de servidor ou um valor ALPN de um ClientHello genuíno. Reconhecer OpenVPN nativo é uma classificação diferente de ler uma extensão TLS, e as duas não se compõem, porque um cliente que nunca envia um ClientHello ao socket de escuta deixa a sonda sem nada para ler. Por isso uma regra que corresponde a OpenVPN responde «este é um cliente OpenVPN» e não vai mais longe. Dois backends OpenVPN atrás dessa regra são indistinguíveis, o frontend não tem base para escolher, e cada sessão aterra no mesmo sítio. O multiplexamento partilha uma porta entre serviços diferentes; não faz alojamento virtual dentro de um serviço.

Disposições que separam mesmo dois servidores

A separação honesta mais barata é um segundo endereço público, um por instância, e os perfis existentes já levam o necessário porque apontam para endereços diferentes. A seguinte é uma porta diferente no mesmo endereço, que não custa nada além de um número em cada perfil. O TCP e o UDP mantêm tabelas de portas separadas, pelo que 1194/tcp e 1194/udp são sockets não relacionados e um de cada pode coexistir no mesmo host; isso é separação de transporte e não encaminhamento por nome, e é frequentemente confundido com ele. Ambas as opções sobrevivem a uma revisão de firewall, porque a regra corresponde a algo que o pacote contém de facto.

Se a fronteira de que precisas corre entre grupos de utilizadores em vez de entre duas implementações, uma instância com configurações de cliente distintas, o seu próprio tratamento de certificados e uma política de acesso explícita pode cobri-la. O que isso compra é política dentro de um servidor, não isolamento entre servidores, e são requisitos diferentes. O isolamento que tem de aguentar sob compromisso continua a precisar do endereço ou da margem da firewall.

Um terminador TLS colocado à frente do OpenVPN pode expor um nome de servidor real a um frontend capaz, mas só quando o lado do cliente também está configurado para essa camada extra. Os perfis existentes não adquirem o comportamento por serem apontados ao mesmo endereço.

Prova o seletor antes de construir

Nomeia o campo que vai identificar um backend, e depois confirma que o cliente o envia de facto; se a resposta for um endereço, o plano aguenta, e se for um nome de servidor dentro de um aperto de mão que nunca chega ao listener, nenhuma quantidade de trabalho de DNS o salvará. Três comandos resolvem depressa o lado que escuta.

ss -lntup | grep -E ':443|:1194'
openssl s_client -connect vpn-a.example:443 -servername vpn-a.example </dev/null | head -n 20
journalctl -u openvpn-server@server-a -n 20 --no-pager

A linha de openssl só dá um certificado onde algo nesse endereço termina TLS; contra um listener OpenVPN nativo encrava ou falha, e isso é em si a resposta sobre o que a camada exterior expõe. A linha de journal, lida em cada backend, mostra que instância aceitou a sessão. Os registos do frontend anotam o que foi classificado e nunca o que era pretendido, pelo que o backend continua a ser a única autoridade sobre onde um utilizador aterrou.

Termina com dois perfis pensados para alcançar servidores diferentes, liga-os um de cada vez e anota o registo do backend para cada um. Se ambas as sessões aparecerem no mesmo journal, falta o seletor em vez de estar mal configurado, e a correção é um endereço ou uma porta que o cliente possa visar. Editar a regra de encaminhamento não ajudará, porque à regra nunca foi dado nada por onde encaminhar. Quando a separação for real, escreve-a ao lado dos perfis, para que a pessoa seguinte não acrescente um segundo alias e espere que faça o trabalho.

Artigos relacionados