Túnel IP muito simples, baseado em DTLS.
Se não houver necessidade de criptografia forte, você pode considerar usar o utun? mais leve?
go install github.com/taoso/dtun/cmd/dtun
# 服务端
dtun -key foo
# 客户端
dtun -connect addr:port -key foo
Aqui está uma lista rápida de alguns fatores a serem considerados.
Não é fácil obter criptografia de dados da camada de transporte estável e confiável, por isso sempre usei o TLS como protocolo subjacente.
O TLS usa TCP e os dados criptografados também são, em grande parte, dados TCP. Desta forma, a transmissão de um pacote de dados da camada superior requer a confirmação das conexões TCP internas e externas. O problema de implementação deste tipo de TCP sobre TCP não é pequeno. Para detalhes, consulte: Referência http://sites.inka.de/~bigred/devel/tcp-tcp.html.
Portanto, é melhor usar a transmissão UDP. Naturalmente, o DTLS é usado para criptografia. Atualmente, o DTLS não oferece suporte a 1.3 e a linguagem go não oferece suporte oficial. Você só pode usar esta implementação de terceiros https://github.com/pion/dtls.
Quer seja TLS ou DTLS, geralmente você precisa criar um certificado. Este processo agora é gratuito, mas ainda é complicado de configurar. Além disso, o certificado resolve apenas o problema de criptografia e não resolve o problema de autenticação. Normalmente, apenas o cliente verifica o certificado do servidor. Você também pode permitir que o servidor verifique o certificado do cliente, mas isso é muito problemático.
Além disso, o DTLS não tem conexão e não pode apenas realizar autenticação ao criar uma conexão como uma conexão TCP.
Portanto, é melhor concluir a autenticação de ambas as extremidades ao mesmo tempo durante o handshake DTLS. Então eu escolho o modo Chave pré-compartilhada (PSK). Precisamos apenas usar -key
para especificar a chave mestra em ambas as extremidades para concluir a autenticação dupla. Uma sessão DTLS não pode ser estabelecida se o cliente não conhecer o PSK.
Além disso, o PSK também precisa especificar um parâmetro de dica. Você pode simplesmente pensar nisso como o nome PSK. O DTLS não está conectado, por isso é difícil determinar se o cliente esteve offline. Decidi ter um parâmetro de dica exclusivo para cada cliente. O servidor aloca dispositivos tun para dicas. Se o cliente for desconectado e reconectado, vários dispositivos tun não serão criados. Mas o efeito colateral é que os clientes do mesmo hinit não podem fazer login ao mesmo tempo.
Para suportar macos, o dispositivo tun só pode ser configurado para o modo ponto a ponto. Se quisermos fazer roteamento e encaminhamento transparentes, veja a imagem abaixo
pc <-----------> router <====== dtun ======> pc2 <---------> www
10.0.0.2/16 10.0.0.1/16 10.1.0.1/16 10.1.0.2/16
Esperamos que os pacotes enviados pelo pc sejam encaminhados para o pc2 através do roteador e depois encaminhados para a rede externa. Geralmente, faremos NAT uma vez no roteador e depois uma vez no pc2. A vantagem disso é que o pc2 não precisa saber a configuração da rede do pc até o roteador. Mas as desvantagens também são óbvias, existem duas nat. O desempenho dos roteadores geralmente não é forte, portanto o NAT deve ser evitado tanto quanto possível.
Portanto, meu plano é enviar diretamente o segmento de rede 10.0.0.0/16 onde o pc está localizado para pc2 e adicionar uma rota no pc2
ip route add 10.0.0.0/16 via 10.1.0.1
Desta forma, o roteador pode encaminhar os pacotes do pc para o pc2 intactos, sendo necessário fazer NAT apenas uma vez no pc2.
Às vezes precisamos especificar uma lista de permissões de roteamento. Use a rota padrão nos segmentos de rede na lista branca e encaminhe os outros através do túnel.
Podemos primeiro adicionar uma rota de lista de permissões ao roteador e definir o próximo salto para a rota padrão do roteador. Em seguida, especifique o IP público do pc2 para seguir a rota padrão do roteador (chave!). adicionado pela última vez
ip route add 0.0.0.0/1 via 10.1.0.2
ip route add 128.0.0.0/1 via 10.1.0.2
0.0.0.0/1
e 128.0.0.1/1
aqui cobrem apenas todo o segmento de rede. O efeito é equivalente ao padrão, mas não substituirá a rota padrão. Se o túnel for fechado de forma anormal, todas as rotas relacionadas serão excluídas automaticamente, o que é muito estável.
Você pode escrevê-lo como um script e executá-lo usando o parâmetro -up
. Meu roteiro é o seguinte:
#! /bin/sh
# curl -S https://cdn.jsdelivr.net/gh/misakaio/chnroutes2@master/chnroutes.txt|grep -v '#'|xargs -I % ip route add % via $DEFAULT_GW 2>/dev/null
VPN_IP= $( ping your-server-name -c 1 | grep from | cut -d ' ' -f4 | cut -d: -f1 )
DEFAULT_GW= $( ip route | grep default | cut -d ' ' -f3 )
ip route add $VPN_IP /32 via $DEFAULT_GW
ip route add 0.0.0.0/1 via $PEER_IP
ip route add 128.0.0.0/1 via $PEER_IP