tox.*, DHT.*;

- second set of *_bootstrap_ex() functions to allow addresses instead of IPs

network.h:
- new message ID for sending/receiving IPv6 nodes

DHT.*:
- get_close_nodes():
  - additional parameter to select which kind of nodes: IPv4 or IPv6

- sendnodes()/handle_sendnodes():
  - the IPv4 message must remain intact even when the Node_format structure (which embeds IP_Port) is expanded
  - added Node4_format to keep the structure "alive"
  - copying in/out of wider to smaller format required in sendnodes()/handle_sendnodes()
  - switch of Node_format from Node4_format to Node46_format by define
This commit is contained in:
Coren[m] 2013-09-09 19:17:21 +02:00
parent 9a8dc575b7
commit a77253c79b
5 changed files with 137 additions and 27 deletions

View File

@ -197,18 +197,37 @@ static int friend_number(DHT *dht, uint8_t *client_id)
*
* TODO: For the love of based Allah make this function cleaner and much more efficient.
*/
static int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list)
static int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_family_t sa_family)
{
uint32_t i, j, k;
uint64_t temp_time = unix_time();
int num_nodes = 0, closest, tout, inlist;
int num_nodes = 0, closest, tout, inlist, ipv46x;
for (i = 0; i < LCLIENT_LIST; ++i) {
tout = is_timeout(temp_time, dht->close_clientlist[i].timestamp, BAD_NODE_TIMEOUT);
inlist = client_in_nodelist(nodes_list, MAX_SENT_NODES, dht->close_clientlist[i].client_id);
/*
* NET_PACKET_SEND_NODES sends ONLY AF_INET
* NET_PACKET_SEND_NODES_EX sends ALL BUT AF_INET (i.e. AF_INET6),
* it could send both, but then a) packet size is an issue and
* b) duplicates the traffic (NET_PACKET_SEND_NODES has to be
* sent anyways for backwards compatibility)
* we COULD send ALL as NET_PACKET_SEND_NODES_EX if we KNEW that the
* partner node understands - that's true if *they* are on IPv6
*/
#ifdef NETWORK_IP_PORT_IS_IPV6
ipv46x = 0;
if (sa_family == AF_INET)
ipv46x = dht->close_clientlist[i].ip_port.ip.family != AF_INET;
else
ipv46x = dht->close_clientlist[i].ip_port.ip.family == AF_INET;
#else
ipv46x = sa_family != AF_INET;
#endif
/* If node isn't good or is already in list. */
if (tout || inlist)
if (tout || inlist || ipv46x)
continue;
if (num_nodes < MAX_SENT_NODES) {
@ -247,8 +266,18 @@ static int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list
MAX_SENT_NODES,
dht->friends_list[i].client_list[j].client_id);
#ifdef NETWORK_IP_PORT_IS_IPV6
ipv46x = 0;
if (sa_family == AF_INET)
ipv46x = dht->friends_list[i].client_list[j].ip_port.ip.family != AF_INET;
else
ipv46x = dht->friends_list[i].client_list[j].ip_port.ip.family == AF_INET;
#else
ipv46x = sa_family != AF_INET;
#endif
/* If node isn't good or is already in list. */
if (tout || inlist)
if (tout || inlist || ipv46x)
continue;
if (num_nodes < MAX_SENT_NODES) {
@ -522,40 +551,61 @@ static int getnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *cli
}
/* Send a send nodes response. */
/* because of BINARY compatibility, the Node_format MUST BE Node4_format,
* IPv6 nodes are sent in a different message */
static int sendnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *client_id, uint64_t ping_id)
{
/* Check if packet is going to be sent to ourself. */
if (id_equal(public_key, dht->c->self_public_key))
return -1;
size_t Node4_format_size = sizeof(Node4_format);
uint8_t data[1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(ping_id)
+ sizeof(Node_format) * MAX_SENT_NODES + ENCRYPTION_PADDING];
+ Node4_format_size * MAX_SENT_NODES + ENCRYPTION_PADDING];
Node_format nodes_list[MAX_SENT_NODES];
int num_nodes = get_close_nodes(dht, client_id, nodes_list);
int num_nodes = get_close_nodes(dht, client_id, nodes_list, AF_INET);
if (num_nodes == 0)
return 0;
uint8_t plain[sizeof(ping_id) + sizeof(Node_format) * MAX_SENT_NODES];
uint8_t encrypt[sizeof(ping_id) + sizeof(Node_format) * MAX_SENT_NODES + ENCRYPTION_PADDING];
uint8_t plain[sizeof(ping_id) + Node4_format_size * MAX_SENT_NODES];
uint8_t encrypt[sizeof(ping_id) + Node4_format_size * MAX_SENT_NODES + ENCRYPTION_PADDING];
uint8_t nonce[crypto_box_NONCEBYTES];
random_nonce(nonce);
memcpy(plain, &ping_id, sizeof(ping_id));
memcpy(plain + sizeof(ping_id), nodes_list, num_nodes * sizeof(Node_format));
#if DHT_NODEFORMAT == 46
Node4_format *nodes4_list = &(plain + sizeof(ping_id));
int i, num_nodes_ok = 0;
for(i = 0; i < num_nodes, i++)
if (nodes_list[i].ip.family == AF_INET) {
memcpy(nodes4_list[num_nodes_ok].client_id, nodes_list[i].client_id, CLIENT_ID_SIZE);
nodes4_list[num_nodes_ok].ip_port.ip.uint32 = nodes_list[i].ip_port.ip.ip4.uint32;
nodes4_list[num_nodes_ok].ip_port.port = nodes_list[i].ip_port.port;
num_nodes_ok++;
}
if (num_nodes_ok < num_nodes) {
/* shouldn't happen */
num_nodes = num_nodes_ok;
}
#else
memcpy(plain + sizeof(ping_id), nodes_list, num_nodes * Node4_format_size);
#endif
int len = encrypt_data( public_key,
dht->c->self_secret_key,
nonce,
plain,
sizeof(ping_id) + num_nodes * sizeof(Node_format),
sizeof(ping_id) + num_nodes * Node4_format_size,
encrypt );
if (len == -1)
return -1;
if ((unsigned int)len != sizeof(ping_id) + num_nodes * sizeof(Node_format) + ENCRYPTION_PADDING)
if ((unsigned int)len != sizeof(ping_id) + num_nodes * Node4_format_size + ENCRYPTION_PADDING)
return -1;
data[0] = NET_PACKET_SEND_NODES;
@ -606,22 +656,23 @@ static int handle_sendnodes(void *object, IP_Port source, uint8_t *packet, uint3
uint32_t cid_size = 1 + CLIENT_ID_SIZE;
cid_size += crypto_box_NONCEBYTES + sizeof(ping_id) + ENCRYPTION_PADDING;
if (length > (cid_size + sizeof(Node_format) * MAX_SENT_NODES) ||
((length - cid_size) % sizeof(Node_format)) != 0 ||
(length < cid_size + sizeof(Node_format)))
size_t Node4_format_size = sizeof(Node4_format);
if (length > (cid_size + Node4_format_size * MAX_SENT_NODES) ||
((length - cid_size) % Node4_format_size) != 0 ||
(length < cid_size + Node4_format_size))
return 1;
uint32_t num_nodes = (length - cid_size) / sizeof(Node_format);
uint8_t plain[sizeof(ping_id) + sizeof(Node_format) * MAX_SENT_NODES];
uint32_t num_nodes = (length - cid_size) / Node4_format_size;
uint8_t plain[sizeof(ping_id) + Node4_format_size * MAX_SENT_NODES];
int len = decrypt_data(
packet + 1,
dht->c->self_secret_key,
packet + 1 + CLIENT_ID_SIZE,
packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES,
sizeof(ping_id) + num_nodes * sizeof(Node_format) + ENCRYPTION_PADDING, plain );
sizeof(ping_id) + num_nodes * Node4_format_size + ENCRYPTION_PADDING, plain );
if ((unsigned int)len != sizeof(ping_id) + num_nodes * sizeof(Node_format))
if ((unsigned int)len != sizeof(ping_id) + num_nodes * Node4_format_size)
return 1;
memcpy(&ping_id, plain, sizeof(ping_id));
@ -630,7 +681,28 @@ static int handle_sendnodes(void *object, IP_Port source, uint8_t *packet, uint3
return 1;
Node_format nodes_list[MAX_SENT_NODES];
#if DHT_NODEFORMAT == 46
Node4_format *nodes4_list = &(plain + sizeof(ping_id));
int i, num_nodes_ok = 0;
for(i = 0; i < num_nodes, i++)
if ((nodes_list[i].ip != 0) && (nodes_list[i].ip != ~0)) {
memcpy(nodes_list[num_nodes_ok].client_id, nodes4_list[i].client_id, CLIENT_ID_SIZE);
nodes_list[num_nodes_ok].ip_port.ip.family = AF_INET;
nodes_list[num_nodes_ok].ip_port.ip.ip4.uint32 = nodes4_list[i].ip_port.ip.uint32;
nodes_list[num_nodes_ok].ip_port.port = nodes4_list[i].ip_port.port;
num_nodes_ok++;
}
if (num_nodes_ok < num_nodes) {
/* shouldn't happen */
num_nodes = num_nodes_ok;
}
#else
memcpy(nodes_list, plain + sizeof(ping_id), num_nodes * sizeof(Node_format));
#endif
addto_lists(dht, source, packet + 1);
@ -808,6 +880,19 @@ void DHT_bootstrap(DHT *dht, IP_Port ip_port, uint8_t *public_key)
getnodes(dht, ip_port, public_key, dht->c->self_public_key);
send_ping_request(dht->ping, dht->c, ip_port, public_key);
}
void DHT_bootstrap_ex(DHT *dht, const char *address, uint16_t port, uint8_t *public_key)
{
IPAny_Port ipany_port;
ipany_port.ip.family = AF_INET;
if (addr_resolve_or_parse_ip(address, &ipany_port.ip)) {
/* IPAny temporary: copy down */
IP_Port ip_port;
ip_port.ip.uint32 = ipany_port.ip.ip4.uint32;
ip_port.port = port;
DHT_bootstrap(dht, ip_port, public_key);
}
}
/* Send the given packet to node with client_id
*

View File

@ -75,10 +75,21 @@ typedef struct {
uint64_t NATping_timestamp;
} DHT_Friend;
/* this must be kept even if IP_Port is expanded: wire compatibility */
typedef struct {
uint8_t client_id[CLIENT_ID_SIZE];
IP_Port ip_port;
} Node_format;
IP4_Port ip_port;
} Node4_format;
typedef struct {
uint8_t client_id[CLIENT_ID_SIZE];
IPAny_Port ip_port;
} Node46_format;
/* IPAny temporary: change to 46 */
#define DHT_NODEFORMAT 4
typedef Node4_format Node_format;
/* #define DHT_NODEFORMAT 46 */
/* typedef Node46_format Node_format; */
typedef struct {
IP_Port ip_port;
@ -88,15 +99,15 @@ typedef struct {
/*----------------------------------------------------------------------------------*/
typedef struct {
Net_Crypto *c;
Net_Crypto *c;
Client_data close_clientlist[LCLIENT_LIST];
DHT_Friend *friends_list;
DHT_Friend *friends_list;
uint16_t num_friends;
Pinged send_nodes[LSEND_NODES_ARRAY];
Node_format toping[MAX_TOPING];
uint64_t last_toping;
uint64_t close_lastgetnodes;
void *ping;
uint64_t close_lastgetnodes;
void *ping;
} DHT;
/*----------------------------------------------------------------------------------*/
@ -137,6 +148,7 @@ void do_DHT(DHT *dht);
* Sends a get nodes request to the given node with ip port and public_key.
*/
void DHT_bootstrap(DHT *dht, IP_Port ip_port, uint8_t *public_key);
void DHT_bootstrap_ex(DHT *dht, const char *address, uint16_t port, uint8_t *public_key);
/* Add nodes to the toping list.
* All nodes in this list are pinged every TIME_TOPING seconds

View File

@ -71,7 +71,8 @@ typedef int sock_t;
#define NET_PACKET_PING_REQUEST 0 /* Ping request packet ID. */
#define NET_PACKET_PING_RESPONSE 1 /* Ping response packet ID. */
#define NET_PACKET_GET_NODES 2 /* Get nodes request packet ID. */
#define NET_PACKET_SEND_NODES 3 /* Send nodes response packet ID. */
#define NET_PACKET_SEND_NODES 3 /* Send nodes response packet ID for IPv4 addresses. */
#define NET_PACKET_SEND_NODES_EX 4 /* Send nodes response packet ID for other addresses. */
#define NET_PACKET_HANDSHAKE 16 /* Handshake packet ID. */
#define NET_PACKET_SYNC 17 /* SYNC packet ID. */
#define NET_PACKET_DATA 18 /* Data packet ID. */
@ -114,8 +115,7 @@ typedef union {
uint16_t padding;
};
uint8_t uint8[8];
} IP_Port;
} IP4_Port;
/* will replace IP_Port as soon as the complete infrastructure is in place
* removed the unused union and padding also */
@ -124,6 +124,12 @@ typedef struct {
uint16_t port;
} IPAny_Port;
#ifdef NETWORK_IP_PORT_IS_IPV6
typedef IPAny_Port IP_Port;
#else
typedef IP4_Port IP_Port;
#endif
/* ipport_equal
* compares two IPAny_Port structures
* unset means unequal

View File

@ -374,6 +374,11 @@ void tox_bootstrap(void *tox, IP_Port ip_port, uint8_t *public_key)
Messenger *m = tox;
DHT_bootstrap(m->dht, ip_port, public_key);
}
void tox_bootstrap_ex(void *tox, const char *address, uint16_t port, uint8_t *public_key)
{
Messenger *m = tox;
DHT_bootstrap_ex(m->dht, address, port, public_key);
};
/* return 0 if we are not connected to the DHT.
* return 1 if we are.

View File

@ -291,8 +291,10 @@ void tox_callback_connectionstatus(Tox *tox, void (*function)(Tox *tox, int, uin
/* Use this function to bootstrap the client.
* Sends a get nodes request to the given node with ip port and public_key.
* tox_bootstrap_ex converts the address into an IP_Port structure internally
*/
void tox_bootstrap(Tox *tox, tox_IP_Port ip_port, uint8_t *public_key);
void tox_bootstrap_ex(Tox *tox, const char *address, uint16_t port, uint8_t *public_key);
/* return 0 if we are not connected to the DHT.
* return 1 if we are.