
É verdade, e para o deus da criptografia, diremos o mesmo hoje.
Aqui, será sobre um túnel IPv4 não criptografado, mas não sobre uma "lâmpada quente", mas sobre uma moderna "LED". E então os soquetes brutos estão piscando e há trabalho com pacotes no espaço do usuário.
Existem protocolos de tunelamento N para todos os gostos e cores:
Mas eu sou um programador, então aumentarei N apenas uma fração e deixarei o desenvolvimento de protocolos reais para os desenvolvedores b.
Em outro projeto que ainda não nasceu , no qual estou envolvido no momento, preciso acessar os hosts por trás do NAT de fora. Usando protocolos com criptografia adulta para isso, nunca deixei a sensação de que era como uma bala de canhão. Porque o túnel é usado em sua maior parte apenas para abrir uma brecha no NAT-e, o tráfego interno geralmente é criptografado também, embora seja bloqueado por HTTPS.
Enquanto pesquisava vários protocolos de tunelamento, a atenção do meu perfeccionista interno foi atraída para o IPIP vez após vez por causa de sua sobrecarga mínima. Mas tem uma desvantagem e meia significativa para minhas tarefas:
- requer IPs públicos em ambos os lados,
- e nenhuma autenticação para você.
Portanto, o perfeccionista foi empurrado de volta para o canto escuro do crânio, ou onde quer que ele se sente.
E uma vez, ao ler artigos sobre túneis com suporte nativo no Linux, me deparei com FOU (Foo-over-UDP), ou seja, tanto faz, envolto em UDP. Até agora, apenas IPIP e GUE (encapsulamento UDP genérico) são suportados de qualquer outra coisa.
“Aqui está uma bala de prata! Eu e um simples IPIP para os olhos. " Eu pensei.
Na verdade, a bala não era inteiramente de prata. O encapsulamento em UDP resolve o primeiro problema - você pode se conectar a clientes por trás do NAT de fora usando uma conexão pré-estabelecida, mas aqui metade da próxima desvantagem do IPIP surge sob uma nova luz - qualquer pessoa da rede privada pode se esconder atrás do IP público visível e da porta do cliente (em IPIP puro não há problema).
Para resolver esse problema e meio, nasceu o utilitário ipipou . Ele implementa um mecanismo feito pelo próprio para autenticar um host remoto, sem interromper a operação de uma FOU vigorosa, que processará pacotes de forma rápida e eficiente no espaço do kernel.
Não precisa do seu script!
Ok, se você conhece a porta pública e o IP do cliente (por exemplo, todos seus, onde quer que vá, o NAT tenta mapear as portas 1 para 1), você pode criar um túnel IPIP-over-FOU com os seguintes comandos, sem nenhum script.
no servidor:
# FOU
modprobe fou
# IPIP FOU.
# ipip .
ip link add name ipipou0 type ipip \
remote 198.51.100.2 local 203.0.113.1 \
encap fou encap-sport 10000 encap-dport 20001 \
mode ipip dev eth0
# FOU
ip fou add port 10000 ipproto 4 local 203.0.113.1 dev eth0
# IP
ip address add 172.28.0.0 peer 172.28.0.1 dev ipipou0
#
ip link set ipipou0 up
no cliente:
modprobe fou
ip link add name ipipou1 type ipip \
remote 203.0.113.1 local 192.168.0.2 \
encap fou encap-sport 10001 encap-dport 10000 encap-csum \
mode ipip dev eth0
# local, peer, peer_port, dev , .
# peer peer_port FOU-listener-.
ip fou add port 10001 ipproto 4 local 192.168.0.2 peer 203.0.113.1 peer_port 10000 dev eth0
ip address add 172.28.0.1 peer 172.28.0.0 dev ipipou1
ip link set ipipou1 up
Onde
ipipou*- o nome da interface de rede do túnel local203.0.113.1- IP público do servidor198.51.100.2- IP público do cliente192.168.0.2- IP do cliente atribuído à interface eth010001- porta do cliente local para FOU20001- porta cliente pública para FOU10000- porta do servidor público para FOUencap-csum— UDP UDP ;noencap-csum, , ( )eth0— ipip172.28.0.1— IP ()172.28.0.0— IP ()
Enquanto a conexão UDP estiver ativa, o túnel estará em um estado de funcionamento, e como ele quebra, que sorte - se o IP: porta do cliente permanecer o mesmo - ele viverá, mudará - ele irá quebrar.
A maneira mais fácil de mudar as coisas é descarregando os módulos do kernel:
modprobe -r fou ipip
Mesmo que a autenticação não seja necessária, o IP público e a porta do cliente nem sempre são conhecidos e geralmente são imprevisíveis ou alteráveis (dependendo do tipo de NAT). Se você omiti-lo
encap-dportno lado do servidor, o túnel não funcionará, não é inteligente o suficiente para usar a porta de conexão remota. Nesse caso, ipipou também pode ajudar, bem, ou WireGuard e outros como ele podem ajudá-lo.
Como funciona?
O cliente (que geralmente está por trás do NAT) configura um túnel (como no exemplo acima) e envia um pacote autenticado ao servidor para que ele possa configurar o túnel por seu lado. Dependendo das configurações, pode ser um pacote vazio (apenas para que o servidor veja o IP público: porta de conexão), ou com dados pelos quais o servidor possa identificar o cliente. Os dados podem ser uma frase-senha simples de texto simples (uma analogia com HTTP Basic Auth) ou dados especialmente formatados assinados com uma chave privada (por analogia com HTTP Digest Auth, só que mais forte, veja a função
client_authno código).
No servidor (ao lado do IP público), quando o ipipou é iniciado, ele cria um manipulador de fila nfqueue e configura o netfilter para que os pacotes necessários sejam enviados para onde devem ir: os pacotes que inicializam a conexão com a fila nfqueue e [quase] todo o resto direto para o ouvinte FOU.
Quem não está no assunto, nfqueue (ou NetfilterQueue) é algo especial
Para algumas linguagens de programação existem ligações para trabalhar com nfqueue, para bash não havia (heh, não é surpresa), eu tive que usar python: ipipou usa NetfilterQueue .
Se o desempenho não for crítico, com a ajuda disso você pode preparar sua própria lógica de maneira relativamente rápida e fácil para trabalhar com pacotes em um nível bastante baixo, por exemplo, esculpir protocolos de transferência de dados experimentais ou rastrear serviços locais e remotos com comportamento não padrão.
Os soquetes brutos funcionam lado a lado com o nfqueue, por exemplo, quando o túnel já está configurado e a FOU está escutando na porta desejada, não funcionará da maneira usual para enviar um pacote da mesma porta - está ocupado, mas você pode pegar e disparar um pacote gerado aleatoriamente diretamente na rede interface usando um socket raw, embora a geração de tal pacote exija um pouco mais de trabalho. É assim que os pacotes com autenticação são criados no ipipou.
Como o ipipou processa apenas os primeiros pacotes da conexão (bem, aqueles que conseguiram vazar para a fila antes de a conexão ser estabelecida), o desempenho dificilmente é afetado.
Assim que o servidor ipipou recebe um pacote autenticado, um túnel é criado e todos os pacotes subsequentes na conexão já são processados pelo kernel ignorando nfqueue. Se a conexão estiver ruim, o primeiro pacote do próximo será enviado para a fila nfqueue, dependendo das configurações, se não for um pacote de autenticação, mas do último IP lembrado e porta do cliente, ele pode ser transmitido ou descartado. Se um pacote autenticado vier de um novo IP e porta, o túnel será reconfigurado para usá-los.
O IPIP-over-FOU usual tem outro problema ao trabalhar com NAT - você não pode criar dois túneis IPIP encapsulados em UDP com o mesmo IP, porque os módulos FOU e IPIP estão bastante isolados um do outro. Essa. um par de clientes atrás de um IP público não será capaz de se conectar simultaneamente ao mesmo servidor desta forma. No futuro, pode ser resolvido no nível do kernel, mas isso não é certo. Enquanto isso, problemas de NAT podem ser resolvidos por NAT - se acontecer de um par de endereços IP já estar ocupado por outro túnel, ipipou fará o NAT do IP público para um IP privado alternativo, voila! - você pode criar túneis até que as portas se esgotem.
Porque nem todos os pacotes na conexão são assinados, então essa proteção simples é vulnerável ao MITM, então se um vilão se esconde no caminho entre o cliente e o servidor, que pode ouvir e controlar o tráfego, ele pode redirecionar os pacotes autenticados por outro endereço e criar um túnel a partir de um host não confiável ...
Se alguém tiver alguma ideia sobre como consertar isso, mantendo a maior parte do tráfego no núcleo, sinta-se à vontade para falar.
A propósito, o encapsulamento UDP se provou muito bem. Comparado ao encapsulamento sobre IP, é muito mais estável e geralmente mais rápido, apesar da sobrecarga adicional do cabeçalho UDP. Isso se deve ao fato de que a maioria dos hosts na Internet funciona razoavelmente bem apenas com os três protocolos mais populares: TCP, UDP, ICMP. A parte perceptível geralmente pode descartar todo o resto, ou processar mais lentamente, porque é otimizada apenas para esses três.
Por exemplo, portanto, QUICK, com base no qual HTTP / 3 foi criado, foi criado por UDP, e não por IP.
Bem, palavras suficientes, é hora de ver como funciona no "mundo real".
Batalha
Usado para emular o mundo real
iperf3. Em termos de grau de proximidade com a realidade, trata-se da emulação do mundo real no Minecraft, mas por enquanto servirá.
A competição envolve:
- canal mestre de referência
- o herói deste artigo é ipipou
- OpenVPN com autenticação, mas sem criptografia
- OpenVPN All Inclusive
- WireGuard sem PresharedKey, com MTU = 1440 (para IPv4 apenas)
Dados técnicos para geeks
As métricas são obtidas pelos seguintes comandos
no cliente:
UDP
TCP
Latência ICMP
( ):
UDP
TCP
ipipou
openvpn ( , )
openvpn (c , , UDP, )
openvpn-manage
wireguard
no cliente:
UDP
CPULOG=NAME.udp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -c SERVER_IP -4 -t 60 -f m -i 10 -B LOCAL_IP -P 2 -u -b 12M; tail -1 "$CPULOG"
# "-b 12M" , "-P", .
TCP
CPULOG=NAME.tcp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -c SERVER_IP -4 -t 60 -f m -i 10 -B LOCAL_IP -P 2; tail -1 "$CPULOG"
Latência ICMP
ping -c 10 SERVER_IP | tail -1
( ):
UDP
CPULOG=NAME.udp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -s -i 10 -f m -1; tail -1 "$CPULOG"
TCP
CPULOG=NAME.tcp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -s -i 10 -f m -1; tail -1 "$CPULOG"
ipipou
/etc/ipipou/server.conf:
server
number 0
fou-dev eth0
fou-local-port 10000
tunl-ip 172.28.0.0
auth-remote-pubkey-b64 eQYNhD/Xwl6Zaq+z3QXDzNI77x8CEKqY1n5kt9bKeEI=
auth-secret topsecret
auth-lifetime 3600
reply-on-auth-ok
verb 3
systemctl start ipipou@server
/etc/ipipou/client.conf:
client
number 0
fou-local @eth0
fou-remote SERVER_IP:10000
tunl-ip 172.28.0.1
# pubkey of auth-key-b64: eQYNhD/Xwl6Zaq+z3QXDzNI77x8CEKqY1n5kt9bKeEI=
auth-key-b64 RuBZkT23na2Q4QH1xfmZCfRgSgPt5s362UPAFbecTso=
auth-secret topsecret
keepalive 27
verb 3
systemctl start ipipou@client
openvpn ( , )
openvpn --genkey --secret ovpn.key # ovpn.key
openvpn --dev tun1 --local SERVER_IP --port 2000 --ifconfig 172.16.17.1 172.16.17.2 --cipher none --auth SHA1 --ncp-disable --secret ovpn.key
openvpn --dev tun1 --local LOCAL_IP --remote SERVER_IP --port 2000 --ifconfig 172.16.17.2 172.16.17.1 --cipher none --auth SHA1 --ncp-disable --secret ovpn.key
openvpn (c , , UDP, )
openvpn-manage
wireguard
/etc/wireguard/server.conf:
[Interface]
Address=172.31.192.1/18
ListenPort=51820
PrivateKey=aMAG31yjt85zsVC5hn5jMskuFdF8C/LFSRYnhRGSKUQ=
MTU=1440
[Peer]
PublicKey=LyhhEIjVQPVmr/sJNdSRqTjxibsfDZ15sDuhvAQ3hVM=
AllowedIPs=172.31.192.2/32
systemctl start wg-quick@server
/etc/wireguard/client.conf:
[Interface]
Address=172.31.192.2/18
PrivateKey=uCluH7q2Hip5lLRSsVHc38nGKUGpZIUwGO/7k+6Ye3I=
MTU=1440
[Peer]
PublicKey=DjJRmGvhl6DWuSf1fldxNRBvqa701c0Sc7OpRr4gPXk=
AllowedIPs=172.31.192.1/32
Endpoint=SERVER_IP:51820
systemctl start wg-quick@client
resultados
Tablet Feio Cru
CPU , .. :
proto bandwidth[Mbps] CPU_idle_client[%] CPU_idle_server[%]
# 20 Mbps (4 core) VPS (1 core)
# pure
UDP 20.4 99.80 93.34
TCP 19.2 99.67 96.68
ICMP latency min/avg/max/mdev = 198.838/198.997/199.360/0.372 ms
# ipipou
UDP 19.8 98.45 99.47
TCP 18.8 99.56 96.75
ICMP latency min/avg/max/mdev = 199.562/208.919/220.222/7.905 ms
# openvpn0 (auth only, no encryption)
UDP 19.3 99.89 72.90
TCP 16.1 95.95 88.46
ICMP latency min/avg/max/mdev = 191.631/193.538/198.724/2.520 ms
# openvpn (full encryption, auth, etc)
UDP 19.6 99.75 72.35
TCP 17.0 94.47 87.99
ICMP latency min/avg/max/mdev = 202.168/202.377/202.900/0.451 ms
# wireguard
UDP 19.3 91.60 94.78
TCP 17.2 96.76 92.87
ICMP latency min/avg/max/mdev = 217.925/223.601/230.696/3.266 ms
## -1Gbps VPS (1 core)
# pure
UDP 729 73.40 39.93
TCP 363 96.95 90.40
ICMP latency min/avg/max/mdev = 106.867/106.994/107.126/0.066 ms
# ipipou
UDP 714 63.10 23.53
TCP 431 95.65 64.56
ICMP latency min/avg/max/mdev = 107.444/107.523/107.648/0.058 ms
# openvpn0 (auth only, no encryption)
UDP 193 17.51 1.62
TCP 12 95.45 92.80
ICMP latency min/avg/max/mdev = 107.191/107.334/107.559/0.116 ms
# wireguard
UDP 629 22.26 2.62
TCP 198 77.40 55.98
ICMP latency min/avg/max/mdev = 107.616/107.788/108.038/0.128 ms
canal para 20 Mbps
canal para 1 Gbps otimista
Em todos os casos o ipipou está bem próximo em termos de desempenho do canal base, e isso é ótimo!
O túnel openvpn não criptografado se comportou de maneira bastante estranha em ambos os casos.
Se alguém for testá-lo, será interessante ouvir o feedback.
Que o IPv6 e o NetPrickle estejam conosco!