mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
Merge remote-tracking branch 'upstream/master' into nTox
This commit is contained in:
commit
6d3ac937af
|
@ -278,7 +278,8 @@ int main(int argc, char *argv[])
|
|||
good_id_b = hex_string_to_bin(good_id_b_str);
|
||||
bad_id = hex_string_to_bin(bad_id_str);
|
||||
|
||||
m = initMessenger();
|
||||
/* IPv6 status from global define */
|
||||
m = initMessenger(TOX_ENABLE_IPV6_DEFAULT);
|
||||
|
||||
/* setup a default friend and friendnum */
|
||||
if (m_addfriend_norequest(m, (uint8_t *)friend_id) < 0)
|
||||
|
|
|
@ -22,5 +22,9 @@ Lossless UDP:
|
|||
[NOT STARTED] Offline messaging
|
||||
[NOT STARTED] Friends list syncing
|
||||
[IN PROGRESS] IPV6 support
|
||||
[DONE] Networking
|
||||
[DONE] DHT + Messenger
|
||||
[NOT STARTED] Group chats
|
||||
|
||||
[IN PROGRESS] GUI (https://github.com/nurupo/ProjectTox-Qt-GUI)
|
||||
[NOT STARTED] Security audit from professionals
|
||||
|
|
|
@ -85,11 +85,27 @@ void manage_keys(DHT *dht)
|
|||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc == 2 && !strncasecmp(argv[1], "-h", 3)) {
|
||||
printf("Usage (connected) : %s [--ipv4|--ipv6] IP PORT KEY\n", argv[0]);
|
||||
printf("Usage (unconnected): %s [--ipv4|--ipv6]\n", argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* let user override default by cmdline */
|
||||
uint8_t ipv6enabled = TOX_ENABLE_IPV6_DEFAULT; /* x */
|
||||
int argvoffset = cmdline_parsefor_ipv46(argc, argv, &ipv6enabled);
|
||||
|
||||
if (argvoffset < 0)
|
||||
exit(1);
|
||||
|
||||
/* Initialize networking -
|
||||
Bind to ip 0.0.0.0:PORT */
|
||||
Bind to ip 0.0.0.0 / [::] : PORT */
|
||||
IP ip;
|
||||
ip.uint32 = 0;
|
||||
ip_init(&ip, ipv6enabled);
|
||||
|
||||
DHT *dht = new_DHT(new_net_crypto(new_networking(ip, PORT)));
|
||||
perror("Initialization");
|
||||
|
||||
manage_keys(dht);
|
||||
printf("Public key: ");
|
||||
uint32_t i;
|
||||
|
@ -108,18 +124,20 @@ int main(int argc, char *argv[])
|
|||
fclose(file);
|
||||
|
||||
printf("\n");
|
||||
printf("Port: %u\n", PORT);
|
||||
printf("Port: %u\n", ntohs(dht->c->lossless_udp->net->port));
|
||||
|
||||
perror("Initialization.");
|
||||
|
||||
if (argc > 3) {
|
||||
if (argc > argvoffset + 3) {
|
||||
printf("Trying to bootstrap into the network...\n");
|
||||
IP_Port bootstrap_info;
|
||||
bootstrap_info.ip.uint32 = inet_addr(argv[1]);
|
||||
bootstrap_info.port = htons(atoi(argv[2]));
|
||||
uint8_t *bootstrap_key = hex_string_to_bin(argv[3]);
|
||||
DHT_bootstrap(dht, bootstrap_info, bootstrap_key);
|
||||
uint16_t port = htons(atoi(argv[argvoffset + 2]));
|
||||
uint8_t *bootstrap_key = hex_string_to_bin(argv[argvoffset + 3]);
|
||||
int res = DHT_bootstrap_from_address(dht, argv[argvoffset + 1],
|
||||
ipv6enabled, port, bootstrap_key);
|
||||
free(bootstrap_key);
|
||||
|
||||
if (!res) {
|
||||
printf("Failed to convert \"%s\" into an IP address. Exiting...\n", argv[argvoffset + 1]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int is_waiting_for_dht_connection = 1;
|
||||
|
@ -134,6 +152,7 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
do_DHT(dht);
|
||||
|
||||
if (last_LANdiscovery + (is_waiting_for_dht_connection ? 5 : LAN_DISCOVERY_INTERVAL) < unix_time()) {
|
||||
send_LANdiscovery(htons(PORT), dht->c);
|
||||
last_LANdiscovery = unix_time();
|
||||
|
|
|
@ -305,7 +305,12 @@ struct server_conf_s configure_server(char *cfg_file)
|
|||
printf("bootstrap_server %d: Invalid port.\n", i);
|
||||
}
|
||||
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
server_conf.info[i].conn.ip.family = AF_INET;
|
||||
server_conf.info[i].conn.ip.ip4.uint32 = resolve_addr(strcpy(tmp_ip, bs_ip));
|
||||
#else
|
||||
server_conf.info[i].conn.ip.uint32 = resolve_addr(strcpy(tmp_ip, bs_ip));
|
||||
#endif
|
||||
server_conf.info[i].conn.port = htons(bs_port);
|
||||
b16_to_key(strcpy(tmp_pk, bs_pk), bs_pk_p);
|
||||
}
|
||||
|
@ -344,7 +349,7 @@ int main(int argc, char *argv[])
|
|||
/* Initialize networking
|
||||
bind to ip 0.0.0.0:PORT */
|
||||
IP ip;
|
||||
ip.uint32 = 0;
|
||||
ip_init(&ip, 0);
|
||||
DHT *dht = new_DHT(new_net_crypto(new_networking(ip, server_conf.port)));
|
||||
/* Read the config file */
|
||||
printf("PID file: %s\n", server_conf.pid_file);
|
||||
|
|
|
@ -66,13 +66,11 @@ void print_clientlist(DHT *dht)
|
|||
}
|
||||
|
||||
p_ip = dht->close_clientlist[i].ip_port;
|
||||
printf("\nIP: %u.%u.%u.%u Port: %u", p_ip.ip.uint8[0], p_ip.ip.uint8[1], p_ip.ip.uint8[2], p_ip.ip.uint8[3],
|
||||
ntohs(p_ip.port));
|
||||
printf("\nIP: %s Port: %u", ip_ntoa(&p_ip.ip), ntohs(p_ip.port));
|
||||
printf("\nTimestamp: %llu", (long long unsigned int) dht->close_clientlist[i].timestamp);
|
||||
printf("\nLast pinged: %llu\n", (long long unsigned int) dht->close_clientlist[i].last_pinged);
|
||||
p_ip = dht->close_clientlist[i].ret_ip_port;
|
||||
printf("OUR IP: %u.%u.%u.%u Port: %u\n", p_ip.ip.uint8[0], p_ip.ip.uint8[1], p_ip.ip.uint8[2], p_ip.ip.uint8[3],
|
||||
ntohs(p_ip.port));
|
||||
printf("OUR IP: %s Port: %u\n", ip_ntoa(&p_ip.ip), ntohs(p_ip.port));
|
||||
printf("Timestamp: %llu\n", (long long unsigned int) dht->close_clientlist[i].ret_timestamp);
|
||||
}
|
||||
}
|
||||
|
@ -91,9 +89,8 @@ void print_friendlist(DHT *dht)
|
|||
printf("%c", dht->friends_list[k].client_id[j]);
|
||||
}
|
||||
|
||||
p_ip = DHT_getfriendip(dht, dht->friends_list[k].client_id);
|
||||
printf("\nIP: %u.%u.%u.%u:%u", p_ip.ip.uint8[0], p_ip.ip.uint8[1], p_ip.ip.uint8[2], p_ip.ip.uint8[3],
|
||||
ntohs(p_ip.port));
|
||||
int friendok = DHT_getfriendip(dht, dht->friends_list[k].client_id, &p_ip);
|
||||
printf("\nIP: %s:%u", ip_ntoa(&p_ip.ip), ntohs(p_ip.port));
|
||||
|
||||
printf("\nCLIENTS IN LIST:\n\n");
|
||||
|
||||
|
@ -108,13 +105,11 @@ void print_friendlist(DHT *dht)
|
|||
}
|
||||
|
||||
p_ip = dht->friends_list[k].client_list[i].ip_port;
|
||||
printf("\nIP: %u.%u.%u.%u:%u", p_ip.ip.uint8[0], p_ip.ip.uint8[1], p_ip.ip.uint8[2], p_ip.ip.uint8[3],
|
||||
ntohs(p_ip.port));
|
||||
printf("\nIP: %s:%u", ip_ntoa(&p_ip.ip), ntohs(p_ip.port));
|
||||
printf("\nTimestamp: %llu", (long long unsigned int) dht->friends_list[k].client_list[i].timestamp);
|
||||
printf("\nLast pinged: %llu\n", (long long unsigned int) dht->friends_list[k].client_list[i].last_pinged);
|
||||
p_ip = dht->friends_list[k].client_list[i].ret_ip_port;
|
||||
printf("ret IP: %u.%u.%u.%u:%u\n", p_ip.ip.uint8[0], p_ip.ip.uint8[1], p_ip.ip.uint8[2], p_ip.ip.uint8[3],
|
||||
ntohs(p_ip.port));
|
||||
printf("ret IP: %s:%u\n", ip_ntoa(&p_ip.ip), ntohs(p_ip.port));
|
||||
printf("Timestamp: %llu\n", (long long unsigned int)dht->friends_list[k].client_list[i].ret_timestamp);
|
||||
}
|
||||
}
|
||||
|
@ -138,19 +133,26 @@ void printpacket(uint8_t *data, uint32_t length, IP_Port ip_port)
|
|||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 4) {
|
||||
printf("Usage: %s [--ipv4|--ipv6] ip port public_key\n", argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* let user override default by cmdline */
|
||||
uint8_t ipv6enabled = TOX_ENABLE_IPV6_DEFAULT; /* x */
|
||||
int argvoffset = cmdline_parsefor_ipv46(argc, argv, &ipv6enabled);
|
||||
|
||||
if (argvoffset < 0)
|
||||
exit(1);
|
||||
|
||||
//memcpy(self_client_id, "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", 32);
|
||||
/* initialize networking */
|
||||
/* bind to ip 0.0.0.0:PORT */
|
||||
IP ip;
|
||||
ip.uint32 = 0;
|
||||
ip_init(&ip, ipv6enabled);
|
||||
|
||||
DHT *dht = new_DHT(new_net_crypto(new_networking(ip, PORT)));
|
||||
|
||||
if (argc < 4) {
|
||||
printf("usage %s ip port public_key\n", argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
new_keys(dht->c);
|
||||
printf("OUR ID: ");
|
||||
uint32_t i;
|
||||
|
@ -170,16 +172,17 @@ int main(int argc, char *argv[])
|
|||
|
||||
DHT_addfriend(dht, hex_string_to_bin(temp_id));
|
||||
|
||||
|
||||
perror("Initialization");
|
||||
IP_Port bootstrap_ip_port;
|
||||
bootstrap_ip_port.port = htons(atoi(argv[2]));
|
||||
/* bootstrap_ip_port.ip.c[0] = 127;
|
||||
* bootstrap_ip_port.ip.c[1] = 0;
|
||||
* bootstrap_ip_port.ip.c[2] = 0;
|
||||
* bootstrap_ip_port.ip.c[3] = 1; */
|
||||
bootstrap_ip_port.ip.uint32 = inet_addr(argv[1]);
|
||||
DHT_bootstrap(dht, bootstrap_ip_port, hex_string_to_bin(argv[3]));
|
||||
|
||||
uint16_t port = htons(atoi(argv[argvoffset + 2]));
|
||||
unsigned char *binary_string = hex_string_to_bin(argv[argvoffset + 3]);
|
||||
int res = DHT_bootstrap_from_address(dht, argv[argvoffset + 1], ipv6enabled, port, binary_string);
|
||||
free(binary_string);
|
||||
|
||||
if (!res) {
|
||||
printf("Failed to convert \"%s\" into an IP address. Exiting...\n", argv[argvoffset + 1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
IP_Port ip_port;
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#include "../toxcore/network.h"
|
||||
#include "../toxcore/Lossless_UDP.h"
|
||||
#include "misc_tools.c"
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
|
@ -66,8 +67,7 @@ void printpacket(uint8_t *data, uint32_t length, IP_Port ip_port)
|
|||
|
||||
void printip(IP_Port ip_port)
|
||||
{
|
||||
printf("\nIP: %u.%u.%u.%u Port: %u", ip_port.ip.uint8[0], ip_port.ip.uint8[1], ip_port.ip.uint8[2], ip_port.ip.uint8[3],
|
||||
ntohs(ip_port.port));
|
||||
printf("\nIP: %s Port: %u", ip_ntoa(&ip_port.ip), ntohs(ip_port.port));
|
||||
}
|
||||
/*
|
||||
void printpackets(Data test)
|
||||
|
@ -152,30 +152,48 @@ void printconnection(int connection_id)
|
|||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 4) {
|
||||
printf("usage: %s ip port filename\n", argv[0]);
|
||||
/* let user override default by cmdline */
|
||||
uint8_t ipv6enabled = TOX_ENABLE_IPV6_DEFAULT; /* x */
|
||||
int argvoffset = cmdline_parsefor_ipv46(argc, argv, &ipv6enabled);
|
||||
|
||||
if (argvoffset < 0)
|
||||
exit(1);
|
||||
|
||||
if (argc < argvoffset + 4) {
|
||||
printf("Usage: %s [--ipv4|--ipv6] ip port filename\n", argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
uint8_t buffer[512];
|
||||
int read;
|
||||
|
||||
FILE *file = fopen(argv[3], "rb");
|
||||
FILE *file = fopen(argv[argvoffset + 3], "rb");
|
||||
|
||||
if (file == NULL)
|
||||
if (file == NULL) {
|
||||
printf("Failed to open file \"%s\".\n", argv[argvoffset + 3]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* initialize networking */
|
||||
/* bind to ip 0.0.0.0:PORT */
|
||||
IP ip;
|
||||
ip.uint32 = 0;
|
||||
ip_init(&ip, ipv6enabled);
|
||||
|
||||
Lossless_UDP *ludp = new_lossless_udp(new_networking(ip, PORT));
|
||||
perror("Initialization");
|
||||
|
||||
IP_Port serverip;
|
||||
serverip.ip.uint32 = inet_addr(argv[1]);
|
||||
serverip.port = htons(atoi(argv[2]));
|
||||
ip_init(&serverip.ip, ipv6enabled);
|
||||
|
||||
if (!addr_resolve(argv[argvoffset + 1], &serverip.ip, NULL)) {
|
||||
printf("Failed to convert \"%s\" into an IP address.\n", argv[argvoffset + 1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
serverip.port = htons(atoi(argv[argvoffset + 2]));
|
||||
printip(serverip);
|
||||
|
||||
int connection = new_connection(ludp, serverip);
|
||||
uint64_t timer = current_time();
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#include "../toxcore/network.h"
|
||||
#include "../toxcore/Lossless_UDP.h"
|
||||
#include "misc_tools.c"
|
||||
|
||||
//Sleep function (x = milliseconds)
|
||||
#ifdef WIN32
|
||||
|
@ -147,24 +148,34 @@ void printconnection(int connection_id)
|
|||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
printf("usage: %s filename\n", argv[0]);
|
||||
/* let user override default by cmdline */
|
||||
uint8_t ipv6enabled = TOX_ENABLE_IPV6_DEFAULT; /* x */
|
||||
int argvoffset = cmdline_parsefor_ipv46(argc, argv, &ipv6enabled);
|
||||
|
||||
if (argvoffset < 0)
|
||||
exit(1);
|
||||
|
||||
if (argc < argvoffset + 2) {
|
||||
printf("Usage: %s [--ipv4|--ipv6] filename\n", argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
uint8_t buffer[512];
|
||||
int read;
|
||||
|
||||
FILE *file = fopen(argv[1], "wb");
|
||||
FILE *file = fopen(argv[argvoffset + 1], "wb");
|
||||
|
||||
if (file == NULL)
|
||||
if (file == NULL) {
|
||||
printf("Failed to open file \"%s\".\n", argv[argvoffset + 1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//initialize networking
|
||||
//bind to ip 0.0.0.0:PORT
|
||||
IP ip;
|
||||
ip.uint32 = 0;
|
||||
ip_init(&ip, ipv6enabled);
|
||||
|
||||
Lossless_UDP *ludp = new_lossless_udp(new_networking(ip, PORT));
|
||||
perror("Initialization");
|
||||
|
||||
|
|
|
@ -95,27 +95,44 @@ void print_message(Messenger *m, int friendnumber, uint8_t *string, uint16_t len
|
|||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 4 && argc != 2) {
|
||||
printf("usage %s ip port public_key (of the DHT bootstrap node)\n or\n %s Save.bak\n", argv[0], argv[0]);
|
||||
/* let user override default by cmdline */
|
||||
uint8_t ipv6enabled = TOX_ENABLE_IPV6_DEFAULT; /* x */
|
||||
int argvoffset = cmdline_parsefor_ipv46(argc, argv, &ipv6enabled);
|
||||
|
||||
if (argvoffset < 0)
|
||||
exit(1);
|
||||
|
||||
/* with optional --ipvx, now it can be 1-4 arguments... */
|
||||
if ((argc != argvoffset + 2) && (argc != argvoffset + 4)) {
|
||||
printf("Usage: %s [--ipv4|--ipv6] ip port public_key (of the DHT bootstrap node)\n", argv[0]);
|
||||
printf("or\n");
|
||||
printf(" %s [--ipv4|--ipv6] Save.bak (to read Save.bak as state file)\n", argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
m = initMessenger();
|
||||
m = initMessenger(ipv6enabled);
|
||||
|
||||
if ( !m ) {
|
||||
fputs("Failed to allocate messenger datastructure\n", stderr);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (argc > 3) {
|
||||
IP_Port bootstrap_ip_port;
|
||||
bootstrap_ip_port.port = htons(atoi(argv[2]));
|
||||
bootstrap_ip_port.ip.uint32 = inet_addr(argv[1]);
|
||||
DHT_bootstrap(m->dht, bootstrap_ip_port, hex_string_to_bin(argv[3]));
|
||||
if (argc == argvoffset + 4) {
|
||||
uint16_t port = htons(atoi(argv[argvoffset + 2]));
|
||||
uint8_t *bootstrap_key = hex_string_to_bin(argv[argvoffset + 3]);
|
||||
int res = DHT_bootstrap_from_address(m->dht, argv[argvoffset + 1],
|
||||
ipv6enabled, port, bootstrap_key);
|
||||
free(bootstrap_key);
|
||||
|
||||
if (!res) {
|
||||
printf("Failed to convert \"%s\" into an IP address. Exiting...\n", argv[argvoffset + 1]);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
FILE *file = fopen(argv[1], "rb");
|
||||
FILE *file = fopen(argv[argvoffset + 1], "rb");
|
||||
|
||||
if ( file == NULL ) {
|
||||
printf("Failed to open \"%s\" - does it exist?\n", argv[argvoffset + 1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,3 +46,37 @@ unsigned char *hex_string_to_bin(char hex_string[])
|
|||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
int cmdline_parsefor_ipv46(int argc, char **argv, uint8_t *ipv6enabled)
|
||||
{
|
||||
int argvoffset = 0, argi;
|
||||
|
||||
for (argi = 1; argi < argc; argi++)
|
||||
if (!strncasecmp(argv[argi], "--ipv", 5)) {
|
||||
if (argv[argi][5] && !argv[argi][6]) {
|
||||
char c = argv[argi][5];
|
||||
|
||||
if (c == '4')
|
||||
*ipv6enabled = 0;
|
||||
else if (c == '6')
|
||||
*ipv6enabled = 1;
|
||||
else {
|
||||
printf("Invalid argument: %s. Try --ipv4 or --ipv6!\n", argv[argi]);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
printf("Invalid argument: %s. Try --ipv4 or --ipv6!\n", argv[argi]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (argvoffset != argi - 1) {
|
||||
printf("Argument must come first: %s.\n", argv[argi]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
argvoffset++;
|
||||
}
|
||||
|
||||
return argvoffset;
|
||||
};
|
||||
|
|
|
@ -292,7 +292,7 @@ void line_eval(Tox *m, char *line)
|
|||
|
||||
int num = atoi(numstring);
|
||||
|
||||
if (tox_sendmessage(m, num, (uint8_t *) message, strlen(message) + 1) != 1) {
|
||||
if (tox_sendmessage(m, num, (uint8_t *) message, strlen(message) + 1) < 1) {
|
||||
new_lines("[i] could not send message");
|
||||
} else {
|
||||
new_lines(format_message(m, message, -1));
|
||||
|
@ -598,36 +598,36 @@ void print_groupmessage(Tox *m, int groupnumber, uint8_t *message, uint16_t leng
|
|||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 4) {
|
||||
printf("Usage: %s [--ipv4|--ipv6] IP PORT KEY [-f keyfile]\n", argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* let user override default by cmdline */
|
||||
uint8_t ipv6enabled = TOX_ENABLE_IPV6_DEFAULT; /* x */
|
||||
int argvoffset = cmdline_parsefor_ipv46(argc, argv, &ipv6enabled);
|
||||
|
||||
if (argvoffset < 0)
|
||||
exit(1);
|
||||
|
||||
int on = 0;
|
||||
int c = 0;
|
||||
int i = 0;
|
||||
char *filename = "data";
|
||||
char idstring[200] = {0};
|
||||
Tox *m;
|
||||
|
||||
if (argc < 4) {
|
||||
printf("[!] Usage: %s [IP] [port] [public_key] <keyfile>\n", argv[0]);
|
||||
if ((argc == 2) && !strcmp(argv[1], "-h")) {
|
||||
print_help();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (argv[i] == NULL) {
|
||||
break;
|
||||
} else if (argv[i][0] == '-') {
|
||||
if (argv[i][1] == 'h') {
|
||||
print_help();
|
||||
exit(0);
|
||||
} else if (argv[i][1] == 'f') {
|
||||
if (argv[i + 1] != NULL)
|
||||
filename = argv[i + 1];
|
||||
else {
|
||||
fputs("[!] you passed '-f' without giving an argument!\n", stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* [-f keyfile] MUST be last two arguments, no point in walking over the list
|
||||
* especially not a good idea to accept it anywhere in the middle */
|
||||
if (argc > argvoffset + 3)
|
||||
if (!strcmp(argv[argc - 2], "-f"))
|
||||
filename = argv[argc - 1];
|
||||
|
||||
m = tox_new();
|
||||
m = tox_new(ipv6enabled);
|
||||
|
||||
if ( !m ) {
|
||||
fputs("Failed to allocate Messenger datastructure", stderr);
|
||||
|
@ -653,18 +653,17 @@ int main(int argc, char *argv[])
|
|||
new_lines(idstring);
|
||||
strcpy(line, "");
|
||||
|
||||
tox_IP_Port bootstrap_ip_port;
|
||||
bootstrap_ip_port.port = htons(atoi(argv[2]));
|
||||
int resolved_address = resolve_addr(argv[1]);
|
||||
|
||||
if (resolved_address != 0)
|
||||
bootstrap_ip_port.ip.i = resolved_address;
|
||||
else
|
||||
exit(1);
|
||||
|
||||
unsigned char *binary_string = hex_string_to_bin(argv[3]);
|
||||
tox_bootstrap(m, bootstrap_ip_port, binary_string);
|
||||
uint16_t port = htons(atoi(argv[argvoffset + 2]));
|
||||
unsigned char *binary_string = hex_string_to_bin(argv[argvoffset + 3]);
|
||||
int res = tox_bootstrap_from_address(m, argv[argvoffset + 1], ipv6enabled, port, binary_string);
|
||||
free(binary_string);
|
||||
|
||||
if (!res) {
|
||||
printf("Failed to convert \"%s\" into an IP address. Exiting...\n", argv[argvoffset + 1]);
|
||||
endwin();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
nodelay(stdscr, TRUE);
|
||||
|
||||
new_lines("[i] change username with /n");
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <ctype.h>
|
||||
|
||||
#include "../toxcore/tox.h"
|
||||
|
||||
#define STRING_LENGTH 256
|
||||
#define HISTORY 50
|
||||
#define PUB_KEY_BYTES 32
|
||||
|
|
487
toxcore/DHT.c
487
toxcore/DHT.c
|
@ -28,8 +28,10 @@
|
|||
#endif
|
||||
|
||||
#include "DHT.h"
|
||||
#include "network.h"
|
||||
#include "ping.h"
|
||||
#include "misc_tools.h"
|
||||
#include "util.h"
|
||||
|
||||
/* The number of seconds for a non responsive node to become bad. */
|
||||
#define BAD_NODE_TIMEOUT 70
|
||||
|
@ -115,11 +117,6 @@ static int client_id_cmp(ClientPair p1, ClientPair p2)
|
|||
return c;
|
||||
}
|
||||
|
||||
static int ipport_equal(IP_Port a, IP_Port b)
|
||||
{
|
||||
return (a.ip.uint32 == b.ip.uint32) && (a.port == b.port);
|
||||
}
|
||||
|
||||
static int id_equal(uint8_t *a, uint8_t *b)
|
||||
{
|
||||
return memcmp(a, b, CLIENT_ID_SIZE) == 0;
|
||||
|
@ -142,20 +139,23 @@ static int client_in_list(Client_data *list, uint32_t length, uint8_t *client_id
|
|||
uint32_t i;
|
||||
uint64_t temp_time = unix_time();
|
||||
|
||||
for (i = 0; i < length; ++i) {
|
||||
/* If ip_port is assigned to a different client_id replace it */
|
||||
if (ipport_equal(list[i].ip_port, ip_port)) {
|
||||
memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE);
|
||||
}
|
||||
|
||||
/* if client_id is in list, find it and maybe overwrite ip_port */
|
||||
for (i = 0; i < length; ++i)
|
||||
if (id_equal(list[i].client_id, client_id)) {
|
||||
/* Refresh the client timestamp. */
|
||||
list[i].timestamp = temp_time;
|
||||
list[i].ip_port.ip.uint32 = ip_port.ip.uint32;
|
||||
list[i].ip_port.port = ip_port.port;
|
||||
list[i].ip_port = ip_port;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* client_id not in list yet: find ip_port to overwrite */
|
||||
for (i = 0; i < length; ++i)
|
||||
if (ipport_equal(&list[i].ip_port, &ip_port)) {
|
||||
/* Refresh the client timestamp. */
|
||||
list[i].timestamp = temp_time;
|
||||
memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -192,92 +192,98 @@ static int friend_number(DHT *dht, uint8_t *client_id)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* Find MAX_SENT_NODES nodes closest to the client_id for the send nodes request:
|
||||
* put them in the nodes_list and return how many were found.
|
||||
*
|
||||
* TODO: For the love of based Allah make this function cleaner and much more efficient.
|
||||
/*
|
||||
* helper for get_close_nodes(). argument list is a monster :D
|
||||
*/
|
||||
static int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list)
|
||||
static void 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,
|
||||
time_t timestamp, int *num_nodes_ptr)
|
||||
{
|
||||
uint32_t i, j, k;
|
||||
uint64_t temp_time = unix_time();
|
||||
int num_nodes = 0, closest, tout, inlist;
|
||||
int num_nodes = *num_nodes_ptr;
|
||||
int i, tout, inlist, ipv46x, j, closest;
|
||||
|
||||
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);
|
||||
for (i = 0; i < client_list_length; i++) {
|
||||
Client_data *client = &client_list[i];
|
||||
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
|
||||
IP *client_ip = &client->ip_port.ip;
|
||||
|
||||
/*
|
||||
* 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
|
||||
* IPv4-in-IPv6 here and convert it down in sendnodes().
|
||||
*/
|
||||
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.in6_addr))
|
||||
ip_treat_as_family = AF_INET;
|
||||
}
|
||||
|
||||
ipv46x = !(sa_family == ip_treat_as_family);
|
||||
#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) {
|
||||
memcpy(nodes_list[num_nodes].client_id,
|
||||
client->client_id,
|
||||
CLIENT_ID_SIZE );
|
||||
|
||||
memcpy( nodes_list[num_nodes].client_id,
|
||||
dht->close_clientlist[i].client_id,
|
||||
CLIENT_ID_SIZE );
|
||||
|
||||
nodes_list[num_nodes].ip_port = dht->close_clientlist[i].ip_port;
|
||||
nodes_list[num_nodes].ip_port = client->ip_port;
|
||||
num_nodes++;
|
||||
|
||||
} else {
|
||||
|
||||
/* 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
|
||||
* is, replace it
|
||||
*/
|
||||
for (j = 0; j < MAX_SENT_NODES; ++j) {
|
||||
closest = id_closest( client_id,
|
||||
nodes_list[j].client_id,
|
||||
dht->close_clientlist[i].client_id );
|
||||
client->client_id );
|
||||
|
||||
/* second client_id is closer than current: change to it */
|
||||
if (closest == 2) {
|
||||
memcpy( nodes_list[j].client_id,
|
||||
dht->close_clientlist[i].client_id,
|
||||
client->client_id,
|
||||
CLIENT_ID_SIZE);
|
||||
|
||||
nodes_list[j].ip_port = dht->close_clientlist[i].ip_port;
|
||||
nodes_list[j].ip_port = client->ip_port;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < dht->num_friends; ++i) {
|
||||
for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) {
|
||||
*num_nodes_ptr = num_nodes;
|
||||
}
|
||||
|
||||
tout = is_timeout(temp_time, dht->friends_list[i].client_list[j].timestamp, BAD_NODE_TIMEOUT);
|
||||
inlist = client_in_nodelist( nodes_list,
|
||||
MAX_SENT_NODES,
|
||||
dht->friends_list[i].client_list[j].client_id);
|
||||
/* Find MAX_SENT_NODES nodes closest to the client_id for the send nodes request:
|
||||
* put them in the nodes_list and return how many were found.
|
||||
*
|
||||
* TODO: For the love of based <your favorite deity, in doubt use "love"> make
|
||||
* this function cleaner and much more efficient.
|
||||
*/
|
||||
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();
|
||||
int num_nodes = 0, i;
|
||||
get_close_nodes_inner(dht, client_id, nodes_list, sa_family,
|
||||
dht->close_clientlist, LCLIENT_LIST, timestamp, &num_nodes);
|
||||
|
||||
/* If node isn't good or is already in list. */
|
||||
if (tout || inlist)
|
||||
continue;
|
||||
|
||||
if (num_nodes < MAX_SENT_NODES) {
|
||||
|
||||
memcpy( nodes_list[num_nodes].client_id,
|
||||
dht->friends_list[i].client_list[j].client_id,
|
||||
CLIENT_ID_SIZE);
|
||||
|
||||
nodes_list[num_nodes].ip_port = dht->friends_list[i].client_list[j].ip_port;
|
||||
num_nodes++;
|
||||
} else {
|
||||
for (k = 0; k < MAX_SENT_NODES; ++k) {
|
||||
|
||||
closest = id_closest( client_id,
|
||||
nodes_list[k].client_id,
|
||||
dht->friends_list[i].client_list[j].client_id );
|
||||
|
||||
if (closest == 2) {
|
||||
memcpy( nodes_list[k].client_id,
|
||||
dht->friends_list[i].client_list[j].client_id,
|
||||
CLIENT_ID_SIZE );
|
||||
|
||||
nodes_list[k].ip_port = dht->friends_list[i].client_list[j].ip_port;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < dht->num_friends; ++i)
|
||||
get_close_nodes_inner(dht, client_id, nodes_list, sa_family,
|
||||
dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS,
|
||||
timestamp, &num_nodes);
|
||||
|
||||
return num_nodes;
|
||||
}
|
||||
|
@ -301,7 +307,7 @@ static int replace_bad( Client_data *list,
|
|||
memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE);
|
||||
list[i].ip_port = ip_port;
|
||||
list[i].timestamp = temp_time;
|
||||
list[i].ret_ip_port.ip.uint32 = 0;
|
||||
ip_reset(&list[i].ret_ip_port.ip);
|
||||
list[i].ret_ip_port.port = 0;
|
||||
list[i].ret_timestamp = 0;
|
||||
return 0;
|
||||
|
@ -349,7 +355,7 @@ static int replace_good( Client_data *list,
|
|||
memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE);
|
||||
list[i].ip_port = ip_port;
|
||||
list[i].timestamp = temp_time;
|
||||
list[i].ret_ip_port.ip.uint32 = 0;
|
||||
ip_reset(&list[i].ret_ip_port.ip);
|
||||
list[i].ret_ip_port.port = 0;
|
||||
list[i].ret_timestamp = 0;
|
||||
return 0;
|
||||
|
@ -447,13 +453,13 @@ static int is_gettingnodes(DHT *dht, IP_Port ip_port, uint64_t ping_id)
|
|||
if (!is_timeout(temp_time, dht->send_nodes[i].timestamp, PING_TIMEOUT)) {
|
||||
pinging = 0;
|
||||
|
||||
if (ip_port.ip.uint32 != 0 && ipport_equal(dht->send_nodes[i].ip_port, ip_port))
|
||||
++pinging;
|
||||
|
||||
if (ping_id != 0 && dht->send_nodes[i].ping_id == ping_id)
|
||||
++pinging;
|
||||
|
||||
if (pinging == (ping_id != 0) + (ip_port.ip.uint32 != 0))
|
||||
if (ip_isset(&ip_port.ip) && ipport_equal(&dht->send_nodes[i].ip_port, &ip_port))
|
||||
++pinging;
|
||||
|
||||
if (pinging == (ping_id != 0) + ip_isset(&ip_port.ip))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -518,44 +524,75 @@ static int getnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *cli
|
|||
memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES);
|
||||
memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len);
|
||||
|
||||
return sendpacket(dht->c->lossless_udp->net->sock, ip_port, data, sizeof(data));
|
||||
return sendpacket(dht->c->lossless_udp->net, ip_port, data, sizeof(data));
|
||||
}
|
||||
|
||||
/* 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];
|
||||
new_nonce(nonce);
|
||||
|
||||
memcpy(plain, &ping_id, sizeof(ping_id));
|
||||
memcpy(plain + sizeof(ping_id), nodes_list, num_nodes * sizeof(Node_format));
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
Node4_format *nodes4_list = (Node4_format *)(plain + sizeof(ping_id));
|
||||
int i, num_nodes_ok = 0;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
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;
|
||||
|
||||
IP *node_ip = &nodes_list[i].ip_port.ip;
|
||||
|
||||
if ((node_ip->family == AF_INET6) && IN6_IS_ADDR_V4MAPPED(&node_ip->ip6.in6_addr))
|
||||
/* embedded IPv4-in-IPv6 address: return it in regular sendnodes packet */
|
||||
nodes4_list[num_nodes_ok].ip_port.ip.uint32 = node_ip->ip6.uint32[3];
|
||||
else if (node_ip->family == AF_INET)
|
||||
nodes4_list[num_nodes_ok].ip_port.ip.uint32 = node_ip->ip4.uint32;
|
||||
else /* shouldn't happen */
|
||||
continue;
|
||||
|
||||
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;
|
||||
|
@ -563,9 +600,57 @@ static int sendnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *cl
|
|||
memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES);
|
||||
memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len);
|
||||
|
||||
return sendpacket(dht->c->lossless_udp->net->sock, ip_port, data, 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + len);
|
||||
return sendpacket(dht->c->lossless_udp->net, ip_port, data, 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + len);
|
||||
}
|
||||
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
/* Send a send nodes response: message for IPv6 nodes */
|
||||
static int sendnodes_ipv6(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 Node_format_size = sizeof(Node_format);
|
||||
uint8_t data[1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(ping_id)
|
||||
+ Node_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, AF_INET6);
|
||||
|
||||
if (num_nodes == 0)
|
||||
return 0;
|
||||
|
||||
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 nonce[crypto_box_NONCEBYTES];
|
||||
new_nonce(nonce);
|
||||
|
||||
memcpy(plain, &ping_id, sizeof(ping_id));
|
||||
memcpy(plain + sizeof(ping_id), nodes_list, num_nodes * Node_format_size);
|
||||
|
||||
int len = encrypt_data( public_key,
|
||||
dht->c->self_secret_key,
|
||||
nonce,
|
||||
plain,
|
||||
sizeof(ping_id) + num_nodes * Node_format_size,
|
||||
encrypt );
|
||||
|
||||
if (len == -1)
|
||||
return -1;
|
||||
|
||||
if ((unsigned int)len != sizeof(ping_id) + num_nodes * Node_format_size + ENCRYPTION_PADDING)
|
||||
return -1;
|
||||
|
||||
data[0] = NET_PACKET_SEND_NODES_IPV6;
|
||||
memcpy(data + 1, dht->c->self_public_key, CLIENT_ID_SIZE);
|
||||
memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES);
|
||||
memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len);
|
||||
|
||||
return sendpacket(dht->c->lossless_udp->net, ip_port, data, 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + len);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int handle_getnodes(void *object, IP_Port source, uint8_t *packet, uint32_t length)
|
||||
{
|
||||
DHT *dht = object;
|
||||
|
@ -593,6 +678,10 @@ static int handle_getnodes(void *object, IP_Port source, uint8_t *packet, uint32
|
|||
|
||||
memcpy(&ping_id, plain, sizeof(ping_id));
|
||||
sendnodes(dht, source, packet + 1, plain + sizeof(ping_id), ping_id);
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
sendnodes_ipv6(dht, source, packet + 1, plain + sizeof(ping_id),
|
||||
ping_id); /* TODO: prevent possible amplification attacks */
|
||||
#endif
|
||||
|
||||
//send_ping_request(dht, source, packet + 1); /* TODO: make this smarter? */
|
||||
|
||||
|
@ -606,22 +695,24 @@ 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));
|
||||
|
@ -629,13 +720,35 @@ static int handle_sendnodes(void *object, IP_Port source, uint8_t *packet, uint3
|
|||
if (!is_gettingnodes(dht, source, ping_id))
|
||||
return 1;
|
||||
|
||||
uint32_t i;
|
||||
Node_format nodes_list[MAX_SENT_NODES];
|
||||
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
Node4_format *nodes4_list = (Node4_format *)(plain + sizeof(ping_id));
|
||||
|
||||
int num_nodes_ok = 0;
|
||||
|
||||
for (i = 0; i < num_nodes; i++)
|
||||
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);
|
||||
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);
|
||||
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < num_nodes; ++i) {
|
||||
send_ping_request(dht->ping, dht->c, nodes_list[i].ip_port, nodes_list[i].client_id);
|
||||
returnedip_ports(dht, nodes_list[i].ip_port, nodes_list[i].client_id, packet + 1);
|
||||
|
@ -644,9 +757,75 @@ static int handle_sendnodes(void *object, IP_Port source, uint8_t *packet, uint3
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
static int handle_sendnodes_ipv6(void *object, IP_Port source, uint8_t *packet, uint32_t length)
|
||||
{
|
||||
DHT *dht = object;
|
||||
uint64_t ping_id;
|
||||
uint32_t cid_size = 1 + CLIENT_ID_SIZE;
|
||||
cid_size += crypto_box_NONCEBYTES + sizeof(ping_id) + ENCRYPTION_PADDING;
|
||||
|
||||
size_t Node_format_size = sizeof(Node_format);
|
||||
|
||||
if (length > (cid_size + Node_format_size * MAX_SENT_NODES) ||
|
||||
((length - cid_size) % Node_format_size) != 0 ||
|
||||
(length < cid_size + Node_format_size))
|
||||
return 1;
|
||||
|
||||
uint32_t num_nodes = (length - cid_size) / Node_format_size;
|
||||
uint8_t plain[sizeof(ping_id) + Node_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 * Node_format_size + ENCRYPTION_PADDING, plain );
|
||||
|
||||
if ((unsigned int)len != sizeof(ping_id) + num_nodes * Node_format_size)
|
||||
return 1;
|
||||
|
||||
memcpy(&ping_id, plain, sizeof(ping_id));
|
||||
|
||||
if (!is_gettingnodes(dht, source, ping_id))
|
||||
return 1;
|
||||
|
||||
uint32_t i;
|
||||
Node_format nodes_list[MAX_SENT_NODES];
|
||||
memcpy(nodes_list, plain + sizeof(ping_id), num_nodes * sizeof(Node_format));
|
||||
|
||||
addto_lists(dht, source, packet + 1);
|
||||
|
||||
for (i = 0; i < num_nodes; ++i) {
|
||||
send_ping_request(dht->ping, dht->c, nodes_list[i].ip_port, nodes_list[i].client_id);
|
||||
returnedip_ports(dht, nodes_list[i].ip_port, nodes_list[i].client_id, packet + 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
/*------------------------END of packet handling functions--------------------------*/
|
||||
|
||||
/*
|
||||
* Send get nodes requests with client_id to max_num peers in list of length length
|
||||
*/
|
||||
static void get_bunchnodes(DHT *dht, Client_data *list, uint16_t length, uint16_t max_num, uint8_t *client_id)
|
||||
{
|
||||
uint64_t temp_time = unix_time();
|
||||
uint32_t i, num = 0;
|
||||
|
||||
for (i = 0; i < length; ++i)
|
||||
if (ipport_isset(&(list[i].ip_port)) && !is_timeout(temp_time, list[i].ret_timestamp, BAD_NODE_TIMEOUT)) {
|
||||
getnodes(dht, list[i].ip_port, list[i].client_id, client_id);
|
||||
++num;
|
||||
|
||||
if (num >= max_num)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int DHT_addfriend(DHT *dht, uint8_t *client_id)
|
||||
{
|
||||
if (friend_number(dht, client_id) != -1) /* Is friend already in DHT? */
|
||||
|
@ -664,6 +843,7 @@ int DHT_addfriend(DHT *dht, uint8_t *client_id)
|
|||
|
||||
dht->friends_list[dht->num_friends].NATping_id = ((uint64_t)random_int() << 32) + random_int();
|
||||
++dht->num_friends;
|
||||
get_bunchnodes(dht, dht->close_clientlist, LCLIENT_LIST, MAX_FRIEND_CLIENTS, client_id);/*TODO: make this better?*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -703,27 +883,30 @@ int DHT_delfriend(DHT *dht, uint8_t *client_id)
|
|||
}
|
||||
|
||||
/* TODO: Optimize this. */
|
||||
IP_Port DHT_getfriendip(DHT *dht, uint8_t *client_id)
|
||||
int DHT_getfriendip(DHT *dht, uint8_t *client_id, IP_Port *ip_port)
|
||||
{
|
||||
uint32_t i, j;
|
||||
uint64_t temp_time = unix_time();
|
||||
IP_Port empty = {{{{0}}, 0, 0}};
|
||||
|
||||
ip_reset(&ip_port->ip);
|
||||
ip_port->port = 0;
|
||||
|
||||
for (i = 0; i < dht->num_friends; ++i) {
|
||||
/* Equal */
|
||||
if (id_equal(dht->friends_list[i].client_id, client_id)) {
|
||||
for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) {
|
||||
if (id_equal(dht->friends_list[i].client_list[j].client_id, client_id)
|
||||
&& !is_timeout(temp_time, dht->friends_list[i].client_list[j].timestamp, BAD_NODE_TIMEOUT))
|
||||
return dht->friends_list[i].client_list[j].ip_port;
|
||||
&& !is_timeout(temp_time, dht->friends_list[i].client_list[j].timestamp, BAD_NODE_TIMEOUT)) {
|
||||
*ip_port = dht->friends_list[i].client_list[j].ip_port;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return empty;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
empty.ip.uint32 = 1;
|
||||
return empty;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Ping each client in the "friends" list every PING_INTERVAL seconds. Send a get nodes request
|
||||
|
@ -808,6 +991,40 @@ 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);
|
||||
}
|
||||
int DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled,
|
||||
uint16_t port, uint8_t *public_key)
|
||||
{
|
||||
IP_Port ip_port_v64;
|
||||
IP *ip_extra = NULL;
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
IP_Port ip_port_v4;
|
||||
ip_init(&ip_port_v64.ip, ipv6enabled);
|
||||
|
||||
if (ipv6enabled) {
|
||||
ip_port_v64.ip.family = AF_UNSPEC;
|
||||
ip_reset(&ip_port_v4.ip);
|
||||
ip_extra = &ip_port_v4.ip;
|
||||
}
|
||||
|
||||
#else
|
||||
ip_init(&ip_port_v64.ip, 0);
|
||||
#endif
|
||||
|
||||
if (addr_resolve_or_parse_ip(address, &ip_port_v64.ip, ip_extra)) {
|
||||
ip_port_v64.port = port;
|
||||
DHT_bootstrap(dht, ip_port_v64, public_key);
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
|
||||
if ((ip_extra != NULL) && ip_isset(ip_extra)) {
|
||||
ip_port_v4.port = port;
|
||||
DHT_bootstrap(dht, ip_port_v4, public_key);
|
||||
}
|
||||
|
||||
#endif
|
||||
return 1;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Send the given packet to node with client_id
|
||||
*
|
||||
|
@ -819,7 +1036,7 @@ int route_packet(DHT *dht, uint8_t *client_id, uint8_t *packet, uint32_t length)
|
|||
|
||||
for (i = 0; i < LCLIENT_LIST; ++i) {
|
||||
if (id_equal(client_id, dht->close_clientlist[i].client_id))
|
||||
return sendpacket(dht->c->lossless_udp->net->sock, dht->close_clientlist[i].ip_port, packet, length);
|
||||
return sendpacket(dht->c->lossless_udp->net, dht->close_clientlist[i].ip_port, packet, length);
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
@ -848,7 +1065,7 @@ static int friend_iplist(DHT *dht, IP_Port *ip_portlist, uint16_t friend_num)
|
|||
client = &friend->client_list[i];
|
||||
|
||||
/* If ip is not zero and node is good. */
|
||||
if (client->ret_ip_port.ip.uint32 != 0 && !is_timeout(temp_time, client->ret_timestamp, BAD_NODE_TIMEOUT)) {
|
||||
if (ip_isset(&client->ret_ip_port.ip) && !is_timeout(temp_time, client->ret_timestamp, BAD_NODE_TIMEOUT)) {
|
||||
|
||||
if (id_equal(client->client_id, friend->client_id))
|
||||
return 0;
|
||||
|
@ -890,8 +1107,8 @@ int route_tofriend(DHT *dht, uint8_t *friend_id, uint8_t *packet, uint32_t lengt
|
|||
client = &friend->client_list[i];
|
||||
|
||||
/* If ip is not zero and node is good. */
|
||||
if (client->ret_ip_port.ip.uint32 != 0 && !is_timeout(temp_time, client->ret_timestamp, BAD_NODE_TIMEOUT)) {
|
||||
int retval = sendpacket(dht->c->lossless_udp->net->sock, client->ip_port, packet, length);
|
||||
if (ip_isset(&client->ret_ip_port.ip) && !is_timeout(temp_time, client->ret_timestamp, BAD_NODE_TIMEOUT)) {
|
||||
int retval = sendpacket(dht->c->lossless_udp->net, client->ip_port, packet, length);
|
||||
|
||||
if ((unsigned int)retval == length)
|
||||
++sent;
|
||||
|
@ -924,7 +1141,7 @@ static int routeone_tofriend(DHT *dht, uint8_t *friend_id, uint8_t *packet, uint
|
|||
client = &friend->client_list[i];
|
||||
|
||||
/* If ip is not zero and node is good. */
|
||||
if (client->ret_ip_port.ip.uint32 != 0 && !is_timeout(temp_time, client->ret_timestamp, BAD_NODE_TIMEOUT)) {
|
||||
if (ip_isset(&client->ret_ip_port.ip) && !is_timeout(temp_time, client->ret_timestamp, BAD_NODE_TIMEOUT)) {
|
||||
ip_list[n] = client->ip_port;
|
||||
++n;
|
||||
}
|
||||
|
@ -933,7 +1150,7 @@ static int routeone_tofriend(DHT *dht, uint8_t *friend_id, uint8_t *packet, uint
|
|||
if (n < 1)
|
||||
return 0;
|
||||
|
||||
int retval = sendpacket(dht->c->lossless_udp->net->sock, ip_list[rand() % n], packet, length);
|
||||
int retval = sendpacket(dht->c->lossless_udp->net, ip_list[rand() % n], packet, length);
|
||||
|
||||
if ((unsigned int)retval == length)
|
||||
return 1;
|
||||
|
@ -1032,7 +1249,8 @@ static int handle_NATping(void *object, IP_Port source, uint8_t *source_pubkey,
|
|||
*/
|
||||
static IP NAT_commonip(IP_Port *ip_portlist, uint16_t len, uint16_t min_num)
|
||||
{
|
||||
IP zero = {{0}};
|
||||
IP zero;
|
||||
ip_reset(&zero);
|
||||
|
||||
if (len > MAX_FRIEND_CLIENTS)
|
||||
return zero;
|
||||
|
@ -1042,7 +1260,7 @@ static IP NAT_commonip(IP_Port *ip_portlist, uint16_t len, uint16_t min_num)
|
|||
|
||||
for (i = 0; i < len; ++i) {
|
||||
for (j = 0; j < len; ++j) {
|
||||
if (ip_portlist[i].ip.uint32 == ip_portlist[j].ip.uint32)
|
||||
if (ip_equal(&ip_portlist[i].ip, &ip_portlist[j].ip))
|
||||
++numbers[i];
|
||||
}
|
||||
|
||||
|
@ -1065,7 +1283,7 @@ static uint16_t NAT_getports(uint16_t *portlist, IP_Port *ip_portlist, uint16_t
|
|||
uint16_t num = 0;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
if (ip_portlist[i].ip.uint32 == ip.uint32) {
|
||||
if (ip_equal(&ip_portlist[i].ip, &ip)) {
|
||||
portlist[num] = ntohs(ip_portlist[i].port);
|
||||
++num;
|
||||
}
|
||||
|
@ -1085,7 +1303,9 @@ static void punch_holes(DHT *dht, IP ip, uint16_t *port_list, uint16_t numports,
|
|||
for (i = dht->friends_list[friend_num].punching_index; i != top; i++) {
|
||||
/* TODO: Improve port guessing algorithm. */
|
||||
uint16_t port = port_list[(i / 2) % numports] + (i / (2 * numports)) * ((i % 2) ? -1 : 1);
|
||||
IP_Port pinging = {{ip, htons(port), 0}};
|
||||
IP_Port pinging;
|
||||
ip_copy(&pinging.ip, &ip);
|
||||
pinging.port = htons(port);
|
||||
send_ping_request(dht->ping, dht->c, pinging, dht->friends_list[friend_num].client_id);
|
||||
}
|
||||
|
||||
|
@ -1116,7 +1336,7 @@ static void do_NAT(DHT *dht)
|
|||
|
||||
IP ip = NAT_commonip(ip_list, num, MAX_FRIEND_CLIENTS / 2);
|
||||
|
||||
if (ip.uint32 == 0)
|
||||
if (!ip_isset(&ip))
|
||||
continue;
|
||||
|
||||
uint16_t port_list[MAX_FRIEND_CLIENTS];
|
||||
|
@ -1145,16 +1365,15 @@ static void do_NAT(DHT *dht)
|
|||
*/
|
||||
int add_toping(DHT *dht, uint8_t *client_id, IP_Port ip_port)
|
||||
{
|
||||
if (ip_port.ip.uint32 == 0)
|
||||
if (!ip_isset(&ip_port.ip))
|
||||
return -1;
|
||||
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < MAX_TOPING; ++i) {
|
||||
if (dht->toping[i].ip_port.ip.uint32 == 0) {
|
||||
if (!ip_isset(&dht->toping[i].ip_port.ip)) {
|
||||
memcpy(dht->toping[i].client_id, client_id, CLIENT_ID_SIZE);
|
||||
dht->toping[i].ip_port.ip.uint32 = ip_port.ip.uint32;
|
||||
dht->toping[i].ip_port.port = ip_port.port;
|
||||
ipport_copy(&dht->toping[i].ip_port, &ip_port);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1162,8 +1381,7 @@ int add_toping(DHT *dht, uint8_t *client_id, IP_Port ip_port)
|
|||
for (i = 0; i < MAX_TOPING; ++i) {
|
||||
if (id_closest(dht->c->self_public_key, dht->toping[i].client_id, client_id) == 2) {
|
||||
memcpy(dht->toping[i].client_id, client_id, CLIENT_ID_SIZE);
|
||||
dht->toping[i].ip_port.ip.uint32 = ip_port.ip.uint32;
|
||||
dht->toping[i].ip_port.port = ip_port.port;
|
||||
ipport_copy(&dht->toping[i].ip_port, &ip_port);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1185,11 +1403,11 @@ static void do_toping(DHT *dht)
|
|||
uint32_t i;
|
||||
|
||||
for (i = 0; i < MAX_TOPING; ++i) {
|
||||
if (dht->toping[i].ip_port.ip.uint32 == 0)
|
||||
if (!ip_isset(&dht->toping[i].ip_port.ip))
|
||||
return;
|
||||
|
||||
send_ping_request(dht->ping, dht->c, dht->toping[i].ip_port, dht->toping[i].client_id);
|
||||
dht->toping[i].ip_port.ip.uint32 = 0;
|
||||
ip_reset(&dht->toping[i].ip_port.ip);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1216,6 +1434,9 @@ DHT *new_DHT(Net_Crypto *c)
|
|||
networking_registerhandler(c->lossless_udp->net, NET_PACKET_PING_RESPONSE, &handle_ping_response, temp);
|
||||
networking_registerhandler(c->lossless_udp->net, NET_PACKET_GET_NODES, &handle_getnodes, temp);
|
||||
networking_registerhandler(c->lossless_udp->net, NET_PACKET_SEND_NODES, &handle_sendnodes, temp);
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
networking_registerhandler(c->lossless_udp->net, NET_PACKET_SEND_NODES_IPV6, &handle_sendnodes_ipv6, temp);
|
||||
#endif
|
||||
init_cryptopackets(temp);
|
||||
cryptopacket_registerhandler(c, CRYPTO_PACKET_NAT_PING, &handle_NATping, temp);
|
||||
return temp;
|
||||
|
@ -1255,24 +1476,26 @@ void DHT_save(DHT *dht, uint8_t *data)
|
|||
*/
|
||||
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 %lu bytes, got %u.\n", sizeof(dht->close_clientlist), size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((size - sizeof(dht->close_clientlist)) % sizeof(DHT_Friend) != 0)
|
||||
uint32_t friendlistsize = size - sizeof(dht->close_clientlist);
|
||||
|
||||
if (friendlistsize % sizeof(DHT_Friend) != 0) {
|
||||
fprintf(stderr, "DHT_load: Expected a multiple of %lu, got %u.\n", sizeof(DHT_Friend), friendlistsize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t i, j;
|
||||
uint16_t temp;
|
||||
/* uint64_t temp_time = unix_time(); */
|
||||
|
||||
Client_data *client;
|
||||
uint16_t friends_num = friendlistsize / sizeof(DHT_Friend);
|
||||
|
||||
temp = (size - sizeof(dht->close_clientlist)) / sizeof(DHT_Friend);
|
||||
|
||||
if (temp != 0) {
|
||||
if (friends_num != 0) {
|
||||
DHT_Friend *tempfriends_list = (DHT_Friend *)(data + sizeof(dht->close_clientlist));
|
||||
|
||||
for (i = 0; i < temp; ++i) {
|
||||
for (i = 0; i < friends_num; ++i) {
|
||||
DHT_addfriend(dht, tempfriends_list[i].client_id);
|
||||
|
||||
for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) {
|
||||
|
|
|
@ -75,10 +75,22 @@ 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];
|
||||
IP4_Port ip_port;
|
||||
} Node4_format;
|
||||
|
||||
typedef struct {
|
||||
uint8_t client_id[CLIENT_ID_SIZE];
|
||||
IP_Port ip_port;
|
||||
} Node_format;
|
||||
} Node46_format;
|
||||
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
typedef Node46_format Node_format;
|
||||
#else
|
||||
typedef Node4_format Node_format;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
IP_Port ip_port;
|
||||
|
@ -88,15 +100,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;
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
|
||||
|
@ -124,19 +136,45 @@ int DHT_delfriend(DHT *dht, uint8_t *client_id);
|
|||
* ip must be 4 bytes long.
|
||||
* port must be 2 bytes long.
|
||||
*
|
||||
* !!! Signature changed !!!
|
||||
*
|
||||
* OLD: IP_Port DHT_getfriendip(DHT *dht, uint8_t *client_id);
|
||||
*
|
||||
* return ip if success.
|
||||
* return ip of 0 if failure (This means the friend is either offline or we have not found him yet).
|
||||
* return ip of 1 if friend is not in list.
|
||||
*
|
||||
* NEW: int DHT_getfriendip(DHT *dht, uint8_t *client_id, IP_Port *ip_port);
|
||||
*
|
||||
* return -1, -- if client_id does NOT refer to a friend
|
||||
* return 0, -- if client_id refers to a friend and we failed to find the friend (yet)
|
||||
* return 1, ip if client_id refers to a friend and we found him
|
||||
*/
|
||||
IP_Port DHT_getfriendip(DHT *dht, uint8_t *client_id);
|
||||
int DHT_getfriendip(DHT *dht, uint8_t *client_id, IP_Port *ip_port);
|
||||
|
||||
/* Run this function at least a couple times per second (It's the main loop). */
|
||||
void do_DHT(DHT *dht);
|
||||
|
||||
/* Use this function to bootstrap the client.
|
||||
* Sends a get nodes request to the given node with ip port and public_key.
|
||||
/*
|
||||
* Use these two functions to bootstrap the client.
|
||||
*/
|
||||
/* Sends a "get nodes" request to the given node with ip, port and public_key
|
||||
* to setup connections
|
||||
*/
|
||||
void DHT_bootstrap(DHT *dht, IP_Port ip_port, uint8_t *public_key);
|
||||
/* Resolves address into an IP address. If successful, sends a "get nodes"
|
||||
* request to the given node with ip, port and public_key to setup connections
|
||||
*
|
||||
* address can be a hostname or an IP address (IPv4 or IPv6).
|
||||
* if ipv6enabled is 0 (zero), the resolving sticks STRICTLY to IPv4 addresses
|
||||
* if ipv6enabled is not 0 (zero), the resolving looks for IPv6 addresses first,
|
||||
* then IPv4 addresses.
|
||||
*
|
||||
* returns 1 if the address could be converted into an IP address
|
||||
* returns 0 otherwise
|
||||
*/
|
||||
int DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled,
|
||||
uint16_t port, uint8_t *public_key);
|
||||
|
||||
/* Add nodes to the toping list.
|
||||
* All nodes in this list are pinged every TIME_TOPING seconds
|
||||
|
|
|
@ -30,12 +30,15 @@
|
|||
#define MAX_INTERFACES 16
|
||||
|
||||
#ifdef __linux
|
||||
#ifndef TOX_ENABLE_IPV6
|
||||
/* Send packet to all broadcast addresses
|
||||
*
|
||||
* return higher than 0 on success.
|
||||
* return 0 on error.
|
||||
*
|
||||
* TODO: Make this work with IPv6 and remove the #ifndef TOX_ENABLE_IPV6.
|
||||
*/
|
||||
static uint32_t send_broadcasts(Networking_Core *net, uint16_t port, uint8_t * data, uint16_t length)
|
||||
static uint32_t send_broadcasts(Networking_Core *net, uint16_t port, uint8_t *data, uint16_t length)
|
||||
{
|
||||
/* Not sure how many platforms this will run on,
|
||||
* so it's wrapped in __linux for now.
|
||||
|
@ -63,28 +66,64 @@ static uint32_t send_broadcasts(Networking_Core *net, uint16_t port, uint8_t * d
|
|||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (ioctl(sock, SIOCGIFBRDADDR, &i_faces[i]) < 0) {
|
||||
return 1;
|
||||
}
|
||||
if (ioctl(sock, SIOCGIFBRDADDR, &i_faces[i]) < 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Just to clarify where we're getting the values from. */
|
||||
sock_holder = (struct sockaddr_in *)&i_faces[i].ifr_broadaddr;
|
||||
if (sock_holder != NULL) {
|
||||
IP_Port ip_port = {{{{sock_holder->sin_addr.s_addr}}, port, 0}};
|
||||
sendpacket(net->sock, ip_port, data, 1 + crypto_box_PUBLICKEYBYTES);
|
||||
}
|
||||
/* Just to clarify where we're getting the values from. */
|
||||
sock_holder = (struct sockaddr_in *)&i_faces[i].ifr_broadaddr;
|
||||
|
||||
if (sock_holder != NULL) {
|
||||
IP_Port ip_port = {{{{sock_holder->sin_addr.s_addr}}, port, 0}};
|
||||
sendpacket(net, ip_port, data, 1 + crypto_box_PUBLICKEYBYTES);
|
||||
}
|
||||
}
|
||||
|
||||
close(sock);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Return the broadcast ip. */
|
||||
static IP broadcast_ip(void)
|
||||
static IP broadcast_ip(sa_family_t family_socket, sa_family_t family_broadcast)
|
||||
{
|
||||
IP ip;
|
||||
ip.uint32 = ~0;
|
||||
ip_reset(&ip);
|
||||
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
|
||||
if (family_socket == AF_INET6) {
|
||||
if (family_broadcast == AF_INET6) {
|
||||
ip.family = AF_INET6;
|
||||
/* FF02::1 is - according to RFC 4291 - multicast all-nodes link-local */
|
||||
/* FE80::*: MUST be exact, for that we would need to look over all
|
||||
* interfaces and check in which status they are */
|
||||
ip.ip6.uint8[ 0] = 0xFF;
|
||||
ip.ip6.uint8[ 1] = 0x02;
|
||||
ip.ip6.uint8[15] = 0x01;
|
||||
} else if (family_broadcast == AF_INET) {
|
||||
ip.family = AF_INET6;
|
||||
ip.ip6.uint32[0] = 0;
|
||||
ip.ip6.uint32[1] = 0;
|
||||
ip.ip6.uint32[2] = htonl(0xFFFF);
|
||||
ip.ip6.uint32[3] = INADDR_BROADCAST;
|
||||
}
|
||||
} else if (family_socket == AF_INET) {
|
||||
if (family_broadcast == AF_INET) {
|
||||
ip.family = AF_INET;
|
||||
ip.ip4.uint32 = INADDR_BROADCAST;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
if (family_socket == AF_INET)
|
||||
if (family_broadcast == AF_INET)
|
||||
ip.uint32 = INADDR_BROADCAST;
|
||||
|
||||
#endif
|
||||
|
||||
return ip;
|
||||
}
|
||||
|
||||
|
@ -93,21 +132,54 @@ static IP broadcast_ip(void)
|
|||
*/
|
||||
static int LAN_ip(IP ip)
|
||||
{
|
||||
if (ip.uint8[0] == 127) /* Loopback. */
|
||||
return 0;
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
|
||||
if (ip.uint8[0] == 10) /* 10.0.0.0 to 10.255.255.255 range. */
|
||||
return 0;
|
||||
if (ip.family == AF_INET) {
|
||||
IP4 ip4 = ip.ip4;
|
||||
#else
|
||||
IP4 ip4 = ip;
|
||||
#endif
|
||||
|
||||
if (ip.uint8[0] == 172 && ip.uint8[1] >= 16 && ip.uint8[1] <= 31) /* 172.16.0.0 to 172.31.255.255 range. */
|
||||
return 0;
|
||||
/* Loopback. */
|
||||
if (ip4.uint8[0] == 127)
|
||||
return 0;
|
||||
|
||||
if (ip.uint8[0] == 192 && ip.uint8[1] == 168) /* 192.168.0.0 to 192.168.255.255 range. */
|
||||
return 0;
|
||||
/* 10.0.0.0 to 10.255.255.255 range. */
|
||||
if (ip4.uint8[0] == 10)
|
||||
return 0;
|
||||
|
||||
if (ip.uint8[0] == 169 && ip.uint8[1] == 254 && ip.uint8[2] != 0
|
||||
&& ip.uint8[2] != 255)/* 169.254.1.0 to 169.254.254.255 range. */
|
||||
return 0;
|
||||
/* 172.16.0.0 to 172.31.255.255 range. */
|
||||
if (ip4.uint8[0] == 172 && ip4.uint8[1] >= 16 && ip4.uint8[1] <= 31)
|
||||
return 0;
|
||||
|
||||
/* 192.168.0.0 to 192.168.255.255 range. */
|
||||
if (ip4.uint8[0] == 192 && ip4.uint8[1] == 168)
|
||||
return 0;
|
||||
|
||||
/* 169.254.1.0 to 169.254.254.255 range. */
|
||||
if (ip4.uint8[0] == 169 && ip4.uint8[1] == 254 && ip4.uint8[2] != 0
|
||||
&& ip4.uint8[2] != 255)
|
||||
return 0;
|
||||
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
} else if (ip.family == AF_INET6)
|
||||
{
|
||||
/* autogenerated for each interface: FE80::* (up to FEBF::*)
|
||||
FF02::1 is - according to RFC 4291 - multicast all-nodes link-local */
|
||||
if (((ip.ip6.uint8[0] == 0xFF) && (ip.ip6.uint8[1] < 3) && (ip.ip6.uint8[15] == 1)) ||
|
||||
((ip.ip6.uint8[0] == 0xFE) && ((ip.ip6.uint8[1] & 0xC0) == 0x80)))
|
||||
return 0;
|
||||
|
||||
/* embedded IPv4-in-IPv6 */
|
||||
if (IN6_IS_ADDR_V4MAPPED(&ip.ip6.in6_addr)) {
|
||||
IP ip4;
|
||||
ip4.family = AF_INET;
|
||||
ip4.ip4.uint32 = ip.ip6.uint32[3];
|
||||
return LAN_ip(ip4);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
@ -132,11 +204,38 @@ int send_LANdiscovery(uint16_t port, Net_Crypto *c)
|
|||
uint8_t data[crypto_box_PUBLICKEYBYTES + 1];
|
||||
data[0] = NET_PACKET_LAN_DISCOVERY;
|
||||
memcpy(data + 1, c->self_public_key, crypto_box_PUBLICKEYBYTES);
|
||||
|
||||
#ifdef __linux
|
||||
#ifndef TOX_ENABLE_IPV6
|
||||
send_broadcasts(c->lossless_udp->net, port, data, 1 + crypto_box_PUBLICKEYBYTES);
|
||||
#endif
|
||||
IP_Port ip_port = {{broadcast_ip(), port, 0}};
|
||||
return sendpacket(c->lossless_udp->net->sock, ip_port, data, 1 + crypto_box_PUBLICKEYBYTES);
|
||||
#endif
|
||||
int res = -1;
|
||||
IP_Port ip_port;
|
||||
ip_port.port = port;
|
||||
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
|
||||
/* IPv6 multicast */
|
||||
if (c->lossless_udp->net->family == AF_INET6) {
|
||||
ip_port.ip = broadcast_ip(AF_INET6, AF_INET6);
|
||||
|
||||
if (ip_isset(&ip_port.ip))
|
||||
if (sendpacket(c->lossless_udp->net, ip_port, data, 1 + crypto_box_PUBLICKEYBYTES) > 0)
|
||||
res = 1;
|
||||
}
|
||||
|
||||
/* IPv4 broadcast (has to be IPv4-in-IPv6 mapping if socket is AF_INET6 */
|
||||
ip_port.ip = broadcast_ip(c->lossless_udp->net->family, AF_INET);
|
||||
#else
|
||||
ip_port.ip = broadcast_ip(AF_INET, AF_INET);
|
||||
#endif
|
||||
|
||||
if (ip_isset(&ip_port.ip))
|
||||
if (sendpacket(c->lossless_udp->net, ip_port, data, 1 + crypto_box_PUBLICKEYBYTES))
|
||||
res = 1;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -44,9 +44,7 @@
|
|||
int getconnection_id(Lossless_UDP *ludp, IP_Port ip_port)
|
||||
{
|
||||
tox_array_for_each(&ludp->connections, Connection, tmp) {
|
||||
if (tmp->ip_port.ip.uint32 == ip_port.ip.uint32 &&
|
||||
tmp->ip_port.port == ip_port.port &&
|
||||
tmp->status > 0) {
|
||||
if (tmp-> status > 0 && ipport_equal(&tmp->ip_port, &ip_port)) {
|
||||
return tmp_i;
|
||||
}
|
||||
}
|
||||
|
@ -61,17 +59,53 @@ int getconnection_id(Lossless_UDP *ludp, IP_Port ip_port)
|
|||
*
|
||||
* TODO: make this better
|
||||
*/
|
||||
|
||||
static uint8_t randtable_initget(Lossless_UDP *ludp, uint32_t index, uint8_t value)
|
||||
{
|
||||
if (ludp->randtable[index][value] == 0)
|
||||
ludp->randtable[index][value] = random_int();
|
||||
|
||||
return ludp->randtable[index][value];
|
||||
}
|
||||
|
||||
static uint32_t handshake_id(Lossless_UDP *ludp, IP_Port source)
|
||||
{
|
||||
uint32_t id = 0, i;
|
||||
uint32_t id = 0, i = 0;
|
||||
|
||||
for (i = 0; i < 6; ++i) {
|
||||
if (ludp->randtable[i][source.uint8[i]] == 0)
|
||||
ludp->randtable[i][source.uint8[i]] = random_int();
|
||||
uint8_t *uint8;
|
||||
uint8 = (uint8_t *)&source.port;
|
||||
id ^= randtable_initget(ludp, i, *uint8);
|
||||
i++, uint8++;
|
||||
id ^= randtable_initget(ludp, i, *uint8);
|
||||
i++;
|
||||
|
||||
id ^= ludp->randtable[i][source.uint8[i]];
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
|
||||
if (source.ip.family == AF_INET) {
|
||||
IP4 ip4 = source.ip.ip4;
|
||||
#else
|
||||
IP4 ip4 = source.ip;
|
||||
#endif
|
||||
int k;
|
||||
|
||||
for (k = 0; k < 4; k++) {
|
||||
id ^= randtable_initget(ludp, i++, ip4.uint8[k]);
|
||||
}
|
||||
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
}
|
||||
|
||||
if (source.ip.family == AF_INET6)
|
||||
{
|
||||
int k;
|
||||
|
||||
for (k = 0; k < 16; k++) {
|
||||
id ^= randtable_initget(ludp, i++, source.ip.ip6.uint8[k]);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* id can't be zero. */
|
||||
if (id == 0)
|
||||
id = 1;
|
||||
|
@ -86,8 +120,21 @@ static uint32_t handshake_id(Lossless_UDP *ludp, IP_Port source)
|
|||
*/
|
||||
static void change_handshake(Lossless_UDP *ludp, IP_Port source)
|
||||
{
|
||||
uint8_t rand = random_int() % 4;
|
||||
ludp->randtable[rand][((uint8_t *)&source)[rand]] = random_int();
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
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();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -290,7 +337,9 @@ IP_Port connection_ip(Lossless_UDP *ludp, int connection_id)
|
|||
if ((unsigned int)connection_id < ludp->connections.len)
|
||||
return tox_array_get(&ludp->connections, connection_id, Connection).ip_port;
|
||||
|
||||
IP_Port zero = {{{{0}}, 0, 0}};
|
||||
IP_Port zero;
|
||||
ip_reset(&zero.ip);
|
||||
zero.port = 0;
|
||||
return zero;
|
||||
}
|
||||
|
||||
|
@ -429,7 +478,7 @@ static int send_handshake(Lossless_UDP *ludp, IP_Port ip_port, uint32_t handshak
|
|||
temp = htonl(handshake_id2);
|
||||
memcpy(packet + 5, &temp, 4);
|
||||
|
||||
return sendpacket(ludp->net->sock, ip_port, packet, sizeof(packet));
|
||||
return sendpacket(ludp->net, ip_port, packet, sizeof(packet));
|
||||
}
|
||||
|
||||
static int send_SYNC(Lossless_UDP *ludp, int connection_id)
|
||||
|
@ -456,7 +505,7 @@ static int send_SYNC(Lossless_UDP *ludp, int connection_id)
|
|||
index += 4;
|
||||
memcpy(packet + index, requested, 4 * number);
|
||||
|
||||
return sendpacket(ludp->net->sock, ip_port, packet, (number * 4 + 4 + 4 + 2));
|
||||
return sendpacket(ludp->net, ip_port, packet, (number * 4 + 4 + 4 + 2));
|
||||
|
||||
}
|
||||
|
||||
|
@ -471,7 +520,7 @@ static int send_data_packet(Lossless_UDP *ludp, int connection_id, uint32_t pack
|
|||
temp = htonl(packet_num);
|
||||
memcpy(packet + 1, &temp, 4);
|
||||
memcpy(packet + 5, connection->sendbuffer[index].data, connection->sendbuffer[index].size);
|
||||
return sendpacket(ludp->net->sock, connection->ip_port, packet, 1 + 4 + connection->sendbuffer[index].size);
|
||||
return sendpacket(ludp->net, connection->ip_port, packet, 1 + 4 + connection->sendbuffer[index].size);
|
||||
}
|
||||
|
||||
/* Sends 1 data packet. */
|
||||
|
|
|
@ -123,7 +123,13 @@ typedef struct {
|
|||
tox_array connections;
|
||||
|
||||
/* Table of random numbers used in handshake_id. */
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
/* IPv6 (16) + port (2)*/
|
||||
uint32_t randtable[18][256];
|
||||
#else
|
||||
/* IPv4 (4) + port (2) */
|
||||
uint32_t randtable[6][256];
|
||||
#endif
|
||||
|
||||
} Lossless_UDP;
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#endif
|
||||
|
||||
#include "Messenger.h"
|
||||
#include "util.h"
|
||||
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
|
||||
|
@ -901,19 +902,17 @@ static void do_allgroupchats(Messenger *m)
|
|||
|
||||
/*********************************/
|
||||
|
||||
#define PORT 33445
|
||||
|
||||
/* Send a LAN discovery packet every LAN_DISCOVERY_INTERVAL seconds. */
|
||||
static void LANdiscovery(Messenger *m)
|
||||
{
|
||||
if (m->last_LANdiscovery + LAN_DISCOVERY_INTERVAL < unix_time()) {
|
||||
send_LANdiscovery(htons(PORT), m->net_crypto);
|
||||
send_LANdiscovery(htons(TOX_PORT_DEFAULT), m->net_crypto);
|
||||
m->last_LANdiscovery = unix_time();
|
||||
}
|
||||
}
|
||||
|
||||
/* Run this at startup. */
|
||||
Messenger *initMessenger(void)
|
||||
Messenger *initMessenger(uint8_t ipv6enabled)
|
||||
{
|
||||
Messenger *m = calloc(1, sizeof(Messenger));
|
||||
|
||||
|
@ -921,8 +920,8 @@ Messenger *initMessenger(void)
|
|||
return NULL;
|
||||
|
||||
IP ip;
|
||||
ip.uint32 = 0;
|
||||
m->net = new_networking(ip, PORT);
|
||||
ip_init(&ip, ipv6enabled);
|
||||
m->net = new_networking(ip, TOX_PORT_DEFAULT);
|
||||
|
||||
if (m->net == NULL) {
|
||||
free(m);
|
||||
|
@ -1006,11 +1005,12 @@ void doFriends(Messenger *m)
|
|||
}
|
||||
}
|
||||
|
||||
IP_Port friendip = DHT_getfriendip(m->dht, m->friendlist[i].client_id);
|
||||
IP_Port friendip;
|
||||
int friendok = DHT_getfriendip(m->dht, m->friendlist[i].client_id, &friendip);
|
||||
|
||||
switch (is_cryptoconnected(m->net_crypto, m->friendlist[i].crypt_connection_id)) {
|
||||
case 0:
|
||||
if (friendip.ip.uint32 > 1)
|
||||
if (friendok == 1)
|
||||
m->friendlist[i].crypt_connection_id = crypto_connect(m->net_crypto, m->friendlist[i].client_id, friendip);
|
||||
|
||||
break;
|
||||
|
@ -1219,6 +1219,22 @@ void doInbound(Messenger *m)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef LOGGING
|
||||
#define DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS 60
|
||||
static time_t lastdump = 0;
|
||||
static char IDString[CLIENT_ID_SIZE * 2 + 1];
|
||||
static char *ID2String(uint8_t *client_id)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < CLIENT_ID_SIZE; i++)
|
||||
sprintf(&IDString[i], "%02X", client_id[i]);
|
||||
|
||||
IDString[CLIENT_ID_SIZE * 2] = 0;
|
||||
return IDString;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The main loop that needs to be run at least 20 times per second. */
|
||||
void doMessenger(Messenger *m)
|
||||
{
|
||||
|
@ -1230,6 +1246,88 @@ void doMessenger(Messenger *m)
|
|||
doFriends(m);
|
||||
do_allgroupchats(m);
|
||||
LANdiscovery(m);
|
||||
|
||||
#ifdef LOGGING
|
||||
|
||||
if (now() > lastdump + DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS) {
|
||||
loglog(" = = = = = = = = \n");
|
||||
|
||||
lastdump = now();
|
||||
uint32_t client, last_pinged;
|
||||
|
||||
for (client = 0; client < LCLIENT_LIST; client++) {
|
||||
Client_data *cptr = &m->dht->close_clientlist[client];
|
||||
|
||||
if (ip_isset(&cptr->ip_port.ip)) {
|
||||
last_pinged = lastdump - cptr->last_pinged;
|
||||
|
||||
if (last_pinged > 999)
|
||||
last_pinged = 999;
|
||||
|
||||
snprintf(logbuffer, sizeof(logbuffer), "C[%2u] %s:%u [%3u] %s\n",
|
||||
client, ip_ntoa(&cptr->ip_port.ip), ntohs(cptr->ip_port.port),
|
||||
last_pinged, ID2String(cptr->client_id));
|
||||
loglog(logbuffer);
|
||||
}
|
||||
}
|
||||
|
||||
loglog(" = = = = = = = = \n");
|
||||
|
||||
uint32_t num_friends = MIN(m->numfriends, m->dht->num_friends);
|
||||
|
||||
if (m->numfriends != m->dht->num_friends) {
|
||||
sprintf(logbuffer, "Friend num in DHT %u != friend num in msger %u\n",
|
||||
m->dht->num_friends, m->numfriends);
|
||||
loglog(logbuffer);
|
||||
}
|
||||
|
||||
uint32_t friend, ping_lastrecv;
|
||||
|
||||
for (friend = 0; friend < num_friends; friend++) {
|
||||
Friend *msgfptr = &m->friendlist[friend];
|
||||
DHT_Friend *dhtfptr = &m->dht->friends_list[friend];
|
||||
|
||||
if (memcmp(msgfptr->client_id, dhtfptr->client_id, CLIENT_ID_SIZE)) {
|
||||
if (sizeof(logbuffer) > 2 * CLIENT_ID_SIZE + 64) {
|
||||
sprintf(logbuffer, "F[%2u] ID(m) %s != ID(d) ", friend,
|
||||
ID2String(msgfptr->client_id));
|
||||
strcat(logbuffer + strlen(logbuffer), ID2String(dhtfptr->client_id));
|
||||
strcat(logbuffer + strlen(logbuffer), "\n");
|
||||
} else
|
||||
sprintf(logbuffer, "F[%2u] ID(m) != ID(d) ", friend);
|
||||
|
||||
loglog(logbuffer);
|
||||
}
|
||||
|
||||
ping_lastrecv = lastdump - msgfptr->ping_lastrecv;
|
||||
|
||||
if (ping_lastrecv > 999)
|
||||
ping_lastrecv = 999;
|
||||
|
||||
snprintf(logbuffer, sizeof(logbuffer), "F[%2u] <%s> %02u [%03u] %s\n",
|
||||
friend, msgfptr->name, msgfptr->crypt_connection_id,
|
||||
ping_lastrecv, ID2String(msgfptr->client_id));
|
||||
loglog(logbuffer);
|
||||
|
||||
for (client = 0; client < MAX_FRIEND_CLIENTS; client++) {
|
||||
Client_data *cptr = &dhtfptr->client_list[client];
|
||||
last_pinged = lastdump - cptr->last_pinged;
|
||||
|
||||
if (last_pinged > 999)
|
||||
last_pinged = 999;
|
||||
|
||||
snprintf(logbuffer, sizeof(logbuffer), "F[%2u] => C[%2u] %s:%u [%3u] %s\n",
|
||||
friend, client, ip_ntoa(&cptr->ip_port.ip),
|
||||
ntohs(cptr->ip_port.port), last_pinged,
|
||||
ID2String(cptr->client_id));
|
||||
loglog(logbuffer);
|
||||
}
|
||||
}
|
||||
|
||||
loglog(" = = = = = = = = \n");
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
/* return size of the messenger data (for saving) */
|
||||
|
@ -1251,19 +1349,23 @@ void Messenger_save(Messenger *m, uint8_t *data)
|
|||
{
|
||||
save_keys(m->net_crypto, data);
|
||||
data += crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
|
||||
|
||||
uint32_t nospam = get_nospam(&(m->fr));
|
||||
memcpy(data, &nospam, sizeof(nospam));
|
||||
data += sizeof(nospam);
|
||||
|
||||
uint32_t size = DHT_size(m->dht);
|
||||
memcpy(data, &size, sizeof(size));
|
||||
data += sizeof(size);
|
||||
DHT_save(m->dht, data);
|
||||
data += size;
|
||||
|
||||
size = sizeof(Friend) * m->numfriends;
|
||||
memcpy(data, &size, sizeof(size));
|
||||
data += sizeof(size);
|
||||
memcpy(data, m->friendlist, sizeof(Friend) * m->numfriends);
|
||||
data += size;
|
||||
|
||||
uint16_t small_size = m->name_length;
|
||||
memcpy(data, &small_size, sizeof(small_size));
|
||||
data += sizeof(small_size);
|
||||
|
@ -1276,59 +1378,70 @@ int Messenger_load(Messenger *m, uint8_t *data, uint32_t length)
|
|||
if (length == ~((uint32_t)0))
|
||||
return -1;
|
||||
|
||||
if (length < crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t) * 3)
|
||||
/* BLOCK1: PUBKEY, SECKEY, NOSPAM, SIZE */
|
||||
if (length < crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t) * 2)
|
||||
return -1;
|
||||
|
||||
length -= crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t) * 3;
|
||||
load_keys(m->net_crypto, data);
|
||||
data += crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
|
||||
length -= crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
|
||||
|
||||
uint32_t nospam;
|
||||
memcpy(&nospam, data, sizeof(nospam));
|
||||
set_nospam(&(m->fr), nospam);
|
||||
data += sizeof(nospam);
|
||||
length -= sizeof(nospam);
|
||||
|
||||
uint32_t size;
|
||||
memcpy(&size, data, sizeof(size));
|
||||
data += sizeof(size);
|
||||
length -= sizeof(size);
|
||||
|
||||
if (length < size)
|
||||
return -1;
|
||||
|
||||
length -= size;
|
||||
|
||||
if (DHT_load(m->dht, data, size) == -1)
|
||||
return -1;
|
||||
fprintf(stderr, "Data file: Something wicked happened to the stored connections...\n");
|
||||
|
||||
/* go on, friends still might be intact */
|
||||
|
||||
data += size;
|
||||
memcpy(&size, data, sizeof(size));
|
||||
data += sizeof(size);
|
||||
length -= size;
|
||||
|
||||
if (length < size || size % sizeof(Friend) != 0)
|
||||
if (length < sizeof(size))
|
||||
return -1;
|
||||
|
||||
Friend *temp = malloc(size);
|
||||
memcpy(temp, data, size);
|
||||
memcpy(&size, data, sizeof(size));
|
||||
data += sizeof(size);
|
||||
length -= sizeof(size);
|
||||
|
||||
uint16_t num = size / sizeof(Friend);
|
||||
if (length < size)
|
||||
return -1;
|
||||
|
||||
uint32_t i;
|
||||
if (!(size % sizeof(Friend))) {
|
||||
uint16_t num = size / sizeof(Friend);
|
||||
Friend temp[num];
|
||||
memcpy(temp, data, size);
|
||||
|
||||
for (i = 0; i < num; ++i) {
|
||||
if (temp[i].status >= 3) {
|
||||
int fnum = m_addfriend_norequest(m, temp[i].client_id);
|
||||
setfriendname(m, fnum, temp[i].name, temp[i].name_length);
|
||||
/* set_friend_statusmessage(fnum, temp[i].statusmessage, temp[i].statusmessage_length); */
|
||||
} else if (temp[i].status != 0) {
|
||||
/* TODO: This is not a good way to do this. */
|
||||
uint8_t address[FRIEND_ADDRESS_SIZE];
|
||||
memcpy(address, temp[i].client_id, crypto_box_PUBLICKEYBYTES);
|
||||
memcpy(address + crypto_box_PUBLICKEYBYTES, &(temp[i].friendrequest_nospam), sizeof(uint32_t));
|
||||
uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum));
|
||||
memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(uint32_t), &checksum, sizeof(checksum));
|
||||
m_addfriend(m, address, temp[i].info, temp[i].info_size);
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < num; ++i) {
|
||||
if (temp[i].status >= 3) {
|
||||
int fnum = m_addfriend_norequest(m, temp[i].client_id);
|
||||
setfriendname(m, fnum, temp[i].name, temp[i].name_length);
|
||||
/* set_friend_statusmessage(fnum, temp[i].statusmessage, temp[i].statusmessage_length); */
|
||||
} else if (temp[i].status != 0) {
|
||||
/* TODO: This is not a good way to do this. */
|
||||
uint8_t address[FRIEND_ADDRESS_SIZE];
|
||||
memcpy(address, temp[i].client_id, crypto_box_PUBLICKEYBYTES);
|
||||
memcpy(address + crypto_box_PUBLICKEYBYTES, &(temp[i].friendrequest_nospam), sizeof(uint32_t));
|
||||
uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum));
|
||||
memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(uint32_t), &checksum, sizeof(checksum));
|
||||
m_addfriend(m, address, temp[i].info, temp[i].info_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(temp);
|
||||
data += size;
|
||||
length -= size;
|
||||
|
||||
|
|
|
@ -427,7 +427,7 @@ int group_message_send(Messenger *m, int groupnumber, uint8_t *message, uint32_t
|
|||
* return allocated instance of Messenger on success.
|
||||
* return 0 if there are problems.
|
||||
*/
|
||||
Messenger *initMessenger(void);
|
||||
Messenger *initMessenger(uint8_t ipv6enabled);
|
||||
|
||||
/* Run this before closing shop
|
||||
* Free all datastructures.
|
||||
|
|
|
@ -50,18 +50,22 @@ int send_friendrequest(DHT *dht, uint8_t *public_key, uint32_t nospam_num, uint8
|
|||
if (len == -1)
|
||||
return -1;
|
||||
|
||||
IP_Port ip_port = DHT_getfriendip(dht, public_key);
|
||||
IP_Port ip_port;
|
||||
int friendok = DHT_getfriendip(dht, public_key, &ip_port);
|
||||
|
||||
if (ip_port.ip.uint32 == 1)
|
||||
// not a friend
|
||||
if (friendok == -1)
|
||||
return -1;
|
||||
|
||||
if (ip_port.ip.uint32 != 0) {
|
||||
if (sendpacket(dht->c->lossless_udp->net->sock, ip_port, packet, len) != -1)
|
||||
// is a friend and we know how to reach him
|
||||
if (friendok == 1) {
|
||||
if (sendpacket(dht->c->lossless_udp->net, ip_port, packet, len) != -1)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// is a friend, we DON'T know how to reach him
|
||||
int num = route_tofriend(dht, public_key, packet, len);
|
||||
|
||||
if (num == 0)
|
||||
|
|
|
@ -189,7 +189,7 @@ static int send_groupchatpacket(Group_Chat *chat, IP_Port ip_port, uint8_t *publ
|
|||
if (len == -1)
|
||||
return -1;
|
||||
|
||||
if (sendpacket(chat->net->sock, ip_port, packet, len) == len)
|
||||
if (sendpacket(chat->net, ip_port, packet, len) == len)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
|
@ -208,7 +208,7 @@ static uint8_t sendto_allpeers(Group_Chat *chat, uint8_t *data, uint16_t length,
|
|||
uint64_t temp_time = unix_time();
|
||||
|
||||
for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) {
|
||||
if (chat->close[i].ip_port.ip.uint32 != 0 && chat->close[i].last_recv + BAD_NODE_TIMEOUT > temp_time) {
|
||||
if (ip_isset(&chat->close[i].ip_port.ip) && chat->close[i].last_recv + BAD_NODE_TIMEOUT > temp_time) {
|
||||
if (send_groupchatpacket(chat, chat->close[i].ip_port, chat->close[i].client_id, data, length, request_id) == 0)
|
||||
++sent;
|
||||
}
|
||||
|
|
|
@ -451,7 +451,7 @@ int crypto_connect(Net_Crypto *c, uint8_t *public_key, IP_Port ip_port)
|
|||
if (id != -1) {
|
||||
IP_Port c_ip = connection_ip(c->lossless_udp, c->crypto_connections[id].number);
|
||||
|
||||
if (c_ip.ip.uint32 == ip_port.ip.uint32 && c_ip.port == ip_port.port)
|
||||
if (ipport_equal(&c_ip, &ip_port))
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#endif
|
||||
|
||||
#include "network.h"
|
||||
#include "util.h"
|
||||
|
||||
/* return current UNIX time in microseconds (us). */
|
||||
uint64_t current_time(void)
|
||||
|
@ -62,17 +63,83 @@ uint32_t random_int(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef LOGGING
|
||||
static void loglogdata(char *message, uint8_t *buffer, size_t buflen, IP_Port *ip_port, ssize_t res);
|
||||
#endif
|
||||
|
||||
/* Basic network functions:
|
||||
* Function to send packet(data) of length length to ip_port.
|
||||
*/
|
||||
#ifdef WIN32
|
||||
int sendpacket(unsigned int sock, IP_Port ip_port, uint8_t *data, uint32_t length)
|
||||
#else
|
||||
int sendpacket(int sock, IP_Port ip_port, uint8_t *data, uint32_t length)
|
||||
#endif
|
||||
int sendpacket(Networking_Core *net, IP_Port ip_port, uint8_t *data, uint32_t length)
|
||||
{
|
||||
ADDR addr = {AF_INET, ip_port.port, ip_port.ip, {0}};
|
||||
return sendto(sock, (char *) data, length, 0, (struct sockaddr *)&addr, sizeof(addr));
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
|
||||
/* socket AF_INET, but target IP NOT: can't send */
|
||||
if ((net->family == AF_INET) && (ip_port.ip.family != AF_INET))
|
||||
return -1;
|
||||
|
||||
#endif
|
||||
|
||||
struct sockaddr_storage addr;
|
||||
size_t addrsize = 0;
|
||||
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
|
||||
if (ip_port.ip.family == AF_INET) {
|
||||
if (net->family == AF_INET6) {
|
||||
/* must convert to IPV4-in-IPV6 address */
|
||||
addrsize = sizeof(struct sockaddr_in6);
|
||||
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;
|
||||
addr6->sin6_family = AF_INET6;
|
||||
addr6->sin6_port = ip_port.port;
|
||||
|
||||
/* there should be a macro for this in a standards compliant
|
||||
* environment, not found */
|
||||
IP6 ip6;
|
||||
|
||||
ip6.uint32[0] = 0;
|
||||
ip6.uint32[1] = 0;
|
||||
ip6.uint32[2] = htonl(0xFFFF);
|
||||
ip6.uint32[3] = ip_port.ip.ip4.uint32;
|
||||
addr6->sin6_addr = ip6.in6_addr;
|
||||
|
||||
addr6->sin6_flowinfo = 0;
|
||||
addr6->sin6_scope_id = 0;
|
||||
} else {
|
||||
IP4 ip4 = ip_port.ip.ip4;
|
||||
#else
|
||||
IP4 ip4 = ip_port.ip;
|
||||
#endif
|
||||
addrsize = sizeof(struct sockaddr_in);
|
||||
struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;
|
||||
addr4->sin_family = AF_INET;
|
||||
addr4->sin_addr = ip4.in_addr;
|
||||
addr4->sin_port = ip_port.port;
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
}
|
||||
} else if (ip_port.ip.family == AF_INET6)
|
||||
{
|
||||
addrsize = sizeof(struct sockaddr_in6);
|
||||
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;
|
||||
addr6->sin6_family = AF_INET6;
|
||||
addr6->sin6_port = ip_port.port;
|
||||
addr6->sin6_addr = ip_port.ip.ip6.in6_addr;
|
||||
|
||||
addr6->sin6_flowinfo = 0;
|
||||
addr6->sin6_scope_id = 0;
|
||||
} else
|
||||
{
|
||||
/* unknown address type*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int res = sendto(net->sock, (char *) data, length, 0, (struct sockaddr *)&addr, addrsize);
|
||||
#ifdef LOGGING
|
||||
loglogdata("O=>", data, length, &ip_port, res);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Function to receive data
|
||||
|
@ -81,13 +148,9 @@ int sendpacket(int sock, IP_Port ip_port, uint8_t *data, uint32_t length)
|
|||
* Packet length is put into length.
|
||||
* Dump all empty packets.
|
||||
*/
|
||||
#ifdef WIN32
|
||||
static int receivepacket(unsigned int sock, IP_Port *ip_port, uint8_t *data, uint32_t *length)
|
||||
#else
|
||||
static int receivepacket(int sock, IP_Port *ip_port, uint8_t *data, uint32_t *length)
|
||||
#endif
|
||||
static int receivepacket(sock_t sock, IP_Port *ip_port, uint8_t *data, uint32_t *length)
|
||||
{
|
||||
ADDR addr;
|
||||
struct sockaddr_storage addr;
|
||||
#ifdef WIN32
|
||||
int addrlen = sizeof(addr);
|
||||
#else
|
||||
|
@ -95,11 +158,48 @@ static int receivepacket(int sock, IP_Port *ip_port, uint8_t *data, uint32_t *le
|
|||
#endif
|
||||
(*(int32_t *)length) = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen);
|
||||
|
||||
if (*(int32_t *)length <= 0)
|
||||
return -1; /* Nothing received or empty packet. */
|
||||
if (*(int32_t *)length <= 0) {
|
||||
#ifdef LOGGING
|
||||
|
||||
if ((length < 0) && (errno != EWOULDBLOCK)) {
|
||||
sprintf(logbuffer, "Unexpected error reading from socket: %u, %s\n", errno, strerror(errno));
|
||||
loglog(logbuffer);
|
||||
}
|
||||
|
||||
#endif
|
||||
return -1; /* Nothing received or empty packet. */
|
||||
}
|
||||
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
|
||||
if (addr.ss_family == AF_INET) {
|
||||
struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr;
|
||||
ip_port->ip.family = addr_in->sin_family;
|
||||
ip_port->ip.ip4.in_addr = addr_in->sin_addr;
|
||||
ip_port->port = addr_in->sin_port;
|
||||
} else if (addr.ss_family == AF_INET6) {
|
||||
struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&addr;
|
||||
ip_port->ip.family = addr_in6->sin6_family;
|
||||
ip_port->ip.ip6.in6_addr = addr_in6->sin6_addr;
|
||||
ip_port->port = addr_in6->sin6_port;
|
||||
} else
|
||||
return -1;
|
||||
|
||||
#else
|
||||
|
||||
if (addr.ss_family == AF_INET) {
|
||||
struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr;
|
||||
ip_port->ip.in_addr = addr_in->sin_addr;
|
||||
ip_port->port = addr_in->sin_port;
|
||||
} else
|
||||
return -1;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef LOGGING
|
||||
loglogdata("=>O", data, MAX_UDP_PACKET_SIZE, ip_port, *length);
|
||||
#endif
|
||||
|
||||
ip_port->ip = addr.ip;
|
||||
ip_port->port = addr.port;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -118,13 +218,20 @@ void networking_poll(Networking_Core *net)
|
|||
while (receivepacket(net->sock, &ip_port, data, &length) != -1) {
|
||||
if (length < 1) continue;
|
||||
|
||||
if (!(net->packethandlers[data[0]].function)) continue;
|
||||
if (!(net->packethandlers[data[0]].function)) {
|
||||
#ifdef LOGGING
|
||||
sprintf(logbuffer, "[%02u] -- Packet has no handler.\n", data[0]);
|
||||
loglog(logbuffer);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
net->packethandlers[data[0]].function(net->packethandlers[data[0]].object, ip_port, data, length);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t at_startup_ran;
|
||||
|
||||
uint8_t at_startup_ran = 0;
|
||||
static int at_startup(void)
|
||||
{
|
||||
if (at_startup_ran != 0)
|
||||
|
@ -163,16 +270,34 @@ static void at_shutdown(void)
|
|||
*/
|
||||
Networking_Core *new_networking(IP ip, uint16_t port)
|
||||
{
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
|
||||
/* 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) {
|
||||
fprintf(stderr, "Invalid address family: %u\n", ip.family);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (at_startup() != 0)
|
||||
return NULL;
|
||||
|
||||
/* Initialize our socket. */
|
||||
Networking_Core *temp = calloc(1, sizeof(Networking_Core));
|
||||
|
||||
if (temp == NULL)
|
||||
return NULL;
|
||||
|
||||
temp->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
temp->family = ip.family;
|
||||
#else
|
||||
temp->family = AF_INET;
|
||||
#endif
|
||||
temp->port = 0;
|
||||
|
||||
/* Initialize our socket. */
|
||||
/* add log message what we're creating */
|
||||
temp->sock = socket(temp->family, SOCK_DGRAM, IPPROTO_UDP);
|
||||
|
||||
/* Check for socket error. */
|
||||
#ifdef WIN32
|
||||
|
@ -185,6 +310,7 @@ Networking_Core *new_networking(IP ip, uint16_t port)
|
|||
#else
|
||||
|
||||
if (temp->sock < 0) {
|
||||
fprintf(stderr, "Failed to get a socket?! %u, %s\n", errno, strerror(errno));
|
||||
free(temp);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -205,7 +331,7 @@ Networking_Core *new_networking(IP ip, uint16_t port)
|
|||
return -1;
|
||||
*/
|
||||
|
||||
/* Enable broadcast on socket. */
|
||||
/* Enable broadcast on socket */
|
||||
int broadcast = 1;
|
||||
setsockopt(temp->sock, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast));
|
||||
|
||||
|
@ -219,10 +345,140 @@ Networking_Core *new_networking(IP ip, uint16_t port)
|
|||
fcntl(temp->sock, F_SETFL, O_NONBLOCK, 1);
|
||||
#endif
|
||||
|
||||
/* Bind our socket to port PORT and address 0.0.0.0 */
|
||||
ADDR addr = {AF_INET, htons(port), ip, {0}};
|
||||
bind(temp->sock, (struct sockaddr *)&addr, sizeof(addr));
|
||||
return temp;
|
||||
#ifdef LOGGING
|
||||
loginit(ntohs(port));
|
||||
#endif
|
||||
|
||||
/* Bind our socket to port PORT and the given IP address (usually 0.0.0.0 or ::) */
|
||||
uint16_t *portptr = NULL;
|
||||
struct sockaddr_storage addr;
|
||||
size_t addrsize;
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
|
||||
if (temp->family == AF_INET) {
|
||||
IP4 ip4 = ip.ip4;
|
||||
#else
|
||||
IP4 ip4 = ip;
|
||||
#endif
|
||||
addrsize = sizeof(struct sockaddr_in);
|
||||
struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;
|
||||
addr4->sin_family = AF_INET;
|
||||
addr4->sin_port = 0;
|
||||
addr4->sin_addr = ip4.in_addr;
|
||||
|
||||
portptr = &addr4->sin_port;
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
} else if (temp->family == AF_INET6)
|
||||
{
|
||||
addrsize = sizeof(struct sockaddr_in6);
|
||||
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;
|
||||
addr6->sin6_family = AF_INET6;
|
||||
addr6->sin6_port = 0;
|
||||
addr6->sin6_addr = ip.ip6.in6_addr;
|
||||
|
||||
addr6->sin6_flowinfo = 0;
|
||||
addr6->sin6_scope_id = 0;
|
||||
|
||||
portptr = &addr6->sin6_port;
|
||||
} else
|
||||
return NULL;
|
||||
|
||||
if (ip.family == AF_INET6)
|
||||
{
|
||||
char ipv6only = 0;
|
||||
#ifdef LOGGING
|
||||
int res =
|
||||
#endif
|
||||
setsockopt(temp->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&ipv6only, sizeof(ipv6only));
|
||||
#ifdef LOGGING
|
||||
|
||||
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",
|
||||
errno, strerror(errno));
|
||||
loglog(logbuffer);
|
||||
} else
|
||||
loglog("Embedded IPv4 addresses enabled successfully.\n");
|
||||
|
||||
#endif
|
||||
|
||||
/* multicast local nodes */
|
||||
struct ipv6_mreq mreq;
|
||||
memset(&mreq, 0, sizeof(mreq));
|
||||
mreq.ipv6mr_multiaddr.s6_addr[ 0] = 0xFF;
|
||||
mreq.ipv6mr_multiaddr.s6_addr[ 1] = 0x02;
|
||||
mreq.ipv6mr_multiaddr.s6_addr[15] = 0x01;
|
||||
mreq.ipv6mr_interface = 0;
|
||||
#ifdef LOGGING
|
||||
res =
|
||||
#endif
|
||||
setsockopt(temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
|
||||
#ifdef LOGGING
|
||||
|
||||
if (res < 0) {
|
||||
sprintf(logbuffer, "Failed to activate local multicast membership. (%u, %s)\n",
|
||||
errno, strerror(errno));
|
||||
loglog(logbuffer);
|
||||
} else
|
||||
loglog("Local multicast group FF02::1 joined successfully.\n");
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* a hanging program or a different user might block the standard port;
|
||||
* as long as it isn't a parameter coming from the commandline,
|
||||
* try a few ports after it, to see if we can find a "free" one
|
||||
*
|
||||
* if we go on without binding, the first sendto() automatically binds to
|
||||
* a free port chosen by the system (i.e. anything from 1024 to 65535)
|
||||
*
|
||||
* returning NULL after bind fails has both advantages and disadvantages:
|
||||
* advantage:
|
||||
* we can rely on getting the port in the range 33445..33450, which
|
||||
* enables us to tell joe user to open their firewall to a small range
|
||||
*
|
||||
* disadvantage:
|
||||
* some clients might not test return of tox_new(), blindly assuming that
|
||||
* it worked ok (which it did previously without a successful bind)
|
||||
*/
|
||||
uint16_t port_to_try = port;
|
||||
*portptr = htons(port_to_try);
|
||||
int tries, res;
|
||||
|
||||
for (tries = TOX_PORTRANGE_FROM; tries <= TOX_PORTRANGE_TO; tries++)
|
||||
{
|
||||
res = bind(temp->sock, (struct sockaddr *)&addr, addrsize);
|
||||
|
||||
if (!res) {
|
||||
temp->port = *portptr;
|
||||
#ifdef LOGGING
|
||||
sprintf(logbuffer, "Bound successfully to %s:%u.\n", ip_ntoa(&ip), ntohs(temp->port));
|
||||
loglog(logbuffer);
|
||||
#endif
|
||||
|
||||
/* errno isn't reset on success, only set on failure, the failed
|
||||
* binds with parallel clients yield a -EPERM to the outside if
|
||||
* errno isn't cleared here */
|
||||
if (tries > 0)
|
||||
errno = 0;
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
port_to_try++;
|
||||
|
||||
if (port_to_try > TOX_PORTRANGE_TO)
|
||||
port_to_try = TOX_PORTRANGE_FROM;
|
||||
|
||||
*portptr = htons(port_to_try);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Failed to bind socket: %u, %s (IP/Port: %s:%u\n", errno,
|
||||
strerror(errno), ip_ntoa(&ip), port);
|
||||
kill_networking(temp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Function to cleanup networking stuff. */
|
||||
|
@ -236,3 +492,391 @@ void kill_networking(Networking_Core *net)
|
|||
free(net);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ip_equal
|
||||
* compares two IPAny structures
|
||||
* unset means unequal
|
||||
*
|
||||
* returns 0 when not equal or when uninitialized
|
||||
*/
|
||||
int ip_equal(IP *a, IP *b)
|
||||
{
|
||||
if (!a || !b)
|
||||
return 0;
|
||||
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
|
||||
/* same family */
|
||||
if (a->family == b->family) {
|
||||
if (a->family == AF_INET)
|
||||
return (a->ip4.in_addr.s_addr == b->ip4.in_addr.s_addr);
|
||||
else if (a->family == AF_INET6)
|
||||
return IN6_ARE_ADDR_EQUAL(&a->ip6.in6_addr, &b->ip6.in6_addr);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* different family: check on the IPv6 one if it is the IPv4 one embedded */
|
||||
if ((a->family == AF_INET) && (b->family == AF_INET6)) {
|
||||
if (IN6_IS_ADDR_V4COMPAT(&b->ip6.in6_addr))
|
||||
return (a->ip4.in_addr.s_addr == b->ip6.uint32[3]);
|
||||
} else if ((a->family == AF_INET6) && (b->family == AF_INET)) {
|
||||
if (IN6_IS_ADDR_V4COMPAT(&a->ip6.in6_addr))
|
||||
return (a->ip6.uint32[3] == b->ip4.in_addr.s_addr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
return (a->uint32 == b->uint32);
|
||||
#endif
|
||||
};
|
||||
|
||||
/* ipport_equal
|
||||
* compares two IPAny_Port structures
|
||||
* unset means unequal
|
||||
*
|
||||
* returns 0 when not equal or when uninitialized
|
||||
*/
|
||||
int ipport_equal(IP_Port *a, IP_Port *b)
|
||||
{
|
||||
if (!a || !b)
|
||||
return 0;
|
||||
|
||||
if (!a->port || (a->port != b->port))
|
||||
return 0;
|
||||
|
||||
return ip_equal(&a->ip, &b->ip);
|
||||
};
|
||||
|
||||
/* nulls out ip */
|
||||
void ip_reset(IP *ip)
|
||||
{
|
||||
if (!ip)
|
||||
return;
|
||||
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
memset(ip, 0, sizeof(IP));
|
||||
#else
|
||||
ip->uint32 = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* nulls out ip, sets family according to flag */
|
||||
void ip_init(IP *ip, uint8_t ipv6enabled)
|
||||
{
|
||||
if (!ip)
|
||||
return;
|
||||
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
memset(ip, 0, sizeof(IP));
|
||||
ip->family = ipv6enabled ? AF_INET6 : AF_INET;
|
||||
#else
|
||||
ip->uint32 = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* checks if ip is valid */
|
||||
int ip_isset(IP *ip)
|
||||
{
|
||||
if (!ip)
|
||||
return 0;
|
||||
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
return (ip->family != 0);
|
||||
#else
|
||||
return (ip->uint32 != 0);
|
||||
#endif
|
||||
};
|
||||
|
||||
/* checks if ip is valid */
|
||||
int ipport_isset(IP_Port *ipport)
|
||||
{
|
||||
if (!ipport)
|
||||
return 0;
|
||||
|
||||
if (!ipport->port)
|
||||
return 0;
|
||||
|
||||
return ip_isset(&ipport->ip);
|
||||
};
|
||||
|
||||
/* copies an ip structure (careful about direction!) */
|
||||
void ip_copy(IP *target, IP *source)
|
||||
{
|
||||
if (!source || !target)
|
||||
return;
|
||||
|
||||
memcpy(target, source, sizeof(IP));
|
||||
};
|
||||
|
||||
/* copies an ip_port structure (careful about direction!) */
|
||||
void ipport_copy(IP_Port *target, IP_Port *source)
|
||||
{
|
||||
if (!source || !target)
|
||||
return;
|
||||
|
||||
memcpy(target, source, sizeof(IP_Port));
|
||||
};
|
||||
|
||||
/* ip_ntoa
|
||||
* converts ip into a string
|
||||
* uses a static buffer, so mustn't used multiple times in the same output
|
||||
*/
|
||||
/* there would be INET6_ADDRSTRLEN, but it might be too short for the error message */
|
||||
static char addresstext[96];
|
||||
const char *ip_ntoa(IP *ip)
|
||||
{
|
||||
if (ip) {
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
|
||||
if (ip->family == AF_INET) {
|
||||
addresstext[0] = 0;
|
||||
struct in_addr *addr = (struct in_addr *)&ip->ip4;
|
||||
inet_ntop(ip->family, addr, addresstext, sizeof(addresstext));
|
||||
} else if (ip->family == AF_INET6) {
|
||||
addresstext[0] = '[';
|
||||
struct in6_addr *addr = (struct in6_addr *)&ip->ip6;
|
||||
inet_ntop(ip->family, addr, &addresstext[1], sizeof(addresstext) - 3);
|
||||
size_t len = strlen(addresstext);
|
||||
addresstext[len] = ']';
|
||||
addresstext[len + 1] = 0;
|
||||
} else
|
||||
snprintf(addresstext, sizeof(addresstext), "(IP invalid, family %u)", ip->family);
|
||||
|
||||
#else
|
||||
addresstext[0] = 0;
|
||||
struct in_addr *addr = (struct in_addr *)&ip;
|
||||
inet_ntop(AF_INET, addr, addresstext, sizeof(addresstext));
|
||||
#endif
|
||||
} else
|
||||
snprintf(addresstext, sizeof(addresstext), "(IP invalid: NULL)");
|
||||
|
||||
/* brute force protection against lacking termination */
|
||||
addresstext[sizeof(addresstext) - 1] = 0;
|
||||
return addresstext;
|
||||
};
|
||||
|
||||
/*
|
||||
* addr_parse_ip
|
||||
* directly parses the input into an IP structure
|
||||
* tries IPv4 first, then IPv6
|
||||
*
|
||||
* input
|
||||
* address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6)
|
||||
*
|
||||
* output
|
||||
* IP: family and the value is set on success
|
||||
*
|
||||
* returns 1 on success, 0 on failure
|
||||
*/
|
||||
|
||||
int addr_parse_ip(const char *address, IP *to)
|
||||
{
|
||||
if (!address || !to)
|
||||
return 0;
|
||||
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
struct in_addr addr4;
|
||||
|
||||
if (1 == inet_pton(AF_INET, address, &addr4)) {
|
||||
to->family = AF_INET;
|
||||
to->ip4.in_addr = addr4;
|
||||
return 1;
|
||||
};
|
||||
|
||||
struct in6_addr addr6;
|
||||
|
||||
if (1 == inet_pton(AF_INET6, address, &addr6)) {
|
||||
to->family = AF_INET6;
|
||||
to->ip6.in6_addr = addr6;
|
||||
return 1;
|
||||
};
|
||||
|
||||
#else
|
||||
struct in_addr addr4;
|
||||
|
||||
if (1 == inet_pton(AF_INET, address, &addr4)) {
|
||||
to->in_addr = addr4;
|
||||
return 1;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
/*
|
||||
* addr_resolve():
|
||||
* uses getaddrinfo to resolve an address into an IP address
|
||||
* uses the first IPv4/IPv6 addresses returned by getaddrinfo
|
||||
*
|
||||
* input
|
||||
* address: a hostname (or something parseable to an IP address)
|
||||
* to: to.family MUST be initialized, either set to a specific IP version
|
||||
* (AF_INET/AF_INET6) or to the unspecified AF_UNSPEC (= 0), if both
|
||||
* IP versions are acceptable
|
||||
* extra can be NULL and is only set in special circumstances, see returns
|
||||
*
|
||||
* returns in *to a valid IPAny (v4/v6),
|
||||
* prefers v6 if ip.family was AF_UNSPEC and both available
|
||||
* returns in *extra an IPv4 address, if family was AF_UNSPEC and *to is AF_INET6
|
||||
* returns 0 on failure
|
||||
*/
|
||||
|
||||
int addr_resolve(const char *address, IP *to, IP *extra)
|
||||
{
|
||||
if (!address || !to)
|
||||
return 0;
|
||||
|
||||
sa_family_t family;
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
family = to->family;
|
||||
#else
|
||||
family = AF_INET;
|
||||
#endif
|
||||
|
||||
struct addrinfo *server = NULL;
|
||||
struct addrinfo *walker = NULL;
|
||||
struct addrinfo hints;
|
||||
int rc;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = family;
|
||||
hints.ai_socktype = SOCK_DGRAM; // type of socket Tox uses.
|
||||
|
||||
if (at_startup() != 0)
|
||||
return 0;
|
||||
|
||||
rc = getaddrinfo(address, NULL, &hints, &server);
|
||||
|
||||
// Lookup failed.
|
||||
if (rc != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
IP4 ip4;
|
||||
memset(&ip4, 0, sizeof(ip4));
|
||||
IP6 ip6;
|
||||
memset(&ip6, 0, sizeof(ip6));
|
||||
#endif
|
||||
|
||||
for (walker = server; (walker != NULL) && (rc != 3); walker = walker->ai_next) {
|
||||
switch (walker->ai_family) {
|
||||
case AF_INET:
|
||||
if (walker->ai_family == family) { /* AF_INET requested, done */
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr;
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
to->ip4.in_addr = addr->sin_addr;
|
||||
#else
|
||||
to->in_addr = addr->sin_addr;
|
||||
#endif
|
||||
rc = 3;
|
||||
}
|
||||
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
else if (!(rc & 1)) { /* AF_UNSPEC requested, store away */
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr;
|
||||
ip4.in_addr = addr->sin_addr;
|
||||
rc |= 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
break; /* switch */
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
|
||||
case AF_INET6:
|
||||
if (walker->ai_family == family) { /* AF_INET6 requested, done */
|
||||
if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) {
|
||||
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr;
|
||||
to->ip6.in6_addr = addr->sin6_addr;
|
||||
rc = 3;
|
||||
}
|
||||
} else if (!(rc & 2)) { /* AF_UNSPEC requested, store away */
|
||||
if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) {
|
||||
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr;
|
||||
ip6.in6_addr = addr->sin6_addr;
|
||||
rc |= 2;
|
||||
}
|
||||
}
|
||||
|
||||
break; /* switch */
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
|
||||
if (to->family == AF_UNSPEC) {
|
||||
if (rc & 2) {
|
||||
to->family = AF_INET6;
|
||||
to->ip6 = ip6;
|
||||
|
||||
if ((rc & 1) && (extra != NULL)) {
|
||||
extra->family = AF_INET;
|
||||
extra->ip4 = ip4;
|
||||
}
|
||||
} else if (rc & 1) {
|
||||
to->family = AF_INET;
|
||||
to->ip4 = ip4;
|
||||
} else
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
freeaddrinfo(server);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* addr_resolve_or_parse_ip
|
||||
* resolves string into an IP address
|
||||
*
|
||||
* address: a hostname (or something parseable to an IP address)
|
||||
* to: to.family MUST be initialized, either set to a specific IP version
|
||||
* (AF_INET/AF_INET6) or to the unspecified AF_UNSPEC (= 0), if both
|
||||
* IP versions are acceptable
|
||||
* extra can be NULL and is only set in special circumstances, see returns
|
||||
*
|
||||
* returns in *tro a matching address (IPv6 or IPv4)
|
||||
* returns in *extra, if not NULL, an IPv4 address, if to->family was AF_UNSPEC
|
||||
* returns 1 on success
|
||||
* returns 0 on failure
|
||||
*/
|
||||
int addr_resolve_or_parse_ip(const char *address, IP *to, IP *extra)
|
||||
{
|
||||
if (!addr_resolve(address, to, extra))
|
||||
if (!addr_parse_ip(address, to))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
#ifdef LOGGING
|
||||
static void loglogdata(char *message, uint8_t *buffer, size_t buflen, IP_Port *ip_port, ssize_t res)
|
||||
{
|
||||
if (res < 0)
|
||||
snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %3u%c %s:%u (%u: %s) | %04x%04x\n",
|
||||
buffer[0], message, buflen < 999 ? buflen : 999, 'E',
|
||||
ip_ntoa(&ip_port->ip), ntohs(ip_port->port), errno,
|
||||
strerror(errno), buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0,
|
||||
buflen > 7 ? ntohl(*(uint32_t *)(&buffer[5])) : 0);
|
||||
else if ((res > 0) && (res <= buflen))
|
||||
snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %3u%c %s:%u (%u: %s) | %04x%04x\n",
|
||||
buffer[0], message, res < 999 ? res : 999, res < buflen ? '<' : '=',
|
||||
ip_ntoa(&ip_port->ip), ntohs(ip_port->port), 0,
|
||||
"OK", buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0,
|
||||
buflen > 7 ? ntohl(*(uint32_t *)(&buffer[5])) : 0);
|
||||
else /* empty or overwrite */
|
||||
snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %u%c%u %s:%u (%u: %s) | %04x%04x\n",
|
||||
buffer[0], message, res, !res ? '0' : '>', buflen,
|
||||
ip_ntoa(&ip_port->ip), ntohs(ip_port->port), 0,
|
||||
"OK", buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0,
|
||||
buflen > 7 ? ntohl(*(uint32_t *)(&buffer[5])) : 0);
|
||||
|
||||
logbuffer[sizeof(logbuffer) - 1] = 0;
|
||||
loglog(logbuffer);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -39,17 +39,22 @@
|
|||
#include <windows.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
typedef unsigned int sock_t;
|
||||
|
||||
#else // Linux includes
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
|
||||
typedef int sock_t;
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef VANILLA_NACL
|
||||
|
@ -61,13 +66,20 @@
|
|||
#define crypto_box_MACBYTES (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES)
|
||||
#endif
|
||||
|
||||
#ifndef IPV6_ADD_MEMBERSHIP
|
||||
#ifdef IPV6_JOIN_GROUP
|
||||
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
|
||||
#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define MAX_UDP_PACKET_SIZE 65507
|
||||
|
||||
#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_IPV6 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. */
|
||||
|
@ -75,6 +87,10 @@
|
|||
#define NET_PACKET_LAN_DISCOVERY 33 /* LAN discovery packet ID. */
|
||||
#define NET_PACKET_GROUP_CHATS 48 /* Group chats packet ID. */
|
||||
|
||||
#define TOX_PORTRANGE_FROM 33445
|
||||
#define TOX_PORTRANGE_TO 33455
|
||||
#define TOX_PORT_DEFAULT TOX_PORTRANGE_FROM
|
||||
|
||||
/* Current time, unix format */
|
||||
#define unix_time() ((uint64_t)time(NULL))
|
||||
|
||||
|
@ -83,27 +99,123 @@ typedef union {
|
|||
uint8_t uint8[4];
|
||||
uint16_t uint16[2];
|
||||
uint32_t uint32;
|
||||
} IP;
|
||||
struct in_addr in_addr;
|
||||
} IP4;
|
||||
|
||||
typedef union {
|
||||
uint8_t uint8[16];
|
||||
uint16_t uint16[8];
|
||||
uint32_t uint32[4];
|
||||
struct in6_addr in6_addr;
|
||||
} IP6;
|
||||
|
||||
typedef struct {
|
||||
sa_family_t family;
|
||||
union {
|
||||
IP4 ip4;
|
||||
IP6 ip6;
|
||||
};
|
||||
} IPAny;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
IP ip;
|
||||
IP4 ip;
|
||||
uint16_t port;
|
||||
/* Not used for anything right now. */
|
||||
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 */
|
||||
typedef struct {
|
||||
int16_t family;
|
||||
IPAny ip;
|
||||
uint16_t port;
|
||||
IP ip;
|
||||
uint8_t zeroes[8];
|
||||
#ifdef ENABLE_IPV6
|
||||
uint8_t zeroes2[12];
|
||||
} IPAny_Port;
|
||||
|
||||
/* #undef TOX_ENABLE_IPV6 */
|
||||
#define TOX_ENABLE_IPV6
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
#define TOX_ENABLE_IPV6_DEFAULT 1
|
||||
typedef IPAny IP;
|
||||
typedef IPAny_Port IP_Port;
|
||||
#else
|
||||
#define TOX_ENABLE_IPV6_DEFAULT 0
|
||||
typedef IP4 IP;
|
||||
typedef IP4_Port IP_Port;
|
||||
#endif
|
||||
} ADDR;
|
||||
|
||||
/* ip_ntoa
|
||||
* converts ip into a string
|
||||
* uses a static buffer, so mustn't used multiple times in the same output
|
||||
*/
|
||||
const char *ip_ntoa(IP *ip);
|
||||
|
||||
/* ip_equal
|
||||
* compares two IPAny structures
|
||||
* unset means unequal
|
||||
*
|
||||
* returns 0 when not equal or when uninitialized
|
||||
*/
|
||||
int ip_equal(IP *a, IP *b);
|
||||
|
||||
/* ipport_equal
|
||||
* compares two IPAny_Port structures
|
||||
* unset means unequal
|
||||
*
|
||||
* returns 0 when not equal or when uninitialized
|
||||
*/
|
||||
int ipport_equal(IP_Port *a, IP_Port *b);
|
||||
|
||||
/* nulls out ip */
|
||||
void ip_reset(IP *ip);
|
||||
/* nulls out ip, sets family according to flag */
|
||||
void ip_init(IP *ip, uint8_t ipv6enabled);
|
||||
/* checks if ip is valid */
|
||||
int ip_isset(IP *ip);
|
||||
/* checks if ip is valid */
|
||||
int ipport_isset(IP_Port *ipport);
|
||||
/* copies an ip structure */
|
||||
void ip_copy(IP *target, IP *source);
|
||||
/* copies an ip_port structure */
|
||||
void ipport_copy(IP_Port *target, IP_Port *source);
|
||||
|
||||
/*
|
||||
* addr_resolve():
|
||||
* uses getaddrinfo to resolve an address into an IP address
|
||||
* uses the first IPv4/IPv6 addresses returned by getaddrinfo
|
||||
*
|
||||
* input
|
||||
* address: a hostname (or something parseable to an IP address)
|
||||
* to: to.family MUST be initialized, either set to a specific IP version
|
||||
* (AF_INET/AF_INET6) or to the unspecified AF_UNSPEC (= 0), if both
|
||||
* IP versions are acceptable
|
||||
* extra can be NULL and is only set in special circumstances, see returns
|
||||
*
|
||||
* returns in *to a valid IPAny (v4/v6),
|
||||
* prefers v6 if ip.family was AF_UNSPEC and both available
|
||||
* returns in *extra an IPv4 address, if family was AF_UNSPEC and *to is AF_INET6
|
||||
* returns 0 on failure
|
||||
*/
|
||||
int addr_resolve(const char *address, IP *to, IP *extra);
|
||||
|
||||
/*
|
||||
* addr_resolve_or_parse_ip
|
||||
* resolves string into an IP address
|
||||
*
|
||||
* address: a hostname (or something parseable to an IP address)
|
||||
* to: to.family MUST be initialized, either set to a specific IP version
|
||||
* (AF_INET/AF_INET6) or to the unspecified AF_UNSPEC (= 0), if both
|
||||
* IP versions are acceptable
|
||||
* extra can be NULL and is only set in special circumstances, see returns
|
||||
*
|
||||
* returns in *tro a matching address (IPv6 or IPv4)
|
||||
* returns in *extra, if not NULL, an IPv4 address, if to->family was AF_UNSPEC
|
||||
* returns 1 on success
|
||||
* returns 0 on failure
|
||||
*/
|
||||
int addr_resolve_or_parse_ip(const char *address, IP *to, IP *extra);
|
||||
|
||||
/* Function to receive data, ip and port of sender is put into ip_port.
|
||||
* Packet data is put into data.
|
||||
|
@ -118,13 +230,11 @@ typedef struct {
|
|||
|
||||
typedef struct {
|
||||
Packet_Handles packethandlers[256];
|
||||
/* Our UDP socket. */
|
||||
#ifdef WIN32
|
||||
unsigned int sock;
|
||||
#else
|
||||
int sock;
|
||||
#endif
|
||||
|
||||
/* Our UDP socket. */
|
||||
sa_family_t family;
|
||||
uint16_t port;
|
||||
sock_t sock;
|
||||
} Networking_Core;
|
||||
|
||||
/* return current time in milleseconds since the epoch. */
|
||||
|
@ -137,12 +247,7 @@ uint32_t random_int(void);
|
|||
/* Basic network functions: */
|
||||
|
||||
/* Function to send packet(data) of length length to ip_port. */
|
||||
#ifdef WIN32
|
||||
int sendpacket(unsigned int sock, IP_Port ip_port, uint8_t *data, uint32_t length);
|
||||
#else
|
||||
int sendpacket(int sock, IP_Port ip_port, uint8_t *data, uint32_t length);
|
||||
#endif
|
||||
|
||||
int sendpacket(Networking_Core *net, IP_Port ip_port, uint8_t *data, uint32_t length);
|
||||
|
||||
/* Function to call when packet beginning with byte is received. */
|
||||
void networking_registerhandler(Networking_Core *net, uint8_t byte, packet_handler_callback cb, void *object);
|
||||
|
@ -163,5 +268,4 @@ Networking_Core *new_networking(IP ip, uint16_t port);
|
|||
/* Function to cleanup networking stuff (doesn't do much right now). */
|
||||
void kill_networking(Networking_Core *net);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -100,7 +100,8 @@ bool is_pinging(void *ping, IP_Port ipp, uint64_t ping_id) // O(n) TODO: Repl
|
|||
{
|
||||
PING *png = ping;
|
||||
|
||||
if (ipp.ip.uint32 == 0 && ping_id == 0)
|
||||
/* shouldn't that be an OR ? */
|
||||
if (!ip_isset(&ipp.ip) && ping_id == 0)
|
||||
return false;
|
||||
|
||||
size_t i, id;
|
||||
|
@ -111,7 +112,8 @@ bool is_pinging(void *ping, IP_Port ipp, uint64_t ping_id) // O(n) TODO: Repl
|
|||
id = (png->pos_pings + i) % PING_NUM_MAX;
|
||||
|
||||
/* ping_id = 0 means match any id. */
|
||||
if ((ipp_eq(png->pings[id].ipp, ipp) || ipp.ip.uint32 == 0) && (png->pings[id].id == ping_id || ping_id == 0)) {
|
||||
if ((!ip_isset(&ipp.ip) || ipport_equal(&png->pings[id].ipp, &ipp)) &&
|
||||
(png->pings[id].id == ping_id || ping_id == 0)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +149,7 @@ int send_ping_request(void *ping, Net_Crypto *c, IP_Port ipp, uint8_t *client_id
|
|||
if (rc != sizeof(ping_id) + ENCRYPTION_PADDING)
|
||||
return 1;
|
||||
|
||||
return sendpacket(c->lossless_udp->net->sock, ipp, pk, sizeof(pk));
|
||||
return sendpacket(c->lossless_udp->net, ipp, pk, sizeof(pk));
|
||||
}
|
||||
|
||||
int send_ping_response(Net_Crypto *c, IP_Port ipp, uint8_t *client_id, uint64_t ping_id)
|
||||
|
@ -172,7 +174,7 @@ int send_ping_response(Net_Crypto *c, IP_Port ipp, uint8_t *client_id, uint64_t
|
|||
if (rc != sizeof(ping_id) + ENCRYPTION_PADDING)
|
||||
return 1;
|
||||
|
||||
return sendpacket(c->lossless_udp->net->sock, ipp, pk, sizeof(pk));
|
||||
return sendpacket(c->lossless_udp->net, ipp, pk, sizeof(pk));
|
||||
}
|
||||
|
||||
int handle_ping_request(void *object, IP_Port source, uint8_t *packet, uint32_t length)
|
||||
|
|
|
@ -441,14 +441,20 @@ int tox_group_message_send(void *tox, int groupnumber, uint8_t *message, uint32_
|
|||
|
||||
/******************END OF GROUP CHAT FUNCTIONS************************/
|
||||
|
||||
/* Use this function to bootstrap the client.
|
||||
/* Use these functions to bootstrap the client.
|
||||
* Sends a get nodes request to the given node with ip port and public_key.
|
||||
*/
|
||||
void tox_bootstrap(void *tox, IP_Port ip_port, uint8_t *public_key)
|
||||
void tox_bootstrap_from_ip(void *tox, IP_Port ip_port, uint8_t *public_key)
|
||||
{
|
||||
Messenger *m = tox;
|
||||
DHT_bootstrap(m->dht, ip_port, public_key);
|
||||
}
|
||||
int tox_bootstrap_from_address(void *tox, const char *address,
|
||||
uint8_t ipv6enabled, uint16_t port, uint8_t *public_key)
|
||||
{
|
||||
Messenger *m = tox;
|
||||
return DHT_bootstrap_from_address(m->dht, address, ipv6enabled, port, public_key);
|
||||
};
|
||||
|
||||
/* return 0 if we are not connected to the DHT.
|
||||
* return 1 if we are.
|
||||
|
@ -464,9 +470,9 @@ int tox_isconnected(void *tox)
|
|||
* return allocated instance of tox on success.
|
||||
* return 0 if there are problems.
|
||||
*/
|
||||
void *tox_new(void)
|
||||
void *tox_new(uint8_t ipv6enabled)
|
||||
{
|
||||
return initMessenger();
|
||||
return initMessenger(ipv6enabled);
|
||||
}
|
||||
|
||||
/* Run this before closing shop.
|
||||
|
|
106
toxcore/tox.h
106
toxcore/tox.h
|
@ -26,6 +26,22 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#ifndef WINVER
|
||||
//Windows XP
|
||||
#define WINVER 0x0501
|
||||
#endif
|
||||
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <netinet/ip.h>
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -36,19 +52,61 @@ extern "C" {
|
|||
|
||||
#define TOX_FRIEND_ADDRESS_SIZE (TOX_CLIENT_ID_SIZE + sizeof(uint32_t) + sizeof(uint16_t))
|
||||
|
||||
#define TOX_PORTRANGE_FROM 33445
|
||||
#define TOX_PORTRANGE_TO 33455
|
||||
#define TOX_PORT_DEFAULT TOX_PORTRANGE_FROM
|
||||
|
||||
typedef union {
|
||||
uint8_t c[4];
|
||||
uint8_t c[4];
|
||||
uint16_t s[2];
|
||||
uint32_t i;
|
||||
} tox_IP;
|
||||
} tox_IP4;
|
||||
|
||||
|
||||
typedef union {
|
||||
uint8_t uint8[16];
|
||||
uint16_t uint16[8];
|
||||
uint32_t uint32[4];
|
||||
struct in6_addr in6_addr;
|
||||
} tox_IP6;
|
||||
|
||||
typedef struct {
|
||||
tox_IP ip;
|
||||
uint16_t port;
|
||||
/* Not used for anything right now. */
|
||||
uint16_t padding;
|
||||
} tox_IP_Port;
|
||||
sa_family_t family;
|
||||
union {
|
||||
tox_IP4 ip4;
|
||||
tox_IP6 ip6;
|
||||
};
|
||||
} tox_IPAny;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
tox_IP4 ip;
|
||||
uint16_t port;
|
||||
/* Not used for anything right now. */
|
||||
uint16_t padding;
|
||||
};
|
||||
uint8_t uint8[8];
|
||||
} tox_IP4_Port;
|
||||
|
||||
/* will replace IP_Port as soon as the complete infrastructure is in place
|
||||
* removed the unused union and padding also */
|
||||
typedef struct {
|
||||
tox_IPAny ip;
|
||||
uint16_t port;
|
||||
} tox_IPAny_Port;
|
||||
|
||||
/* #undef TOX_ENABLE_IPV6 */
|
||||
#define TOX_ENABLE_IPV6
|
||||
#ifdef TOX_ENABLE_IPV6
|
||||
#define TOX_ENABLE_IPV6_DEFAULT 1
|
||||
typedef tox_IPAny tox_IP;
|
||||
typedef tox_IPAny_Port tox_IP_Port;
|
||||
#else
|
||||
#define TOX_ENABLE_IPV6_DEFAULT 0
|
||||
typedef tox_IP4 tox_IP;
|
||||
typedef tox_IP4_Port tox_IP_Port;
|
||||
#endif
|
||||
|
||||
|
||||
/* Errors for m_addfriend
|
||||
* FAERR - Friend Add Error
|
||||
|
@ -342,22 +400,46 @@ int tox_group_message_send(Tox *tox, int groupnumber, uint8_t *message, uint32_t
|
|||
|
||||
/******************END OF GROUP CHAT FUNCTIONS************************/
|
||||
|
||||
/* Use this function to bootstrap the client.
|
||||
* Sends a get nodes request to the given node with ip port and public_key.
|
||||
/*
|
||||
* Use these two functions to bootstrap the client.
|
||||
*/
|
||||
void tox_bootstrap(Tox *tox, tox_IP_Port ip_port, uint8_t *public_key);
|
||||
/* Sends a "get nodes" request to the given node with ip, port and public_key
|
||||
* to setup connections
|
||||
*/
|
||||
void tox_bootstrap_from_ip(Tox *tox, tox_IP_Port ip_port, uint8_t *public_key);
|
||||
/* Resolves address into an IP address. If successful, sends a "get nodes"
|
||||
* request to the given node with ip, port and public_key to setup connections
|
||||
*
|
||||
* address can be a hostname or an IP address (IPv4 or IPv6).
|
||||
* if ipv6enabled is 0 (zero), the resolving sticks STRICTLY to IPv4 addresses
|
||||
* if ipv6enabled is not 0 (zero), the resolving looks for IPv6 addresses first,
|
||||
* then IPv4 addresses.
|
||||
*
|
||||
* returns 1 if the address could be converted into an IP address
|
||||
* returns 0 otherwise
|
||||
*/
|
||||
int tox_bootstrap_from_address(Tox *tox, const char *address, uint8_t ipv6enabled,
|
||||
uint16_t port, uint8_t *public_key);
|
||||
|
||||
/* return 0 if we are not connected to the DHT.
|
||||
* return 1 if we are.
|
||||
*/
|
||||
int tox_isconnected(Tox *tox);
|
||||
|
||||
/* Run this at startup.
|
||||
/*
|
||||
* Run this function at startup.
|
||||
*
|
||||
* Initializes a tox structure
|
||||
* The type of communication socket depends on ipv6enabled:
|
||||
* If set to 0 (zero), creates an IPv4 socket which subsequently only allows
|
||||
* IPv4 communication
|
||||
* If set to anything else, creates an IPv6 socket which allows both IPv4 AND
|
||||
* IPv6 communication
|
||||
*
|
||||
* return allocated instance of tox on success.
|
||||
* return 0 if there are problems.
|
||||
*/
|
||||
Tox *tox_new(void);
|
||||
Tox *tox_new(uint8_t ipv6enabled);
|
||||
|
||||
/* Run this before closing shop.
|
||||
* Free all datastructures. */
|
||||
|
|
|
@ -10,11 +10,12 @@
|
|||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* for CLIENT_ID_SIZE */
|
||||
#include "DHT.h"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
uint64_t now()
|
||||
{
|
||||
return time(NULL);
|
||||
|
@ -32,11 +33,6 @@ uint64_t random_64b()
|
|||
return r;
|
||||
}
|
||||
|
||||
bool ipp_eq(IP_Port a, IP_Port b)
|
||||
{
|
||||
return (a.ip.uint32 == b.ip.uint32) && (a.port == b.port);
|
||||
}
|
||||
|
||||
bool id_eq(uint8_t *dest, uint8_t *src)
|
||||
{
|
||||
return memcmp(dest, src, CLIENT_ID_SIZE) == 0;
|
||||
|
@ -46,3 +42,33 @@ void id_cpy(uint8_t *dest, uint8_t *src)
|
|||
{
|
||||
memcpy(dest, src, CLIENT_ID_SIZE);
|
||||
}
|
||||
|
||||
#ifdef LOGGING
|
||||
time_t starttime = 0;
|
||||
char logbuffer[512];
|
||||
static FILE *logfile = NULL;
|
||||
void loginit(uint16_t port)
|
||||
{
|
||||
if (logfile)
|
||||
fclose(logfile);
|
||||
|
||||
sprintf(logbuffer, "%u-%u.log", ntohs(port), now());
|
||||
logfile = fopen(logbuffer, "w");
|
||||
starttime = now();
|
||||
};
|
||||
void loglog(char *text)
|
||||
{
|
||||
if (logfile) {
|
||||
fprintf(logfile, "%4u ", now() - starttime);
|
||||
fprintf(logfile, text);
|
||||
fflush(logfile);
|
||||
}
|
||||
};
|
||||
void logexit()
|
||||
{
|
||||
if (logfile) {
|
||||
fclose(logfile);
|
||||
logfile = NULL;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -5,8 +5,24 @@
|
|||
* Copyright 2013 plutooo
|
||||
*/
|
||||
|
||||
#ifndef __UTIL_H__
|
||||
#define __UTIL_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
uint64_t now();
|
||||
uint64_t random_64b();
|
||||
bool ipp_eq(IP_Port a, IP_Port b);
|
||||
bool id_eq(uint8_t *dest, uint8_t *src);
|
||||
void id_cpy(uint8_t *dest, uint8_t *src);
|
||||
|
||||
#undef LOGGING
|
||||
/* #define LOGGING */
|
||||
#ifdef LOGGING
|
||||
extern char logbuffer[512];
|
||||
void loginit(uint16_t port);
|
||||
void loglog(char *text);
|
||||
void logexit();
|
||||
#endif
|
||||
|
||||
#endif /* __UTIL_H__ */
|
||||
|
|
Loading…
Reference in New Issue
Block a user