aboutsummaryrefslogtreecommitdiff
path: root/src/plugin/dhtu/plugin_dhtu_ip.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugin/dhtu/plugin_dhtu_ip.c')
-rw-r--r--src/plugin/dhtu/plugin_dhtu_ip.c1171
1 files changed, 1171 insertions, 0 deletions
diff --git a/src/plugin/dhtu/plugin_dhtu_ip.c b/src/plugin/dhtu/plugin_dhtu_ip.c
new file mode 100644
index 000000000..06d0f0f60
--- /dev/null
+++ b/src/plugin/dhtu/plugin_dhtu_ip.c
@@ -0,0 +1,1171 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021, 2022 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
21/**
22 * @author Christian Grothoff
23 *
24 * @file plugin_dhtu_ip.c
25 * @brief plain IP based DHT network underlay
26 */
27#include "platform.h"
28#include "gnunet_dhtu_plugin.h"
29
30/**
31 * How frequently should we re-scan our local interfaces for IPs?
32 */
33#define SCAN_FREQ GNUNET_TIME_UNIT_MINUTES
34
35/**
36 * Maximum number of concurrently active destinations to support.
37 */
38#define MAX_DESTS 256
39
40
41/**
42 * Opaque handle that the underlay offers for our address to be used when
43 * sending messages to another peer.
44 */
45struct GNUNET_DHTU_Source
46{
47
48 /**
49 * Kept in a DLL.
50 */
51 struct GNUNET_DHTU_Source *next;
52
53 /**
54 * Kept in a DLL.
55 */
56 struct GNUNET_DHTU_Source *prev;
57
58 /**
59 * Application context for this source.
60 */
61 void *app_ctx;
62
63 /**
64 * Address in URL form ("ip+udp://$PID/$IP:$PORT")
65 */
66 char *address;
67
68 /**
69 * My actual address.
70 */
71 struct sockaddr_storage addr;
72
73 /**
74 * Number of bytes in @a addr.
75 */
76 socklen_t addrlen;
77
78 /**
79 * Last generation this address was observed.
80 */
81 unsigned int scan_generation;
82
83};
84
85
86/**
87 * Opaque handle that the underlay offers for the target peer when sending
88 * messages to another peer.
89 */
90struct GNUNET_DHTU_Target
91{
92
93 /**
94 * Kept in a DLL.
95 */
96 struct GNUNET_DHTU_Target *next;
97
98 /**
99 * Kept in a DLL.
100 */
101 struct GNUNET_DHTU_Target *prev;
102
103 /**
104 * Application context for this target.
105 */
106 void *app_ctx;
107
108 /**
109 * Head of preferences expressed for this target.
110 */
111 struct GNUNET_DHTU_PreferenceHandle *ph_head;
112
113 /**
114 * Tail of preferences expressed for this target.
115 */
116 struct GNUNET_DHTU_PreferenceHandle *ph_tail;
117
118 /**
119 * Peer's identity.
120 */
121 struct GNUNET_PeerIdentity pid;
122
123 /**
124 * Target IP address.
125 */
126 struct sockaddr_storage addr;
127
128 /**
129 * Number of bytes in @a addr.
130 */
131 socklen_t addrlen;
132
133 /**
134 * Preference counter, length of the @a ph_head DLL.
135 */
136 unsigned int ph_count;
137
138};
139
140/**
141 * Opaque handle expressing a preference of the DHT to
142 * keep a particular target connected.
143 */
144struct GNUNET_DHTU_PreferenceHandle
145{
146 /**
147 * Kept in a DLL.
148 */
149 struct GNUNET_DHTU_PreferenceHandle *next;
150
151 /**
152 * Kept in a DLL.
153 */
154 struct GNUNET_DHTU_PreferenceHandle *prev;
155
156 /**
157 * Target a preference was expressed for.
158 */
159 struct GNUNET_DHTU_Target *target;
160};
161
162
163/**
164 * Closure for all plugin functions.
165 */
166struct Plugin
167{
168 /**
169 * Callbacks into the DHT.
170 */
171 struct GNUNET_DHTU_PluginEnvironment *env;
172
173 /**
174 * Head of sources where we receive traffic.
175 */
176 struct GNUNET_DHTU_Source *src_head;
177
178 /**
179 * Tail of sources where we receive traffic.
180 */
181 struct GNUNET_DHTU_Source *src_tail;
182
183 /**
184 * Head of destinations that are active. Sorted by
185 * last use, with latest used at the head.
186 */
187 struct GNUNET_DHTU_Target *dst_head;
188
189 /**
190 * Tail of destinations that are active.
191 */
192 struct GNUNET_DHTU_Target *dst_tail;
193
194 /**
195 * Map from hashes of sockaddrs to targets.
196 */
197 struct GNUNET_CONTAINER_MultiHashMap *dsts;
198
199 /**
200 * Task that scans for IP address changes.
201 */
202 struct GNUNET_SCHEDULER_Task *scan_task;
203
204 /**
205 * Task that reads incoming UDP packets.
206 */
207 struct GNUNET_SCHEDULER_Task *read_task;
208
209 /**
210 * Port we bind to.
211 */
212 char *port;
213
214 /**
215 * My UDP socket.
216 */
217 struct GNUNET_NETWORK_Handle *sock;
218
219 /**
220 * My identity.
221 */
222 struct GNUNET_PeerIdentity my_id;
223
224 /**
225 * How often have we scanned for IPs?
226 */
227 unsigned int scan_generation;
228
229 /**
230 * Port as a 16-bit value.
231 */
232 uint16_t port16;
233};
234
235
236/**
237 * Create a target to which we may send traffic.
238 *
239 * @param plugin our plugin
240 * @param pid presumed identity of the target
241 * @param addr target address
242 * @param addrlen number of bytes in @a addr
243 * @return new target object
244 */
245static struct GNUNET_DHTU_Target *
246create_target (struct Plugin *plugin,
247 const struct GNUNET_PeerIdentity *pid,
248 const struct sockaddr *addr,
249 socklen_t addrlen)
250{
251 struct GNUNET_DHTU_Target *dst;
252
253 if (MAX_DESTS <=
254 GNUNET_CONTAINER_multihashmap_size (plugin->dsts))
255 {
256 struct GNUNET_HashCode key;
257
258 dst = NULL;
259 for (struct GNUNET_DHTU_Target *pos = plugin->dst_head;
260 NULL != pos;
261 pos = pos->next)
262 {
263 /* >= here assures we remove oldest entries first */
264 if ( (NULL == dst) ||
265 (dst->ph_count >= pos->ph_count) )
266 dst = pos;
267 }
268 GNUNET_assert (NULL != dst);
269 plugin->env->disconnect_cb (dst->app_ctx);
270 GNUNET_CRYPTO_hash (&dst->addr,
271 dst->addrlen,
272 &key);
273 GNUNET_assert (GNUNET_YES ==
274 GNUNET_CONTAINER_multihashmap_remove (plugin->dsts,
275 &key,
276 dst));
277 GNUNET_CONTAINER_DLL_remove (plugin->dst_head,
278 plugin->dst_tail,
279 dst);
280 GNUNET_assert (NULL == dst->ph_head);
281 GNUNET_free (dst);
282 }
283 dst = GNUNET_new (struct GNUNET_DHTU_Target);
284 dst->addrlen = addrlen;
285 dst->pid = *pid;
286 memcpy (&dst->addr,
287 addr,
288 addrlen);
289 GNUNET_CONTAINER_DLL_insert (plugin->dst_head,
290 plugin->dst_tail,
291 dst);
292 plugin->env->connect_cb (plugin->env->cls,
293 dst,
294 &dst->pid,
295 &dst->app_ctx);
296 return dst;
297}
298
299
300/**
301 * Find target matching @a addr. If none exists,
302 * create one!
303 *
304 * @param plugin the plugin handle
305 * @param pid presumed identity of the target
306 * @param addr socket address to find
307 * @param addrlen number of bytes in @a addr
308 * @return matching target object
309 */
310static struct GNUNET_DHTU_Target *
311find_target (struct Plugin *plugin,
312 const struct GNUNET_PeerIdentity *pid,
313 const void *addr,
314 size_t addrlen)
315{
316 struct GNUNET_HashCode key;
317 struct GNUNET_DHTU_Target *dst;
318
319 GNUNET_CRYPTO_hash (addr,
320 addrlen,
321 &key);
322 dst = GNUNET_CONTAINER_multihashmap_get (plugin->dsts,
323 &key);
324 if (NULL == dst)
325 {
326 dst = create_target (plugin,
327 pid,
328 (const struct sockaddr *) addr,
329 addrlen);
330 GNUNET_assert (GNUNET_YES ==
331 GNUNET_CONTAINER_multihashmap_put (
332 plugin->dsts,
333 &key,
334 dst,
335 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
336 }
337 else
338 {
339 /* move to head of DLL */
340 GNUNET_CONTAINER_DLL_remove (plugin->dst_head,
341 plugin->dst_tail,
342 dst);
343 GNUNET_CONTAINER_DLL_insert (plugin->dst_head,
344 plugin->dst_tail,
345 dst);
346
347 }
348 return dst;
349}
350
351
352/**
353 * Request creation of a session with a peer at the given @a address.
354 *
355 * @param cls closure (internal context for the plugin)
356 * @param pid identity of the target peer
357 * @param address target address to connect to
358 */
359static void
360ip_try_connect (void *cls,
361 const struct GNUNET_PeerIdentity *pid,
362 const char *address)
363{
364 struct Plugin *plugin = cls;
365 char *colon;
366 const char *port;
367 char *addr;
368 struct addrinfo hints = {
369 .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV
370 };
371 struct addrinfo *result = NULL;
372
373 if (0 !=
374 strncmp (address,
375 "ip+",
376 strlen ("ip+")))
377 return;
378 address += strlen ("ip+");
379 if (0 !=
380 strncmp (address,
381 "udp://",
382 strlen ("udp://")))
383 return;
384 address += strlen ("udp://");
385 addr = GNUNET_strdup (address);
386 colon = strchr (addr, ':');
387 if (NULL == colon)
388 {
389 port = plugin->port;
390 }
391 else
392 {
393 *colon = '\0';
394 port = colon + 1;
395 }
396 if (0 !=
397 getaddrinfo (addr,
398 port,
399 &hints,
400 &result))
401 {
402 GNUNET_break (0);
403 GNUNET_free (addr);
404 return;
405 }
406 GNUNET_free (addr);
407 (void) find_target (plugin,
408 pid,
409 result->ai_addr,
410 result->ai_addrlen);
411 freeaddrinfo (result);
412}
413
414
415/**
416 * Request underlay to keep the connection to @a target alive if possible.
417 * Hold may be called multiple times to express a strong preference to
418 * keep a connection, say because a @a target is in multiple tables.
419 *
420 * @param cls closure
421 * @param target connection to keep alive
422 */
423static struct GNUNET_DHTU_PreferenceHandle *
424ip_hold (void *cls,
425 struct GNUNET_DHTU_Target *target)
426{
427 struct GNUNET_DHTU_PreferenceHandle *ph;
428
429 ph = GNUNET_new (struct GNUNET_DHTU_PreferenceHandle);
430 ph->target = target;
431 GNUNET_CONTAINER_DLL_insert (target->ph_head,
432 target->ph_tail,
433 ph);
434 target->ph_count++;
435 return ph;
436}
437
438
439/**
440 * Do no long request underlay to keep the connection alive.
441 *
442 * @param cls closure
443 * @param target connection to keep alive
444 */
445static void
446ip_drop (struct GNUNET_DHTU_PreferenceHandle *ph)
447{
448 struct GNUNET_DHTU_Target *target = ph->target;
449
450 GNUNET_CONTAINER_DLL_remove (target->ph_head,
451 target->ph_tail,
452 ph);
453 target->ph_count--;
454 GNUNET_free (ph);
455}
456
457
458/**
459 * Send message to some other participant over the network. Note that
460 * sending is not guaranteeing that the other peer actually received the
461 * message. For any given @a target, the DHT must wait for the @a
462 * finished_cb to be called before calling send() again.
463 *
464 * @param cls closure (internal context for the plugin)
465 * @param target receiver identification
466 * @param msg message
467 * @param msg_size number of bytes in @a msg
468 * @param finished_cb function called once transmission is done
469 * (not called if @a target disconnects, then only the
470 * disconnect_cb is called).
471 * @param finished_cb_cls closure for @a finished_cb
472 */
473static void
474ip_send (void *cls,
475 struct GNUNET_DHTU_Target *target,
476 const void *msg,
477 size_t msg_size,
478 GNUNET_SCHEDULER_TaskCallback finished_cb,
479 void *finished_cb_cls)
480{
481 struct Plugin *plugin = cls;
482 char buf[sizeof (plugin->my_id) + msg_size];
483
484 memcpy (buf,
485 &plugin->my_id,
486 sizeof (plugin->my_id));
487 memcpy (&buf[sizeof (plugin->my_id)],
488 msg,
489 msg_size);
490 GNUNET_NETWORK_socket_sendto (plugin->sock,
491 buf,
492 sizeof (buf),
493 (const struct sockaddr *) &target->addr,
494 target->addrlen);
495 finished_cb (finished_cb_cls);
496}
497
498
499/**
500 * Create a new source on which we may be receiving traffic.
501 *
502 * @param plugin our plugin
503 * @param addr our address
504 * @param addrlen number of bytes in @a addr
505 * @return new source object
506 */
507static struct GNUNET_DHTU_Source *
508create_source (struct Plugin *plugin,
509 const struct sockaddr *addr,
510 socklen_t addrlen)
511{
512 struct GNUNET_DHTU_Source *src;
513
514 src = GNUNET_new (struct GNUNET_DHTU_Source);
515 src->addrlen = addrlen;
516 memcpy (&src->addr,
517 addr,
518 addrlen);
519 src->scan_generation = plugin->scan_generation;
520 switch (addr->sa_family)
521 {
522 case AF_INET:
523 {
524 const struct sockaddr_in *s4 = (const struct sockaddr_in *) addr;
525 char buf[INET_ADDRSTRLEN];
526
527 GNUNET_assert (sizeof (struct sockaddr_in) == addrlen);
528 GNUNET_asprintf (&src->address,
529 "ip+udp://%s:%u",
530 inet_ntop (AF_INET,
531 &s4->sin_addr,
532 buf,
533 sizeof (buf)),
534 ntohs (s4->sin_port));
535 }
536 break;
537 case AF_INET6:
538 {
539 const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) addr;
540 char buf[INET6_ADDRSTRLEN];
541
542 GNUNET_assert (sizeof (struct sockaddr_in6) == addrlen);
543 GNUNET_asprintf (&src->address,
544 "ip+udp://[%s]:%u",
545 inet_ntop (AF_INET6,
546 &s6->sin6_addr,
547 buf,
548 sizeof (buf)),
549 ntohs (s6->sin6_port));
550 }
551 break;
552 default:
553 GNUNET_break (0);
554 GNUNET_free (src);
555 return NULL;
556 }
557 GNUNET_CONTAINER_DLL_insert (plugin->src_head,
558 plugin->src_tail,
559 src);
560 plugin->env->address_add_cb (plugin->env->cls,
561 src->address,
562 src,
563 &src->app_ctx);
564 return src;
565}
566
567
568/**
569 * Compare two addresses excluding the ports for equality. Only compares IP
570 * address. Must only be called on AF_INET or AF_INET6 addresses.
571 *
572 * @param a1 address to compare
573 * @param a2 address to compare
574 * @param alen number of bytes in @a a1 and @a a2
575 * @return 0 if @a a1 == @a a2.
576 */
577static int
578addrcmp_np (const struct sockaddr *a1,
579 const struct sockaddr *a2,
580 size_t alen)
581{
582 GNUNET_assert (a1->sa_family == a2->sa_family);
583 switch (a1->sa_family)
584 {
585 case AF_INET:
586 GNUNET_assert (sizeof (struct sockaddr_in) == alen);
587 {
588 const struct sockaddr_in *s1 = (const struct sockaddr_in *) a1;
589 const struct sockaddr_in *s2 = (const struct sockaddr_in *) a2;
590
591 if (s1->sin_addr.s_addr != s2->sin_addr.s_addr)
592 return 1;
593 break;
594 }
595 case AF_INET6:
596 GNUNET_assert (sizeof (struct sockaddr_in6) == alen);
597 {
598 const struct sockaddr_in6 *s1 = (const struct sockaddr_in6 *) a1;
599 const struct sockaddr_in6 *s2 = (const struct sockaddr_in6 *) a2;
600
601 if (0 != GNUNET_memcmp (&s1->sin6_addr,
602 &s2->sin6_addr))
603 return 1;
604 break;
605 }
606 default:
607 GNUNET_assert (0);
608 }
609 return 0;
610}
611
612
613/**
614 * Compare two addresses for equality. Only
615 * compares IP address and port. Must only be
616 * called on AF_INET or AF_INET6 addresses.
617 *
618 * @param a1 address to compare
619 * @param a2 address to compare
620 * @param alen number of bytes in @a a1 and @a a2
621 * @return 0 if @a a1 == @a a2.
622 */
623static int
624addrcmp (const struct sockaddr *a1,
625 const struct sockaddr *a2,
626 size_t alen)
627{
628 GNUNET_assert (a1->sa_family == a2->sa_family);
629 switch (a1->sa_family)
630 {
631 case AF_INET:
632 GNUNET_assert (sizeof (struct sockaddr_in) == alen);
633 {
634 const struct sockaddr_in *s1 = (const struct sockaddr_in *) a1;
635 const struct sockaddr_in *s2 = (const struct sockaddr_in *) a2;
636
637 if (s1->sin_port != s2->sin_port)
638 return 1;
639 if (s1->sin_addr.s_addr != s2->sin_addr.s_addr)
640 return 1;
641 break;
642 }
643 case AF_INET6:
644 GNUNET_assert (sizeof (struct sockaddr_in6) == alen);
645 {
646 const struct sockaddr_in6 *s1 = (const struct sockaddr_in6 *) a1;
647 const struct sockaddr_in6 *s2 = (const struct sockaddr_in6 *) a2;
648
649 if (s1->sin6_port != s2->sin6_port)
650 return 1;
651 if (0 != GNUNET_memcmp (&s1->sin6_addr,
652 &s2->sin6_addr))
653 return 1;
654 break;
655 }
656 default:
657 GNUNET_assert (0);
658 }
659 return 0;
660}
661
662
663/**
664 * Callback function invoked for each interface found.
665 *
666 * @param cls closure
667 * @param name name of the interface (can be NULL for unknown)
668 * @param isDefault is this presumably the default interface
669 * @param addr address of this interface (can be NULL for unknown or unassigned)
670 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
671 * @param netmask the network mask (can be NULL for unknown or unassigned)
672 * @param addrlen length of the address
673 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
674 */
675static enum GNUNET_GenericReturnValue
676process_ifcs (void *cls,
677 const char *name,
678 int isDefault,
679 const struct sockaddr *addr,
680 const struct sockaddr *broadcast_addr,
681 const struct sockaddr *netmask,
682 socklen_t addrlen)
683{
684 struct Plugin *plugin = cls;
685 struct GNUNET_DHTU_Source *src;
686
687 for (src = plugin->src_head;
688 NULL != src;
689 src = src->next)
690 {
691 if ( (addrlen == src->addrlen) &&
692 (0 == addrcmp_np (addr,
693 (const struct sockaddr *) &src->addr,
694 addrlen)) )
695 {
696 src->scan_generation = plugin->scan_generation;
697 return GNUNET_OK;
698 }
699 }
700 switch (addr->sa_family)
701 {
702 case AF_INET:
703 {
704 struct sockaddr_in v4;
705
706 GNUNET_assert (sizeof(v4) == addrlen);
707 memcpy (&v4,
708 addr,
709 addrlen);
710 v4.sin_port = htons (plugin->port16);
711 (void) create_source (plugin,
712 (const struct sockaddr *) &v4,
713 sizeof (v4));
714 break;
715 }
716 case AF_INET6:
717 {
718 struct sockaddr_in6 v6;
719
720 GNUNET_assert (sizeof(v6) == addrlen);
721 memcpy (&v6,
722 addr,
723 addrlen);
724 v6.sin6_port = htons (plugin->port16);
725 (void) create_source (plugin,
726 (const struct sockaddr *) &v6,
727 sizeof (v6));
728 break;
729 }
730 }
731 return GNUNET_OK;
732}
733
734
735/**
736 * Scan network interfaces for IP address changes.
737 *
738 * @param cls a `struct Plugin`
739 */
740static void
741scan (void *cls)
742{
743 struct Plugin *plugin = cls;
744 struct GNUNET_DHTU_Source *next;
745
746 plugin->scan_generation++;
747 GNUNET_OS_network_interfaces_list (&process_ifcs,
748 plugin);
749 for (struct GNUNET_DHTU_Source *src = plugin->src_head;
750 NULL != src;
751 src = next)
752 {
753 next = src->next;
754 if (src->scan_generation >= plugin->scan_generation)
755 continue;
756 GNUNET_CONTAINER_DLL_remove (plugin->src_head,
757 plugin->src_tail,
758 src);
759 plugin->env->address_del_cb (src->app_ctx);
760 GNUNET_free (src->address);
761 GNUNET_free (src);
762 }
763 plugin->scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
764 &scan,
765 plugin);
766}
767
768
769/**
770 * Find our source matching @a addr. If none exists,
771 * create one!
772 *
773 * @param plugin the plugin handle
774 * @param addr socket address to find
775 * @param addrlen number of bytes in @a addr
776 * @return matching source object
777 */
778static struct GNUNET_DHTU_Source *
779find_source (struct Plugin *plugin,
780 const void *addr,
781 size_t addrlen)
782{
783 for (struct GNUNET_DHTU_Source *src = plugin->src_head;
784 NULL != src;
785 src = src->next)
786 {
787 if ( (addrlen == src->addrlen) &&
788 (0 == addrcmp (addr,
789 (const struct sockaddr *) &src->addr,
790 addrlen)) )
791 return src;
792 }
793
794 return create_source (plugin,
795 (const struct sockaddr *) addr,
796 addrlen);
797}
798
799
800/**
801 * UDP socket is ready to receive. Read.
802 *
803 * @param cls our `struct Plugin *`
804 */
805static void
806read_cb (void *cls)
807{
808 struct Plugin *plugin = cls;
809 ssize_t ret;
810 const struct GNUNET_PeerIdentity *pid;
811 char buf[65536] GNUNET_ALIGN;
812 struct sockaddr_storage sa;
813 struct iovec iov = {
814 .iov_base = buf,
815 .iov_len = sizeof (buf)
816 };
817 char ctl[128];
818 struct msghdr mh = {
819 .msg_name = &sa,
820 .msg_namelen = sizeof (sa),
821 .msg_iov = &iov,
822 .msg_iovlen = 1,
823 .msg_control = ctl,
824 .msg_controllen = sizeof (ctl)
825 };
826 struct GNUNET_DHTU_Target *dst = NULL;
827 struct GNUNET_DHTU_Source *src = NULL;
828
829 ret = recvmsg (GNUNET_NETWORK_get_fd (plugin->sock),
830 &mh,
831 MSG_DONTWAIT);
832 plugin->read_task = GNUNET_SCHEDULER_add_read_net (
833 GNUNET_TIME_UNIT_FOREVER_REL,
834 plugin->sock,
835 &read_cb,
836 plugin);
837 if (ret < 0)
838 return; /* read failure, hopefully EAGAIN */
839 if (ret < sizeof (*pid))
840 {
841 GNUNET_break_op (0);
842 return;
843 }
844 /* find IP where we received message */
845 for (struct cmsghdr *cmsg = CMSG_FIRSTHDR (&mh);
846 NULL != cmsg;
847 cmsg = CMSG_NXTHDR (&mh,
848 cmsg))
849 {
850 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
851 "Got CMSG level %u (%d/%d), type %u (%d/%d)\n",
852 cmsg->cmsg_level,
853 (cmsg->cmsg_level == IPPROTO_IP),
854 (cmsg->cmsg_level == IPPROTO_IPV6),
855 cmsg->cmsg_type,
856 (cmsg->cmsg_type == IP_PKTINFO),
857 (cmsg->cmsg_type == IPV6_PKTINFO));
858 if ( (cmsg->cmsg_level == IPPROTO_IP) &&
859 (cmsg->cmsg_type == IP_PKTINFO) )
860 {
861 if (CMSG_LEN (sizeof (struct in_pktinfo)) ==
862 cmsg->cmsg_len)
863 {
864 struct in_pktinfo pi;
865
866 memcpy (&pi,
867 CMSG_DATA (cmsg),
868 sizeof (pi));
869 {
870 struct sockaddr_in sa = {
871 .sin_family = AF_INET,
872 .sin_addr = pi.ipi_addr,
873 .sin_port = htons (plugin->port16)
874 };
875
876 src = find_source (plugin,
877 &sa,
878 sizeof (sa));
879 /* For sources we discovered by reading,
880 force the generation far into the future */
881 src->scan_generation = plugin->scan_generation + 60;
882 }
883 break;
884 }
885 else
886 GNUNET_break (0);
887 }
888 if ( (cmsg->cmsg_level == IPPROTO_IPV6) &&
889 (cmsg->cmsg_type == IPV6_PKTINFO) )
890 {
891 if (CMSG_LEN (sizeof (struct in6_pktinfo)) ==
892 cmsg->cmsg_len)
893 {
894 struct in6_pktinfo pi;
895
896 memcpy (&pi,
897 CMSG_DATA (cmsg),
898 sizeof (pi));
899 {
900 struct sockaddr_in6 sa = {
901 .sin6_family = AF_INET6,
902 .sin6_addr = pi.ipi6_addr,
903 .sin6_port = htons (plugin->port16),
904 .sin6_scope_id = pi.ipi6_ifindex
905 };
906
907 src = find_source (plugin,
908 &sa,
909 sizeof (sa));
910 /* For sources we discovered by reading,
911 force the generation far into the future */
912 src->scan_generation = plugin->scan_generation + 60;
913 break;
914 }
915 }
916 else
917 GNUNET_break (0);
918 }
919 }
920 if (NULL == src)
921 {
922 GNUNET_break (0);
923 return;
924 }
925 pid = (const struct GNUNET_PeerIdentity *) buf;
926 dst = find_target (plugin,
927 pid,
928 &sa,
929 mh.msg_namelen);
930 if (NULL == dst)
931 {
932 GNUNET_break (0);
933 return;
934 }
935 plugin->env->receive_cb (plugin->env->cls,
936 &dst->app_ctx,
937 &src->app_ctx,
938 &buf[sizeof(*pid)],
939 ret - sizeof (*pid));
940}
941
942
943/**
944 * Entry point for the plugin.
945 *
946 * @param cls closure (the `struct GNUNET_DHTU_PluginEnvironment`)
947 * @return the plugin's API
948 */
949void *
950libgnunet_plugin_dhtu_ip_init (void *cls)
951{
952 struct GNUNET_DHTU_PluginEnvironment *env = cls;
953 struct GNUNET_DHTU_PluginFunctions *api;
954 struct Plugin *plugin;
955 char *port;
956 unsigned int nport;
957 int sock;
958 int af;
959 unsigned long long nse;
960
961 if (GNUNET_OK !=
962 GNUNET_CONFIGURATION_get_value_number (env->cfg,
963 "DHTU-IP",
964 "NSE",
965 &nse))
966 {
967 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
968 "DHTU-IP",
969 "NSE");
970 return NULL;
971 }
972 if (GNUNET_OK !=
973 GNUNET_CONFIGURATION_get_value_string (env->cfg,
974 "DHTU-IP",
975 "UDP_PORT",
976 &port))
977 {
978 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
979 "DHTU-IP",
980 "UDP_PORT");
981 return NULL;
982 }
983 {
984 char dummy;
985
986 if ( (1 != sscanf (port,
987 "%u%c",
988 &nport,
989 &dummy)) ||
990 (nport > UINT16_MAX) )
991 {
992 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
993 "DHTU-IP",
994 "UDP_PORT",
995 "must be number below 65536");
996 GNUNET_free (port);
997 return NULL;
998 }
999 }
1000 plugin = GNUNET_new (struct Plugin);
1001 plugin->env = env;
1002 plugin->port = port;
1003 plugin->port16 = (uint16_t) nport;
1004 if (GNUNET_OK !=
1005 GNUNET_CRYPTO_get_peer_identity (env->cfg,
1006 &plugin->my_id))
1007 {
1008 GNUNET_free (plugin);
1009 return NULL;
1010 }
1011 af = AF_INET6;
1012 sock = socket (af,
1013 SOCK_DGRAM,
1014 IPPROTO_UDP);
1015 if (-1 == sock)
1016 {
1017 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1018 "socket");
1019 GNUNET_free (plugin->port);
1020 GNUNET_free (plugin);
1021 return NULL;
1022 }
1023 switch (af)
1024 {
1025 case AF_INET:
1026 {
1027 int on = 1;
1028
1029 if (0 !=
1030 setsockopt (sock,
1031 IPPROTO_IP,
1032 IP_PKTINFO,
1033 &on,
1034 sizeof (on)))
1035 {
1036 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1037 "setsockopt");
1038 }
1039 }
1040 {
1041 struct sockaddr_in sa = {
1042 .sin_family = AF_INET,
1043 .sin_port = htons ((uint16_t) nport)
1044 };
1045
1046 if (0 !=
1047 bind (sock,
1048 (const struct sockaddr *) &sa,
1049 sizeof (sa)))
1050 {
1051 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1052 "socket");
1053 GNUNET_break (0 ==
1054 close (sock));
1055 GNUNET_free (plugin->port);
1056 GNUNET_free (plugin);
1057 return NULL;
1058 }
1059 }
1060 break;
1061 case AF_INET6:
1062 {
1063 int on = 1;
1064
1065 if (0 !=
1066 setsockopt (sock,
1067 IPPROTO_IPV6,
1068 IPV6_RECVPKTINFO,
1069 &on,
1070 sizeof (on)))
1071 {
1072 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1073 "setsockopt");
1074 }
1075 }
1076 {
1077 struct sockaddr_in6 sa = {
1078 .sin6_family = AF_INET6,
1079 .sin6_port = htons ((uint16_t) nport)
1080 };
1081
1082 if (0 !=
1083 bind (sock,
1084 (const struct sockaddr *) &sa,
1085 sizeof (sa)))
1086 {
1087 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1088 "socket");
1089 GNUNET_break (0 ==
1090 close (sock));
1091 GNUNET_free (plugin->port);
1092 GNUNET_free (plugin);
1093 return NULL;
1094 }
1095 }
1096 break;
1097 }
1098 plugin->dsts = GNUNET_CONTAINER_multihashmap_create (128,
1099 GNUNET_NO);
1100 plugin->sock = GNUNET_NETWORK_socket_box_native (sock);
1101 plugin->read_task = GNUNET_SCHEDULER_add_read_net (
1102 GNUNET_TIME_UNIT_FOREVER_REL,
1103 plugin->sock,
1104 &read_cb,
1105 plugin);
1106 env->network_size_cb (env->cls,
1107 GNUNET_TIME_UNIT_ZERO_ABS,
1108 log (nse) / log (2),
1109 -1.0 /* stddev */);
1110 plugin->scan_task = GNUNET_SCHEDULER_add_now (&scan,
1111 plugin);
1112 api = GNUNET_new (struct GNUNET_DHTU_PluginFunctions);
1113 api->cls = plugin;
1114 api->try_connect = &ip_try_connect;
1115 api->hold = &ip_hold;
1116 api->drop = &ip_drop;
1117 api->send = &ip_send;
1118 return api;
1119}
1120
1121
1122/**
1123 * Exit point from the plugin.
1124 *
1125 * @param cls closure (our `struct Plugin`)
1126 * @return NULL
1127 */
1128void *
1129libgnunet_plugin_dhtu_ip_done (void *cls)
1130{
1131 struct GNUNET_DHTU_PluginFunctions *api = cls;
1132 struct Plugin *plugin = api->cls;
1133 struct GNUNET_DHTU_Source *src;
1134 struct GNUNET_DHTU_Target *dst;
1135
1136 while (NULL != (dst = plugin->dst_head))
1137 {
1138 plugin->env->disconnect_cb (dst->app_ctx);
1139 GNUNET_assert (NULL == dst->ph_head);
1140 GNUNET_CONTAINER_DLL_remove (plugin->dst_head,
1141 plugin->dst_tail,
1142 dst);
1143 GNUNET_free (dst);
1144 }
1145 while (NULL != (src = plugin->src_head))
1146 {
1147 plugin->env->address_del_cb (src->app_ctx);
1148 GNUNET_CONTAINER_DLL_remove (plugin->src_head,
1149 plugin->src_tail,
1150 src);
1151 GNUNET_free (src->address);
1152 GNUNET_free (src);
1153 }
1154 plugin->env->network_size_cb (plugin->env->cls,
1155 GNUNET_TIME_UNIT_FOREVER_ABS,
1156 0.0,
1157 0.0);
1158 GNUNET_CONTAINER_multihashmap_destroy (plugin->dsts);
1159 if (NULL != plugin->read_task)
1160 {
1161 GNUNET_SCHEDULER_cancel (plugin->read_task);
1162 plugin->read_task = NULL;
1163 }
1164 GNUNET_SCHEDULER_cancel (plugin->scan_task);
1165 GNUNET_break (GNUNET_OK ==
1166 GNUNET_NETWORK_socket_close (plugin->sock));
1167 GNUNET_free (plugin->port);
1168 GNUNET_free (plugin);
1169 GNUNET_free (api);
1170 return NULL;
1171}