Some fixes.

This commit is contained in:
irungentoo 2013-09-13 17:08:54 -04:00
parent 36e5636406
commit 64d000cdfa
3 changed files with 218 additions and 160 deletions

View File

@ -31,7 +31,6 @@
#include "network.h" #include "network.h"
#include "ping.h" #include "ping.h"
#include "misc_tools.h" #include "misc_tools.h"
#include "Messenger.h"
#include "util.h" #include "util.h"
/* The number of seconds for a non responsive node to become bad. */ /* The number of seconds for a non responsive node to become bad. */
@ -197,73 +196,75 @@ static int friend_number(DHT *dht, uint8_t *client_id)
* helper for get_close_nodes(). argument list is a monster :D * helper for get_close_nodes(). argument list is a monster :D
*/ */
static int get_close_nodes_inner(DHT *dht, uint8_t *client_id, Node_format *nodes_list, static int get_close_nodes_inner(DHT *dht, uint8_t *client_id, Node_format *nodes_list,
sa_family_t sa_family, Client_data *client_list, uint32_t client_list_length, sa_family_t sa_family, Client_data *client_list, uint32_t client_list_length,
time_t timestamp, int *num_nodes_ptr) time_t timestamp, int *num_nodes_ptr)
{ {
int num_nodes = 0; int num_nodes = 0;
int i, tout, inlist, ipv46x, j, closest; int i, tout, inlist, ipv46x, j, closest;
for(i = 0; i < client_list_length; i++) {
Client_data *client = &client_list[i]; for (i = 0; i < client_list_length; i++) {
tout = is_timeout(timestamp, client->timestamp, BAD_NODE_TIMEOUT); Client_data *client = &client_list[i];
inlist = client_in_nodelist(nodes_list, MAX_SENT_NODES, client->client_id); tout = is_timeout(timestamp, client->timestamp, BAD_NODE_TIMEOUT);
inlist = client_in_nodelist(nodes_list, MAX_SENT_NODES, client->client_id);
#ifdef TOX_ENABLE_IPV6 #ifdef TOX_ENABLE_IPV6
IP *client_ip = &client->ip_port.ip; IP *client_ip = &client->ip_port.ip;
/* /*
* Careful: AF_INET isn't seen as AF_INET on dual-stack sockets for * Careful: AF_INET isn't seen as AF_INET on dual-stack sockets for
* our connections, instead we have to look if it is an embedded * our connections, instead we have to look if it is an embedded
* IPv4-in-IPv6 here and convert it down in sendnodes(). * IPv4-in-IPv6 here and convert it down in sendnodes().
*/ */
sa_family_t ip_treat_as_family = client_ip->family; sa_family_t ip_treat_as_family = client_ip->family;
if ((dht->c->lossless_udp->net->family == AF_INET6) &&
(client_ip->family == AF_INET6)) {
/* socket is AF_INET6, address claims AF_INET6:
* check for embedded IPv4-in-IPv6 */
if (IN6_IS_ADDR_V4MAPPED(&client_ip->ip6))
ip_treat_as_family = AF_INET;
}
ipv46x = !(sa_family == ip_treat_as_family); if ((dht->c->lossless_udp->net->family == AF_INET6) &&
(client_ip->family == AF_INET6)) {
/* socket is AF_INET6, address claims AF_INET6:
* check for embedded IPv4-in-IPv6 */
if (IN6_IS_ADDR_V4MAPPED(&client_ip->ip6))
ip_treat_as_family = AF_INET;
}
ipv46x = !(sa_family == ip_treat_as_family);
#else #else
ipv46x = !(sa_family == AF_INET); ipv46x = !(sa_family == AF_INET);
#endif #endif
/* If node isn't good or is already in list. */ /* If node isn't good or is already in list. */
if (tout || inlist || ipv46x) if (tout || inlist || ipv46x)
continue; continue;
if (num_nodes < MAX_SENT_NODES) { if (num_nodes < MAX_SENT_NODES) {
memcpy(nodes_list[num_nodes].client_id, memcpy(nodes_list[num_nodes].client_id,
client->client_id, client->client_id,
CLIENT_ID_SIZE ); CLIENT_ID_SIZE );
nodes_list[num_nodes].ip_port = client->ip_port; nodes_list[num_nodes].ip_port = client->ip_port;
num_nodes++; num_nodes++;
} else { } else {
/* see if node_list contains a client_id that's "further away" /* see if node_list contains a client_id that's "further away"
* compared to the one we're looking at at the moment, if there * compared to the one we're looking at at the moment, if there
* is, replace it * is, replace it
*/ */
for (j = 0; j < MAX_SENT_NODES; ++j) { for (j = 0; j < MAX_SENT_NODES; ++j) {
closest = id_closest( client_id, closest = id_closest( client_id,
nodes_list[j].client_id, nodes_list[j].client_id,
client->client_id ); client->client_id );
/* second client_id is closer than current: change to it */ /* second client_id is closer than current: change to it */
if (closest == 2) { if (closest == 2) {
memcpy( nodes_list[j].client_id, memcpy( nodes_list[j].client_id,
client->client_id, client->client_id,
CLIENT_ID_SIZE); CLIENT_ID_SIZE);
nodes_list[j].ip_port = client->ip_port; nodes_list[j].ip_port = client->ip_port;
break; break;
} }
} }
} }
} }
*num_nodes_ptr = num_nodes; *num_nodes_ptr = num_nodes;
} }
/* Find MAX_SENT_NODES nodes closest to the client_id for the send nodes request: /* Find MAX_SENT_NODES nodes closest to the client_id for the send nodes request:
@ -274,15 +275,15 @@ static int get_close_nodes_inner(DHT *dht, uint8_t *client_id, Node_format *node
*/ */
static int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_family_t sa_family) static int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_family_t sa_family)
{ {
time_t timestamp = unix_time(); time_t timestamp = unix_time();
int num_nodes = 0, i; int num_nodes = 0, i;
get_close_nodes_inner(dht, client_id, nodes_list, sa_family, get_close_nodes_inner(dht, client_id, nodes_list, sa_family,
dht->close_clientlist, LCLIENT_LIST, timestamp, &num_nodes); dht->close_clientlist, LCLIENT_LIST, timestamp, &num_nodes);
for (i = 0; i < dht->num_friends; ++i) for (i = 0; i < dht->num_friends; ++i)
get_close_nodes_inner(dht, client_id, nodes_list, sa_family, get_close_nodes_inner(dht, client_id, nodes_list, sa_family,
dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS,
timestamp, &num_nodes); timestamp, &num_nodes);
return num_nodes; return num_nodes;
} }
@ -554,11 +555,13 @@ static int sendnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *cl
#ifdef TOX_ENABLE_IPV6 #ifdef TOX_ENABLE_IPV6
Node4_format *nodes4_list = (Node4_format *)(plain + sizeof(ping_id)); Node4_format *nodes4_list = (Node4_format *)(plain + sizeof(ping_id));
int i, num_nodes_ok = 0; int i, num_nodes_ok = 0;
for(i = 0; i < num_nodes; i++) {
for (i = 0; i < num_nodes; i++) {
memcpy(nodes4_list[num_nodes_ok].client_id, nodes_list[i].client_id, CLIENT_ID_SIZE); memcpy(nodes4_list[num_nodes_ok].client_id, nodes_list[i].client_id, CLIENT_ID_SIZE);
nodes4_list[num_nodes_ok].ip_port.port = nodes_list[i].ip_port.port; nodes4_list[num_nodes_ok].ip_port.port = nodes_list[i].ip_port.port;
IP *node_ip = &nodes_list[i].ip_port.ip; IP *node_ip = &nodes_list[i].ip_port.ip;
if ((node_ip->family == AF_INET6) && IN6_IS_ADDR_V4MAPPED(&node_ip->ip6)) if ((node_ip->family == AF_INET6) && IN6_IS_ADDR_V4MAPPED(&node_ip->ip6))
/* embedded IPv4-in-IPv6 address: return it in regular sendnodes packet */ /* embedded IPv4-in-IPv6 address: return it in regular sendnodes packet */
nodes4_list[num_nodes_ok].ip_port.ip.uint32 = node_ip->ip6.s6_addr32[3]; nodes4_list[num_nodes_ok].ip_port.ip.uint32 = node_ip->ip6.s6_addr32[3];
@ -574,6 +577,7 @@ static int sendnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *cl
/* shouldn't happen */ /* shouldn't happen */
num_nodes = num_nodes_ok; num_nodes = num_nodes_ok;
} }
#else #else
memcpy(plain + sizeof(ping_id), nodes_list, num_nodes * Node4_format_size); memcpy(plain + sizeof(ping_id), nodes_list, num_nodes * Node4_format_size);
#endif #endif
@ -620,7 +624,7 @@ static int sendnodes_ipv6(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_
uint8_t plain[sizeof(ping_id) + Node_format_size * MAX_SENT_NODES]; uint8_t plain[sizeof(ping_id) + Node_format_size * MAX_SENT_NODES];
uint8_t encrypt[sizeof(ping_id) + Node_format_size * MAX_SENT_NODES + ENCRYPTION_PADDING]; uint8_t encrypt[sizeof(ping_id) + Node_format_size * MAX_SENT_NODES + ENCRYPTION_PADDING];
uint8_t nonce[crypto_box_NONCEBYTES]; uint8_t nonce[crypto_box_NONCEBYTES];
random_nonce(nonce); new_nonce(nonce);
memcpy(plain, &ping_id, sizeof(ping_id)); memcpy(plain, &ping_id, sizeof(ping_id));
memcpy(plain + sizeof(ping_id), nodes_list, num_nodes * Node_format_size); memcpy(plain + sizeof(ping_id), nodes_list, num_nodes * Node_format_size);
@ -691,6 +695,7 @@ static int handle_sendnodes(void *object, IP_Port source, uint8_t *packet, uint3
cid_size += crypto_box_NONCEBYTES + sizeof(ping_id) + ENCRYPTION_PADDING; cid_size += crypto_box_NONCEBYTES + sizeof(ping_id) + ENCRYPTION_PADDING;
size_t Node4_format_size = sizeof(Node4_format); size_t Node4_format_size = sizeof(Node4_format);
if (length > (cid_size + Node4_format_size * MAX_SENT_NODES) || if (length > (cid_size + Node4_format_size * MAX_SENT_NODES) ||
((length - cid_size) % Node4_format_size) != 0 || ((length - cid_size) % Node4_format_size) != 0 ||
(length < cid_size + Node4_format_size)) (length < cid_size + Node4_format_size))
@ -721,7 +726,8 @@ static int handle_sendnodes(void *object, IP_Port source, uint8_t *packet, uint3
Node4_format *nodes4_list = (Node4_format *)(plain + sizeof(ping_id)); Node4_format *nodes4_list = (Node4_format *)(plain + sizeof(ping_id));
int num_nodes_ok = 0; int num_nodes_ok = 0;
for(i = 0; i < num_nodes; i++)
for (i = 0; i < num_nodes; i++)
if ((nodes4_list[i].ip_port.ip.uint32 != 0) && (nodes4_list[i].ip_port.ip.uint32 != ~0)) { if ((nodes4_list[i].ip_port.ip.uint32 != 0) && (nodes4_list[i].ip_port.ip.uint32 != ~0)) {
memcpy(nodes_list[num_nodes_ok].client_id, nodes4_list[i].client_id, CLIENT_ID_SIZE); 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.family = AF_INET;
@ -735,6 +741,7 @@ static int handle_sendnodes(void *object, IP_Port source, uint8_t *packet, uint3
/* shouldn't happen */ /* shouldn't happen */
num_nodes = num_nodes_ok; num_nodes = num_nodes_ok;
} }
#else #else
memcpy(nodes_list, plain + sizeof(ping_id), num_nodes * sizeof(Node_format)); memcpy(nodes_list, plain + sizeof(ping_id), num_nodes * sizeof(Node_format));
#endif #endif
@ -758,6 +765,7 @@ static int handle_sendnodes_ipv6(void *object, IP_Port source, uint8_t *packet,
cid_size += crypto_box_NONCEBYTES + sizeof(ping_id) + ENCRYPTION_PADDING; cid_size += crypto_box_NONCEBYTES + sizeof(ping_id) + ENCRYPTION_PADDING;
size_t Node_format_size = sizeof(Node4_format); size_t Node_format_size = sizeof(Node4_format);
if (length > (cid_size + Node_format_size * MAX_SENT_NODES) || if (length > (cid_size + Node_format_size * MAX_SENT_NODES) ||
((length - cid_size) % Node_format_size) != 0 || ((length - cid_size) % Node_format_size) != 0 ||
(length < cid_size + Node_format_size)) (length < cid_size + Node_format_size))
@ -964,17 +972,19 @@ void DHT_bootstrap(DHT *dht, IP_Port ip_port, uint8_t *public_key)
send_ping_request(dht->ping, dht->c, ip_port, public_key); send_ping_request(dht->ping, dht->c, ip_port, public_key);
} }
int DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled, int DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled,
uint16_t port, uint8_t *public_key) uint16_t port, uint8_t *public_key)
{ {
IP_Port ip_port_v64, ip_port_v4; IP_Port ip_port_v64, ip_port_v4;
IP *ip_extra = NULL; IP *ip_extra = NULL;
#ifdef TOX_ENABLE_IPV6 #ifdef TOX_ENABLE_IPV6
ip_init(&ip_port_v64.ip, ipv6enabled); ip_init(&ip_port_v64.ip, ipv6enabled);
if (ipv6enabled) { if (ipv6enabled) {
ip_port_v64.ip.family = AF_UNSPEC; ip_port_v64.ip.family = AF_UNSPEC;
ip_reset(&ip_port_v4.ip); ip_reset(&ip_port_v4.ip);
ip_extra = &ip_port_v4.ip; ip_extra = &ip_port_v4.ip;
} }
#else #else
ip_init(&ip_port_v64.ip, 0); ip_init(&ip_port_v64.ip, 0);
#endif #endif
@ -983,14 +993,15 @@ int DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enable
ip_port_v64.port = port; ip_port_v64.port = port;
DHT_bootstrap(dht, ip_port_v64, public_key); DHT_bootstrap(dht, ip_port_v64, public_key);
#ifdef TOX_ENABLE_IPV6 #ifdef TOX_ENABLE_IPV6
if ((ip_extra != NULL) && ip_isset(ip_extra)) { if ((ip_extra != NULL) && ip_isset(ip_extra)) {
ip_port_v4.port = port; ip_port_v4.port = port;
DHT_bootstrap(dht, ip_port_v4, public_key); DHT_bootstrap(dht, ip_port_v4, public_key);
} }
#endif #endif
return 1; return 1;
} } else
else
return 0; return 0;
} }
@ -1303,6 +1314,7 @@ static void do_NAT(DHT *dht)
dht->friends_list[i].recvNATping_timestamp + PUNCH_INTERVAL * 2 >= temp_time) { dht->friends_list[i].recvNATping_timestamp + PUNCH_INTERVAL * 2 >= temp_time) {
IP ip = NAT_commonip(ip_list, num, MAX_FRIEND_CLIENTS / 2); IP ip = NAT_commonip(ip_list, num, MAX_FRIEND_CLIENTS / 2);
if (!ip_isset(&ip)) if (!ip_isset(&ip))
continue; continue;
@ -1443,12 +1455,13 @@ void DHT_save(DHT *dht, uint8_t *data)
*/ */
int DHT_load(DHT *dht, uint8_t *data, uint32_t size) int DHT_load(DHT *dht, uint8_t *data, uint32_t size)
{ {
if (size < sizeof(dht->close_clientlist)) { if (size < sizeof(dht->close_clientlist)) {
fprintf(stderr, "DHT_load: Expected at least %u bytes, got %u.\n", sizeof(dht->close_clientlist), size); fprintf(stderr, "DHT_load: Expected at least %u bytes, got %u.\n", sizeof(dht->close_clientlist), size);
return -1; return -1;
} }
uint32_t friendlistsize = size - sizeof(dht->close_clientlist); uint32_t friendlistsize = size - sizeof(dht->close_clientlist);
if (friendlistsize % sizeof(DHT_Friend) != 0) { if (friendlistsize % sizeof(DHT_Friend) != 0) {
fprintf(stderr, "DHT_load: Expected a multiple of %u, got %u.\n", sizeof(DHT_Friend), friendlistsize); fprintf(stderr, "DHT_load: Expected a multiple of %u, got %u.\n", sizeof(DHT_Friend), friendlistsize);
return -1; return -1;
@ -1457,6 +1470,7 @@ int DHT_load(DHT *dht, uint8_t *data, uint32_t size)
uint32_t i, j; uint32_t i, j;
Client_data *client; Client_data *client;
uint16_t friends_num = friendlistsize / sizeof(DHT_Friend); uint16_t friends_num = friendlistsize / sizeof(DHT_Friend);
if (friends_num != 0) { if (friends_num != 0) {
DHT_Friend *tempfriends_list = (DHT_Friend *)(data + sizeof(dht->close_clientlist)); DHT_Friend *tempfriends_list = (DHT_Friend *)(data + sizeof(dht->close_clientlist));
@ -1473,6 +1487,7 @@ int DHT_load(DHT *dht, uint8_t *data, uint32_t size)
} }
Client_data *tempclose_clientlist = (Client_data *)data; Client_data *tempclose_clientlist = (Client_data *)data;
for (i = 0; i < LCLIENT_LIST; ++i) { for (i = 0; i < LCLIENT_LIST; ++i) {
if (tempclose_clientlist[i].timestamp != 0) if (tempclose_clientlist[i].timestamp != 0)
DHT_bootstrap(dht, tempclose_clientlist[i].ip_port, DHT_bootstrap(dht, tempclose_clientlist[i].ip_port,

View File

@ -80,26 +80,30 @@ static uint32_t handshake_id(Lossless_UDP *ludp, IP_Port source)
i++; i++;
#ifdef TOX_ENABLE_IPV6 #ifdef TOX_ENABLE_IPV6
if (source.ip.family == AF_INET)
{ if (source.ip.family == AF_INET) {
IP4 ip4 = source.ip.ip4; IP4 ip4 = source.ip.ip4;
#else #else
IP4 ip4 = source.ip; IP4 ip4 = source.ip;
#endif #endif
int k; int k;
for (k = 0; k < 4; k++) { for (k = 0; k < 4; k++) {
id ^= randtable_initget(ludp, i++, ip4.uint8[k]); id ^= randtable_initget(ludp, i++, ip4.uint8[k]);
} }
#ifdef TOX_ENABLE_IPV6 #ifdef TOX_ENABLE_IPV6
} }
if (source.ip.family == AF_INET6) if (source.ip.family == AF_INET6)
{ {
int k; int k;
for (k = 0; k < 16; k++) { for (k = 0; k < 16; k++) {
id ^= randtable_initget(ludp, i++, source.ip.ip6.s6_addr[k]); id ^= randtable_initget(ludp, i++, source.ip.ip6.s6_addr[k]);
} }
} }
#endif #endif
/* id can't be zero. */ /* id can't be zero. */
@ -116,8 +120,21 @@ static uint32_t handshake_id(Lossless_UDP *ludp, IP_Port source)
*/ */
static void change_handshake(Lossless_UDP *ludp, IP_Port source) static void change_handshake(Lossless_UDP *ludp, IP_Port source)
{ {
uint8_t rand = random_int() % 4; #ifdef TOX_ENABLE_IPV6
ludp->randtable[rand][((uint8_t *)&source)[rand]] = random_int(); uint8_t rand;
if (source.ip.family == AF_INET) {
rand = 2 + random_int() % 4;
} else if (source.ip.family == AF_INET6) {
rand = 2 + random_int() % 16;
} else {
return;
}
#else
uint8_t rand = 2 + random_int() % 4;
#endif
ludp->randtable[rand][((uint8_t *)&source.ip)[rand]] = random_int();
} }
/* /*

View File

@ -73,15 +73,18 @@ static void loglogdata(char *message, uint8_t *buffer, size_t buflen, IP_Port *i
int sendpacket(Networking_Core *net, IP_Port ip_port, uint8_t *data, uint32_t length) int sendpacket(Networking_Core *net, IP_Port ip_port, uint8_t *data, uint32_t length)
{ {
#ifdef TOX_ENABLE_IPV6 #ifdef TOX_ENABLE_IPV6
/* socket AF_INET, but target IP NOT: can't send */ /* socket AF_INET, but target IP NOT: can't send */
if ((net->family == AF_INET) && (ip_port.ip.family != AF_INET)) if ((net->family == AF_INET) && (ip_port.ip.family != AF_INET))
return 0; return -1;
#endif #endif
struct sockaddr_storage addr; struct sockaddr_storage addr;
size_t addrsize = 0; size_t addrsize = 0;
#ifdef TOX_ENABLE_IPV6 #ifdef TOX_ENABLE_IPV6
if (ip_port.ip.family == AF_INET) { if (ip_port.ip.family == AF_INET) {
if (net->family == AF_INET6) { if (net->family == AF_INET6) {
/* must convert to IPV4-in-IPV6 address */ /* must convert to IPV4-in-IPV6 address */
@ -99,11 +102,10 @@ int sendpacket(Networking_Core *net, IP_Port ip_port, uint8_t *data, uint32_t le
addr6->sin6_flowinfo = 0; addr6->sin6_flowinfo = 0;
addr6->sin6_scope_id = 0; addr6->sin6_scope_id = 0;
} } else {
else {
IP4 ip4 = ip_port.ip.ip4; IP4 ip4 = ip_port.ip.ip4;
#else #else
IP4 ip4 = ip_port.ip; IP4 ip4 = ip_port.ip;
#endif #endif
addrsize = sizeof(struct sockaddr_in); addrsize = sizeof(struct sockaddr_in);
struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr; struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;
@ -112,8 +114,8 @@ int sendpacket(Networking_Core *net, IP_Port ip_port, uint8_t *data, uint32_t le
addr4->sin_port = ip_port.port; addr4->sin_port = ip_port.port;
#ifdef TOX_ENABLE_IPV6 #ifdef TOX_ENABLE_IPV6
} }
} } else if (ip_port.ip.family == AF_INET6)
else if (ip_port.ip.family == AF_INET6) { {
addrsize = sizeof(struct sockaddr_in6); addrsize = sizeof(struct sockaddr_in6);
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;
addr6->sin6_family = AF_INET6; addr6->sin6_family = AF_INET6;
@ -122,10 +124,12 @@ int sendpacket(Networking_Core *net, IP_Port ip_port, uint8_t *data, uint32_t le
addr6->sin6_flowinfo = 0; addr6->sin6_flowinfo = 0;
addr6->sin6_scope_id = 0; addr6->sin6_scope_id = 0;
} else { } else
{
/* unknown address type*/ /* unknown address type*/
return 0; return -1;
} }
#endif #endif
int res = sendto(net->sock, (char *) data, length, 0, (struct sockaddr *)&addr, addrsize); int res = sendto(net->sock, (char *) data, length, 0, (struct sockaddr *)&addr, addrsize);
@ -153,37 +157,40 @@ static int receivepacket(sock_t sock, IP_Port *ip_port, uint8_t *data, uint32_t
if (*(int32_t *)length <= 0) { if (*(int32_t *)length <= 0) {
#ifdef LOGGING #ifdef LOGGING
if ((length < 0) && (errno != EWOULDBLOCK)) { if ((length < 0) && (errno != EWOULDBLOCK)) {
sprintf(logbuffer, "Unexpected error reading from socket: %u, %s\n", errno, strerror(errno)); sprintf(logbuffer, "Unexpected error reading from socket: %u, %s\n", errno, strerror(errno));
loglog(logbuffer); loglog(logbuffer);
} }
#endif #endif
return -1; /* Nothing received or empty packet. */ return -1; /* Nothing received or empty packet. */
} }
#ifdef TOX_ENABLE_IPV6 #ifdef TOX_ENABLE_IPV6
if (addr.ss_family == AF_INET) { if (addr.ss_family == AF_INET) {
struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr; struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr;
ip_port->ip.family = addr_in->sin_family; ip_port->ip.family = addr_in->sin_family;
ip_port->ip.ip4.in_addr = addr_in->sin_addr; ip_port->ip.ip4.in_addr = addr_in->sin_addr;
ip_port->port = addr_in->sin_port; ip_port->port = addr_in->sin_port;
} } else if (addr.ss_family == AF_INET6) {
else if (addr.ss_family == AF_INET6) {
struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&addr; struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&addr;
ip_port->ip.family = addr_in6->sin6_family; ip_port->ip.family = addr_in6->sin6_family;
ip_port->ip.ip6 = addr_in6->sin6_addr; ip_port->ip.ip6 = addr_in6->sin6_addr;
ip_port->port = addr_in6->sin6_port; ip_port->port = addr_in6->sin6_port;
} } else
else
return -1; return -1;
#else #else
if (addr.ss_family == AF_INET) { if (addr.ss_family == AF_INET) {
struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr; struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr;
ip_port->ip.in_addr = addr_in->sin_addr; ip_port->ip.in_addr = addr_in->sin_addr;
ip_port->port = addr_in->sin_port; ip_port->port = addr_in->sin_port;
} } else
else
return -1; return -1;
#endif #endif
#ifdef LOGGING #ifdef LOGGING
@ -261,17 +268,20 @@ static void at_shutdown(void)
Networking_Core *new_networking(IP ip, uint16_t port) Networking_Core *new_networking(IP ip, uint16_t port)
{ {
#ifdef TOX_ENABLE_IPV6 #ifdef TOX_ENABLE_IPV6
/* maybe check for invalid IPs like 224+.x.y.z? if there is any IP set ever */ /* maybe check for invalid IPs like 224+.x.y.z? if there is any IP set ever */
if (ip.family != AF_INET && ip.family != AF_INET6) { if (ip.family != AF_INET && ip.family != AF_INET6) {
fprintf(stderr, "Invalid address family: %u\n", ip.family); fprintf(stderr, "Invalid address family: %u\n", ip.family);
return NULL; return NULL;
} }
#endif #endif
if (at_startup() != 0) if (at_startup() != 0)
return NULL; return NULL;
Networking_Core *temp = calloc(1, sizeof(Networking_Core)); Networking_Core *temp = calloc(1, sizeof(Networking_Core));
if (temp == NULL) if (temp == NULL)
return NULL; return NULL;
@ -341,11 +351,11 @@ Networking_Core *new_networking(IP ip, uint16_t port)
struct sockaddr_storage addr; struct sockaddr_storage addr;
size_t addrsize; size_t addrsize;
#ifdef TOX_ENABLE_IPV6 #ifdef TOX_ENABLE_IPV6
if (temp->family == AF_INET)
{ if (temp->family == AF_INET) {
IP4 ip4 = ip.ip4; IP4 ip4 = ip.ip4;
#else #else
IP4 ip4 = ip; IP4 ip4 = ip;
#endif #endif
addrsize = sizeof(struct sockaddr_in); addrsize = sizeof(struct sockaddr_in);
struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr; struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;
@ -355,8 +365,7 @@ Networking_Core *new_networking(IP ip, uint16_t port)
portptr = &addr4->sin_port; portptr = &addr4->sin_port;
#ifdef TOX_ENABLE_IPV6 #ifdef TOX_ENABLE_IPV6
} } else if (temp->family == AF_INET6)
else if (temp->family == AF_INET6)
{ {
addrsize = sizeof(struct sockaddr_in6); addrsize = sizeof(struct sockaddr_in6);
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;
@ -368,21 +377,23 @@ Networking_Core *new_networking(IP ip, uint16_t port)
addr6->sin6_scope_id = 0; addr6->sin6_scope_id = 0;
portptr = &addr6->sin6_port; portptr = &addr6->sin6_port;
} } else
else
return NULL; return NULL;
if (ip.family == AF_INET6) { if (ip.family == AF_INET6)
{
char ipv6only = 0; char ipv6only = 0;
int res = setsockopt(temp->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&ipv6only, sizeof(ipv6only)); int res = setsockopt(temp->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&ipv6only, sizeof(ipv6only));
#ifdef LOGGING #ifdef LOGGING
if (res < 0) { if (res < 0) {
sprintf(logbuffer, "Failed to enable dual-stack on IPv6 socket, won't be able to receive from/send to IPv4 addresses. (%u, %s)\n", sprintf(logbuffer,
"Failed to enable dual-stack on IPv6 socket, won't be able to receive from/send to IPv4 addresses. (%u, %s)\n",
errno, strerror(errno)); errno, strerror(errno));
loglog(logbuffer); loglog(logbuffer);
} } else
else
loglog("Embedded IPv4 addresses enabled successfully.\n"); loglog("Embedded IPv4 addresses enabled successfully.\n");
#endif #endif
/* multicast local nodes */ /* multicast local nodes */
@ -394,15 +405,17 @@ Networking_Core *new_networking(IP ip, uint16_t port)
mreq.ipv6mr_interface = 0; mreq.ipv6mr_interface = 0;
res = setsockopt(temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); res = setsockopt(temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
#ifdef LOGGING #ifdef LOGGING
if (res < 0) { if (res < 0) {
sprintf(logbuffer, "Failed to activate local multicast membership. (%u, %s)\n", sprintf(logbuffer, "Failed to activate local multicast membership. (%u, %s)\n",
errno, strerror(errno)); errno, strerror(errno));
loglog(logbuffer); loglog(logbuffer);
} } else
else
loglog("Local multicast group FF02::1 joined successfully.\n"); loglog("Local multicast group FF02::1 joined successfully.\n");
#endif #endif
} }
#endif #endif
/* a hanging program or a different user might block the standard port; /* a hanging program or a different user might block the standard port;
@ -424,16 +437,18 @@ Networking_Core *new_networking(IP ip, uint16_t port)
uint16_t port_to_try = port; uint16_t port_to_try = port;
*portptr = htons(port_to_try); *portptr = htons(port_to_try);
int tries, res; int tries, res;
for(tries = TOX_PORTRANGE_FROM; tries <= TOX_PORTRANGE_TO; tries++)
for (tries = TOX_PORTRANGE_FROM; tries <= TOX_PORTRANGE_TO; tries++)
{ {
res = bind(temp->sock, (struct sockaddr *)&addr, addrsize); res = bind(temp->sock, (struct sockaddr *)&addr, addrsize);
if (!res)
{ if (!res) {
temp->port = *portptr; temp->port = *portptr;
#ifdef LOGGING #ifdef LOGGING
sprintf(logbuffer, "Bound successfully to %s:%u.\n", ip_ntoa(&ip), ntohs(temp->port)); sprintf(logbuffer, "Bound successfully to %s:%u.\n", ip_ntoa(&ip), ntohs(temp->port));
loglog(logbuffer); loglog(logbuffer);
#endif #endif
/* errno isn't reset on success, only set on failure, the failed /* errno isn't reset on success, only set on failure, the failed
* binds with parallel clients yield a -EPERM to the outside if * binds with parallel clients yield a -EPERM to the outside if
* errno isn't cleared here */ * errno isn't cleared here */
@ -444,6 +459,7 @@ Networking_Core *new_networking(IP ip, uint16_t port)
} }
port_to_try++; port_to_try++;
if (port_to_try > TOX_PORTRANGE_TO) if (port_to_try > TOX_PORTRANGE_TO)
port_to_try = TOX_PORTRANGE_FROM; port_to_try = TOX_PORTRANGE_FROM;
@ -451,7 +467,7 @@ Networking_Core *new_networking(IP ip, uint16_t port)
} }
fprintf(stderr, "Failed to bind socket: %u, %s (IP/Port: %s:%u\n", errno, fprintf(stderr, "Failed to bind socket: %u, %s (IP/Port: %s:%u\n", errno,
strerror(errno), ip_ntoa(&ip), port); strerror(errno), ip_ntoa(&ip), port);
free(temp); free(temp);
return NULL; return NULL;
} }
@ -480,6 +496,7 @@ int ip_equal(IP *a, IP *b)
return 0; return 0;
#ifdef TOX_ENABLE_IPV6 #ifdef TOX_ENABLE_IPV6
if (a->family == AF_INET) if (a->family == AF_INET)
return (a->ip4.in_addr.s_addr == b->ip4.in_addr.s_addr); return (a->ip4.in_addr.s_addr == b->ip4.in_addr.s_addr);
@ -589,28 +606,27 @@ const char *ip_ntoa(IP *ip)
{ {
if (ip) { if (ip) {
#ifdef TOX_ENABLE_IPV6 #ifdef TOX_ENABLE_IPV6
if (ip->family == AF_INET) { if (ip->family == AF_INET) {
addresstext[0] = 0; addresstext[0] = 0;
struct in_addr *addr = (struct in_addr *)&ip->ip4; struct in_addr *addr = (struct in_addr *)&ip->ip4;
inet_ntop(ip->family, addr, addresstext, sizeof(addresstext)); inet_ntop(ip->family, addr, addresstext, sizeof(addresstext));
} } else if (ip->family == AF_INET6) {
else if (ip->family == AF_INET6) {
addresstext[0] = '['; addresstext[0] = '[';
struct in6_addr *addr = (struct in6_addr *)&ip->ip6; struct in6_addr *addr = (struct in6_addr *)&ip->ip6;
inet_ntop(ip->family, addr, &addresstext[1], sizeof(addresstext) - 3); inet_ntop(ip->family, addr, &addresstext[1], sizeof(addresstext) - 3);
size_t len = strlen(addresstext); size_t len = strlen(addresstext);
addresstext[len] = ']'; addresstext[len] = ']';
addresstext[len + 1] = 0; addresstext[len + 1] = 0;
} } else
else
snprintf(addresstext, sizeof(addresstext), "(IP invalid, family %u)", ip->family); snprintf(addresstext, sizeof(addresstext), "(IP invalid, family %u)", ip->family);
#else #else
addresstext[0] = 0; addresstext[0] = 0;
struct in_addr *addr = (struct in_addr *)&ip; struct in_addr *addr = (struct in_addr *)&ip;
inet_ntop(AF_INET, addr, addresstext, sizeof(addresstext)); inet_ntop(AF_INET, addr, addresstext, sizeof(addresstext));
#endif #endif
} } else
else
snprintf(addresstext, sizeof(addresstext), "(IP invalid: NULL)"); snprintf(addresstext, sizeof(addresstext), "(IP invalid: NULL)");
/* brute force protection against lacking termination */ /* brute force protection against lacking termination */
@ -639,6 +655,7 @@ int addr_parse_ip(const char *address, IP *to)
#ifdef TOX_ENABLE_IPV6 #ifdef TOX_ENABLE_IPV6
struct in_addr addr4; struct in_addr addr4;
if (1 == inet_pton(AF_INET, address, &addr4)) { if (1 == inet_pton(AF_INET, address, &addr4)) {
to->family = AF_INET; to->family = AF_INET;
to->ip4.in_addr = addr4; to->ip4.in_addr = addr4;
@ -646,17 +663,21 @@ int addr_parse_ip(const char *address, IP *to)
}; };
struct in6_addr addr6; struct in6_addr addr6;
if (1 == inet_pton(AF_INET6, address, &addr6)) { if (1 == inet_pton(AF_INET6, address, &addr6)) {
to->family = AF_INET6; to->family = AF_INET6;
to->ip6 = addr6; to->ip6 = addr6;
return 1; return 1;
}; };
#else #else
struct in_addr addr4; struct in_addr addr4;
if (1 == inet_pton(AF_INET, address, &addr4)) { if (1 == inet_pton(AF_INET, address, &addr4)) {
to->in_addr = addr4; to->in_addr = addr4;
return 1; return 1;
}; };
#endif #endif
return 0; return 0;
@ -714,6 +735,7 @@ int addr_resolve(const char *address, IP *to, IP *extra)
#endif #endif
rc = getaddrinfo(address, NULL, &hints, &server); rc = getaddrinfo(address, NULL, &hints, &server);
// Lookup failed. // Lookup failed.
if (rc != 0) { if (rc != 0) {
#ifdef __WIN32__ #ifdef __WIN32__
@ -729,64 +751,68 @@ int addr_resolve(const char *address, IP *to, IP *extra)
memset(&ip6, 0, sizeof(ip6)); memset(&ip6, 0, sizeof(ip6));
#endif #endif
for(walker = server; (walker != NULL) && (rc != 3); walker = walker->ai_next) { for (walker = server; (walker != NULL) && (rc != 3); walker = walker->ai_next) {
switch(walker->ai_family) { switch (walker->ai_family) {
case AF_INET: case AF_INET:
if (walker->ai_family == family) { if (walker->ai_family == family) {
struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr; struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr;
#ifdef TOX_ENABLE_IPV6 #ifdef TOX_ENABLE_IPV6
to->ip4.in_addr = addr->sin_addr; to->ip4.in_addr = addr->sin_addr;
#else #else
to->in_addr = addr->sin_addr; to->in_addr = addr->sin_addr;
#endif #endif
rc = 3;
}
#ifdef TOX_ENABLE_IPV6
else if (!(rc & 1)) {
struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr;
to->ip4.in_addr = addr->sin_addr;
rc |= 1;
}
#endif
break; /* switch */
#ifdef TOX_ENABLE_IPV6
case AF_INET6:
if (walker->ai_family == family) {
if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) {
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr;
to->ip6 = addr->sin6_addr;
rc = 3; rc = 3;
} }
} else if (!(rc & 2)) {
if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) { #ifdef TOX_ENABLE_IPV6
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr; else if (!(rc & 1)) {
ip6 = addr->sin6_addr; struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr;
rc |= 2; to->ip4.in_addr = addr->sin_addr;
rc |= 1;
} }
}
break; /* switch */ #endif
break; /* switch */
#ifdef TOX_ENABLE_IPV6
case AF_INET6:
if (walker->ai_family == family) {
if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) {
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr;
to->ip6 = addr->sin6_addr;
rc = 3;
}
} else if (!(rc & 2)) {
if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) {
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr;
ip6 = addr->sin6_addr;
rc |= 2;
}
}
break; /* switch */
#endif #endif
} }
} }
#ifdef TOX_ENABLE_IPV6 #ifdef TOX_ENABLE_IPV6
if (to->family == AF_UNSPEC) { if (to->family == AF_UNSPEC) {
if (rc & 2) { if (rc & 2) {
to->family = AF_INET6; to->family = AF_INET6;
to->ip6 = ip6; to->ip6 = ip6;
if ((rc & 1) && (extra != NULL)) { if ((rc & 1) && (extra != NULL)) {
extra->family = AF_INET; extra->family = AF_INET;
extra->ip4 = ip4; extra->ip4 = ip4;
} }
} } else if (rc & 1) {
else if (rc & 1) {
to->family = AF_INET; to->family = AF_INET;
to->ip4 = ip4; to->ip4 = ip4;
} } else
else
rc = 0; rc = 0;
} }
#endif #endif
@ -826,22 +852,22 @@ static void loglogdata(char *message, uint8_t *buffer, size_t buflen, IP_Port *i
{ {
if (res < 0) if (res < 0)
snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %3u%c %s:%u (%u: %s) | %04x%04x\n", snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %3u%c %s:%u (%u: %s) | %04x%04x\n",
buffer[0], message, buflen < 999 ? buflen : 999, 'E', buffer[0], message, buflen < 999 ? buflen : 999, 'E',
ip_ntoa(&ip_port->ip), ntohs(ip_port->port), errno, ip_ntoa(&ip_port->ip), ntohs(ip_port->port), errno,
strerror(errno), buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0, strerror(errno), buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0,
buflen > 7 ? ntohl(*(uint32_t *)(&buffer[5])) : 0); buflen > 7 ? ntohl(*(uint32_t *)(&buffer[5])) : 0);
else if ((res > 0) && (res <= buflen)) else if ((res > 0) && (res <= buflen))
snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %3u%c %s:%u (%u: %s) | %04x%04x\n", snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %3u%c %s:%u (%u: %s) | %04x%04x\n",
buffer[0], message, res < 999 ? res : 999, res < buflen ? '<' : '=', buffer[0], message, res < 999 ? res : 999, res < buflen ? '<' : '=',
ip_ntoa(&ip_port->ip), ntohs(ip_port->port), 0, ip_ntoa(&ip_port->ip), ntohs(ip_port->port), 0,
"OK", buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0, "OK", buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0,
buflen > 7 ? ntohl(*(uint32_t *)(&buffer[5])) : 0); buflen > 7 ? ntohl(*(uint32_t *)(&buffer[5])) : 0);
else /* empty or overwrite */ else /* empty or overwrite */
snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %u%c%u %s:%u (%u: %s) | %04x%04x\n", snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %u%c%u %s:%u (%u: %s) | %04x%04x\n",
buffer[0], message, res, !res ? '0' : '>', buflen, buffer[0], message, res, !res ? '0' : '>', buflen,
ip_ntoa(&ip_port->ip), ntohs(ip_port->port), 0, ip_ntoa(&ip_port->ip), ntohs(ip_port->port), 0,
"OK", buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0, "OK", buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0,
buflen > 7 ? ntohl(*(uint32_t *)(&buffer[5])) : 0); buflen > 7 ? ntohl(*(uint32_t *)(&buffer[5])) : 0);
logbuffer[sizeof(logbuffer) - 1] = 0; logbuffer[sizeof(logbuffer) - 1] = 0;
loglog(logbuffer); loglog(logbuffer);