Quero construir um serviço similar ao ngrok e estou tentando entender a arquitetura por trás do gerenciamento de subdomínios do ngrok para seu serviço de tunelamento. Pelo que posso ver, o ngrok fornece subdomínios exclusivos (como abcde.ngrok.io) para cada túnel, mas estou intrigado sobre como eles gerenciam isso em escala.
Especificamente:
- Cada túnel tem um endereço IP separado? Se sim, como é que o ngrok tem um número tão grande de IPs? Como eles adicionam dinamicamente novos registros DNS para seus IPs?
- Se diferentes subdomínios são gerenciados pelo mesmo endereço IP, como o ngrok entende que eu me conectei ao a.ngrok.io, não ao b.ngrok.io se ambos têm o mesmo endereço IP? Eu sei, existem tecnologias como SNI, mas como isso funciona então se eu fizer um túnel TCP sem criptografia TLS?
E a pergunta principal: há uma maneira de implementar um sistema similar para um projeto de menor escala? Quais seriam os componentes-chave?
Qualquer insight sobre a arquitetura potencial ou melhores práticas para implementar tal sistema seria muito apreciado! Obrigado!
Não, os endereços dos túneis são compartilhados entre os usuários.
Primeiro, subdomínios curinga. O DNS suporta registros nomeados como
*.example.com
, que cobririam automaticamente qualquer subdomínio (de um nível).example.com
que não fosse especificamente definido de outra forma.Segundo: registros DNS, por analogia com URLs HTTP, não precisam ser adicionados em algum lugar, pois não há um banco de dados central de subdomínios; em vez disso, essas informações são fornecidas somente pelos próprios servidores de nomes do Ngrok. Então, assim como um webapp HTTP pode responder dinamicamente para várias URLs por meio de código, é possível escrever um servidor DNS que responda dinamicamente para vários subdomínios.
Para túneis TCP simples, eles realmente não sabem disso. Até onde eu entendo o sistema deles, eles só usam números de porta TCP para distinguir entre túneis, já que você nunca obtém um subdomínio inteiro – você obtém apenas uma única porta TCP naquele endereço IP.
Depende da escala. Em uma escala realmente pequena (como talvez 0–3 usuários), até mesmo servidores SSH padrão podem fornecer o mesmo tipo de tunelamento usando
ssh -R
(e o Ngrok ainda oferece o mesmo tipo de interface estilo SSH para seu backend personalizado).O código básico para tal serviço começaria como um proxy TCP comum (rinetd, haproxy, nginx) – você abre um soquete de escuta e, para cada conexão recebida, faz uma conexão de saída e cria um loop poll() que copia dados de um soquete para o outro.
Para fazê-lo funcionar como o serviço do Ngrok, no entanto (onde a ideia é que o Ngrok não pode se conectar ao backend; o backend tem que se conectar ao Ngrok), você precisaria alterá-lo para que o proxy esteja escutando conexões de 'cliente' e conexões de 'agente' em dois ouvintes diferentes, e pareando-os de forma semelhante. (Semelhante a como
socat tcp-l:1234 tcp-l:2345
funcionaria.)Isso seria limitado a um cliente por vez, então o próximo passo seria alterar a conexão 'agente-proxy' para que ela pudesse multiplexar dados de vários clientes (semelhante a, por exemplo, como SSH ou QUIC têm vários "fluxos" distintos de dados dentro da conexão TCP) – e fazer o 'agente' desmultiplexá-los.
Por exemplo, o proxy agora aceita uma conexão 'agente' e, para cada conexão 'cliente' recebida, ele envia um comando ao agente como "cliente nº 5 conectado – abra uma nova conexão com o backend, por favor" e "envie este pedaço de dados pela conexão de backend nº 5", e assim por diante. (Isso é muito parecido com o modo como
ssh -R
funciona também.)O resto é apenas tornar o proxy mais flexível, por exemplo, fazendo com que ele aloque automaticamente um novo ouvinte 'cliente' sempre que receber uma conexão 'agente', implementando verificações de manutenção de atividade para NAT, etc.