/* Create a new onion path. * * Create a new onion path out of nodes (nodes is a list of 3 nodes) * * new_path must be an empty memory location of atleast Onion_Path size. * * return -1 on failure. * return 0 on success. */ int create_onion_path(const DHT *dht, Onion_Path *new_path, const Node_format *nodes) { if (!new_path || !nodes) return -1; encrypt_precompute(nodes[0].client_id, dht->self_secret_key, new_path->shared_key1); memcpy(new_path->public_key1, dht->self_public_key, crypto_box_PUBLICKEYBYTES); uint8_t random_public_key[crypto_box_PUBLICKEYBYTES]; uint8_t random_secret_key[crypto_box_SECRETKEYBYTES]; crypto_box_keypair(random_public_key, random_secret_key); encrypt_precompute(nodes[1].client_id, random_secret_key, new_path->shared_key2); memcpy(new_path->public_key2, random_public_key, crypto_box_PUBLICKEYBYTES); crypto_box_keypair(random_public_key, random_secret_key); encrypt_precompute(nodes[2].client_id, random_secret_key, new_path->shared_key3); memcpy(new_path->public_key3, random_public_key, crypto_box_PUBLICKEYBYTES); new_path->ip_port1 = nodes[0].ip_port; new_path->ip_port2 = nodes[1].ip_port; new_path->ip_port3 = nodes[2].ip_port; /* to_net_family(&new_path->ip_port1.ip); */ to_net_family(&new_path->ip_port2.ip); to_net_family(&new_path->ip_port3.ip); return 0; }
/* Send the packets to tell our friends what our DHT public key is. * * if onion_dht_both is 0, use only the onion to send the packet. * if it is 1, use only the dht. * if it is something else, use both. * * return the number of packets sent on success * return -1 on failure. */ static int send_fakeid_announce(Onion_Client *onion_c, uint16_t friend_num, uint8_t onion_dht_both) { if (friend_num >= onion_c->num_friends) return -1; uint8_t data[FAKEID_DATA_MAX_LENGTH]; data[0] = FAKEID_DATA_ID; uint64_t no_replay = unix_time(); host_to_net((uint8_t *)&no_replay, sizeof(no_replay)); memcpy(data + 1, &no_replay, sizeof(no_replay)); memcpy(data + 1 + sizeof(uint64_t), onion_c->dht->self_public_key, crypto_box_PUBLICKEYBYTES); Node_format nodes[MAX_SENT_NODES]; uint16_t num_nodes = closelist_nodes(onion_c->dht, nodes, MAX_SENT_NODES); uint32_t i; for (i = 0; i < num_nodes; ++i) to_net_family(&nodes[i].ip_port.ip); memcpy(data + FAKEID_DATA_MIN_LENGTH, nodes, sizeof(Node_format) * num_nodes); int num1 = -1, num2 = -1; if (onion_dht_both != 1) num1 = send_onion_data(onion_c, friend_num, data, FAKEID_DATA_MIN_LENGTH + sizeof(Node_format) * num_nodes); if (onion_dht_both != 0) num2 = send_dht_fakeid(onion_c, friend_num, data, FAKEID_DATA_MIN_LENGTH + sizeof(Node_format) * num_nodes); if (num1 == -1) return num2; if (num2 == -1) return num1; return num1 + num2; }
/* packing and unpacking functions */ static void ip_pack(uint8_t *data, IP source) { to_net_family(&source); data[0] = source.family; if (source.family == TOX_AF_INET || source.family == TOX_TCP_INET) { memset(data + 1, 0, SIZE_IP6); memcpy(data + 1, source.ip4.uint8, SIZE_IP4); } else { memcpy(data + 1, source.ip6.uint8, SIZE_IP6); } }
/* Create a onion packet. * * Use Onion_Path path to create packet for data of length to dest. * Maximum length of data is ONION_MAX_DATA_SIZE. * packet should be at least ONION_MAX_PACKET_SIZE big. * * return -1 on failure. * return length of created packet on success. */ int create_onion_packet(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest, const uint8_t *data, uint32_t length) { if (1 + length + SEND_1 > max_packet_length || length == 0) return -1; to_net_family(&dest.ip); uint8_t step1[SIZE_IPPORT + length]; ipport_pack(step1, &dest); memcpy(step1 + SIZE_IPPORT, data, length); uint8_t nonce[crypto_box_NONCEBYTES]; random_nonce(nonce); uint8_t step2[SIZE_IPPORT + SEND_BASE + length]; ipport_pack(step2, &path->ip_port3); memcpy(step2 + SIZE_IPPORT, path->public_key3, crypto_box_PUBLICKEYBYTES); int len = encrypt_data_symmetric(path->shared_key3, nonce, step1, sizeof(step1), step2 + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES); if ((uint32_t)len != SIZE_IPPORT + length + crypto_box_MACBYTES) return -1; uint8_t step3[SIZE_IPPORT + SEND_BASE * 2 + length]; ipport_pack(step3, &path->ip_port2); memcpy(step3 + SIZE_IPPORT, path->public_key2, crypto_box_PUBLICKEYBYTES); len = encrypt_data_symmetric(path->shared_key2, nonce, step2, sizeof(step2), step3 + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES); if ((uint32_t)len != SIZE_IPPORT + SEND_BASE + length + crypto_box_MACBYTES) return -1; packet[0] = NET_PACKET_ONION_SEND_INITIAL; memcpy(packet + 1, nonce, crypto_box_NONCEBYTES); memcpy(packet + 1 + crypto_box_NONCEBYTES, path->public_key1, crypto_box_PUBLICKEYBYTES); len = encrypt_data_symmetric(path->shared_key1, nonce, step3, sizeof(step3), packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES); if ((uint32_t)len != SIZE_IPPORT + SEND_BASE * 2 + length + crypto_box_MACBYTES) return -1; return 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + len; }
static int send_sendnodes(const Group_Chat *chat, IP_Port ip_port, int peernum, uint64_t pingid) { if ((uint32_t)peernum >= chat->numpeers) return -1; sendnodes_data contents; contents.pingid = pingid; uint32_t i, j = 0; for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { if (!is_timeout(chat->close[i].last_recv, BAD_GROUPNODE_TIMEOUT)) { id_copy(contents.nodes[j].client_id, chat->close[i].client_id); contents.nodes[j].ip_port = chat->close[i].ip_port; to_net_family(&contents.nodes[j].ip_port.ip); ++j; } } return send_groupchatpacket(chat, ip_port, chat->group[peernum].client_id, (uint8_t *)&contents, sizeof(contents.pingid) + sizeof(groupchat_nodes) * j, CRYPTO_PACKET_GROUP_CHAT_SEND_NODES); }