static int handle_send_2(void *object, IP_Port source, const uint8_t *packet, uint32_t length) { Onion *onion = object; if (length > ONION_MAX_PACKET_SIZE) return 1; if (length <= 1 + SEND_3) return 1; change_symmetric_key(onion); uint8_t plain[ONION_MAX_PACKET_SIZE]; uint8_t shared_key[crypto_box_BEFORENMBYTES]; get_shared_key(&onion->shared_keys_3, shared_key, onion->dht->self_secret_key, packet + 1 + crypto_box_NONCEBYTES); int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_2), plain); if ((uint32_t)len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_2 + crypto_box_MACBYTES)) return 1; IP_Port send_to; ipport_unpack(&send_to, plain); to_host_family(&send_to.ip); uint8_t data[ONION_MAX_PACKET_SIZE]; memcpy(data, plain + SIZE_IPPORT, len - SIZE_IPPORT); uint32_t data_len = (len - SIZE_IPPORT); uint8_t *ret_part = data + (len - SIZE_IPPORT); new_nonce(ret_part); uint8_t ret_data[RETURN_2 + SIZE_IPPORT]; ipport_pack(ret_data, &source); memcpy(ret_data + SIZE_IPPORT, packet + (length - RETURN_2), RETURN_2); len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ret_data, sizeof(ret_data), ret_part + crypto_box_NONCEBYTES); if (len != RETURN_3 - crypto_box_NONCEBYTES) return 1; data_len += RETURN_3; if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len) return 1; return 0; }
static int handle_fakeid_announce(void *object, uint8_t *source_pubkey, uint8_t *data, uint32_t length) { Onion_Client *onion_c = object; if (length < FAKEID_DATA_MIN_LENGTH) return 1; if (length > FAKEID_DATA_MAX_LENGTH) return 1; if ((length - FAKEID_DATA_MIN_LENGTH) % sizeof(Node_format) != 0) return 1; int friend_num = onion_friend_num(onion_c, source_pubkey); if (friend_num == -1) return 1; if (memcmp(data + 1, onion_c->friends_list[friend_num].fake_client_id, crypto_box_PUBLICKEYBYTES) != 0) { DHT_delfriend(onion_c->dht, onion_c->friends_list[friend_num].fake_client_id); if (DHT_addfriend(onion_c->dht, data + 1) == 1) { return 1; } memcpy(onion_c->friends_list[friend_num].fake_client_id, data + 1, crypto_box_PUBLICKEYBYTES); } uint16_t num_nodes = (length - FAKEID_DATA_MIN_LENGTH) / sizeof(Node_format); Node_format nodes[num_nodes]; memcpy(nodes, data + 1 + crypto_box_PUBLICKEYBYTES, sizeof(nodes)); uint32_t i; for (i = 0; i < num_nodes; ++i) { to_host_family(&nodes[i].ip_port.ip); DHT_getnodes(onion_c->dht, &nodes[i].ip_port, nodes[i].client_id, onion_c->friends_list[friend_num].fake_client_id); } //TODO replay protection return 0; }
static int client_ping_nodes(Onion_Client *onion_c, uint32_t num, Node_format *nodes, uint16_t num_nodes, IP_Port source) { if (num > onion_c->num_friends) return -1; if (num_nodes == 0) return 0; Onion_Node *list_nodes = NULL; uint8_t *reference_id = NULL; if (num == 0) { list_nodes = onion_c->clients_announce_list; reference_id = onion_c->dht->c->self_public_key; } else { list_nodes = onion_c->friends_list[num - 1].clients_list; reference_id = onion_c->friends_list[num - 1].real_client_id; } uint32_t i; int lan_ips_accepted = (LAN_ip(source.ip) == 0); for (i = 0; i < num_nodes; ++i) { to_host_family(&nodes[i].ip_port.ip); if (!lan_ips_accepted) if (LAN_ip(nodes[i].ip_port.ip) == 0) continue; if (is_timeout(list_nodes[0].timestamp, ONION_NODE_TIMEOUT) || id_closest(reference_id, list_nodes[0].client_id, nodes[i].client_id) == 2) { client_send_announce_request(onion_c, num, nodes[i].ip_port, nodes[i].client_id, NULL); } } return 0; }
static int handle_sendnodes(Group_Chat *chat, IP_Port source, int peernum, uint8_t *data, uint32_t len) { if ((uint32_t)peernum >= chat->numpeers) return 1; if (len > sizeof(sendnodes_data) || len < sizeof(uint64_t)) return 1; if ((len - sizeof(uint64_t)) % sizeof(groupchat_nodes) != 0) return 1; if (is_timeout(chat->group[peernum].last_pinged, GROUP_PING_TIMEOUT)) return 1; sendnodes_data contents; memcpy(&contents, data, len); if (contents.pingid != chat->group[peernum].pingid) return 1; uint16_t numnodes = (len - sizeof(contents.pingid)) / sizeof(groupchat_nodes); uint32_t i; IPPTs ippts_send; ippts_send.timestamp = unix_time(); for (i = 0; i < numnodes; ++i) { if (peer_okping(chat, contents.nodes[i].client_id) > 0) { int peern = peer_in_chat(chat, contents.nodes[i].client_id); if (peern == -1) { /*NOTE: This is just for testing and will be removed later.*/ peern = addpeer(chat, contents.nodes[i].client_id); } if (peern == -1) continue; to_host_family(&contents.nodes[i].ip_port.ip); send_getnodes(chat, contents.nodes[i].ip_port, peern); if (chat->assoc) { ippts_send.ip_port = contents.nodes[i].ip_port; Assoc_add_entry(chat->assoc, contents.nodes[i].client_id, &ippts_send, NULL, 0); } } } int ok = add_closepeer(chat, chat->group[peernum].client_id, source); if (chat->assoc) { ippts_send.ip_port = chat->group[peernum].ping_via; ippts_send.timestamp = chat->group[peernum].last_pinged; IP_Port ipp_recv; ipp_recv = source; Assoc_add_entry(chat->assoc, contents.nodes[i].client_id, &ippts_send, &ipp_recv, ok == 0 ? 1 : 0); } return 0; }