1 Introdução
Este documento é uma especificação textual do protocolo Tox e todos os módulos de suporte necessários para implementá-lo. O objetivo deste documento é fornecer orientação suficiente para garantir uma implementação completa e correta do protocolo.
Todos os tipos de dados são definidos antes de seu primeiro uso e sua representação binária no protocolo é fornecida. As exibições de protocolo são normativas e devem ser implementadas exatamente conforme especificado. Para alguns tipos, são fornecidas representações legíveis por humanos. Uma implementação pode optar por não ter essa representação ou uma representação diferente. Uma implementação PODE escolher qualquer representação de memória para os tipos especificados, desde que possam ser codificados e decodificados a partir da representação de protocolo especificada.
Os formatos binários são especificados em tabelas com comprimento, tipo e conteúdo. Quando aplicável, tipos de enumeração específicos são usados, portanto, os tipos podem ser inexplicáveis em alguns casos. O comprimento pode ser um número fixo em bytes (por exemplo, 32), um número em bits (por exemplo, 7 bits), um comprimento escolhido (por exemplo, 4 | 16) ou um intervalo aberto (por exemplo, [0, 100]). Intervalos abertos são indicados por [n,], o que significa um comprimento mínimo de n sem comprimento máximo especificado.
1.1 Alvos e Modelo de Ameaça
(TODO: este é apenas um local para inserir; é necessária uma descrição mais técnica)
Esta seção deve dar uma ideia dos propósitos e não-alvos do Tox para que o leitor:
entendeu quais problemas o Tox pretendia resolver
poderia verificar se eles são resolvidos pela especificação fornecida
poderia fazer os melhores compromissos e decisões em sua própria implementação do protocolo.
1.1.1 O que o Tox faz
1.1.1.1 Autenticação
O endereço do usuário é sua chave pública, então "adicionar um amigo" na verdade significa verificar a chave. A desvantagem é que após o comprometimento (divulgar a chave secreta) você terá que gerar uma nova identidade.
1.1.1.2 Criptografia de ponta a ponta
Todas as mensagens são criptografadas com chaves derivadas de DH, portanto, as chaves são conhecidas apenas pelo remetente e pelo destinatário e nunca são transmitidas pela rede.
1.1.1.2.1 Total sigilo de encaminhamento
Obtido com chaves efêmeras (TODO: como são usadas no protocolo atual? o problema foi resolvido?).
1.1.1.3 Confiabilidade
Tox deve ser uma rede totalmente distribuída que não dependa de nenhum ponto único de falha. Isso é obtido por meio do uso de conexões DHT e diretas (P2P) entre pares na rede. Um ponto de entrada ainda é necessário. O processo de conexão a uma rede é chamado de bootstrapping. Bootstrapping pode e deve ser feito usando vários pontos de entrada.
Tox deve funcionar em (quase) qualquer tipo de NAT e firewall; isso é obtido por meio do uso de perfuração, UPnP e retransmissão TCP.
Resiliência aos principais DoS e outros ataques.
1.1.1.4 Zero-conf (Facilidade de uso)
O usuário final deve ser capaz de usar um mensageiro que simplesmente funcione. A segurança que é muito difícil de usar é inútil.
1.1.2 O que não está no Tox
1.1.2.1 Anonimato
Se o modo TCP não for usado, os participantes se comunicam diretamente entre si. Uma razão para isso é que a transmissão de vídeo ao vivo usando qualquer coisa que não seja uma conexão direta é bastante cara (em termos de largura de banda) e também significa atrasos.
Seu endereço IP é visível para hosts em sua lista de amigos. Eles podem vincular seu ID diretamente ao seu endereço IP.
As pesquisas de amigos usam nós DHT temporários e túneis de cebola, portanto, seu ID não pode ser vinculado ao seu IP com base apenas em dados públicos (TODO: por exemplo, dados armazenados no DHT? o que mais está aberto?); Enquanto um adversário interceptando o tráfego em um segmento de rede suficientemente grande é (provavelmente) capaz de realizar algum tipo de ataque estatístico; (TODO: que problema isso deve resolver? resolve? Como não nos importamos com o anonimato, só consigo pensar em impedir alguns ataques direcionados de negação de serviço.)
Caso o anonimato seja um problema, o Tox pode ser proxy por meio de um proxy HTTP ou SOCKS5. Para anonimato, você deve usar o modo somente TCP.
1.2 Inteiros
O protocolo usa quatro tipos inteiros não assinados restritos. Bounded significa que eles têm um limite superior além do qual o incremento não é definido. Tipos inteiros suportam aritmética modular, portanto, o estouro desaparece. Tipos sem sinal significam que seu limite inferior é 0. Tipos inteiros com sinal não são usados. A codificação binária de todos os tipos inteiros é uma sequência de bytes de largura fixa com a codificação inteira em Big Endian , salvo indicação em contrário.
Digite o nome tipo C tipo de ferrugem Comprimento limite superior
Palavra8 uint8_t u8 1 255 (0xff)
Palavra16 uint16_t u16 2 65535 (0xffff)
Palavra32 uint32_t u32 4 4294967295 (0xffffffff)
Palavra64 uint64_t u64 8 18446744073709551615 (0xffffffffffffffffff)
1.3 Strings
Uma string é uma estrutura de dados usada para texto legível por humanos. Linhas são sequências de glifos. Um glifo consiste em um ponto de código Unicode de largura diferente de zero e zero ou mais pontos de código Unicode de largura zero. A representação legível por humanos de uma string começa e termina com aspas (") e contém todos os glifos legíveis por humanos em sua totalidade. Os caracteres de controle são representados isomorficamente à representação legível por humanos. Ou seja, cada caractere de controle tem exatamente um - representação legível e há um mapeamento da representação legível por humanos para o caractere de controle. Portanto, o uso de caracteres de controle Unicode (U+240x) não é permitido sem token adicional
2 Crypto
O módulo Crypto contém todas as funções e tipos de dados relacionados à criptografia. Isso inclui geração de número aleatório, criptografia e descriptografia, geração de chave, operações nonce e geração aleatória nonce.
2.1 Chave
Um número criptográfico é um inteiro grande, sem sinal (positivo) de tamanho fixo. Sua codificação binária é um inteiro com um grande número final exatamente de acordo com o tamanho do byte codificado. A codificação legível por humanos é um número de base 16 codificado como String. A implementação de libsodium NaCl fornece as funções de sódio_bin2hex e sódio_hex2bin para ajudar a implementar a codificação legível por humanos. A codificação de memória desses números criptográficos em NaCl já satisfaz a codificação binária, portanto, para aplicativos que usam diretamente essas APIs, a codificação e decodificação binária é uma função de identificação.
Tox usa quatro tipos de criptonúmeros:
tipo bits tamanho do byte codificado
chave pública 256 32
Chave secreta 256 32
Chave Combinada 256 32
nonce 192 24
2.1.1 Par de chaves
Um par de chaves é um par de chaves públicas e privadas. Um novo par de chaves é gerado usando a função crypto_box_keypair da biblioteca de criptografia NaCl. Duas chamadas separadas para a função de geração do par de chaves devem retornar pares de chaves diferentes. Consulte a documentação do NaCl para obter detalhes.
A chave pública pode ser calculada a partir da chave privada usando a função NaCl crypto_scalarmult_base, que calcula o produto escalar do elemento de grupo padrão e a chave privada. Consulte a documentação do NaCl para obter detalhes.
2.1.2 Tecla de combinação
A chave combinada é calculada a partir das chaves pública e privada usando a função NaCl crypto_box_beforenm. Dados dois pares de chaves KP1 (SK1, PK1) e KP2 (SK2, PK2), então a chave combinada calculada de (SK1, PK2) é igual à chave calculada de (SK2, PK1). Isso permite a criptografia simétrica porque as redes peer podem derivar a mesma chave pública de sua chave privada e da chave pública do peer.
No protocolo Tox, os pacotes são criptografados usando a chave pública do destinatário e a chave privada do remetente. O destinatário descriptografa os pacotes usando a chave privada do destinatário e a chave pública do remetente.
O fato de a mesma chave ser usada para criptografar e descriptografar pacotes em ambos os lados significa que os pacotes enviados podem ser retransmitidos de volta ao remetente, se nada impedir isso.
A geração de uma chave pré-compartilhada é a parte mais intensiva de recursos da criptografia/descriptografia, o que significa que o uso de recursos pode ser bastante reduzido armazenando chaves pré-compartilhadas e reutilizando-as tanto quanto possível.
2.1.3 Nonce
Um nonce aleatório é gerado usando um gerador de números aleatórios criptograficamente seguro da biblioteca NaCl randombytes.
O valor do nonce é incrementado interpretando-o como um Big Endian e adicionando 1. Se o nonce tiver um valor máximo, o valor após o incremento será 0.
A maioria das partes do protocolo usa nes aleatório. Isso evita que novos nes sejam associados aos anteriores. Se muitos pacotes diferentes puderem ser agrupados devido à forma como os innes são gerados, isso poderá resultar, por exemplo, em pacotes agrupados de anúncios de cebola e DHT. Isso introduziria uma falha no sistema, pois os inimigos poderiam agrupar as chaves DHT e as chaves de longo prazo de algumas pessoas.
2.2 Box
O protocolo Tox distingue entre dois tipos de texto: Texto Simples e Texto Cifrado. O texto cifrado pode ser transmitido por canais de transmissão de dados não confiáveis. O texto normal pode ser confidencial ou insensível. O texto simples sensível deve ser convertido em texto cifrado usando uma função de criptografia antes que possa ser transmitido por links de dados não confiáveis.
A função de criptografia pega a chave combinada, chave de código, texto simples e retorna o texto cifrado. Ele usa crypto_box_afternm para executar a criptografia. O significado da frase "criptografia com chave privada, chave pública e nonce" é calcular a chave combinada da chave privada e da chave pública e, em seguida, usar a função de criptografia para converter.
A função de descriptografia pega a chave combinada, o nonce e o texto cifrado e retorna o texto simples ou um erro. Ele usa crypto_box_open_afternm da biblioteca NaCl. Como a cifra é simétrica, a função de criptografia também pode realizar a descriptografia, mas não autenticará a mensagem, portanto, a implementação deve ter cuidado para usar as funções corretas.
crypto_box usa criptografia simétrica xsalsa20 e autenticação poly1305.
As funções de solicitação de criação e manipulação são funções de criptografia e descriptografia para o tipo de pacote DHT usado para enviar dados diretamente para outros nós DHT. Honestamente, eles deveriam estar no módulo DHT, mas parecem se encaixar melhor aqui. TODO: Quais são exatamente esses recursos?
3 Informações do nó
3.1 Protocolo de transporte
O protocolo de transporte é um protocolo da camada de transporte localizado diretamente abaixo do próprio protocolo Tox. Tox suporta dois protocolos de transporte: UDP e TCP. A representação binária do protocolo de transporte é um bit: 0 para UDP, 1 para TCP. Se um bit for codificado como um único valor, ele será armazenado no bit menos significativo do byte. Se for seguido por outros dados compactados em bits, ocupa exatamente um bit.
A representação legível por humanos para UDP é UDP e para TCP é TCP.
3.2 Endereço do host
Um endereço de host é um endereço IPv4 ou IPv6. A representação binária de um endereço IPv4 é um inteiro não assinado de 32 bits Big Endian (4 bytes). Para um endereço IPv6, este é um inteiro não assinado de 128 bits Big Endian (16 bytes). A representação binária de um endereço de host é um inteiro sem sinal de 7 bits que especifica a família de endereços (2 para IPv4, 10 para IPv6) seguido do próprio endereço.
Portanto, quando empacotado junto com o protocolo de transporte, o primeiro bit do byte compactado é o protocolo e os próximos 7 bits são a família de endereços.
3.3 Número da porta
O número da porta é um número de 16 bits. Sua representação binária é um grande número inteiro sem sinal finito de 16 bits (2 bytes).
Comprimento tipo contente
1 bit protocolo de transporte UDP=0, TCP=1
7 bits Endereço Família 2=IPv4, 10=IPv6
4 | 16 endereço de IP 4 bytes para IPv4, 16 bytes para IPv6
2 número da porta número da porta
32 chave pública ID do nó
O formato de nó compactado é uma forma de armazenar informações sobre os nós em um formato pequeno, mas analisável. Para manter mais de um nó, basta adicionar outro nó ao anterior: [nó compactado 1][nó compactado 2][...].
No formato de host compactado, o primeiro byte (o bit mais significativo do protocolo, os 7 bits menos significativos da família de endereços) é chamado de tipo IP. A tabela a seguir é informativa e pode ser usada para simplificar a implementação.
Tipo de IP protocolo de transporte Endereço Família
2 (0x02) UDP IPv4
10 (0x0a) UDP IPv6
130 (0x82) TCP IPv4
138 (0x8a) TCP IPv6
O número 130 é usado para retransmissões IPv4 TCP e 138 é usado para retransmissões IPv6 TCP.
A razão para esses números é que no Linux os números para IPv4 e IPv6 (definidos por AF_INET e AF_INET6) são 2 e 10. Os números TCP são simplesmente números UDP + 128. 4 Pacote de protocolo Um pacote de protocolo é um elemento de nível superior do
Protocolo tox
. Todos os outros tipos de pacotes são agrupados em pacotes de protocolo. Consiste em um tipo de pacote e uma carga útil. A representação binária do tipo de pacote é um byte (8 bits). A carga útil é uma sequência arbitrária de bytes.
Comprimento tipo contente
1 tipo de pacote O identificador de tipo de pacote
[0,] bytes carga útil
Esses pacotes de nível superior podem ser transmitidos de várias maneiras, sendo a mais comum a transmissão por uma rede usando UDP ou TCP. O protocolo em si não prescreve métodos de transporte e uma implementação é gratuita para implementar transportes adicionais, como WebRTC, IRC ou pipes.
Ao longo do restante do documento, os vários tipos de pacotes de protocolo são especificados com o tipo de pacote e a carga útil. A aparência do pacote não é repetida na descrição da carga útil (TODO: na verdade, a maioria é repetida, mas não será repetida mais tarde).
Dentro da carga de pacotes de protocolo, outros tipos de pacotes podem indicar tipos adicionais de pacotes. Por exemplo, dentro do pacote Crypto Data (0x1b), o módulo Messenger define seus próprios protocolos para mensagens, transferência de arquivos e assim por diante. Os pacotes de protocolo da camada superior não são criptografados, embora sua carga útil possa ser criptografada.
4.1 Tipos de pacotes
Abaixo está uma lista abrangente de tipos de pacotes de nível superior e seu número. Sua carga útil está listada em seções especiais. Cada seção é nomeada de acordo com o tipo de pacote que descreve, seguida por um valor de byte entre parênteses, como Solicitação de Ping (0x00).
valor do byte tipo de pacote
0x00 Solicitação de ping
0x01 Resposta do ping
0x02 Solicitação de nós
0x04 Resposta dos nós
0x18 Solicitação de Cookie
0x19 Resposta do Cookie
0x1a Aperto de mão criptográfico
0x1b Dados criptográficos
0x20 Solicitação DHT
0x21 Descoberta LAN
0x80 Cebola Pedido 0
0x81 Cebola Pedido 1
0x82 Cebola Pedido 2
0x83 Solicitação de anúncio
0x84 Anunciar resposta
0x85 Solicitação de dados de cebola
0x86 Resposta de Dados Onion
0x8c Resposta Cebola 3
0x8d Resposta Cebola 2
0x8e Resposta Cebola 1
0xf0 Informações de Bootstrap
5 DHT
DHT é um complexo auto-organizado de todos os nós da rede Tox. Um nó em uma rede Tox também é chamado de "nó Tox". Quando falamos de "pares" queremos dizer qualquer nó que não seja um nó local (assunto). Este módulo se encarrega de encontrar o IP e a porta dos hosts e estabelecer uma rota para eles diretamente via UDP, usando perfuração, se necessário. O DHT só funciona em UDP e, portanto, só é usado se o UDP estiver funcionando.
Cada nó no Tox DHT possui um par de chaves efêmero chamado par de chaves DHT, que consiste em uma chave DHT privada e uma chave DHT pública. A chave pública DHT serve como o endereço do host. O par de chaves DHT é atualizado cada vez que a instância tox é fechada ou reiniciada. A implementação pode atualizar a chave com mais frequência, mas isso fará com que todos os pares sejam desabilitados.
A chave pública DHT de um amigo pode ser encontrada usando o módulo onion. Quando a chave pública DHT de um amigo é conhecida, o DHT é usado para procurá-la e conectar-se diretamente a eles por UDP.
5.1 Distância
A Distância é um número inteiro positivo. Sua representação legível por humanos é um número de base 16. Distância (tipo) é um monóide ordenado com um operador binário associativo + e elemento de identidade 0.
DHT usa uma métrica para determinar a distância entre dois nós. O tipo Distância é um contradomínio dessa métrica. Atualmente, a métrica utilizada pelo Tox DHT é o XOR das chaves públicas dos nós: distance(x, y) = x XOR y. Para esses cálculos, as chaves públicas são interpretadas como números inteiros grandes (consulte Cryptonumbers).
Quando falamos de um "nó próximo" queremos dizer que sua distância ao nó em questão é pequena em comparação com a distância a outros nós.
Uma implementação não é obrigada a fornecer um tipo de distância, portanto, não possui uma representação binária definida. Por exemplo, em vez de calcular uma Distância e compará-la com outra Distância, uma implementação pode optar por implementar Distância como um par de chaves públicas e definir uma ordenação em Distância sem calcular o valor cumulativo total. Isso funciona porque, uma vez que a decisão de ordenação pode ser feita nos bits mais significativos, os bits subsequentes não afetarão essa decisão.
XOR é uma métrica válida, ou seja, satisfaz as condições necessárias:
Distância de não negatividade(x, y) >= 0: Como as chaves públicas são criptonúmeros positivos por definição, seu XOR é necessariamente positivo.
Identidade de números não negativos distance(x, y) == 0 iff x == y: XOR de dois inteiros é zero se eles forem iguais.
Symmetry distance(x, y) == distance(y, x): XOR é uma operação simétrica.
Subaditividade distância(x, z) <= distância(x, y) + distância(y, z): segue da associatividade desde que x XOR z = x XOR (y XOR y) XOR z = distância(x, y) XOR distância( y, z), que não é maior que distance(x, y) + distance(y, z).
Além disso, XOR tem outras propriedades úteis:
Unidirecional: para uma chave x e uma distância d, existe uma e apenas uma chave y tal que distance(x, y) = d.
Segue-se que pesquisas repetidas provavelmente seguirão o mesmo caminho, portanto, o armazenamento em cache faz sentido.
Fonte: maymounkov-kademlia
Exemplo: Dados três nós com as chaves 2, 5 e 6:
2 XOR 5 = 7
2 XOR 6 = 4
5 XOR 2 = 7
5 XOR 6 = 3 6
XOR 2 = 4 6
XOR 5 = 3
Nó mais próximo de 2 e 5 é 6. O nó mais próximo de 6 é 5 com 3 removido. Este exemplo mostra que uma chave que é próxima em termos de adição de número inteiro não é necessariamente próxima em termos de XOR.
5,2 K-baldes
K-buckets é uma estrutura de dados para armazenar eficientemente um conjunto de nós próximos a uma chave específica, chamada de chave base. A chave base é constante durante todo o tempo de vida da instância de k-buckets.
k-buckets é um mapa de pequenos inteiros 0 <= n < 256 em um conjunto de até k nós de informação. O conjunto é chamado de balde. k é chamado de tamanho do balde. Por padrão, o tamanho do depósito é 8.
O número n acima é o índice do depósito. Este é um número inteiro positivo com intervalo [0, 255], ou seja, o intervalo de um inteiro sem sinal de 8 bits.
elemento balde - este elemento é um conjunto ordenado e as entradas são classificadas por distância da chave base. Assim, o primeiro (menor) elemento de um conjunto é o mais próximo da chave base nesse conjunto, o último (maior) elemento é o mais distante.
5.2.1 Índice de bucket
O índice de bucket pode ser calculado usando a seguinte função: bucketIndex(baseKey, nodeKey) = 255 - log_2(distance(baseKey, nodeKey)). Esta função não é definida quando baseKey == nodeKey, o que significa que o k-bucket nunca conterá informações do nó sobre o nó base.
Assim, cada k-bucket contém apenas Node Infos, para as chaves das quais o seguinte é verdadeiro: se o nó com a chave nodeKey estiver no k-bucket com índice n, então bucketIndex(baseKey, nodeKey) == n. Assim, o n'ésimo k-balde consiste em nós para os quais a distância até o nó base está no intervalo [2^n, 2^(n+1) - 1].
O índice do balde pode ser calculado eficientemente determinando o primeiro bit onde as duas chaves diferem, começando com o bit mais significativo. Portanto, se a chave DHT local começar, por exemplo, com 0x80 e a chave do nó com o balde começar com 0x40, o índice do balde para esse nó será 0. Se o segundo bit for diferente, o índice do balde será 1. Se as chaves forem quase as mesmas e apenas a última diferir em bits, então o índice do bucket é 255.
5.2.2 Atualizando k-buckets
TODO: isso difere da política do kademlia de menor tempo de check-out; por que a solução existente foi escolhida, como ela afeta a segurança, o desempenho e a resistência ao envenenamento? O artigo original afirma que favorecer nós ativos antigos resulta em melhor resiliência e resistência a ataques DDoS básicos;
Qualquer operação de atualização ou pesquisa em uma instância de k-buckets que envolva um único nó requer que primeiro calculemos o índice de bucket para esse nó. Uma atualização envolvendo informações do nó com nodeKey == baseKey não tem efeito. Se a atualização resultar em um elemento vazio, esse elemento será removido do mapa. Um bloco está cheio se contiver o número máximo de registros especificado pelo tamanho do bloco.
Um nó é viável para um registro se o balde estiver vazio ou se a chave pública do nó tiver uma distância menor da chave base do que o registro atual com a distância mais longa. Se o nó estiver ativo e o depósito estiver cheio, a entrada com a maior distância da chave base será removida para que o tamanho do depósito não exceda o tamanho máximo do depósito configurado. Adicionar um nó
cuja chave já existe atualiza as informações do nó no balde. A remoção de um nó para o qual não existe nenhuma informação de nó no k-bucket não tem efeito. Portanto, excluir um nó duas vezes é permitido e tem o mesmo efeito de excluí-lo uma vez.
5.3 Estado do nó DHT
Cada nó DHT contém um par de chaves chamado par de chaves DHT.
O nó DHT também armazena um conjunto de informações do nó que estão próximas de sua própria chave pública DHT. Para isso, a estrutura de dados k-buckets é usada e a chave pública DHT local é usada como chave base.
5.4 Auto-organização
A auto-organização em DHT ocorre conectando cada par DHT a um número arbitrário de pares mais próximos de sua própria chave pública DHT e alguns mais distantes.
Se cada par na rede conhece pares com uma chave pública DHT mais próxima de sua chave pública DHT, então, para encontrar um par particular com chave pública X, é suficiente para um par consultar recursivamente pares no DHT para pares conhecidos com DHT público chaves mais próximas de X. Finalmente, eventualmente, o peer encontrará os peers no DHT que estão mais próximos a esse peer e, se esse peer estiver online, ele os encontrará.
5.5 Pacote DHT
O Pacote DHT contém a chave pública DHT do remetente, o Nonce de criptografia e a carga útil criptografada. A carga útil é criptografada com a chave DHT privada do remetente, a chave pública DHT do destinatário e um nonce que é enviado com o pacote. Os pacotes DHT são enviados dentro de pacotes de protocolo com um tipo de pacote variável.
Comprimento tipo contente
32 chave pública Chave pública DHT do remetente
24 nonce Nonce aleatório
[16,] bytes Carga útil criptografada
O comprimento da carga criptografada é de pelo menos 16 bytes porque a criptografia inclui um MAC de 16 bytes. Portanto, uma carga útil de 16 bytes seria uma mensagem vazia. O protocolo DHT nunca envia mensagens nulas, portanto, o tamanho mínimo real do pacote Ping é de 27 bytes.
5.6 Serviços RPC
O serviço RPC DHT consiste em um pacote de solicitação e um pacote de resposta. O pacote DHT RPC contém a carga útil e o ID da solicitação. Esse identificador é um número inteiro sem sinal de 64 bits que ajuda a identificar a resposta para uma determinada solicitação. O ID do pedido no pacote de resposta deve ser igual ao ID do pedido ao qual está respondendo.
Os pacotes DHT RPC são criptografados e enviados dentro de pacotes DHT.
Comprimento tipo contente
[0,] bytes carga útil
8 uint64_t Identificação do Pedido
O tamanho mínimo da carga útil é 0, mas, na realidade, o menor tamanho razoável da carga útil é 1. Como ambas as direções de comunicação usam a mesma chave simétrica, uma solicitação criptografada será uma resposta criptografada válida se contiver o mesmo texto simples.
As partes do protocolo que usam pacotes RPC devem tomar cuidado para que a carga de solicitação não seja a carga de resposta real. Por exemplo, os pacotes Ping carregam um sinalizador booleano que indica se a carga útil corresponde a uma solicitação ou resposta.
O ID da solicitação fornece alguma resistência a ataques de repetição. Se não houvesse um identificador de solicitação, seria fácil para um invasor reproduzir respostas antigas e, assim, fornecer aos nós informações desatualizadas. O valor exato do ID da solicitação será especificado posteriormente na seção DHT.
5.6.1 O serviço Ping
O serviço Ping é utilizado para verificar periodicamente se outro nó ainda está ativo.
A carga útil de um pacote Ping consiste apenas em um valor booleano indicando se é uma solicitação ou uma resposta.
Um valor booleano de um byte é adicionado dentro da carga útil criptografada para impedir que os pares gerem uma resposta Ping válida de uma solicitação Ping sem descriptografar o pacote e criptografar um novo. Como a criptografia simétrica é usada, a resposta de ping criptografada será igual em bytes à solicitação de ping sem o byte de diferença.
Comprimento tipo contente
1 Bool Sinalizador de resposta: 0x00 para solicitação, 0x01 para resposta
5.6.1.1 Solicitação de ping (0x00)
Uma solicitação de ping é um pacote de ping com o sinalizador de resposta definido como falso. Quando uma solicitação de ping é recebida e decodificada com sucesso, um pacote de resposta de ping é criado e enviado de volta ao solicitante.
5.6.1.2 Resposta Ping (0x01)
Uma Resposta Ping é um pacote Ping com o sinalizador de resposta definido como Verdadeiro.
5.6.2 Serviço de Nodos
O Serviço de Nodos é utilizado para consultar outro nodo DHT até 4 nodos conhecidos por ele que estejam mais próximos do nodo solicitado.
O serviço DHT Nodes RPC usa o formato de nó compactado.
5.6.2.1 Nós de solicitação (0x02)
Comprimento tipo contente
32 chave pública Chave pública DHT solicitada
A chave pública DHT enviada na solicitação é consultada pelo remetente.
5.6.2.2 Resposta do nó (0x04 )
Comprimento tipo contente
1 int Número de nós na resposta (máximo 4)
[39, 204] Informações do nó Nós no formato de nós compactados
Um host IPv4 tem 39 bytes, um host IPv6 tem 51 bytes, então o tamanho máximo é 51 * 4 = 204 bytes.
As respostas de nó devem conter os 4 nós mais próximos que o remetente da resposta possui em sua lista de nós conhecidos.
5.7 Como funciona o DHT
Apenas o protocolo UDP (IP Tipo 2 e 10) é usado no módulo DHT ao enviar nós com formato de nó compactado. Isso ocorre porque o protocolo TCP é usado para enviar informações de retransmissão TCP, enquanto o DHT é apenas UDP.
Isso é feito para aumentar a velocidade de localização de pares. O Toxcore também mantém os 8 nós (eles devem ser iguais ou menores que os nós que o Toxcore mantém para cada índice em sua lista fechada para garantir que todos os pares mais próximos que encontrar conheçam o nó que está sendo pesquisado) mais próximos de cada uma das chaves públicas em sua lista de amigos DHT (ou na lista de chaves DHT públicas que ele está tentando encontrar e conectar). O Toxcore faz ping em cada nó nas listas a cada 60 segundos para ver se está ativo. Ele não se armazena em nenhuma das listas e não envia nenhuma solicitação para si mesmo. Os nós podem estar em mais de uma lista, por exemplo, se a chave pública DHT do peer estiver muito próxima da chave pública DHT do amigo que está sendo procurado. Ele também envia solicitações get node para um nodo aleatório (a aleatoriedade o torna imprevisível, previsibilidade, ou saber qual nó fará o ping em seguida, pode aliviar alguns ataques de interrupção de rede adicionando um possível vetor de ataque) em cada uma dessas listas de nós a cada 20 segundos, com a chave pública de pesquisa sendo sua chave pública para o nó mais próximo e pública chaves de pesquisa - aquelas na lista de amigos do DHT. Os nós são removidos após 122 segundos sem resposta. Os nós são adicionados às listas depois de receber um ping válido ou enviar uma resposta de nó deles. Se o nó já estiver na lista, ele será atualizado se seu endereço IP for alterado. Um nó só pode ser adicionado à lista se a lista não estiver completa ou se a chave pública DHT do nó estiver mais próxima do que a chave pública DHT de pelo menos um dos nós da lista para a chave pública que está sendo procurada no lista. Quando um nó é adicionado à lista completa,
Aumentar o número de nós para 32 aumentará o número de pacotes necessários para verificar se cada um está ativo, o que aumentará o uso da largura de banda, mas melhorará a confiabilidade. Se o número de nós fosse reduzido, a confiabilidade diminuiria junto com o uso da largura de banda. A razão para esta relação entre a confiabilidade e o número de nós é que, se assumirmos que nem todos os nós têm portas UDP abertas ou estão atrás do NAT, isso significa que cada um desses nós deve ser capaz de armazenar um certo número de nós atrás do NAT, então que outros possam encontrar esses hosts por trás do NAT. Por exemplo, se 7/8 hosts estiverem atrás do NAT, usar 8 hosts não será suficiente, pois a probabilidade de algum desses hosts não ser encontrado na rede será muito alta. Se os tempos limite de ping e os atrasos entre pings fossem maiores, isso reduziria o uso da largura de banda, mas aumentaria o número de nós desconectados que ainda estão armazenados nas listas. Reduzir esses atrasos teria o efeito oposto.
Aumentar o número de hosts mais próximos de cada chave pública de 8 para 16 aumenta o uso da largura de banda, pode melhorar a eficácia dos ataques NAT simétricos e melhorar a confiabilidade. Reduzir esse número terá o efeito oposto.
Ao receber um pacote de nó de envio, o toxcore verifica se cada um dos nós recebidos pode ser adicionado a qualquer uma das listas. Se o host puder ser adicionado, o toxcore envia um pacote de ping, se não puder, ele o ignora. Ao receber um pacote get node, o toxcore encontrará os 4 nós em suas listas de nós que estão mais próximos da chave pública no pacote e os enviará na resposta do nó de envio. Os tempos limite e o número de nós nas listas para toxcore foram escolhidos puramente pelo tato e provavelmente não são os melhores valores. Isso também se aplica a comportamentos simples e que precisam ser aprimorados para tornar a rede mais resistente a ataques sybil.
5.8 pacotes de solicitação DHT
Comprimento contente
1 uint8_t(0x20)
32 chave pública DHT do receptor
32 chave pública DHT do remetente
24 nonce
? mensagem criptografada
Os pacotes de solicitação DHT são pacotes que podem ser enviados por meio de um nó DHT para outro nó que ele conhece. Eles são usados para enviar dados criptografados para amigos com os quais não estamos necessariamente conectados diretamente no DHT.
Um nó DHT que recebe um pacote de solicitação DHT verifica se a chave pública do destinatário é sua chave pública DHT e, em caso afirmativo, descriptografa e processa o pacote. Caso contrário, eles verificarão se conhecem essa chave pública DHT (se estiver em sua lista de nós fechados). Se não, eles descartam o pacote. Nesse caso, eles reenviarão exatamente o mesmo pacote para esse nó DHT.
A mensagem criptografada é criptografada usando a chave pública DHT do destinatário, a chave DHT privada do remetente e um nonce (24 bytes gerados aleatoriamente).
Os pacotes de solicitação DHT são usados para pacotes DHTPK (consulte cebola) e pacotes de ping NAT.
5.8.1 Pacotes de ping NAT
Encapsulados em um pacote de requisição DHT.
Os pacotes de ping NAT são usados para verificar se um amigo ao qual não estamos conectados diretamente está online e pronto
5.8.1.1 Solicitação de ping NAT
Comprimento contente
1 uint8_t (0xfe)
1 uint8_t(0x00)
8 uint64_t número aleatório
A solicitação de ping NAT recebida deve ser verificada se é de um amigo.
A verificação é realizada comparando a chave pública do pacote de requisição DHT, no qual esta requisição de ping NAT foi encapsulada, com uma lista de chaves públicas dos próprios amigos.
Se uma solicitação de ping NAT...
...for de um amigo, uma resposta de ping NAT com o mesmo número aleatório da solicitação deve ser enviada de volta por nós que conheçam o amigo que enviou a solicitação.
Se não houver nodos que conheçam o amigo, o pacote será descartado.
...não do seu próprio amigo, o pacote será descartado.
5.8.1.2 Resposta de ping NAT
Comprimento contente
1 uint8_t (0xfe)
1 uint8_t (0x01)
8 uint64_t número aleatório (o mesmo que foi recebido no pedido)
5.9 Mecanismo de conexão de ponta a ponta
para determinar se deve iniciar uma conexão de ponta a ponta:
Solicitação de 8 pares mais próximos do próprio ponto IP:porta amiga.
Pelo menos 4+ hosts retornam o IP:port do amigo.
Envie uma solicitação de ping DHT para cada uma dessas IP:portas.
Se nenhuma resposta for recebida, inicie uma conexão de ponta a ponta.
Os números 8 e 4 são usados no toxcore e foram escolhidos com base apenas na "sensação" e podem não ser os ideais.
Antes de iniciar uma conexão de ponta a ponta, um pacote de ping NAT é enviado ao amigo por meio de colegas que afirmam conhecer o amigo. Se uma resposta de ping NAT for recebida com o mesmo número aleatório, a conexão de ponta a ponta deve ser iniciada.
Receber uma resposta de ping NAT significa que um amigo está online e está procurando por nós ativamente, pois essa é a única maneira de conhecer os nós que nos conhecem. passthrough só funcionará se um amigo estiver tentando se conectar ativamente conosco.
As solicitações de ping NAT são enviadas a cada 3 segundos para toxcore. Se nenhuma resposta for recebida em 6 segundos, a conexão de ponta a ponta será encerrada.
O envio de pings NAT em intervalos mais longos pode aumentar a chance de outro host deixar a rede e os pacotes de ping enviados durante a conexão de ponta a ponta serão enviados para a contraparte "morta", mas isso pode reduzir o uso de largura de banda. Reduzir os intervalos terá o efeito oposto.
Para "end-to-end", assumimos que as pessoas que usam Tox usam um dos três tipos de NAT:
Cone NAT
Cone restrito NAT
NAT Simétrico
Existem 3 casos que o toxcore pode enfrentar com uma conexão end-to-end:
4+ peers próximos a uma determinada chave pública retornaram o mesmo IP: porta
4+ peers próximos a uma determinada chave pública retornaram o mesmo IP, mas uma porta diferente
perto de um determinado PK peers retornaram diferentes IP:portas
5.9.1 Cone NAT
Comportamento do software NAT:
Atribua uma porta inteira a cada soquete UDP por trás do NAT, qualquer pacote de qualquer IP:porta enviado para aquela porta designada da Internet será encaminhado para a tomada atrás dele.
A conectividade de ponta a ponta com NATs de cone convencionais é obtida simplesmente pela maneira como o DHT funciona, ou seja, enviamos uma solicitação de ping DHT para o IP:port do amigo e recebemos uma resposta de ping DHT.
5.9.2 Cone restrito NAT
Comportamento do software NAT:
Atribua uma porta inteira a cada soquete UDP por trás do NAT. Encaminhe pacotes apenas de IPs para os quais o soquete UDP enviou o pacote.
Se mais de 4 nós perto de nós retornarem o IP:porta do mesmo amigo, isso significa que o amigo está em um NAT de cone restrito.
Uma conexão ponta a ponta pode ser feita fazendo com que um amigo envie um pacote para nossa porta IP: pública. Isso significa que uma conexão de ponta a ponta pode ser alcançada facilmente e que devemos continuar enviando pings DHT regulares para este IP: porta até obtermos uma resposta de ping DHT. Vai dar certo porque um amigo está nos procurando no DHT. Tendo nos encontrado, o amigo enviará um pacote para nosso IP:port público, estabelecendo assim uma conexão.
5.9.3 NAT Simétrico
Pior opção.
Comportamento do software NAT:
Atribua uma nova porta para cada IP:porta para a qual um pacote é enviado. Trate cada novo ponto para o qual um pacote UDP é enviado como uma conexão. Encaminhar pacotes para o soquete somente a partir do IP:port atribuído nesta conexão.
Em caso de implementação ruim, crash & burn, fazendo os usuários chorarem.
Pares próximos não retornam a mesma porta para um amigo - o que significa que o amigo está em um NAT simétrico.
Alguns NATs simétricos abrem portas sequencialmente, o que pode fazer com que as portas retornadas por nós próximos a nós sejam, por exemplo, 1345, 1347, 1389, 1395.
A conexão de ponta a ponta com NATs simétricos é baseada em adivinhar quais portas são mais prováveis de serem usadas por um amigo quando ele tenta nos enviar um ping. As solicitações de ping DHT são enviadas para essas portas até que uma resposta de ping DHT seja recebida.
Toxcore tenta todas as portas próximas a cada porta retornada (por exemplo, para as 4 portas listadas anteriormente, ele tentará: 1345, 1347, 1389, 1395, 1346, 1348, 1390, 1396, 1344, 1346...), gradualmente tentando portas mais distantes daquelas relatadas por nós próximos.
Tente até 48 portas a cada 3 segundos até que uma conexão seja estabelecida.
Após 5 tentativas, double(?)range(?) e comece a tentar as portas de 1024, 48 ao mesmo tempo, incluindo portas previamente adivinhadas.
Isso parece consertar as coisas para alguns NATs simétricos, provavelmente porque muitos deles redefinem o contador em 1024.
-irungentoo o número de pacotes enviados para diferentes IPs em um curto período de tempo. Reduzir o número de portas retarda o processo de conexão de ponta a ponta
Embora isso funcione, o método pode ser aprimorado.
5.9.4 IP:portas diferentes
Pode ocorrer quando pares retornam IPs e portas diferentes.
Existem 2 casos em que isso pode acontecer:
O amigo está atrás de um NAT muito rígido que não pode ser perfurado.
um amigo se conectou recentemente a uma conexão de internet diferente e alguns colegas ainda possuem informações desatualizadas.
Nada pode ser feito se o NAT for muito rígido, por isso é recomendável usar o IP mais comum retornado pelos pares e ignorar outros IP:portas.
5.10 Informações sobre os nós Bootstrap DHT (0xf0)
Os nós Bootstrap são nós Tox regulares com uma chave pública DHT estável. Isso significa que a chave pública DHT não muda nas reinicializações. Os nós Bootstrap DHT têm um tipo de solicitação adicional: Bootstrap Info. A solicitação é um pacote de 78 bytes, onde o primeiro byte é 0xf0. O resto dos bytes são ignorados.
O formato da resposta é o seguinte:
Comprimento tipo contente
4 Palavra32 Versão do nó de inicialização
256 bytes Mensagem do Dia
6 LAN Discovery LAN
Discovery é uma maneira de descobrir pares Tox que estão localizados em uma LAN. Se dois amigos Tox estiverem em uma rede local, a maneira mais eficaz de se comunicarem é usar a rede local. Se um cliente Tox estiver aberto em uma LAN onde exista outro cliente Tox, é recomendável inicializar a rede usando o cliente Tox na LAN. Isso é exatamente o que a descoberta de LAN faz.
A descoberta da LAN ocorre enviando um pacote UDP pelo soquete toxcore UDP para o endereço de transmissão da interface em IPv4, o endereço de transmissão global (255.255.255.255) e o endereço multicast em IPv6 (FF02::1) na porta Tox UDP padrão (33445 ).
Pacote de descoberta de LAN:
Comprimento contente
1 uint8_t(33)
32 Chave pública DHT
Os pacotes LAN Discovery contêm a chave pública DHT do remetente. Quando um pacote LAN Discovery é recebido, um pacote DHT get nodes será enviado ao remetente do pacote. Isso significa que a instância DHT fará o download de si mesma para todos os pares dos quais recebe um desses pacotes. Com esse mecanismo, os clientes Tox inicializarão automaticamente a partir de outros clientes Tox em execução na rede local.
Quando esse mecanismo está ativado, o toxcore envia esses pacotes a cada 10 segundos para reduzir a latência. Os pacotes podem ser enviados a cada 60 segundos, mas isso tornará a busca por pares na rede 6 vezes mais lenta.
A pesquisa de LAN permite que dois amigos na LAN se encontrem porque o DHT prioriza endereços de LAN sobre endereços fora da LAN para pares DHT. Uma solicitação de obtenção de nó bem-sucedida/solicitação de inicialização de um par também deve adicioná-lo à lista de pares DHT se estivermos procurando por ele. Um par não precisa ser adicionado imediatamente se o pacote de descoberta de LAN com a chave pública DHT que estamos fazendo ping precisar ser enviado e uma resposta válida precisar ser recebida antes que possamos dizer que o par foi encontrado.
A detecção de LAN é como o Tox lida e faz com que tudo funcione bem na LAN.