GNUnet 0.22.0
nat.c
Go to the documentation of this file.
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
28#include "platform.h"
29#include "gnunet_util_lib.h"
30
31#define LOG(kind, ...) GNUNET_log_from (kind, "util-nat", __VA_ARGS__)
32
33#define SEND_DELAY \
34 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MICROSECONDS, 10)
35
36#define TIMEOUT_DELAY \
37 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100)
38
43#define RTT_DIFF \
44 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 150)
45
47
49
51
52unsigned int udp_port;
53
57unsigned int nr_open_sockets;
58
65struct GNUNET_BurstSync *
68{
69 struct GNUNET_BurstSync *burst_sync = GNUNET_new (struct GNUNET_BurstSync);
70
72 burst_sync->sync_ready = sync_ready;
73
74 return burst_sync;
75}
76
77
88void
90 struct GNUNET_BurstSync *burst_sync,
92 struct GNUNET_StartBurstCls *task_cls)
93{
94 struct GNUNET_TIME_Relative other_rtt;
95 struct GNUNET_TIME_Relative rel1;
96 struct GNUNET_TIME_Relative rel2;
97
98 other_rtt = GNUNET_TIME_relative_ntoh (burst_sync->rtt_average);
99 rel1 = GNUNET_TIME_relative_subtract (other_rtt, rtt_average);
100 rel2 = GNUNET_TIME_relative_subtract (rtt_average, other_rtt);
102 "other sync ready %u, other rtt %lu and rtt %lu rel1 %lu rel2 %lu\n",
103 burst_sync->sync_ready,
104 (unsigned long) other_rtt.rel_value_us,
105 (unsigned long) rtt_average.rel_value_us,
106 (unsigned long) rel1.rel_value_us,
107 (unsigned long) rel2.rel_value_us);
108 if ((other_rtt.rel_value_us != GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us &&
109 rtt_average.rel_value_us != GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us) &&
110 rel1.rel_value_us < RTT_DIFF.rel_value_us &&
111 rel2.rel_value_us < RTT_DIFF.rel_value_us)
112 {
114 "other sync ready 1\n");
115 if (GNUNET_YES == burst_sync->sync_ready)
116 {
118 "other sync ready 2\n");
119 task_cls->delay = GNUNET_TIME_relative_saturating_multiply (rtt_average,
120 2);
121 }
122 else
123 {
125 "other sync ready 3\n");
126 task_cls->delay = GNUNET_TIME_relative_saturating_multiply (rtt_average,
127 4);
128 }
129 task_cls->sync_ready = GNUNET_YES;
130 task (task_cls);
131 }
132 else
133 {
135 "other sync ready 6\n");
136 task_cls->sync_ready = GNUNET_NO;
137 }
138}
139
140
141void
142GNUNET_stop_burst (struct GNUNET_NETWORK_Handle *do_not_touch);
143
144
150static void
151sock_read (void *cls)
152{
153 struct GNUNET_UdpSocketInfo *sock_info = cls;
154 struct sockaddr_storage sa;
155 socklen_t salen = sizeof(sa);
156 char buf[UINT16_MAX];
157 ssize_t rcvd;
158
159 sock_info->read_task = NULL;
160
162 "Reading from socket\n");
163 while (1)
164 {
165 rcvd = GNUNET_NETWORK_socket_recvfrom (sock_info->udp_sock,
166 buf,
167 sizeof(buf),
168 (struct sockaddr *) &sa,
169 &salen);
170 if (-1 == rcvd)
171 {
172 struct sockaddr *addr = (struct sockaddr*) &sa;
173
174 if (EAGAIN == errno)
175 break; // We are done reading data
177 "Failed to recv from %s family %d failed sock %p\n",
178 GNUNET_a2s ((struct sockaddr*) &sa,
179 sizeof (*addr)),
180 addr->sa_family,
181 sock_info->udp_sock);
183 return;
184 }
186 "Read %llu bytes\n",
187 (unsigned long long) rcvd);
188 if (0 == rcvd)
189 {
190 GNUNET_break_op (0);
192 "Read 0 bytes from UDP socket\n");
193 return;
194 }
195 /* first, see if it is a GNUNET_BurstMessage */
196 if (rcvd == sizeof (struct GNUNET_BurstMessage))
197 {
198 struct GNUNET_BurstMessage *bm = (struct GNUNET_BurstMessage *) buf;
199
201 "Received a burst message from remote port %u to local port %u!\n",
202 bm->local_port,
203 sock_info->port);
204 sock_info->actual_address = (struct sockaddr *) &sa;
205 sock_info->nus (sock_info);
206 GNUNET_stop_burst (sock_info->udp_sock);
207 return;
208 }
209 else
211 "Received a non burst message on local port %u %lu!\n",
212 sock_info->port,
213 sizeof (struct GNUNET_BurstMessage));
214 }
215}
216
217
225static struct sockaddr *
226udp_address_to_sockaddr (const char *bindto, socklen_t *sock_len)
227{
228 struct sockaddr *in;
229 unsigned int port;
230 char dummy[2];
231 char *colon;
232 char *cp;
233
234 cp = GNUNET_strdup (bindto);
235 colon = strrchr (cp, ':');
236 if (NULL != colon)
237 {
238 /* interpret value after colon as port */
239 *colon = '\0';
240 colon++;
241 if (1 == sscanf (colon, "%u%1s", &port, dummy))
242 {
243 /* interpreting value as just a PORT number */
244 if (port > UINT16_MAX)
245 {
247 "BINDTO specification `%s' invalid: value too large for port\n",
248 bindto);
249 GNUNET_free (cp);
250 return NULL;
251 }
252 }
253 else
254 {
255 GNUNET_log (
257 "BINDTO specification `%s' invalid: last ':' not followed by number\n",
258 bindto);
259 GNUNET_free (cp);
260 return NULL;
261 }
262 }
263 else
264 {
265 /* interpret missing port as 0, aka pick any free one */
266 port = 0;
267 }
268 {
269 /* try IPv4 */
270 struct sockaddr_in v4;
271
272 memset (&v4, 0, sizeof(v4));
273 if (1 == inet_pton (AF_INET, cp, &v4.sin_addr))
274 {
275 v4.sin_family = AF_INET;
276 v4.sin_port = htons ((uint16_t) port);
277#if HAVE_SOCKADDR_IN_SIN_LEN
278 v4.sin_len = sizeof(struct sockaddr_in);
279#endif
280 in = GNUNET_memdup (&v4, sizeof(struct sockaddr_in));
281 *sock_len = sizeof(struct sockaddr_in);
282 GNUNET_free (cp);
283 return in;
284 }
285 }
286 {
287 /* try IPv6 */
288 struct sockaddr_in6 v6;
289 const char *start;
290
291 memset (&v6, 0, sizeof(v6));
292 start = cp;
293 if (('[' == *cp) && (']' == cp[strlen (cp) - 1]))
294 {
295 start++; /* skip over '[' */
296 cp[strlen (cp) - 1] = '\0'; /* eat ']' */
297 }
298 if (1 == inet_pton (AF_INET6, start, &v6.sin6_addr))
299 {
300 v6.sin6_family = AF_INET6;
301 v6.sin6_port = htons ((uint16_t) port);
302#if HAVE_SOCKADDR_IN_SIN_LEN
303 v6.sin6_len = sizeof(struct sockaddr_in6);
304#endif
305 in = GNUNET_memdup (&v6, sizeof(v6));
306 *sock_len = sizeof(v6);
307 GNUNET_free (cp);
308 return in;
309 }
310 }
311 /* #5528 FIXME (feature!): maybe also try getnameinfo()? */
312 GNUNET_free (cp);
313 return NULL;
314}
315
316
317static void
319{
320 struct GNUNET_UdpSocketInfo *sock_info = cls;
321
323 "timeout task\n");
324 if (NULL != sock_info->read_task)
329 "timeout nr_open_sockets %u\n",
331 if (NULL != sock_infos_head)
334 sock_info);
336 "freeing sock_info %p\n",
337 sock_info);
338 GNUNET_free (sock_info);
339}
340
341
342static void
343read_send (void *cls)
344{
345 struct GNUNET_UdpSocketInfo *sock_info = cls;
348 struct GNUNET_BurstMessage bm;
349 struct sockaddr *in;
350 socklen_t in_len;
351 char dgram[sizeof (struct GNUNET_BurstMessage)];
352 char *address;
353 struct sockaddr *bind_in;
354 socklen_t bind_in_len;
355 char *bind_address;
356 struct GNUNET_TIME_Relative again = GNUNET_TIME_relative_multiply (sock_info->
357 rtt,
358 4);
359
360 read_send_task = NULL;
361 GNUNET_memcpy (si, sock_info, sizeof (struct GNUNET_UdpSocketInfo));
362 if (sock_info->std_port == udp_port)
363 udp_port++;
364 if (512 < nr_open_sockets)
365 {
367 "Trying again in %s",
370 &read_send,
371 sock_info);
372 }
373
375 "%s:%u",
376 sock_info->address,
377 udp_port);
379 "3 sock %p addr %s addr %s %u\n",
380 sock_info,
381 sock_info->address,
382 address,
384 in = udp_address_to_sockaddr (address, &in_len);
385 if (NULL == in)
386 {
388 "Failed to setup UDP socket address with path `%s'\n",
389 address);
390 GNUNET_assert (0);
391 }
393 address = NULL;
394 GNUNET_asprintf (&bind_address,
395 "%s:%u",
396 sock_info->bind_address,
397 udp_port);
399 "4 sock addr %s addr %s\n",
400 sock_info->bind_address,
401 bind_address);
402 bind_in = udp_address_to_sockaddr (bind_address, &bind_in_len);
403 if (NULL == bind_in)
404 {
406 "Failed to setup UDP socket bind address with path `%s'\n",
407 bind_address);
408 GNUNET_assert (0);
409 }
410 GNUNET_free (bind_address);
411 bind_address = NULL;
412 udp_sock =
413 GNUNET_NETWORK_socket_create (bind_in->sa_family,
414 SOCK_DGRAM,
415 IPPROTO_UDP);
416 if (NULL == udp_sock)
417 {
420 "Failed to create socket for %s family %d\n",
421 GNUNET_a2s (bind_in,
422 bind_in_len),
423 in->sa_family);
424 GNUNET_free (bind_in);
425 if (EMFILE == errno)
426 {
428 "Trying again in %s, because of EMFILE\n",
431 &read_send,
432 sock_info);
433 GNUNET_free (si);
434 GNUNET_free (in);
435 GNUNET_free (bind_in);
436 return;
437 }
438 GNUNET_free (sock_info);
439 goto next_port;
440 }
441 if (GNUNET_OK !=
443 bind_in,
444 bind_in_len))
445 {
448 "Failed to bind socket for %s family %d sock %p\n",
449 GNUNET_a2s (bind_in,
450 bind_in_len),
451 bind_in->sa_family,
452 udp_sock);
454 udp_sock = NULL;
455 GNUNET_free (sock_info);
456 goto next_port;
457 }
459 bm.local_port = udp_port;
460 sock_info->udp_sock = udp_sock;
461 sock_info->port = udp_port;
464 udp_sock,
465 &sock_read,
466 sock_info);
468 "Timeout in %s\n",
470 ;
473 sock_info);
474
476
477 memcpy (dgram, &bm, sizeof(bm));
479 dgram,
480 sizeof(dgram),
481 in,
482 in_len))
483 {
485 "Sending burst to %s family %d failed sock %p\n",
486 GNUNET_a2s (in,
487 in_len),
488 in->sa_family,
489 udp_sock);
490 timeout_task_cb (sock_info);
491 }
492
493next_port:
494 GNUNET_free (si);
495 GNUNET_free (in);
496 GNUNET_free (bind_in);
497
498 if (65535 == udp_port)
499 return;
500 udp_port++;
501
503 &read_send,
504 si);
505}
506
507
511{
512 struct GNUNET_BurstMessage bm = {0};
514 char dgram[sizeof (struct GNUNET_BurstMessage)];
515 char *address;
516 struct sockaddr *in;
517 socklen_t in_len;
518
520 "%s:%u",
521 sock_info->address,
522 sock_info->std_port);
524 "2 sock addr %s addr %s rtt %s %u\n",
525 sock_info->address,
526 address,
527 GNUNET_TIME_relative2s (sock_info->rtt,
528 false),
529 sock_info->std_port);
530 bm.local_port = sock_info->std_port;
531 in = udp_address_to_sockaddr (address, &in_len);
532 memcpy (dgram, &bm, sizeof(bm));
533 if (-1 == GNUNET_NETWORK_socket_sendto (sock_info->udp_sock,
534 dgram,
535 sizeof(dgram),
536 in,
537 in_len))
538 {
540 "Sending burst to %s family %d failed sock %p\n",
541 GNUNET_a2s (in,
542 in_len),
543 in->sa_family,
544 sock_info->udp_sock);
545 }
546
547 nr_open_sockets = 0;
548 udp_port = 1024;
549 sock_info->has_port = GNUNET_NO;
550 sock_info->nus = nus;
551
552 GNUNET_memcpy (si, sock_info, sizeof (struct GNUNET_UdpSocketInfo));
553
555 &read_send,
556 si);
557 GNUNET_free (in);
559 return read_send_task;
560}
561
562
563void
565{
566 struct GNUNET_UdpSocketInfo *sock_info;
567 struct GNUNET_UdpSocketInfo *pos;
568
570 "stopping burst\n");
571 if (NULL != read_send_task)
572 {
574 read_send_task = NULL;
575 }
576 pos = sock_infos_head;
577 while (NULL != pos)
578 {
579 sock_info = pos;
580 pos = sock_info->next;
583 sock_info);
584 if (NULL != sock_info->read_task)
586 if (NULL != sock_info->timeout_task)
588 if (do_not_touch != sock_info->udp_sock)
589 {
591 if (NULL != sock_info->address)
592 GNUNET_free (sock_info->address);
594 "freeing sock_info %p\n",
595 sock_info);
596 GNUNET_free (sock_info);
597 }
598 }
599}
static int start
Set if we are to start default services (including ARM).
Definition: gnunet-arm.c:38
static uint16_t port
Port number.
Definition: gnunet-bcd.c:147
static struct GNUNET_NETWORK_Handle * udp_sock
Our socket.
static char * address
GNS address for this phone.
static struct in_addr dummy
Target "dummy" address of the packet we pretend to respond to.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
#define GNUNET_log(kind,...)
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
const char * GNUNET_a2s(const struct sockaddr *addr, socklen_t addrlen)
Convert a "struct sockaddr*" (IPv4 or IPv6 address) to a string (for printing debug messages).
#define GNUNET_log_strerror(level, cmd)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
#define GNUNET_memdup(buf, size)
Allocate and initialize a block of memory.
void GNUNET_is_burst_ready(struct GNUNET_TIME_Relative rtt_average, struct GNUNET_BurstSync *burst_sync, GNUNET_SCHEDULER_TaskCallback task, struct GNUNET_StartBurstCls *task_cls)
Checks if we are ready and starts burst when we and the other peer is ready.
Definition: nat.c:89
struct GNUNET_SCHEDULER_Task * GNUNET_get_udp_socket(struct GNUNET_UdpSocketInfo *sock_info, GNUNET_NotifyUdpSocket nus)
Method to get a UDP socket for a peer that is natted.
Definition: nat.c:509
struct GNUNET_BurstSync * GNUNET_get_burst_sync_msg(struct GNUNET_TIME_Relative rtt_average, enum GNUNET_GenericReturnValue sync_ready)
Create GNUNET_BurstSync message.
Definition: nat.c:66
void GNUNET_stop_burst(struct GNUNET_NETWORK_Handle *do_not_touch)
Method to stop all sockets we established to the other peer.
Definition: nat.c:564
void(* GNUNET_NotifyUdpSocket)(struct GNUNET_UdpSocketInfo *sock_info)
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_close(struct GNUNET_NETWORK_Handle *desc)
Close a socket.
Definition: network.c:508
ssize_t GNUNET_NETWORK_socket_recvfrom(const struct GNUNET_NETWORK_Handle *desc, void *buffer, size_t length, struct sockaddr *src_addr, socklen_t *addrlen)
Read data from a socket (always non-blocking).
Definition: network.c:688
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_create(int domain, int type, int protocol)
Create a new socket.
Definition: network.c:833
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_bind(struct GNUNET_NETWORK_Handle *desc, const struct sockaddr *address, socklen_t address_len)
Bind a socket to a particular address.
Definition: network.c:439
ssize_t GNUNET_NETWORK_socket_sendto(const struct GNUNET_NETWORK_Handle *desc, const void *message, size_t length, const struct sockaddr *dest_addr, socklen_t dest_len)
Send data to a particular destination (always non-blocking).
Definition: network.c:772
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_read_net(struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *rfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition: scheduler.c:1510
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:979
void(* GNUNET_SCHEDULER_TaskCallback)(void *cls)
Signature of the main function of a task.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition: scheduler.c:1276
const char * GNUNET_TIME_relative2s(struct GNUNET_TIME_Relative delta, bool do_round)
Give relative time in human-readable fancy format.
Definition: time.c:264
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
struct GNUNET_TIME_Relative GNUNET_TIME_relative_ntoh(struct GNUNET_TIME_RelativeNBO a)
Convert relative time from network byte order.
Definition: time.c:630
struct GNUNET_TIME_Relative GNUNET_TIME_relative_saturating_multiply(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Saturating multiply relative time by a given factor.
Definition: time.c:533
const char * GNUNET_STRINGS_relative_time_to_string(struct GNUNET_TIME_Relative delta, int do_round)
Give relative time in human-readable fancy format.
Definition: strings.c:570
struct GNUNET_TIME_Relative GNUNET_TIME_relative_subtract(struct GNUNET_TIME_Relative a1, struct GNUNET_TIME_Relative a2)
Subtract relative timestamp from the other.
Definition: time.c:605
struct GNUNET_TIME_Relative GNUNET_TIME_relative_multiply(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Multiply relative time by a given factor.
Definition: time.c:486
struct GNUNET_TIME_RelativeNBO GNUNET_TIME_relative_hton(struct GNUNET_TIME_Relative a)
Convert relative time to network byte order.
Definition: time.c:620
static void timeout_task_cb(void *cls)
Definition: nat.c:318
#define RTT_DIFF
Difference of the average RTT for the DistanceVector calculate by us and the target we are willing to...
Definition: nat.c:43
static void read_send(void *cls)
Definition: nat.c:343
static void sock_read(void *cls)
Socket read task.
Definition: nat.c:151
#define SEND_DELAY
Definition: nat.c:33
static struct GNUNET_SCHEDULER_Task * read_send_task
Definition: nat.c:50
#define TIMEOUT_DELAY
Definition: nat.c:36
static struct sockaddr * udp_address_to_sockaddr(const char *bindto, socklen_t *sock_len)
Convert UDP bind specification to a struct sockaddr *
Definition: nat.c:226
static struct GNUNET_UdpSocketInfo * sock_infos_tail
Definition: nat.c:48
static struct GNUNET_UdpSocketInfo * sock_infos_head
Definition: nat.c:46
unsigned int nr_open_sockets
Maximum of open sockets.
Definition: nat.c:57
unsigned int udp_port
Definition: nat.c:52
Message send during burst mode.
unsigned int local_port
The local port the message was send from.
Wrapper struct with the average RTT of message to some peer and if this peer und us is ready to sync.
enum GNUNET_GenericReturnValue sync_ready
Is this peer already ready to sync.
struct GNUNET_TIME_RelativeNBO rtt_average
The average RTT for the peer to communicate with.
handle to a socket
Definition: network.c:53
Entry in list of pending tasks.
Definition: scheduler.c:135
Struct wrapping information we use for starting the burst.
struct GNUNET_TIME_Relative delay
The delay - calculate from the RTT and which peer was ready to sync first, after we will start the bu...
unsigned int sync_ready
We are ready to start the burst.
Time for relative time used by GNUnet, in microseconds.
uint64_t rel_value_us
The actual value.
Struct with the socket we like to use to send messages to another peer.
const char * bind_address
Our address without port.
enum GNUNET_GenericReturnValue has_port
Flag indicating, if the address is without port information.
struct GNUNET_TIME_Relative rtt
The actual RTT between the peers.
GNUNET_NotifyUdpSocket nus
The notify function to call if burst mode was successful.
char * address
The address of the other peer without port.
unsigned int port
The port we are bound to.
struct GNUNET_UdpSocketInfo * next
This is a linked list.
unsigned int std_port
Default local port we are bound to.
struct sockaddr * actual_address
The address of the other peer we received a burst message from.
struct GNUNET_SCHEDULER_Task * timeout_task
Timeout task for this socket.
struct GNUNET_NETWORK_Handle * udp_sock
struct GNUNET_SCHEDULER_Task * read_task
The read task for retrieving a burst message for this socket.