Este repositório contém cliente e servidor que permitem encapsular o tráfego TCP e UDP por meio de outros protocolos de rede.
Atualmente, os túneis suportados são:
A ferramenta principal é escrita em Rust e os testes ponta a ponta são escritos em Python.
docker pull ghcr.io/dlemel8/tunneler-server:latest
docker pull ghcr.io/dlemel8/tunneler-client:latest
cargo --version || curl --proto ' =https ' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cargo build --release
Há também um arquivo docker se você preferir construir uma imagem docker local
docker run -e LOCAL_PORT=45301
-e REMOTE_PORT=5201
-e REMOTE_ADDRESS=localhost
-e TUNNELED_TYPE=udp
--rm -p 45301:45301 ghcr.io/dlemel8/tunneler-server:latest tcp
./target/release/client
--tunneled-type tcp
--remote-address 1.1.1.1
--remote-port 53
--log-level debug
dns
--read-timeout-in-milliseconds 100
--idle-client-timeout-in-milliseconds 30000
Execute a imagem docker ou o binário compilado com --help
para obter mais informações
cargo test --all-targets
python3 -m pip install -r e2e_tests/requirements.txt
PYTHONPATH=. python3 -m pytest -v
Este repositório contém alguns exemplos de implantação de servidor usando Docker Compose:
Você pode executar cada exemplo localmente ou implantá-lo usando Terraform e Ansible. Veja mais informações aqui.
Cada executável contém 2 componentes que se comunicam através de um canal de fluxos de clientes (uma tupla de leitor e gravador de bytes):
O tráfego baseado em TCP é convertido trivialmente em fluxo. A conversão de tráfego baseada em UDP depende do protocolo do túnel.
O tráfego baseado em UDP também precisa de uma forma de identificar os clientes existentes para continuar suas sessões. A solução é um Cache de Clientes na memória que mapeia um identificador do cliente para seu fluxo.
Para converter o tráfego UDP em um fluxo, um cabeçalho de tamanho de 2 bytes (em big endian) precede a carga útil de cada pacote.
O UDP Listener usa o endereço do pacote de entrada como uma chave para seu cache de clientes.
Temos alguns desafios aqui:
Para resolver esses desafios, cada sessão do cliente começa com a geração de um ID de cliente aleatório (4 caracteres alfanuméricos). O cliente lê os dados para encapsular e executá-los por meio de um pipeline de codificadores:
Os dados codificados são então usados como o nome de uma consulta DNS TXT.
Se você possui um servidor DNS autoritativo, o cliente pode enviar a solicitação para um resolvedor DNS recursivo. O Resolver obterá seu IP do registrador de nomes de domínio e encaminhará a solicitação para o seu IP. Outra opção (mais rápida, porém mais óbvia para qualquer analisador de tráfego) é configurar o cliente para enviar a solicitação diretamente para o seu IP (na porta UDP/53 ou em qualquer outra porta que o servidor esteja escutando).
O servidor decodifica os dados (ignorando qualquer tráfego que não seja do cliente) e usa o ID do cliente como uma chave para seu cache de clientes.
Para lidar com respostas grandes do servidor e ACKs TCP vazios, o tempo limite de leitura é usado tanto no cliente quanto no servidor. Se o tempo limite de leitura expirar, uma mensagem vazia será enviada. Tanto o cliente quanto o servidor usam o tempo limite de inatividade para interromper o encaminhamento e a limpeza de recursos locais.
Para implementar a autenticação mútua, usamos uma autoridade de certificação privada:
Tanto o cliente quanto o servidor estão configurados para usar sua chave e certificado no handshake TLS. O certificado CA é usado como certificado raiz.
Como a extensão Indicação de Nome do Servidor é usada, o cliente está solicitando um nome de servidor específico e o servidor está servindo seu certificado somente se esse nome tiver sido solicitado. O nome do servidor também deve fazer parte do certificado, por exemplo, como Nome Alternativo do Assunto.