diff options
Diffstat (limited to 'toxcore/network.c')
-rw-r--r-- | toxcore/network.c | 692 |
1 files changed, 668 insertions, 24 deletions
diff --git a/toxcore/network.c b/toxcore/network.c index c6c4965e..4b6dc3be 100644 --- a/toxcore/network.c +++ b/toxcore/network.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #endif | 26 | #endif |
27 | 27 | ||
28 | #include "network.h" | 28 | #include "network.h" |
29 | #include "util.h" | ||
29 | 30 | ||
30 | /* return current UNIX time in microseconds (us). */ | 31 | /* return current UNIX time in microseconds (us). */ |
31 | uint64_t current_time(void) | 32 | uint64_t current_time(void) |
@@ -62,17 +63,83 @@ uint32_t random_int(void) | |||
62 | #endif | 63 | #endif |
63 | } | 64 | } |
64 | 65 | ||
66 | #ifdef LOGGING | ||
67 | static void loglogdata(char *message, uint8_t *buffer, size_t buflen, IP_Port *ip_port, ssize_t res); | ||
68 | #endif | ||
69 | |||
65 | /* Basic network functions: | 70 | /* Basic network functions: |
66 | * Function to send packet(data) of length length to ip_port. | 71 | * Function to send packet(data) of length length to ip_port. |
67 | */ | 72 | */ |
68 | #ifdef WIN32 | 73 | int sendpacket(Networking_Core *net, IP_Port ip_port, uint8_t *data, uint32_t length) |
69 | int sendpacket(unsigned int sock, IP_Port ip_port, uint8_t *data, uint32_t length) | 74 | { |
75 | #ifdef TOX_ENABLE_IPV6 | ||
76 | |||
77 | /* socket AF_INET, but target IP NOT: can't send */ | ||
78 | if ((net->family == AF_INET) && (ip_port.ip.family != AF_INET)) | ||
79 | return -1; | ||
80 | |||
81 | #endif | ||
82 | |||
83 | struct sockaddr_storage addr; | ||
84 | size_t addrsize = 0; | ||
85 | |||
86 | #ifdef TOX_ENABLE_IPV6 | ||
87 | |||
88 | if (ip_port.ip.family == AF_INET) { | ||
89 | if (net->family == AF_INET6) { | ||
90 | /* must convert to IPV4-in-IPV6 address */ | ||
91 | addrsize = sizeof(struct sockaddr_in6); | ||
92 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; | ||
93 | addr6->sin6_family = AF_INET6; | ||
94 | addr6->sin6_port = ip_port.port; | ||
95 | |||
96 | /* there should be a macro for this in a standards compliant | ||
97 | * environment, not found */ | ||
98 | IP6 ip6; | ||
99 | |||
100 | ip6.uint32[0] = 0; | ||
101 | ip6.uint32[1] = 0; | ||
102 | ip6.uint32[2] = htonl(0xFFFF); | ||
103 | ip6.uint32[3] = ip_port.ip.ip4.uint32; | ||
104 | addr6->sin6_addr = ip6.in6_addr; | ||
105 | |||
106 | addr6->sin6_flowinfo = 0; | ||
107 | addr6->sin6_scope_id = 0; | ||
108 | } else { | ||
109 | IP4 ip4 = ip_port.ip.ip4; | ||
70 | #else | 110 | #else |
71 | int sendpacket(int sock, IP_Port ip_port, uint8_t *data, uint32_t length) | 111 | IP4 ip4 = ip_port.ip; |
72 | #endif | 112 | #endif |
73 | { | 113 | addrsize = sizeof(struct sockaddr_in); |
74 | ADDR addr = {AF_INET, ip_port.port, ip_port.ip, {0}}; | 114 | struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr; |
75 | return sendto(sock, (char *) data, length, 0, (struct sockaddr *)&addr, sizeof(addr)); | 115 | addr4->sin_family = AF_INET; |
116 | addr4->sin_addr = ip4.in_addr; | ||
117 | addr4->sin_port = ip_port.port; | ||
118 | #ifdef TOX_ENABLE_IPV6 | ||
119 | } | ||
120 | } else if (ip_port.ip.family == AF_INET6) | ||
121 | { | ||
122 | addrsize = sizeof(struct sockaddr_in6); | ||
123 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; | ||
124 | addr6->sin6_family = AF_INET6; | ||
125 | addr6->sin6_port = ip_port.port; | ||
126 | addr6->sin6_addr = ip_port.ip.ip6.in6_addr; | ||
127 | |||
128 | addr6->sin6_flowinfo = 0; | ||
129 | addr6->sin6_scope_id = 0; | ||
130 | } else | ||
131 | { | ||
132 | /* unknown address type*/ | ||
133 | return -1; | ||
134 | } | ||
135 | |||
136 | #endif | ||
137 | |||
138 | int res = sendto(net->sock, (char *) data, length, 0, (struct sockaddr *)&addr, addrsize); | ||
139 | #ifdef LOGGING | ||
140 | loglogdata("O=>", data, length, &ip_port, res); | ||
141 | #endif | ||
142 | return res; | ||
76 | } | 143 | } |
77 | 144 | ||
78 | /* Function to receive data | 145 | /* Function to receive data |
@@ -81,13 +148,9 @@ int sendpacket(int sock, IP_Port ip_port, uint8_t *data, uint32_t length) | |||
81 | * Packet length is put into length. | 148 | * Packet length is put into length. |
82 | * Dump all empty packets. | 149 | * Dump all empty packets. |
83 | */ | 150 | */ |
84 | #ifdef WIN32 | 151 | static int receivepacket(sock_t sock, IP_Port *ip_port, uint8_t *data, uint32_t *length) |
85 | static int receivepacket(unsigned int sock, IP_Port *ip_port, uint8_t *data, uint32_t *length) | ||
86 | #else | ||
87 | static int receivepacket(int sock, IP_Port *ip_port, uint8_t *data, uint32_t *length) | ||
88 | #endif | ||
89 | { | 152 | { |
90 | ADDR addr; | 153 | struct sockaddr_storage addr; |
91 | #ifdef WIN32 | 154 | #ifdef WIN32 |
92 | int addrlen = sizeof(addr); | 155 | int addrlen = sizeof(addr); |
93 | #else | 156 | #else |
@@ -95,11 +158,48 @@ static int receivepacket(int sock, IP_Port *ip_port, uint8_t *data, uint32_t *le | |||
95 | #endif | 158 | #endif |
96 | (*(int32_t *)length) = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen); | 159 | (*(int32_t *)length) = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen); |
97 | 160 | ||
98 | if (*(int32_t *)length <= 0) | 161 | if (*(int32_t *)length <= 0) { |
162 | #ifdef LOGGING | ||
163 | |||
164 | if ((length < 0) && (errno != EWOULDBLOCK)) { | ||
165 | sprintf(logbuffer, "Unexpected error reading from socket: %u, %s\n", errno, strerror(errno)); | ||
166 | loglog(logbuffer); | ||
167 | } | ||
168 | |||
169 | #endif | ||
99 | return -1; /* Nothing received or empty packet. */ | 170 | return -1; /* Nothing received or empty packet. */ |
171 | } | ||
172 | |||
173 | #ifdef TOX_ENABLE_IPV6 | ||
174 | |||
175 | if (addr.ss_family == AF_INET) { | ||
176 | struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr; | ||
177 | ip_port->ip.family = addr_in->sin_family; | ||
178 | ip_port->ip.ip4.in_addr = addr_in->sin_addr; | ||
179 | ip_port->port = addr_in->sin_port; | ||
180 | } else if (addr.ss_family == AF_INET6) { | ||
181 | struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&addr; | ||
182 | ip_port->ip.family = addr_in6->sin6_family; | ||
183 | ip_port->ip.ip6.in6_addr = addr_in6->sin6_addr; | ||
184 | ip_port->port = addr_in6->sin6_port; | ||
185 | } else | ||
186 | return -1; | ||
187 | |||
188 | #else | ||
189 | |||
190 | if (addr.ss_family == AF_INET) { | ||
191 | struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr; | ||
192 | ip_port->ip.in_addr = addr_in->sin_addr; | ||
193 | ip_port->port = addr_in->sin_port; | ||
194 | } else | ||
195 | return -1; | ||
196 | |||
197 | #endif | ||
198 | |||
199 | #ifdef LOGGING | ||
200 | loglogdata("=>O", data, MAX_UDP_PACKET_SIZE, ip_port, *length); | ||
201 | #endif | ||
100 | 202 | ||
101 | ip_port->ip = addr.ip; | ||
102 | ip_port->port = addr.port; | ||
103 | return 0; | 203 | return 0; |
104 | } | 204 | } |
105 | 205 | ||
@@ -118,13 +218,20 @@ void networking_poll(Networking_Core *net) | |||
118 | while (receivepacket(net->sock, &ip_port, data, &length) != -1) { | 218 | while (receivepacket(net->sock, &ip_port, data, &length) != -1) { |
119 | if (length < 1) continue; | 219 | if (length < 1) continue; |
120 | 220 | ||
121 | if (!(net->packethandlers[data[0]].function)) continue; | 221 | if (!(net->packethandlers[data[0]].function)) { |
222 | #ifdef LOGGING | ||
223 | sprintf(logbuffer, "[%02u] -- Packet has no handler.\n", data[0]); | ||
224 | loglog(logbuffer); | ||
225 | #endif | ||
226 | continue; | ||
227 | } | ||
122 | 228 | ||
123 | net->packethandlers[data[0]].function(net->packethandlers[data[0]].object, ip_port, data, length); | 229 | net->packethandlers[data[0]].function(net->packethandlers[data[0]].object, ip_port, data, length); |
124 | } | 230 | } |
125 | } | 231 | } |
126 | 232 | ||
127 | uint8_t at_startup_ran; | 233 | |
234 | uint8_t at_startup_ran = 0; | ||
128 | static int at_startup(void) | 235 | static int at_startup(void) |
129 | { | 236 | { |
130 | if (at_startup_ran != 0) | 237 | if (at_startup_ran != 0) |
@@ -163,16 +270,34 @@ static void at_shutdown(void) | |||
163 | */ | 270 | */ |
164 | Networking_Core *new_networking(IP ip, uint16_t port) | 271 | Networking_Core *new_networking(IP ip, uint16_t port) |
165 | { | 272 | { |
273 | #ifdef TOX_ENABLE_IPV6 | ||
274 | |||
275 | /* maybe check for invalid IPs like 224+.x.y.z? if there is any IP set ever */ | ||
276 | if (ip.family != AF_INET && ip.family != AF_INET6) { | ||
277 | fprintf(stderr, "Invalid address family: %u\n", ip.family); | ||
278 | return NULL; | ||
279 | } | ||
280 | |||
281 | #endif | ||
282 | |||
166 | if (at_startup() != 0) | 283 | if (at_startup() != 0) |
167 | return NULL; | 284 | return NULL; |
168 | 285 | ||
169 | /* Initialize our socket. */ | ||
170 | Networking_Core *temp = calloc(1, sizeof(Networking_Core)); | 286 | Networking_Core *temp = calloc(1, sizeof(Networking_Core)); |
171 | 287 | ||
172 | if (temp == NULL) | 288 | if (temp == NULL) |
173 | return NULL; | 289 | return NULL; |
174 | 290 | ||
175 | temp->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); | 291 | #ifdef TOX_ENABLE_IPV6 |
292 | temp->family = ip.family; | ||
293 | #else | ||
294 | temp->family = AF_INET; | ||
295 | #endif | ||
296 | temp->port = 0; | ||
297 | |||
298 | /* Initialize our socket. */ | ||
299 | /* add log message what we're creating */ | ||
300 | temp->sock = socket(temp->family, SOCK_DGRAM, IPPROTO_UDP); | ||
176 | 301 | ||
177 | /* Check for socket error. */ | 302 | /* Check for socket error. */ |
178 | #ifdef WIN32 | 303 | #ifdef WIN32 |
@@ -185,6 +310,7 @@ Networking_Core *new_networking(IP ip, uint16_t port) | |||
185 | #else | 310 | #else |
186 | 311 | ||
187 | if (temp->sock < 0) { | 312 | if (temp->sock < 0) { |
313 | fprintf(stderr, "Failed to get a socket?! %u, %s\n", errno, strerror(errno)); | ||
188 | free(temp); | 314 | free(temp); |
189 | return NULL; | 315 | return NULL; |
190 | } | 316 | } |
@@ -205,7 +331,7 @@ Networking_Core *new_networking(IP ip, uint16_t port) | |||
205 | return -1; | 331 | return -1; |
206 | */ | 332 | */ |
207 | 333 | ||
208 | /* Enable broadcast on socket. */ | 334 | /* Enable broadcast on socket */ |
209 | int broadcast = 1; | 335 | int broadcast = 1; |
210 | setsockopt(temp->sock, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast)); | 336 | setsockopt(temp->sock, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast)); |
211 | 337 | ||
@@ -219,10 +345,140 @@ Networking_Core *new_networking(IP ip, uint16_t port) | |||
219 | fcntl(temp->sock, F_SETFL, O_NONBLOCK, 1); | 345 | fcntl(temp->sock, F_SETFL, O_NONBLOCK, 1); |
220 | #endif | 346 | #endif |
221 | 347 | ||
222 | /* Bind our socket to port PORT and address 0.0.0.0 */ | 348 | #ifdef LOGGING |
223 | ADDR addr = {AF_INET, htons(port), ip, {0}}; | 349 | loginit(ntohs(port)); |
224 | bind(temp->sock, (struct sockaddr *)&addr, sizeof(addr)); | 350 | #endif |
225 | return temp; | 351 | |
352 | /* Bind our socket to port PORT and the given IP address (usually 0.0.0.0 or ::) */ | ||
353 | uint16_t *portptr = NULL; | ||
354 | struct sockaddr_storage addr; | ||
355 | size_t addrsize; | ||
356 | #ifdef TOX_ENABLE_IPV6 | ||
357 | |||
358 | if (temp->family == AF_INET) { | ||
359 | IP4 ip4 = ip.ip4; | ||
360 | #else | ||
361 | IP4 ip4 = ip; | ||
362 | #endif | ||
363 | addrsize = sizeof(struct sockaddr_in); | ||
364 | struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr; | ||
365 | addr4->sin_family = AF_INET; | ||
366 | addr4->sin_port = 0; | ||
367 | addr4->sin_addr = ip4.in_addr; | ||
368 | |||
369 | portptr = &addr4->sin_port; | ||
370 | #ifdef TOX_ENABLE_IPV6 | ||
371 | } else if (temp->family == AF_INET6) | ||
372 | { | ||
373 | addrsize = sizeof(struct sockaddr_in6); | ||
374 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; | ||
375 | addr6->sin6_family = AF_INET6; | ||
376 | addr6->sin6_port = 0; | ||
377 | addr6->sin6_addr = ip.ip6.in6_addr; | ||
378 | |||
379 | addr6->sin6_flowinfo = 0; | ||
380 | addr6->sin6_scope_id = 0; | ||
381 | |||
382 | portptr = &addr6->sin6_port; | ||
383 | } else | ||
384 | return NULL; | ||
385 | |||
386 | if (ip.family == AF_INET6) | ||
387 | { | ||
388 | char ipv6only = 0; | ||
389 | #ifdef LOGGING | ||
390 | int res = | ||
391 | #endif | ||
392 | setsockopt(temp->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&ipv6only, sizeof(ipv6only)); | ||
393 | #ifdef LOGGING | ||
394 | |||
395 | if (res < 0) { | ||
396 | sprintf(logbuffer, | ||
397 | "Failed to enable dual-stack on IPv6 socket, won't be able to receive from/send to IPv4 addresses. (%u, %s)\n", | ||
398 | errno, strerror(errno)); | ||
399 | loglog(logbuffer); | ||
400 | } else | ||
401 | loglog("Embedded IPv4 addresses enabled successfully.\n"); | ||
402 | |||
403 | #endif | ||
404 | |||
405 | /* multicast local nodes */ | ||
406 | struct ipv6_mreq mreq; | ||
407 | memset(&mreq, 0, sizeof(mreq)); | ||
408 | mreq.ipv6mr_multiaddr.s6_addr[ 0] = 0xFF; | ||
409 | mreq.ipv6mr_multiaddr.s6_addr[ 1] = 0x02; | ||
410 | mreq.ipv6mr_multiaddr.s6_addr[15] = 0x01; | ||
411 | mreq.ipv6mr_interface = 0; | ||
412 | #ifdef LOGGING | ||
413 | res = | ||
414 | #endif | ||
415 | setsockopt(temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); | ||
416 | #ifdef LOGGING | ||
417 | |||
418 | if (res < 0) { | ||
419 | sprintf(logbuffer, "Failed to activate local multicast membership. (%u, %s)\n", | ||
420 | errno, strerror(errno)); | ||
421 | loglog(logbuffer); | ||
422 | } else | ||
423 | loglog("Local multicast group FF02::1 joined successfully.\n"); | ||
424 | |||
425 | #endif | ||
426 | } | ||
427 | |||
428 | #endif | ||
429 | |||
430 | /* a hanging program or a different user might block the standard port; | ||
431 | * as long as it isn't a parameter coming from the commandline, | ||
432 | * try a few ports after it, to see if we can find a "free" one | ||
433 | * | ||
434 | * if we go on without binding, the first sendto() automatically binds to | ||
435 | * a free port chosen by the system (i.e. anything from 1024 to 65535) | ||
436 | * | ||
437 | * returning NULL after bind fails has both advantages and disadvantages: | ||
438 | * advantage: | ||
439 | * we can rely on getting the port in the range 33445..33450, which | ||
440 | * enables us to tell joe user to open their firewall to a small range | ||
441 | * | ||
442 | * disadvantage: | ||
443 | * some clients might not test return of tox_new(), blindly assuming that | ||
444 | * it worked ok (which it did previously without a successful bind) | ||
445 | */ | ||
446 | uint16_t port_to_try = port; | ||
447 | *portptr = htons(port_to_try); | ||
448 | int tries, res; | ||
449 | |||
450 | for (tries = TOX_PORTRANGE_FROM; tries <= TOX_PORTRANGE_TO; tries++) | ||
451 | { | ||
452 | res = bind(temp->sock, (struct sockaddr *)&addr, addrsize); | ||
453 | |||
454 | if (!res) { | ||
455 | temp->port = *portptr; | ||
456 | #ifdef LOGGING | ||
457 | sprintf(logbuffer, "Bound successfully to %s:%u.\n", ip_ntoa(&ip), ntohs(temp->port)); | ||
458 | loglog(logbuffer); | ||
459 | #endif | ||
460 | |||
461 | /* errno isn't reset on success, only set on failure, the failed | ||
462 | * binds with parallel clients yield a -EPERM to the outside if | ||
463 | * errno isn't cleared here */ | ||
464 | if (tries > 0) | ||
465 | errno = 0; | ||
466 | |||
467 | return temp; | ||
468 | } | ||
469 | |||
470 | port_to_try++; | ||
471 | |||
472 | if (port_to_try > TOX_PORTRANGE_TO) | ||
473 | port_to_try = TOX_PORTRANGE_FROM; | ||
474 | |||
475 | *portptr = htons(port_to_try); | ||
476 | } | ||
477 | |||
478 | fprintf(stderr, "Failed to bind socket: %u, %s (IP/Port: %s:%u\n", errno, | ||
479 | strerror(errno), ip_ntoa(&ip), port); | ||
480 | kill_networking(temp); | ||
481 | return NULL; | ||
226 | } | 482 | } |
227 | 483 | ||
228 | /* Function to cleanup networking stuff. */ | 484 | /* Function to cleanup networking stuff. */ |
@@ -236,3 +492,391 @@ void kill_networking(Networking_Core *net) | |||
236 | free(net); | 492 | free(net); |
237 | return; | 493 | return; |
238 | } | 494 | } |
495 | |||
496 | /* ip_equal | ||
497 | * compares two IPAny structures | ||
498 | * unset means unequal | ||
499 | * | ||
500 | * returns 0 when not equal or when uninitialized | ||
501 | */ | ||
502 | int ip_equal(IP *a, IP *b) | ||
503 | { | ||
504 | if (!a || !b) | ||
505 | return 0; | ||
506 | |||
507 | #ifdef TOX_ENABLE_IPV6 | ||
508 | |||
509 | /* same family */ | ||
510 | if (a->family == b->family) { | ||
511 | if (a->family == AF_INET) | ||
512 | return (a->ip4.in_addr.s_addr == b->ip4.in_addr.s_addr); | ||
513 | else if (a->family == AF_INET6) | ||
514 | return IN6_ARE_ADDR_EQUAL(&a->ip6.in6_addr, &b->ip6.in6_addr); | ||
515 | else | ||
516 | return 0; | ||
517 | } | ||
518 | |||
519 | /* different family: check on the IPv6 one if it is the IPv4 one embedded */ | ||
520 | if ((a->family == AF_INET) && (b->family == AF_INET6)) { | ||
521 | if (IN6_IS_ADDR_V4MAPPED(&b->ip6.in6_addr)) | ||
522 | return (a->ip4.in_addr.s_addr == b->ip6.uint32[3]); | ||
523 | } else if ((a->family == AF_INET6) && (b->family == AF_INET)) { | ||
524 | if (IN6_IS_ADDR_V4MAPPED(&a->ip6.in6_addr)) | ||
525 | return (a->ip6.uint32[3] == b->ip4.in_addr.s_addr); | ||
526 | } | ||
527 | |||
528 | return 0; | ||
529 | #else | ||
530 | return (a->uint32 == b->uint32); | ||
531 | #endif | ||
532 | }; | ||
533 | |||
534 | /* ipport_equal | ||
535 | * compares two IPAny_Port structures | ||
536 | * unset means unequal | ||
537 | * | ||
538 | * returns 0 when not equal or when uninitialized | ||
539 | */ | ||
540 | int ipport_equal(IP_Port *a, IP_Port *b) | ||
541 | { | ||
542 | if (!a || !b) | ||
543 | return 0; | ||
544 | |||
545 | if (!a->port || (a->port != b->port)) | ||
546 | return 0; | ||
547 | |||
548 | return ip_equal(&a->ip, &b->ip); | ||
549 | }; | ||
550 | |||
551 | /* nulls out ip */ | ||
552 | void ip_reset(IP *ip) | ||
553 | { | ||
554 | if (!ip) | ||
555 | return; | ||
556 | |||
557 | #ifdef TOX_ENABLE_IPV6 | ||
558 | memset(ip, 0, sizeof(IP)); | ||
559 | #else | ||
560 | ip->uint32 = 0; | ||
561 | #endif | ||
562 | }; | ||
563 | |||
564 | /* nulls out ip, sets family according to flag */ | ||
565 | void ip_init(IP *ip, uint8_t ipv6enabled) | ||
566 | { | ||
567 | if (!ip) | ||
568 | return; | ||
569 | |||
570 | #ifdef TOX_ENABLE_IPV6 | ||
571 | memset(ip, 0, sizeof(IP)); | ||
572 | ip->family = ipv6enabled ? AF_INET6 : AF_INET; | ||
573 | #else | ||
574 | ip->uint32 = 0; | ||
575 | #endif | ||
576 | }; | ||
577 | |||
578 | /* checks if ip is valid */ | ||
579 | int ip_isset(IP *ip) | ||
580 | { | ||
581 | if (!ip) | ||
582 | return 0; | ||
583 | |||
584 | #ifdef TOX_ENABLE_IPV6 | ||
585 | return (ip->family != 0); | ||
586 | #else | ||
587 | return (ip->uint32 != 0); | ||
588 | #endif | ||
589 | }; | ||
590 | |||
591 | /* checks if ip is valid */ | ||
592 | int ipport_isset(IP_Port *ipport) | ||
593 | { | ||
594 | if (!ipport) | ||
595 | return 0; | ||
596 | |||
597 | if (!ipport->port) | ||
598 | return 0; | ||
599 | |||
600 | return ip_isset(&ipport->ip); | ||
601 | }; | ||
602 | |||
603 | /* copies an ip structure (careful about direction!) */ | ||
604 | void ip_copy(IP *target, IP *source) | ||
605 | { | ||
606 | if (!source || !target) | ||
607 | return; | ||
608 | |||
609 | memcpy(target, source, sizeof(IP)); | ||
610 | }; | ||
611 | |||
612 | /* copies an ip_port structure (careful about direction!) */ | ||
613 | void ipport_copy(IP_Port *target, IP_Port *source) | ||
614 | { | ||
615 | if (!source || !target) | ||
616 | return; | ||
617 | |||
618 | memcpy(target, source, sizeof(IP_Port)); | ||
619 | }; | ||
620 | |||
621 | /* ip_ntoa | ||
622 | * converts ip into a string | ||
623 | * uses a static buffer, so mustn't used multiple times in the same output | ||
624 | */ | ||
625 | /* there would be INET6_ADDRSTRLEN, but it might be too short for the error message */ | ||
626 | static char addresstext[96]; | ||
627 | const char *ip_ntoa(IP *ip) | ||
628 | { | ||
629 | if (ip) { | ||
630 | #ifdef TOX_ENABLE_IPV6 | ||
631 | |||
632 | if (ip->family == AF_INET) { | ||
633 | addresstext[0] = 0; | ||
634 | struct in_addr *addr = (struct in_addr *)&ip->ip4; | ||
635 | inet_ntop(ip->family, addr, addresstext, sizeof(addresstext)); | ||
636 | } else if (ip->family == AF_INET6) { | ||
637 | addresstext[0] = '['; | ||
638 | struct in6_addr *addr = (struct in6_addr *)&ip->ip6; | ||
639 | inet_ntop(ip->family, addr, &addresstext[1], sizeof(addresstext) - 3); | ||
640 | size_t len = strlen(addresstext); | ||
641 | addresstext[len] = ']'; | ||
642 | addresstext[len + 1] = 0; | ||
643 | } else | ||
644 | snprintf(addresstext, sizeof(addresstext), "(IP invalid, family %u)", ip->family); | ||
645 | |||
646 | #else | ||
647 | addresstext[0] = 0; | ||
648 | struct in_addr *addr = (struct in_addr *)&ip; | ||
649 | inet_ntop(AF_INET, addr, addresstext, sizeof(addresstext)); | ||
650 | #endif | ||
651 | } else | ||
652 | snprintf(addresstext, sizeof(addresstext), "(IP invalid: NULL)"); | ||
653 | |||
654 | /* brute force protection against lacking termination */ | ||
655 | addresstext[sizeof(addresstext) - 1] = 0; | ||
656 | return addresstext; | ||
657 | }; | ||
658 | |||
659 | /* | ||
660 | * addr_parse_ip | ||
661 | * directly parses the input into an IP structure | ||
662 | * tries IPv4 first, then IPv6 | ||
663 | * | ||
664 | * input | ||
665 | * address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6) | ||
666 | * | ||
667 | * output | ||
668 | * IP: family and the value is set on success | ||
669 | * | ||
670 | * returns 1 on success, 0 on failure | ||
671 | */ | ||
672 | |||
673 | int addr_parse_ip(const char *address, IP *to) | ||
674 | { | ||
675 | if (!address || !to) | ||
676 | return 0; | ||
677 | |||
678 | #ifdef TOX_ENABLE_IPV6 | ||
679 | struct in_addr addr4; | ||
680 | |||
681 | if (1 == inet_pton(AF_INET, address, &addr4)) { | ||
682 | to->family = AF_INET; | ||
683 | to->ip4.in_addr = addr4; | ||
684 | return 1; | ||
685 | }; | ||
686 | |||
687 | struct in6_addr addr6; | ||
688 | |||
689 | if (1 == inet_pton(AF_INET6, address, &addr6)) { | ||
690 | to->family = AF_INET6; | ||
691 | to->ip6.in6_addr = addr6; | ||
692 | return 1; | ||
693 | }; | ||
694 | |||
695 | #else | ||
696 | struct in_addr addr4; | ||
697 | |||
698 | if (1 == inet_pton(AF_INET, address, &addr4)) { | ||
699 | to->in_addr = addr4; | ||
700 | return 1; | ||
701 | }; | ||
702 | |||
703 | #endif | ||
704 | |||
705 | return 0; | ||
706 | }; | ||
707 | |||
708 | /* | ||
709 | * addr_resolve(): | ||
710 | * uses getaddrinfo to resolve an address into an IP address | ||
711 | * uses the first IPv4/IPv6 addresses returned by getaddrinfo | ||
712 | * | ||
713 | * input | ||
714 | * address: a hostname (or something parseable to an IP address) | ||
715 | * to: to.family MUST be initialized, either set to a specific IP version | ||
716 | * (AF_INET/AF_INET6) or to the unspecified AF_UNSPEC (= 0), if both | ||
717 | * IP versions are acceptable | ||
718 | * extra can be NULL and is only set in special circumstances, see returns | ||
719 | * | ||
720 | * returns in *to a valid IPAny (v4/v6), | ||
721 | * prefers v6 if ip.family was AF_UNSPEC and both available | ||
722 | * returns in *extra an IPv4 address, if family was AF_UNSPEC and *to is AF_INET6 | ||
723 | * returns 0 on failure | ||
724 | */ | ||
725 | |||
726 | int addr_resolve(const char *address, IP *to, IP *extra) | ||
727 | { | ||
728 | if (!address || !to) | ||
729 | return 0; | ||
730 | |||
731 | sa_family_t family; | ||
732 | #ifdef TOX_ENABLE_IPV6 | ||
733 | family = to->family; | ||
734 | #else | ||
735 | family = AF_INET; | ||
736 | #endif | ||
737 | |||
738 | struct addrinfo *server = NULL; | ||
739 | struct addrinfo *walker = NULL; | ||
740 | struct addrinfo hints; | ||
741 | int rc; | ||
742 | |||
743 | memset(&hints, 0, sizeof(hints)); | ||
744 | hints.ai_family = family; | ||
745 | hints.ai_socktype = SOCK_DGRAM; // type of socket Tox uses. | ||
746 | |||
747 | if (at_startup() != 0) | ||
748 | return 0; | ||
749 | |||
750 | rc = getaddrinfo(address, NULL, &hints, &server); | ||
751 | |||
752 | // Lookup failed. | ||
753 | if (rc != 0) { | ||
754 | return 0; | ||
755 | } | ||
756 | |||
757 | #ifdef TOX_ENABLE_IPV6 | ||
758 | IP4 ip4; | ||
759 | memset(&ip4, 0, sizeof(ip4)); | ||
760 | IP6 ip6; | ||
761 | memset(&ip6, 0, sizeof(ip6)); | ||
762 | #endif | ||
763 | |||
764 | for (walker = server; (walker != NULL) && (rc != 3); walker = walker->ai_next) { | ||
765 | switch (walker->ai_family) { | ||
766 | case AF_INET: | ||
767 | if (walker->ai_family == family) { /* AF_INET requested, done */ | ||
768 | struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr; | ||
769 | #ifdef TOX_ENABLE_IPV6 | ||
770 | to->ip4.in_addr = addr->sin_addr; | ||
771 | #else | ||
772 | to->in_addr = addr->sin_addr; | ||
773 | #endif | ||
774 | rc = 3; | ||
775 | } | ||
776 | |||
777 | #ifdef TOX_ENABLE_IPV6 | ||
778 | else if (!(rc & 1)) { /* AF_UNSPEC requested, store away */ | ||
779 | struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr; | ||
780 | ip4.in_addr = addr->sin_addr; | ||
781 | rc |= 1; | ||
782 | } | ||
783 | |||
784 | #endif | ||
785 | break; /* switch */ | ||
786 | #ifdef TOX_ENABLE_IPV6 | ||
787 | |||
788 | case AF_INET6: | ||
789 | if (walker->ai_family == family) { /* AF_INET6 requested, done */ | ||
790 | if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) { | ||
791 | struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr; | ||
792 | to->ip6.in6_addr = addr->sin6_addr; | ||
793 | rc = 3; | ||
794 | } | ||
795 | } else if (!(rc & 2)) { /* AF_UNSPEC requested, store away */ | ||
796 | if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) { | ||
797 | struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr; | ||
798 | ip6.in6_addr = addr->sin6_addr; | ||
799 | rc |= 2; | ||
800 | } | ||
801 | } | ||
802 | |||
803 | break; /* switch */ | ||
804 | #endif | ||
805 | } | ||
806 | } | ||
807 | |||
808 | #ifdef TOX_ENABLE_IPV6 | ||
809 | |||
810 | if (to->family == AF_UNSPEC) { | ||
811 | if (rc & 2) { | ||
812 | to->family = AF_INET6; | ||
813 | to->ip6 = ip6; | ||
814 | |||
815 | if ((rc & 1) && (extra != NULL)) { | ||
816 | extra->family = AF_INET; | ||
817 | extra->ip4 = ip4; | ||
818 | } | ||
819 | } else if (rc & 1) { | ||
820 | to->family = AF_INET; | ||
821 | to->ip4 = ip4; | ||
822 | } else | ||
823 | rc = 0; | ||
824 | } | ||
825 | |||
826 | #endif | ||
827 | |||
828 | |||
829 | freeaddrinfo(server); | ||
830 | return rc; | ||
831 | } | ||
832 | |||
833 | /* | ||
834 | * addr_resolve_or_parse_ip | ||
835 | * resolves string into an IP address | ||
836 | * | ||
837 | * address: a hostname (or something parseable to an IP address) | ||
838 | * to: to.family MUST be initialized, either set to a specific IP version | ||
839 | * (AF_INET/AF_INET6) or to the unspecified AF_UNSPEC (= 0), if both | ||
840 | * IP versions are acceptable | ||
841 | * extra can be NULL and is only set in special circumstances, see returns | ||
842 | * | ||
843 | * returns in *tro a matching address (IPv6 or IPv4) | ||
844 | * returns in *extra, if not NULL, an IPv4 address, if to->family was AF_UNSPEC | ||
845 | * returns 1 on success | ||
846 | * returns 0 on failure | ||
847 | */ | ||
848 | int addr_resolve_or_parse_ip(const char *address, IP *to, IP *extra) | ||
849 | { | ||
850 | if (!addr_resolve(address, to, extra)) | ||
851 | if (!addr_parse_ip(address, to)) | ||
852 | return 0; | ||
853 | |||
854 | return 1; | ||
855 | }; | ||
856 | |||
857 | #ifdef LOGGING | ||
858 | static void loglogdata(char *message, uint8_t *buffer, size_t buflen, IP_Port *ip_port, ssize_t res) | ||
859 | { | ||
860 | if (res < 0) | ||
861 | snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %3u%c %s:%u (%u: %s) | %04x%04x\n", | ||
862 | buffer[0], message, buflen < 999 ? buflen : 999, 'E', | ||
863 | ip_ntoa(&ip_port->ip), ntohs(ip_port->port), errno, | ||
864 | strerror(errno), buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0, | ||
865 | buflen > 7 ? ntohl(*(uint32_t *)(&buffer[5])) : 0); | ||
866 | else if ((res > 0) && (res <= buflen)) | ||
867 | snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %3u%c %s:%u (%u: %s) | %04x%04x\n", | ||
868 | buffer[0], message, res < 999 ? res : 999, res < buflen ? '<' : '=', | ||
869 | ip_ntoa(&ip_port->ip), ntohs(ip_port->port), 0, | ||
870 | "OK", buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0, | ||
871 | buflen > 7 ? ntohl(*(uint32_t *)(&buffer[5])) : 0); | ||
872 | else /* empty or overwrite */ | ||
873 | snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %u%c%u %s:%u (%u: %s) | %04x%04x\n", | ||
874 | buffer[0], message, res, !res ? '0' : '>', buflen, | ||
875 | ip_ntoa(&ip_port->ip), ntohs(ip_port->port), 0, | ||
876 | "OK", buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0, | ||
877 | buflen > 7 ? ntohl(*(uint32_t *)(&buffer[5])) : 0); | ||
878 | |||
879 | logbuffer[sizeof(logbuffer) - 1] = 0; | ||
880 | loglog(logbuffer); | ||
881 | } | ||
882 | #endif | ||