/* Add a friend who we want to connect to.
 *
 * return -1 on failure.
 * return the friend number on success or if the friend was already added.
 */
int onion_addfriend(Onion_Client *onion_c, uint8_t *client_id)
{
    int num = onion_friend_num(onion_c, client_id);

    if (num != -1)
        return num;

    uint32_t i, index = ~0;

    for (i = 0; i < onion_c->num_friends; ++i) {
        if (onion_c->friends_list[i].status == 0) {
            index = i;
            break;
        }
    }

    if (index == (uint32_t)~0) {
        if (realloc_onion_friends(onion_c, onion_c->num_friends + 1) == -1)
            return -1;

        index = onion_c->num_friends;
        memset(&(onion_c->friends_list[onion_c->num_friends]), 0, sizeof(Onion_Friend));
        ++onion_c->num_friends;
    }

    onion_c->friends_list[index].status = 1;
    memcpy(onion_c->friends_list[index].real_client_id, client_id, crypto_box_PUBLICKEYBYTES);
    crypto_box_keypair(onion_c->friends_list[index].temp_public_key, onion_c->friends_list[index].temp_secret_key);
    return index;
}
Exemple #2
0
static int handle_fakeid_announce(void *object, const uint8_t *source_pubkey, const uint8_t *data, uint16_t length)
{
    Onion_Client *onion_c = object;

    if (length < FAKEID_DATA_MIN_LENGTH)
        return 1;

    if (length > FAKEID_DATA_MAX_LENGTH)
        return 1;

    int friend_num = onion_friend_num(onion_c, source_pubkey);

    if (friend_num == -1)
        return 1;

    uint64_t no_replay;
    memcpy(&no_replay, data + 1, sizeof(uint64_t));
    net_to_host((uint8_t *) &no_replay, sizeof(no_replay));

    if (no_replay <= onion_c->friends_list[friend_num].last_noreplay)
        return 1;

    onion_c->friends_list[friend_num].last_noreplay = no_replay;

    if (onion_c->friends_list[friend_num].dht_pk_callback)
        onion_c->friends_list[friend_num].dht_pk_callback(onion_c->friends_list[friend_num].dht_pk_callback_object,
                onion_c->friends_list[friend_num].dht_pk_callback_number, data + 1 + sizeof(uint64_t));

    onion_set_friend_DHT_pubkey(onion_c, friend_num, data + 1 + sizeof(uint64_t));
    onion_c->friends_list[friend_num].last_seen = unix_time();

    uint16_t len_nodes = length - FAKEID_DATA_MIN_LENGTH;

    if (len_nodes != 0) {
        Node_format nodes[MAX_SENT_NODES];
        int num_nodes = unpack_nodes(nodes, MAX_SENT_NODES, 0, data + 1 + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES,
                                     len_nodes, 1);

        if (num_nodes <= 0)
            return 1;

        int i;

        for (i = 0; i < num_nodes; ++i) {
            uint8_t family = nodes[i].ip_port.ip.family;

            if (family == AF_INET || family == AF_INET6) {
                DHT_getnodes(onion_c->dht, &nodes[i].ip_port, nodes[i].client_id, onion_c->friends_list[friend_num].fake_client_id);
            } else if (family == TCP_INET || family == TCP_INET6) {
                if (onion_c->friends_list[friend_num].tcp_relay_node_callback) {
                    void *obj = onion_c->friends_list[friend_num].tcp_relay_node_callback_object;
                    uint32_t number = onion_c->friends_list[friend_num].tcp_relay_node_callback_number;
                    onion_c->friends_list[friend_num].tcp_relay_node_callback(obj, number, nodes[i].ip_port, nodes[i].client_id);
                }
            }
        }
    }

    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;

    uint64_t no_replay;
    net_to_host(data + 1, sizeof(no_replay));
    memcpy(&no_replay, data + 1, sizeof(uint64_t));

    if (no_replay <= onion_c->friends_list[friend_num].last_noreplay)
        return 1;

    onion_c->friends_list[friend_num].last_noreplay = no_replay;

    if (memcmp(data + 1 + sizeof(uint64_t), 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);

        onion_c->friends_list[friend_num].last_seen = unix_time();

        if (DHT_addfriend(onion_c->dht, data + 1 + sizeof(uint64_t)) == 1) {
            return 1;
        }

        onion_c->friends_list[friend_num].is_fake_clientid = 1;
        memcpy(onion_c->friends_list[friend_num].fake_client_id, data + 1 + sizeof(uint64_t), crypto_box_PUBLICKEYBYTES);
    }

    uint16_t num_nodes = (length - FAKEID_DATA_MIN_LENGTH) / sizeof(Node_format);
    Node_format nodes[num_nodes];
    memcpy(nodes, data + 1 + sizeof(uint64_t) + 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);
    }

    return 0;
}
/* Try to send a friend request to peer with public_key.
 * data is the data in the request and length is the length.
 *
 *  return -1 if failure.
 *  return  0 if it sent the friend request directly to the friend.
 *  return the number of peers it was routed through if it did not send it directly.
 */
int send_friendrequest(Onion_Client *onion_c, uint8_t *public_key, uint32_t nospam_num, uint8_t *data, uint32_t length)
{
    if (length + sizeof(nospam_num) > MAX_DATA_SIZE)
        return -1;

    uint8_t temp[MAX_DATA_SIZE];
    temp[0] = CRYPTO_PACKET_FRIEND_REQ;
    memcpy(temp + 1, &nospam_num, sizeof(nospam_num));
    memcpy(temp + 1 + sizeof(nospam_num), data, length);

    int friend_num = onion_friend_num(onion_c, public_key);

    if (friend_num == -1)
        return -1;

    int num = send_onion_data(onion_c, friend_num, temp, 1 + sizeof(nospam_num) + length);

    if (num <= 0)
        return -1;

    return num;
}