Skip to content

Commit

Permalink
Add groupchat API function that returns an IP address string for a peer
Browse files Browse the repository at this point in the history
This function will return an IP address string associated with a peer.
If the peer is not accepting direct connections a placeholder value
will be returned, indicating that their real IP address is unknown.
We do not return TCP relay IP addresses because a TCP connection
with a peer may use multiple relays simultaneously.
  • Loading branch information
JFreegman committed Dec 5, 2023
1 parent 63fb294 commit 9846f38
Show file tree
Hide file tree
Showing 10 changed files with 225 additions and 11 deletions.
26 changes: 26 additions & 0 deletions auto_tests/group_general_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <string.h>

#include "auto_test_support.h"
#include "../toxcore/tox_private.h"

typedef struct State {
size_t peer_joined_count;
Expand Down Expand Up @@ -42,6 +43,22 @@ typedef struct State {

#define PEER_LIMIT 20

static void print_ip(Tox *tox, uint32_t groupnumber, uint32_t peer_id)
{
Tox_Err_Group_Peer_Query err;
size_t length = tox_group_peer_get_ip_address_size(tox, groupnumber, peer_id, &err);

ck_assert_msg(err == TOX_ERR_GROUP_PEER_QUERY_OK, "failed to get ip address size: error %d", err);

uint8_t ip_str[TOX_GROUP_PEER_IP_STRING_MAX_LENGTH];
tox_group_peer_get_ip_address(tox, groupnumber, peer_id, ip_str, &err);
ip_str[length] = '\0';

ck_assert_msg(err == TOX_ERR_GROUP_PEER_QUERY_OK, "failed to get ip address: error %d", err);

fprintf(stderr, "%s\n", ip_str);
}

static bool all_group_peers_connected(AutoTox *autotoxes, uint32_t tox_count, uint32_t groupnumber, size_t name_length)
{
for (size_t i = 0; i < tox_count; ++i) {
Expand Down Expand Up @@ -119,6 +136,9 @@ static void group_peer_join_handler(Tox *tox, uint32_t groupnumber, uint32_t pee
}
}

fprintf(stderr, "%s joined with IP: ", peer_name);
print_ip(tox, groupnumber, peer_id);

state->peer_id = peer_id;
++state->peer_joined_count;
}
Expand Down Expand Up @@ -178,6 +198,11 @@ static void group_peer_self_join_handler(Tox *tox, uint32_t groupnumber, void *u
ck_assert_msg(query_err == TOX_ERR_GROUP_STATE_QUERIES_OK, "%d", query_err);
ck_assert(memcmp(topic, TOPIC, TOPIC_LEN) == 0);

uint32_t peer_id = tox_group_self_get_peer_id(tox, groupnumber, nullptr);

fprintf(stderr, "self joined with IP: ");
print_ip(tox, groupnumber, peer_id);

++state->self_joined_count;
}

Expand Down Expand Up @@ -341,6 +366,7 @@ static void group_announce_test(AutoTox *autotoxes)
ck_assert(memcmp(tox0_pk_query, tox0_self_pk, TOX_GROUP_PEER_PUBLIC_KEY_SIZE) == 0);

fprintf(stderr, "Peer 0 disconnecting...\n");

// tox 0 disconnects then reconnects
Tox_Err_Group_Disconnect d_err;
tox_group_disconnect(tox0, groupnumber, &d_err);
Expand Down
2 changes: 1 addition & 1 deletion other/bootstrap_daemon/docker/tox-bootstrapd.sha256
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8bf35cb22ca6d5d85f5fe8993a6ce9424d2048f9bd6a57ab45dc52a6c8444fb3 /usr/local/bin/tox-bootstrapd
852007e7309fff6e540e4c5f76e50228211cd3c449179c1c8a956980b347d822 /usr/local/bin/tox-bootstrapd
57 changes: 57 additions & 0 deletions toxcore/group_chats.c
Original file line number Diff line number Diff line change
Expand Up @@ -3506,6 +3506,63 @@ int gc_get_peer_public_key_by_peer_id(const GC_Chat *chat, uint32_t peer_id, uin
return 0;
}

/** @brief Puts a string of the IP associated with `ip_port` in `ip_str` if the
* connection is direct, otherwise puts a placeholder in the buffer indicating that
* the IP cannot be displayed.
*/
non_null()
static void get_gc_ip_ntoa(const IP_Port *ip_port, Ip_Ntoa *ip_str)
{
net_ip_ntoa(&ip_port->ip, ip_str);

if (!ip_str->ip_is_valid) {
ip_str->buf[0] = '-';
ip_str->buf[1] = '\0';
ip_str->length = 1;

Check warning on line 3521 in toxcore/group_chats.c

View check run for this annotation

Codecov / codecov/patch

toxcore/group_chats.c#L3519-L3521

Added lines #L3519 - L3521 were not covered by tests
}
}

int gc_get_peer_ip_address_size(const GC_Chat *chat, uint32_t peer_id)
{
const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
const GC_Connection *gconn = get_gc_connection(chat, peer_number);

if (gconn == nullptr) {
return -1;

Check warning on line 3531 in toxcore/group_chats.c

View check run for this annotation

Codecov / codecov/patch

toxcore/group_chats.c#L3531

Added line #L3531 was not covered by tests
}

const IP_Port *ip_port = peer_number == 0 ? &chat->self_ip_port : &gconn->addr.ip_port;

Ip_Ntoa ip_str;
get_gc_ip_ntoa(ip_port, &ip_str);

return ip_str.length;
}

int gc_get_peer_ip_address(const GC_Chat *chat, uint32_t peer_id, uint8_t *ip_addr)
{
const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
const GC_Connection *gconn = get_gc_connection(chat, peer_number);

if (gconn == nullptr) {
return -1;

Check warning on line 3548 in toxcore/group_chats.c

View check run for this annotation

Codecov / codecov/patch

toxcore/group_chats.c#L3548

Added line #L3548 was not covered by tests
}

if (ip_addr == nullptr) {
return -2;

Check warning on line 3552 in toxcore/group_chats.c

View check run for this annotation

Codecov / codecov/patch

toxcore/group_chats.c#L3552

Added line #L3552 was not covered by tests
}

const IP_Port *ip_port = peer_number == 0 ? &chat->self_ip_port : &gconn->addr.ip_port;

Ip_Ntoa ip_str;
get_gc_ip_ntoa(ip_port, &ip_str);

assert(ip_str.length <= IP_NTOA_LEN);
memcpy(ip_addr, ip_str.buf, ip_str.length);

return 0;
}

unsigned int gc_get_peer_connection_status(const GC_Chat *chat, uint32_t peer_id)
{
const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
Expand Down
23 changes: 23 additions & 0 deletions toxcore/group_chats.h
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,29 @@ int gc_get_peer_nick_size(const GC_Chat *chat, uint32_t peer_id);
non_null(1) nullable(3)
int gc_get_peer_public_key_by_peer_id(const GC_Chat *chat, uint32_t peer_id, uint8_t *public_key);

/** @brief Returns the length of the IP address for the peer designated by `peer_id`.
* Returns -1 if peer_id is invalid.
*/
non_null()
int gc_get_peer_ip_address_size(const GC_Chat *chat, uint32_t peer_id);

/** @brief Copies peer_id's IP address to `ip_addr`.
*
* If the peer is forcing TCP connections this will be a placeholder value indicating
* that their real IP address is unknown to us.
*
* If `peer_id` designates ourself, it will write either our own IP address or a
* placeholder value, depending on whether or not we're forcing TCP connections.
*
* `ip_addr` should have room for at least IP_NTOA_LEN bytes.
*
* Returns 0 on success.
* Returns -1 if peer_id is invalid or doesn't correspond to a valid peer connection.
* Returns -2 if `ip_addr` is null.
*/
non_null(1) nullable(3)
int gc_get_peer_ip_address(const GC_Chat *chat, uint32_t peer_id, uint8_t *ip_addr);

/** @brief Gets the connection status for peer associated with `peer_id`.
*
* If `peer_id` designates ourself, the return value indicates whether we're capable
Expand Down
15 changes: 7 additions & 8 deletions toxcore/network.c
Original file line number Diff line number Diff line change
Expand Up @@ -1514,30 +1514,29 @@ void ipport_copy(IP_Port *target, const IP_Port *source)
*target = *source;
}

/** @brief Converts IP into a string.
*
* Writes error message into the buffer on error.
*
* @param ip_str contains a buffer of the required size.
*
* @return Pointer to the buffer inside `ip_str` containing the IP string.
*/
const char *net_ip_ntoa(const IP *ip, Ip_Ntoa *ip_str)
{
assert(ip_str != nullptr);

ip_str->ip_is_valid = false;

if (ip == nullptr) {
snprintf(ip_str->buf, sizeof(ip_str->buf), "(IP invalid: NULL)");
ip_str->length = strlen(ip_str->buf);

Check warning on line 1525 in toxcore/network.c

View check run for this annotation

Codecov / codecov/patch

toxcore/network.c#L1525

Added line #L1525 was not covered by tests
return ip_str->buf;
}

if (!ip_parse_addr(ip, ip_str->buf, sizeof(ip_str->buf))) {
snprintf(ip_str->buf, sizeof(ip_str->buf), "(IP invalid, family %u)", ip->family.value);
ip_str->length = strlen(ip_str->buf);
return ip_str->buf;
}

/* brute force protection against lacking termination */
ip_str->buf[sizeof(ip_str->buf) - 1] = '\0';
ip_str->length = strlen(ip_str->buf);
ip_str->ip_is_valid = true;

return ip_str->buf;
}

Expand Down
7 changes: 5 additions & 2 deletions toxcore/network.h
Original file line number Diff line number Diff line change
Expand Up @@ -343,11 +343,14 @@ bool ipv6_ipv4_in_v6(const IP6 *a);
/** this would be TOX_INET6_ADDRSTRLEN, but it might be too short for the error message */
#define IP_NTOA_LEN 96 // TODO(irungentoo): magic number. Why not INET6_ADDRSTRLEN ?

/** Contains a null terminated string of an IP address. */
typedef struct Ip_Ntoa {
char buf[IP_NTOA_LEN];
char buf[IP_NTOA_LEN]; // a string formatted IP address or an error message.
uint16_t length; // the length of the string (not including the null byte).
bool ip_is_valid; // if this is false `buf` will contain an error message.
} Ip_Ntoa;

/** @brief Converts IP into a string.
/** @brief Converts IP into a null terminated string.
*
* Writes error message into the buffer on error.
*
Expand Down
2 changes: 2 additions & 0 deletions toxcore/tox.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ static_assert(FILE_ID_LENGTH == CRYPTO_SYMMETRIC_KEY_SIZE,
"FILE_ID_LENGTH is assumed to be equal to CRYPTO_SYMMETRIC_KEY_SIZE");
static_assert(TOX_DHT_NODE_IP_STRING_SIZE == IP_NTOA_LEN,
"TOX_DHT_NODE_IP_STRING_SIZE is assumed to be equal to IP_NTOA_LEN");
static_assert(TOX_GROUP_PEER_IP_STRING_MAX_LENGTH == IP_NTOA_LEN,
"TOX_GROUP_PEER_IP_STRING_MAX_LENGTH is assumed to be equal to IP_NTOA_LEN");
static_assert(TOX_DHT_NODE_PUBLIC_KEY_SIZE == CRYPTO_PUBLIC_KEY_SIZE,
"TOX_DHT_NODE_PUBLIC_KEY_SIZE is assumed to be equal to CRYPTO_PUBLIC_KEY_SIZE");
static_assert(TOX_FILE_ID_LENGTH == CRYPTO_SYMMETRIC_KEY_SIZE,
Expand Down
4 changes: 4 additions & 0 deletions toxcore/tox_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ uint32_t tox_group_peer_public_key_size(void)
{
return TOX_GROUP_PEER_PUBLIC_KEY_SIZE;
}
uint32_t tox_group_peer_ip_string_max_length(void)

Check warning on line 127 in toxcore/tox_api.c

View check run for this annotation

Codecov / codecov/patch

toxcore/tox_api.c#L127

Added line #L127 was not covered by tests
{
return TOX_GROUP_PEER_IP_STRING_MAX_LENGTH;

Check warning on line 129 in toxcore/tox_api.c

View check run for this annotation

Codecov / codecov/patch

toxcore/tox_api.c#L129

Added line #L129 was not covered by tests
}
uint32_t tox_dht_node_ip_string_size(void)
{
return TOX_DHT_NODE_IP_STRING_SIZE;
Expand Down
55 changes: 55 additions & 0 deletions toxcore/tox_private.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <assert.h>

#include "ccompat.h"
#include "group_chats.h"
#include "mem.h"
#include "network.h"
#include "tox_struct.h"
Expand Down Expand Up @@ -166,3 +167,57 @@ uint16_t tox_dht_get_num_closelist_announce_capable(const Tox *tox){
return num_cap;
}

#ifndef VANILLA_NACL
size_t tox_group_peer_get_ip_address_size(const Tox *tox, uint32_t group_number, uint32_t peer_id,
Tox_Err_Group_Peer_Query *error)
{
assert(tox != nullptr);

tox_lock(tox);
const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);

if (chat == nullptr) {
SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_GROUP_NOT_FOUND);
tox_unlock(tox);
return -1;

Check warning on line 182 in toxcore/tox_private.c

View check run for this annotation

Codecov / codecov/patch

toxcore/tox_private.c#L180-L182

Added lines #L180 - L182 were not covered by tests
}

const int ret = gc_get_peer_ip_address_size(chat, peer_id);
tox_unlock(tox);

if (ret == -1) {
SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_PEER_NOT_FOUND);
return -1;

Check warning on line 190 in toxcore/tox_private.c

View check run for this annotation

Codecov / codecov/patch

toxcore/tox_private.c#L189-L190

Added lines #L189 - L190 were not covered by tests
} else {
SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_OK);
return ret;
}
}

bool tox_group_peer_get_ip_address(const Tox *tox, uint32_t group_number, uint32_t peer_id, uint8_t *ip_addr,
Tox_Err_Group_Peer_Query *error)
{
assert(tox != nullptr);

tox_lock(tox);
const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);

if (chat == nullptr) {
SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_GROUP_NOT_FOUND);
tox_unlock(tox);
return false;

Check warning on line 208 in toxcore/tox_private.c

View check run for this annotation

Codecov / codecov/patch

toxcore/tox_private.c#L206-L208

Added lines #L206 - L208 were not covered by tests
}

const int ret = gc_get_peer_ip_address(chat, peer_id, ip_addr);
tox_unlock(tox);

if (ret == -1) {
SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_PEER_NOT_FOUND);
return false;

Check warning on line 216 in toxcore/tox_private.c

View check run for this annotation

Codecov / codecov/patch

toxcore/tox_private.c#L215-L216

Added lines #L215 - L216 were not covered by tests
}

SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_OK);
return true;
}

#endif /* VANILLA_NACL */
45 changes: 45 additions & 0 deletions toxcore/tox_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,51 @@ uint16_t tox_dht_get_num_closelist(const Tox *tox);
*/
uint16_t tox_dht_get_num_closelist_announce_capable(const Tox *tox);


/*******************************************************************************
*
* :: DHT groupchat queries.
*
******************************************************************************/

/**
* Maximum size of a peer IP address string.
*/
#define TOX_GROUP_PEER_IP_STRING_MAX_LENGTH 96

uint32_t tox_group_peer_ip_string_max_length(void);

/**
* Return the length of the peer's IP address in string form. If the group number or ID
* is invalid, the return value is unspecified.
*
* @param group_number The group number of the group we wish to query.
* @param peer_id The ID of the peer whose IP address length we want to retrieve.
*/
size_t tox_group_peer_get_ip_address_size(const Tox *tox, uint32_t group_number, uint32_t peer_id,
Tox_Err_Group_Peer_Query *error);
/**
* Write the IP address associated with the designated peer_id for the designated group number
* to ip_addr.
*
* If the peer is forcing TCP connections a placeholder value will be written instead,
* indicating that their real IP address is unknown to us.
*
* If `peer_id` designates ourself, it will write either our own IP address or a placeholder value,
* depending on whether or not we're forcing TCP connections.
*
* Call tox_group_peer_get_ip_address_size to determine the allocation size for the `ip_addr` parameter.
*
* @param group_number The group number of the group we wish to query.
* @param peer_id The ID of the peer whose public key we wish to retrieve.
* @param ip_addr A valid memory region large enough to store the IP address string.
* If this parameter is NULL, this function call has no effect.
*
* @return true on success.
*/
bool tox_group_peer_get_ip_address(const Tox *tox, uint32_t group_number, uint32_t peer_id, uint8_t *ip_addr,
Tox_Err_Group_Peer_Query *error);

#ifdef __cplusplus
}
#endif
Expand Down

0 comments on commit 9846f38

Please sign in to comment.