GNUnet 0.28.1-dev.6-1-gcf4da5b7a
 
Loading...
Searching...
No Matches
gnunet-service-nat.c
Go to the documentation of this file.
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2016, 2017 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
37#include "platform.h"
38#include "gnunet_util_lib.h"
39#include "gnunet_protocols.h"
42#include "gnunet_nat_service.h"
43#include "gnunet-service-nat.h"
48#include "nat.h"
49#include <gcrypt.h>
50
51
56#define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
57
61#define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply ( \
62 GNUNET_TIME_UNIT_SECONDS, 5)
63
67#define DYNDNS_FREQUENCY GNUNET_TIME_relative_multiply ( \
68 GNUNET_TIME_UNIT_MINUTES, 7)
69
70
75{
79 struct sockaddr_storage ss;
80
87};
88
89
94{
99
104
110
115 struct sockaddr_storage addr;
116
120 int af;
121
127 int old;
128
133};
134
135
139struct ClientHandle
140{
144 struct ClientHandle *next;
145
149 struct ClientHandle *prev;
150
155
159 struct GNUNET_MQ_Handle *mq;
160
165
175
180
185
191
196
201
206
210 uint16_t ext_dns_port;
211
216
221
226 uint16_t num_caddrs;
227
231 uint8_t proto;
232};
233
234
239{
244
249
254
259 struct sockaddr_in external_addr;
260
266 struct sockaddr_storage stun_server_addr;
267
272};
273
274
279
284
288static const struct GNUNET_CONFIGURATION_Handle *cfg;
289
294
299
303static struct ClientHandle *ch_head;
304
308static struct ClientHandle *ch_tail;
309
314
319
323static struct StunExternalIP *se_head;
324
328static struct StunExternalIP *se_tail;
329
335
341
350
356static void
358{
360 lal_tail,
361 lal);
362 if (NULL != lal->hc)
363 {
365 "Lost NATed local address %s, stopping NAT server\n",
366 GNUNET_a2s ((const struct sockaddr *) &lal->addr,
367 sizeof(struct sockaddr_in)));
368
370 lal->hc = NULL;
371 }
372 GNUNET_free (lal);
373}
374
375
379static void
381{
382 struct LocalAddressList *lal;
383
384 while (NULL != (lal = lal_head))
385 free_lal (lal);
386}
387
388
397static int
398check_register (void *cls,
399 const struct GNUNET_NAT_RegisterMessage *message)
400{
401 uint16_t num_addrs = ntohs (message->num_addrs);
402 const char *off = (const char *) &message[1];
403 size_t left = ntohs (message->header.size) - sizeof(*message);
404
405 for (unsigned int i = 0; i < num_addrs; i++)
406 {
407 size_t alen;
408 const struct sockaddr *sa = (const struct sockaddr *) off;
409
410 if (sizeof(sa_family_t) > left)
411 {
412 GNUNET_break (0);
413 return GNUNET_SYSERR;
414 }
415 switch (sa->sa_family)
416 {
417 case AF_INET:
418 alen = sizeof(struct sockaddr_in);
419 break;
420
421 case AF_INET6:
422 alen = sizeof(struct sockaddr_in6);
423 break;
424
425#if AF_UNIX
426 case AF_UNIX:
427 alen = sizeof(struct sockaddr_un);
428 break;
429#endif
430 default:
431 GNUNET_break (0);
432 return GNUNET_SYSERR;
433 }
434 if (alen > left)
435 {
436 GNUNET_break (0);
437 return GNUNET_SYSERR;
438 }
439 off += alen;
440 left -= alen;
441 }
442 if (left != ntohs (message->str_len))
443 {
444 GNUNET_break (0);
445 return GNUNET_SYSERR;
446 }
447 return GNUNET_OK;
448}
449
450
459static int
460match_ipv4 (const char *network,
461 const struct in_addr *ip,
462 uint8_t bits)
463{
464 struct in_addr net;
465
466 if (0 == ip->s_addr)
467 return GNUNET_YES;
468 if (0 == bits)
469 return GNUNET_YES;
470 GNUNET_assert (1 == inet_pton (AF_INET,
471 network,
472 &net));
473 return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
474}
475
476
485static int
486match_ipv6 (const char *network,
487 const struct in6_addr *ip,
488 uint8_t bits)
489{
490 struct in6_addr net;
491 struct in6_addr mask;
492 unsigned int off;
493
494 if (0 == bits)
495 return GNUNET_YES;
496 GNUNET_assert (1 == inet_pton (AF_INET6,
497 network,
498 &net));
499 memset (&mask, 0, sizeof(mask));
500 if (0 == GNUNET_memcmp (&mask,
501 ip))
502 return GNUNET_YES;
503 off = 0;
504 while (bits > 8)
505 {
506 mask.s6_addr[off++] = 0xFF;
507 bits -= 8;
508 }
509 while (bits > 0)
510 {
511 mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
512 bits--;
513 }
514 for (unsigned j = 0; j < sizeof(struct in6_addr) / sizeof(uint32_t); j++)
515 if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
516 (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
517 return GNUNET_NO;
518 return GNUNET_YES;
519}
520
521
529static int
530is_nat_v4 (const struct in_addr *ip)
531{
532 return
533 match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
534 match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
535 match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
536 match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
537 match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
538}
539
540
548static int
549is_nat_v6 (const struct in6_addr *ip)
550{
551 return
552 match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
553 match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
554 match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
555}
556
557
573
574
588static int
589ifc_proc (void *cls,
590 const char *name,
591 int isDefault,
592 const struct sockaddr *addr,
593 const struct sockaddr *broadcast_addr,
594 const struct sockaddr *netmask,
595 socklen_t addrlen)
596{
597 struct IfcProcContext *ifc_ctx = cls;
598 struct LocalAddressList *lal;
599 size_t alen;
600 const struct in_addr *ip4;
601 const struct in6_addr *ip6;
603
604 switch (addr->sa_family)
605 {
606 case AF_INET:
607 alen = sizeof(struct sockaddr_in);
608 ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
609 if (match_ipv4 ("127.0.0.0", ip4, 8))
611 else if (is_nat_v4 (ip4))
613 else
615 break;
616
617 case AF_INET6:
618 alen = sizeof(struct sockaddr_in6);
619 ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
620 if (match_ipv6 ("::1", ip6, 128))
622 else if (is_nat_v6 (ip6))
624 else
626 if ((ip6->s6_addr[11] == 0xFF) &&
627 (ip6->s6_addr[12] == 0xFE))
628 {
629 /* contains a MAC, be extra careful! */
631 }
632 break;
633
634#if AF_UNIX
635 case AF_UNIX:
636 GNUNET_break (0);
637 return GNUNET_OK;
638#endif
639 default:
640 GNUNET_break (0);
641 return GNUNET_OK;
642 }
643 lal = GNUNET_malloc (sizeof(*lal));
644 lal->af = addr->sa_family;
645 lal->ac = ac;
646 GNUNET_memcpy (&lal->addr,
647 addr,
648 alen);
650 ifc_ctx->lal_tail,
651 lal);
652 return GNUNET_OK;
653}
654
655
666static void
668 struct ClientHandle *ch,
669 int add,
670 const void *addr,
671 size_t addr_len)
672{
673 struct GNUNET_MQ_Envelope *env;
675
677 "Notifying client about %s of IP %s\n",
678 add ? "addition" : "removal",
679 GNUNET_a2s (addr,
680 addr_len));
682 addr_len,
684 msg->add_remove = htonl (add);
685 msg->addr_class = htonl (ac);
686 GNUNET_memcpy (&msg[1],
687 addr,
688 addr_len);
690 env);
691}
692
693
702static void
704 struct ClientHandle *ch,
705 int add)
706{
707 size_t alen;
708 struct sockaddr_in v4;
709 struct sockaddr_in6 v6;
710
711 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
712 {
714 "Not notifying client as it does not care about addresses\n");
715 return;
716 }
717 switch (delta->af)
718 {
719 case AF_INET:
720 alen = sizeof(struct sockaddr_in);
721 GNUNET_memcpy (&v4,
722 &delta->addr,
723 alen);
724
725 /* Check for client notifications */
726 for (unsigned int i = 0; i < ch->num_caddrs; i++)
727 {
728 const struct sockaddr_in *c4;
729
730 if (AF_INET != ch->caddrs[i].ss.ss_family)
731 continue; /* IPv4 not relevant */
732 c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss;
734 (0 == c4->sin_addr.s_addr) &&
735 match_ipv4 ("127.0.0.1", &v4.sin_addr, 8))
736 continue; /* bound to "any", and this is loopback: nobody else
737 can reach it, so do not let it end up in a HELLO */
738 if (match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) &&
739 (0 != c4->sin_addr.s_addr) &&
740 (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)))
741 continue; /* bound to loopback, but this is not loopback */
742 if ((! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8)) &&
743 match_ipv4 ("127.0.0.1", &v4.sin_addr, 8))
744 continue; /* bound to non-loopback, but this is loopback */
745 if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
746 (0 != c4->sin_addr.s_addr) &&
747 (! is_nat_v4 (&v4.sin_addr)))
748 continue; /* based on external-IP, but this IP is not
749 from private address range. */
750 if ((0 != GNUNET_memcmp (&v4.sin_addr,
751 &c4->sin_addr)) &&
752 (0 != c4->sin_addr.s_addr) &&
753 (! is_nat_v4 (&c4->sin_addr)))
754 continue; /* this IP is not from private address range,
755 and IP does not match. */
756
757 /* OK, IP seems relevant, notify client */
758 if (0 == htons (v4.sin_port))
759 v4.sin_port = c4->sin_port;
760 notify_client (delta->ac,
761 ch,
762 add,
763 &v4,
764 alen);
765 }
766 break;
767
768 case AF_INET6:
769 alen = sizeof(struct sockaddr_in6);
770 GNUNET_memcpy (&v6,
771 &delta->addr,
772 alen);
773 for (unsigned int i = 0; i < ch->num_caddrs; i++)
774 {
775 const struct sockaddr_in6 *c6;
776
777 if (AF_INET6 != ch->caddrs[i].ss.ss_family)
778 continue; /* IPv4 not relevant */
779 c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss;
781 (0 == GNUNET_memcmp (&c6->sin6_addr,
782 &in6addr_any)) &&
783 (match_ipv6 ("::1", &v6.sin6_addr, 128) ||
784 match_ipv6 ("fe80::", &v6.sin6_addr, 10)))
785 continue; /* bound to "any", and this address is either loopback
786 or link-local. Neither is reachable from another
787 host -- a link-local address is not even usable
788 without the scope identifier, which does not
789 survive the trip through a HELLO. */
790 if (match_ipv6 ("::1", &c6->sin6_addr, 128) &&
791 (0 != GNUNET_memcmp (&c6->sin6_addr,
792 &in6addr_any)) &&
793 (! match_ipv6 ("::1", &v6.sin6_addr, 128)))
794 continue; /* bound to loopback, but this is not loopback */
795 if ((! match_ipv6 ("::1", &c6->sin6_addr, 128)) &&
796 match_ipv6 ("::1", &v6.sin6_addr, 128))
797 continue; /* bound to non-loopback, but this is loopback */
798 if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
799 (0 != GNUNET_memcmp (&c6->sin6_addr,
800 &in6addr_any)) &&
801 (! is_nat_v6 (&v6.sin6_addr)))
802 continue; /* based on external-IP, but this IP is not
803 from private address range. */
804 if ((0 != GNUNET_memcmp (&v6.sin6_addr,
805 &c6->sin6_addr)) &&
806 (0 != GNUNET_memcmp (&c6->sin6_addr,
807 &in6addr_any)) &&
808 (! is_nat_v6 (&c6->sin6_addr)))
809 continue; /* this IP is not from private address range,
810 and IP does not match. */
811 if ((match_ipv6 ("fe80::", &c6->sin6_addr, 10)) &&
812 (0 != GNUNET_memcmp (&c6->sin6_addr,
813 &in6addr_any)) &&
814 (0 != GNUNET_memcmp (&v6.sin6_addr,
815 &c6->sin6_addr)) &&
816 (0 == (delta->ac & GNUNET_NAT_AC_EXTERN)))
817 continue; /* client bound to link-local, and the other address
818 does not match and is not an external IP */
819
820 /* OK, IP seems relevant, notify client */
821 if (0 == htons (v6.sin6_port))
822 v6.sin6_port = c6->sin6_port;
823 notify_client (delta->ac,
824 ch,
825 add,
826 &v6,
827 alen);
828 }
829 break;
830
831 default:
832 GNUNET_break (0);
833 return;
834 }
835}
836
837
845static void
847 int add)
848{
849 for (struct ClientHandle *ch = ch_head;
850 NULL != ch;
851 ch = ch->next)
853 ch,
854 add);
855}
856
857
866static void
868 const struct in_addr *v4,
869 int add)
870{
871 struct ClientHandle *ch = cls;
872 struct sockaddr_in sa;
873 int have_v4;
874
875 /* (0) check if this impacts 'hole_external' */
876 if ((NULL != ch->hole_external) &&
877 (0 == strcasecmp (ch->hole_external,
878 "AUTO")))
879 {
880 struct LocalAddressList lal;
881 struct sockaddr_in *s4;
882
884 "Detected eternal IP, can now back-fill AUTO:%u in hole punching specification of `%s'\n",
885 (unsigned int) ch->ext_dns_port,
886 ch->section_name);
887 memset (&lal, 0, sizeof(lal));
888 s4 = (struct sockaddr_in *) &lal.addr;
889 s4->sin_family = AF_INET;
890 s4->sin_port = htons (ch->ext_dns_port);
891 s4->sin_addr = *v4;
892 lal.af = AF_INET;
895 ch,
896 add);
897 }
898
899 /* (1) check if client cares. */
900 if (! ch->natted_address)
901 return;
902 have_v4 = GNUNET_NO;
903 for (unsigned int i = 0; i < ch->num_caddrs; i++)
904 {
905 const struct sockaddr_storage *ss = &ch->caddrs[i].ss;
906
907 if (AF_INET != ss->ss_family)
908 continue;
909 have_v4 = GNUNET_YES;
910 break;
911 }
912 if (GNUNET_NO == have_v4)
913 return; /* IPv6-only */
914
915 /* (2) build address info */
916 memset (&sa,
917 0,
918 sizeof(sa));
919 sa.sin_family = AF_INET;
920 sa.sin_addr = *v4;
921 sa.sin_port = htons (0);
922
924 "Detected eternal IP %s, notifying client of external IP (without port)\n",
925 GNUNET_a2s ((const struct sockaddr *) &sa,
926 sizeof(sa)));
927 /* (3) notify client of change */
931 ch,
932 add,
933 &sa,
934 sizeof(sa));
935}
936
937
945static void
947 const struct sockaddr_in *ra)
948{
949 struct LocalAddressList *lal = cls;
950 const struct sockaddr_in *l4;
951
952 GNUNET_assert (AF_INET == lal->af);
953 l4 = (const struct sockaddr_in *) &lal->addr;
954 for (struct ClientHandle *ch = ch_head;
955 NULL != ch;
956 ch = ch->next)
957 {
959 struct GNUNET_MQ_Envelope *env;
960 int match;
961
962 /* Check if client is in applicable range for ICMP NAT traversal
963 for this local address */
964 if (! ch->natted_address)
965 continue;
966 match = GNUNET_NO;
967 for (unsigned int i = 0; i < ch->num_caddrs; i++)
968 {
969 struct ClientAddress *ca = &ch->caddrs[i];
970 const struct sockaddr_in *c4;
971
972 if (AF_INET != ca->ss.ss_family)
973 continue;
974 c4 = (const struct sockaddr_in *) &ca->ss;
975 if ((0 != c4->sin_addr.s_addr) &&
976 (l4->sin_addr.s_addr != c4->sin_addr.s_addr))
977 continue;
978 match = GNUNET_YES;
979 break;
980 }
981 if (! match)
982 continue;
983
984 /* Notify applicable client about connection reversal request */
985 env = GNUNET_MQ_msg_extra (crrm,
986 sizeof(struct sockaddr_in),
988 GNUNET_memcpy (&crrm[1],
989 ra,
990 sizeof(struct sockaddr_in));
992 env);
993 }
994}
995
996
1002static void
1003run_scan (void *cls)
1004{
1005 struct IfcProcContext ifc_ctx;
1006 int found;
1007 int have_nat;
1008 struct LocalAddressList *lnext;
1009
1011 &run_scan,
1012 NULL);
1013 memset (&ifc_ctx,
1014 0,
1015 sizeof(ifc_ctx));
1017 &ifc_ctx);
1018 /* remove addresses that disappeared */
1019 for (struct LocalAddressList *lal = lal_head;
1020 NULL != lal;
1021 lal = lnext)
1022 {
1023 lnext = lal->next;
1024 found = GNUNET_NO;
1025 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1026 NULL != pos;
1027 pos = pos->next)
1028 {
1029 if ((pos->af == lal->af) &&
1030 (0 == memcmp (&lal->addr,
1031 &pos->addr,
1032 (AF_INET == lal->af)
1033 ? sizeof(struct sockaddr_in)
1034 : sizeof(struct sockaddr_in6))))
1035 {
1036 found = GNUNET_YES;
1037 }
1038 }
1039 if (GNUNET_NO == found)
1040 {
1041 notify_clients (lal,
1042 GNUNET_NO);
1043 free_lal (lal);
1044 }
1045 }
1046
1047 /* add addresses that appeared */
1048 have_nat = GNUNET_NO;
1049 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1050 NULL != pos;
1051 pos = ifc_ctx.lal_head)
1052 {
1053 found = GNUNET_NO;
1054 if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac))
1055 have_nat = GNUNET_YES;
1056 for (struct LocalAddressList *lal = lal_head;
1057 NULL != lal;
1058 lal = lal->next)
1059 {
1060 if ((pos->af == lal->af) &&
1061 (0 == memcmp (&lal->addr,
1062 &pos->addr,
1063 (AF_INET == lal->af)
1064 ? sizeof(struct sockaddr_in)
1065 : sizeof(struct sockaddr_in6))))
1066 found = GNUNET_YES;
1067 }
1069 ifc_ctx.lal_tail,
1070 pos);
1071 if (GNUNET_YES == found)
1072 {
1073 GNUNET_free (pos);
1074 }
1075 else
1076 {
1077 notify_clients (pos,
1078 GNUNET_YES);
1080 lal_tail,
1081 pos);
1082 if ((AF_INET == pos->af) &&
1083 (NULL == pos->hc) &&
1084 (0 != (GNUNET_NAT_AC_LAN & pos->ac)))
1085 {
1086 const struct sockaddr_in *s4
1087 = (const struct sockaddr_in *) &pos->addr;
1088
1090 "Found NATed local address %s, starting NAT server\n",
1091 GNUNET_a2s ((const struct sockaddr *) &pos->addr,
1092 sizeof(*s4)));
1093 pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
1095 pos,
1096 cfg);
1097 }
1098 }
1099 }
1100 GN_nat_status_changed (have_nat);
1101}
1102
1103
1115static void
1117 int add_remove,
1118 const struct sockaddr *addr,
1119 socklen_t addrlen,
1121{
1122 struct ClientHandle *ch = cls;
1124
1125 switch (result)
1126 {
1128 GNUNET_assert (NULL != addr);
1129 break;
1130
1135 "Running upnpc failed: %d\n",
1136 result);
1137 return;
1138
1141 "external-ip binary not found\n");
1142 return;
1143
1146 "upnpc binary not found\n");
1147 return;
1148
1151 "external-ip binary could not be run\n");
1152 return;
1153
1156 "upnpc failed to create port mapping\n");
1157 return;
1158
1161 "Invalid output from upnpc\n");
1162 return;
1163
1166 "Invalid address returned by upnpc\n");
1167 return;
1168
1169 default:
1170 GNUNET_break (0); /* should not be possible */
1171 return;
1172 }
1173 switch (addr->sa_family)
1174 {
1175 case AF_INET:
1176 ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr)
1179 break;
1180
1181 case AF_INET6:
1182 ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr)
1185 break;
1186
1187 default:
1188 GNUNET_break (0);
1189 return;
1190 }
1192 "upnp external address %s: %s\n",
1193 add_remove ? "added" : "removed",
1194 GNUNET_a2s (addr,
1195 addrlen));
1196 notify_client (ac,
1197 ch,
1198 add_remove,
1199 addr,
1200 addrlen);
1201}
1202
1203
1212static void
1213dyndns_lookup (void *cls);
1214
1215
1225static void
1227 const struct sockaddr *addr,
1228 socklen_t addrlen)
1229{
1230 struct ClientHandle *ch = cls;
1231 struct LocalAddressList *lal;
1232 struct sockaddr_storage ss;
1233 struct sockaddr_in *v4;
1234 struct sockaddr_in6 *v6;
1235
1236 if (NULL == addr)
1237 {
1238 struct LocalAddressList *laln;
1239
1240 ch->ext_dns = NULL;
1241 ch->ext_dns_task
1244 ch);
1245 /* Current iteration is over, remove 'old' IPs now */
1246 for (lal = ch->ext_addr_head; NULL != lal; lal = laln)
1247 {
1248 laln = lal->next;
1249 if (GNUNET_YES == lal->old)
1250 {
1251 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
1252 ch->ext_addr_tail,
1253 lal);
1255 ch,
1256 GNUNET_NO);
1257 GNUNET_free (lal);
1258 }
1259 }
1260 return;
1261 }
1263 "Got IP `%s' for external address `%s'\n",
1265 addrlen),
1266 ch->hole_external);
1267
1268 /* build sockaddr storage with port number */
1269 memset (&ss,
1270 0,
1271 sizeof(ss));
1272 GNUNET_memcpy (&ss,
1273 addr,
1274 addrlen);
1275 switch (addr->sa_family)
1276 {
1277 case AF_INET:
1278 v4 = (struct sockaddr_in *) &ss;
1279 v4->sin_port = htons (ch->ext_dns_port);
1280 break;
1281
1282 case AF_INET6:
1283 v6 = (struct sockaddr_in6 *) &ss;
1284 v6->sin6_port = htons (ch->ext_dns_port);
1285 break;
1286
1287 default:
1288 GNUNET_break (0);
1289 return;
1290 }
1291 /* See if 'ss' matches any of our known addresses */
1292 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1293 {
1294 if (GNUNET_NO == lal->old)
1295 continue; /* already processed, skip */
1296 if ((addr->sa_family == lal->addr.ss_family) &&
1297 (0 == memcmp (&ss,
1298 &lal->addr,
1299 addrlen)))
1300 {
1301 /* Address unchanged, remember so we do not remove */
1302 lal->old = GNUNET_NO;
1303 return; /* done here */
1304 }
1305 }
1306 /* notify client, and remember IP for later removal! */
1307 lal = GNUNET_new (struct LocalAddressList);
1308 lal->addr = ss;
1309 lal->af = ss.ss_family;
1311 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1312 ch->ext_addr_tail,
1313 lal);
1315 ch,
1316 GNUNET_YES);
1317}
1318
1319
1328static void
1329dyndns_lookup (void *cls)
1330{
1331 struct ClientHandle *ch = cls;
1332 struct LocalAddressList *lal;
1333
1335 "Performing DNS lookup for punched hole given for `%s' as `%s:%u'\n",
1336 ch->section_name,
1337 ch->hole_external,
1338 (unsigned int) ch->ext_dns_port);
1339 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1340 lal->old = GNUNET_YES;
1341 ch->ext_dns_task = NULL;
1342 ch->ext_dns = GNUNET_RESOLVER_ip_get (ch->hole_external,
1343 AF_UNSPEC,
1346 ch);
1347}
1348
1349
1361static void
1363{
1364 char *port;
1365 unsigned int pnum;
1366 struct sockaddr_in *s4;
1367 struct LocalAddressList *lal;
1368
1369 port = strrchr (ch->hole_external, ':');
1370 if (NULL == port)
1371 {
1373 _ ("Malformed punched hole specification `%s' (lacks port)\n"),
1374 ch->hole_external);
1375 return;
1376 }
1377 if ((1 != sscanf (port + 1,
1378 "%u",
1379 &pnum)) ||
1380 (pnum > 65535))
1381 {
1383 _ (
1384 "Invalid port number in punched hole specification `%s' (lacks port)\n"),
1385 port + 1);
1386 return;
1387 }
1388 ch->ext_dns_port = (uint16_t) pnum;
1389 *port = '\0';
1390
1391 lal = GNUNET_new (struct LocalAddressList);
1392 if ('[' == *ch->hole_external)
1393 {
1394 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &lal->addr;
1395
1396 s6->sin6_family = AF_INET6;
1397 if (']' != (ch->hole_external[strlen (ch->hole_external) - 1]))
1398 {
1400 _ ("Malformed punched hole specification `%s' (lacks `]')\n"),
1401 ch->hole_external);
1402 GNUNET_free (lal);
1403 return;
1404 }
1405 ch->hole_external[strlen (ch->hole_external) - 1] = '\0';
1406 if (1 != inet_pton (AF_INET6,
1407 ch->hole_external + 1,
1408 &s6->sin6_addr))
1409 {
1411 _ (
1412 "Malformed punched hole specification `%s' (IPv6 address invalid)"),
1413 ch->hole_external + 1);
1414 GNUNET_free (lal);
1415 return;
1416 }
1417 s6->sin6_port = htons (ch->ext_dns_port);
1418 lal->af = AF_INET6;
1420 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1421 ch->ext_addr_tail,
1422 lal);
1424 ch,
1425 GNUNET_YES);
1426 return;
1427 }
1428
1429 s4 = (struct sockaddr_in *) &lal->addr;
1430 s4->sin_family = AF_INET;
1431 if (1 == inet_pton (AF_INET,
1432 ch->hole_external,
1433 &s4->sin_addr))
1434 {
1436 "IPv4 punched hole given for `%s' via `%s:%u'\n",
1437 ch->section_name,
1438 ch->hole_external,
1439 (unsigned int) ch->ext_dns_port);
1440 s4->sin_port = htons (ch->ext_dns_port);
1441 lal->af = AF_INET;
1443 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1444 ch->ext_addr_tail,
1445 lal);
1447 ch,
1448 GNUNET_YES);
1449 return;
1450 }
1451 if (0 == strcasecmp (ch->hole_external,
1452 "AUTO"))
1453 {
1454 /* handled in #notify_client_external_ipv4_change() */
1455 GNUNET_free (lal);
1456 return;
1457 }
1458 /* got a DNS name, trigger lookup! */
1459 GNUNET_free (lal);
1460 ch->ext_dns_task
1462 ch);
1463}
1464
1465
1473static void
1475 const struct GNUNET_NAT_RegisterMessage *message)
1476{
1477 struct ClientHandle *ch = cls;
1478 const char *off;
1479 size_t left;
1480
1481 if ((0 != ch->proto) ||
1482 (NULL != ch->caddrs))
1483 {
1484 /* double registration not allowed */
1485 GNUNET_break (0);
1487 return;
1488 }
1489 ch->flags = message->flags;
1490 ch->proto = message->proto;
1491 ch->num_caddrs = ntohs (message->num_addrs);
1492 ch->caddrs = GNUNET_new_array (ch->num_caddrs,
1493 struct ClientAddress);
1494 left = ntohs (message->header.size) - sizeof(*message);
1495 off = (const char *) &message[1];
1496 for (unsigned int i = 0; i < ch->num_caddrs; i++)
1497 {
1498 const struct sockaddr *sa = (const struct sockaddr *) off;
1499 size_t alen;
1500 uint16_t port;
1501 int is_nat;
1502
1503 if (sizeof(sa_family_t) > left)
1504 {
1505 GNUNET_break (0);
1507 return;
1508 }
1509 is_nat = GNUNET_NO;
1510 switch (sa->sa_family)
1511 {
1512 case AF_INET:
1513 {
1514 struct sockaddr_in s4;
1515
1516 GNUNET_memcpy (&s4,
1517 off,
1518 sizeof(struct sockaddr_in));
1519 alen = sizeof(struct sockaddr_in);
1520 if (is_nat_v4 (&s4.sin_addr))
1521 is_nat = GNUNET_YES;
1522 port = ntohs (s4.sin_port);
1523 }
1524 break;
1525
1526 case AF_INET6:
1527 {
1528 struct sockaddr_in6 s6;
1529
1530 GNUNET_memcpy (&s6,
1531 off,
1532 sizeof(struct sockaddr_in6));
1533 alen = sizeof(struct sockaddr_in6);
1534 if (is_nat_v6 (&s6.sin6_addr))
1535 is_nat = GNUNET_YES;
1536 port = ntohs (s6.sin6_port);
1537 }
1538 break;
1539
1540#if AF_UNIX
1541 case AF_UNIX:
1542 alen = sizeof(struct sockaddr_un);
1543 port = 0;
1544 break;
1545#endif
1546 default:
1547 GNUNET_break (0);
1549 return;
1550 }
1551 /* store address */
1552 GNUNET_assert (alen <= left);
1553 GNUNET_assert (alen <= sizeof(struct sockaddr_storage));
1554 GNUNET_memcpy (&ch->caddrs[i].ss,
1555 off,
1556 alen);
1557
1558 /* If applicable, try UPNPC NAT punching */
1559 if ((is_nat) &&
1560 (enable_upnp) &&
1561 ((IPPROTO_TCP == ch->proto) ||
1562 (IPPROTO_UDP == ch->proto)))
1563 {
1564 ch->natted_address = GNUNET_YES;
1565 ch->caddrs[i].mh
1567 IPPROTO_TCP == ch->proto,
1569 ch);
1570 }
1571
1572 off += alen;
1573 }
1574
1575 ch->section_name
1576 = GNUNET_strndup (off,
1577 ntohs (message->str_len));
1579 "Received REGISTER message from client for subsystem `%s'\n",
1580 ch->section_name);
1581 if (GNUNET_OK ==
1583 ch->section_name,
1584 "HOLE_EXTERNAL",
1585 &ch->hole_external))
1587
1588 /* Actually send IP address list to client */
1589 for (struct LocalAddressList *lal = lal_head;
1590 NULL != lal;
1591 lal = lal->next)
1592 {
1594 ch,
1595 GNUNET_YES);
1596 }
1597 /* Also consider IPv4 determined by `external-ip` */
1598 ch->external_monitor
1600 ch);
1602}
1603
1604
1613static int
1614check_stun (void *cls,
1615 const struct GNUNET_NAT_HandleStunMessage *message)
1616{
1617 size_t sa_len = ntohs (message->sender_addr_size);
1618 size_t expect = sa_len + ntohs (message->payload_size);
1619
1620 if (ntohs (message->header.size) - sizeof(*message) != expect)
1621 {
1622 GNUNET_break (0);
1623 return GNUNET_SYSERR;
1624 }
1625 if (sa_len < sizeof(sa_family_t))
1626 {
1627 GNUNET_break (0);
1628 return GNUNET_SYSERR;
1629 }
1630 return GNUNET_OK;
1631}
1632
1633
1641static void
1642notify_clients_stun_change (const struct sockaddr_in *ip,
1643 int add)
1644{
1645 for (struct ClientHandle *ch = ch_head;
1646 NULL != ch;
1647 ch = ch->next)
1648 {
1649 struct sockaddr_in v4;
1651 struct GNUNET_MQ_Envelope *env;
1652
1653 if (! ch->natted_address)
1654 continue;
1655 v4 = *ip;
1656 v4.sin_port = htons (0);
1658 sizeof(v4),
1660 msg->add_remove = htonl ((int32_t) add);
1661 msg->addr_class = htonl (GNUNET_NAT_AC_EXTERN
1663 GNUNET_memcpy (&msg[1],
1664 &v4,
1665 sizeof(v4));
1667 env);
1668 }
1669}
1670
1671
1679static void
1681{
1682 struct StunExternalIP *se = cls;
1683
1684 se->timeout_task = NULL;
1686 GNUNET_NO);
1688 se_tail,
1689 se);
1690 GNUNET_free (se);
1691}
1692
1693
1701static void
1702handle_stun (void *cls,
1703 const struct GNUNET_NAT_HandleStunMessage *message)
1704{
1705 struct ClientHandle *ch = cls;
1706 const char *buf = (const char *) &message[1];
1707 const struct sockaddr *sa;
1708 const void *payload;
1709 size_t sa_len;
1710 size_t payload_size;
1711 struct sockaddr_in external_addr;
1712
1713 sa_len = ntohs (message->sender_addr_size);
1714 payload_size = ntohs (message->payload_size);
1715 sa = (const struct sockaddr *) &buf[0];
1716 payload = (const struct sockaddr *) &buf[sa_len];
1717 switch (sa->sa_family)
1718 {
1719 case AF_INET:
1720 if (sa_len != sizeof(struct sockaddr_in))
1721 {
1722 GNUNET_break (0);
1724 return;
1725 }
1726 break;
1727
1728 case AF_INET6:
1729 if (sa_len != sizeof(struct sockaddr_in6))
1730 {
1731 GNUNET_break (0);
1733 return;
1734 }
1735 break;
1736 }
1738 "Received HANDLE_STUN message from client\n");
1739 if (GNUNET_OK ==
1741 payload_size,
1742 &external_addr))
1743 {
1744 /* We now know that a server at "sa" claims that
1745 we are visible at IP "external_addr".
1746
1747 We should (for some fixed period of time) tell
1748 all of our clients that listen to a NAT'ed address
1749 that they might want to consider the given 'external_ip'
1750 as their public IP address (this includes TCP and UDP
1751 clients, even if only UDP sends STUN requests).
1752
1753 If we do not get a renewal, the "external_addr" should be
1754 removed again. The timeout frequency should be configurable
1755 (with a sane default), so that the UDP plugin can tell how
1756 often to re-request STUN.
1757 */struct StunExternalIP *se;
1758
1759 /* Check if we had a prior response from this STUN server */
1760 for (se = se_head; NULL != se; se = se->next)
1761 {
1762 if ((se->stun_server_addr_len != sa_len) ||
1763 (0 != memcmp (sa,
1764 &se->stun_server_addr,
1765 sa_len)))
1766 continue; /* different STUN server */
1767 if (0 != GNUNET_memcmp (&external_addr,
1768 &se->external_addr))
1769 {
1770 /* external IP changed, update! */
1772 GNUNET_NO);
1775 GNUNET_YES);
1776 }
1777 /* update timeout */
1779 se->timeout_task
1782 se);
1783 return;
1784 }
1785 /* STUN server is completely new, create fresh entry */
1786 se = GNUNET_new (struct StunExternalIP);
1789 sa,
1790 sa_len);
1791 se->stun_server_addr_len = sa_len;
1794 se);
1796 se_tail,
1797 se);
1799 GNUNET_NO);
1800 }
1802}
1803
1804
1814static int
1816 const struct
1818 message)
1819{
1820 size_t expect;
1821
1822 expect = ntohs (message->local_addr_size)
1823 + ntohs (message->remote_addr_size);
1824 if (ntohs (message->header.size) - sizeof(*message) != expect)
1825 {
1826 GNUNET_break (0);
1827 return GNUNET_SYSERR;
1828 }
1829 return GNUNET_OK;
1830}
1831
1832
1840static void
1842 void *cls,
1843 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1844{
1845 struct ClientHandle *ch = cls;
1846 const char *buf = (const char *) &message[1];
1847 size_t local_sa_len = ntohs (message->local_addr_size);
1848 size_t remote_sa_len = ntohs (message->remote_addr_size);
1849 struct sockaddr_in l4;
1850 struct sockaddr_in r4;
1851 int ret;
1852
1854 "Received REQUEST CONNECTION REVERSAL message from client\n");
1855 if (local_sa_len != sizeof(struct sockaddr_in))
1856 {
1857 GNUNET_break_op (0);
1859 return;
1860 }
1861 if (remote_sa_len != sizeof(struct sockaddr_in))
1862 {
1863 GNUNET_break_op (0);
1865 return;
1866 }
1867 GNUNET_memcpy (&l4,
1868 buf,
1869 sizeof(struct sockaddr_in));
1870 GNUNET_break_op (AF_INET == l4.sin_family);
1871 buf += sizeof(struct sockaddr_in);
1872 GNUNET_memcpy (&r4,
1873 buf,
1874 sizeof(struct sockaddr_in));
1875 GNUNET_break_op (AF_INET == r4.sin_family);
1876 ret = GN_request_connection_reversal (&l4.sin_addr,
1877 ntohs (l4.sin_port),
1878 &r4.sin_addr,
1879 cfg);
1880 if (GNUNET_OK != ret)
1882 _ ("Connection reversal request failed\n"));
1884}
1885
1886
1895static enum GNUNET_GenericReturnValue
1897 void *cls,
1898 const struct GNUNET_NAT_AddGlobalAddressMessage *message)
1899{
1900 // const char *buf = (const char *) &message[1];
1901 // uint16_t blen = ntohs (message->address_length);
1902 size_t left = ntohs (message->header.size) - sizeof(*message);
1903
1904 if (left != ntohs (message->address_length))
1905 {
1906 GNUNET_break_op (0);
1907 return GNUNET_SYSERR;
1908 }
1909 /* if ('\0' != buf[blen - 1]) */
1910 /* { */
1911 /* GNUNET_break_op (0); */
1912 /* return GNUNET_SYSERR; */
1913 /* } */
1914 return GNUNET_OK;
1915}
1916
1917
1925static void
1927 void *cls,
1928 const struct GNUNET_NAT_AddGlobalAddressMessage *message)
1929{
1930 struct ClientHandle *ch = cls;
1931 const char *buf = (const char *) &message[1];
1932 size_t blen = ntohs (message->header.size) - sizeof(*message);
1933 struct sockaddr_in sockaddr_ipv4 = {
1934 .sin_family = AF_INET
1935 };
1936 char addr[INET_ADDRSTRLEN];
1937
1938 /* The address comes straight off the wire and is NOT 0-terminated (which
1939 is why the assertion that it was is commented out in
1940 #check_add_global_address()), while inet_pton() requires a C string:
1941 it used to be handed @e buf directly and so parsed whatever happened to
1942 follow in memory. Copy it out first. Anything too long to be an IPv4
1943 literal is not one, so the length check doubles as a fast reject. */
1944 if (blen >= sizeof(addr))
1945 {
1947 "Ignoring global address `%.*s': not an IPv4 address\n",
1948 (int) blen,
1949 buf);
1951 return;
1952 }
1953 GNUNET_memcpy (addr, buf, blen);
1954 addr[blen] = '\0';
1955 if (1 != inet_pton (AF_INET,
1956 addr,
1957 &sockaddr_ipv4.sin_addr))
1958 {
1959 /* Not a protocol violation: peers legitimately gossip IPv6 (and other)
1960 addresses, and this service only tracks IPv4 NAT state. This used to
1961 be a GNUNET_break(0), which turned every such peer into a steady
1962 stream of "Assertion failed" at ERROR level. */
1964 "Ignoring global address `%s': not an IPv4 address\n",
1965 addr);
1967 return;
1968 }
1969 notify_clients_stun_change (&sockaddr_ipv4,
1970 GNUNET_YES);
1972}
1973
1974
1980static void
1981shutdown_task (void *cls)
1982{
1983 struct StunExternalIP *se;
1984
1985 while (NULL != (se = se_head))
1986 {
1988 se_tail,
1989 se);
1991 GNUNET_free (se);
1992 }
1994 if (NULL != scan_task)
1995 {
1997 scan_task = NULL;
1998 }
1999 if (NULL != stats)
2000 {
2002 GNUNET_NO);
2003 stats = NULL;
2004 }
2005 destroy_lal ();
2006}
2007
2008
2016static void
2017run (void *cls,
2018 const struct GNUNET_CONFIGURATION_Handle *c,
2020{
2021 cfg = c;
2022 if (GNUNET_OK !=
2024 "NAT",
2025 "STUN_STALE",
2028
2031 "NAT",
2032 "RETURN_LOCAL_ADDRESSES");
2033 /* Check for UPnP */
2036 "NAT",
2037 "ENABLE_UPNP");
2038 if (GNUNET_YES == enable_upnp)
2039 {
2040 /* check if it works */
2041 if (GNUNET_SYSERR ==
2043 GNUNET_NO,
2044 NULL))
2045 {
2047 _ (
2048 "UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
2050 }
2051 }
2052 if (GNUNET_OK !=
2054 "nat",
2055 "DYNDNS_FREQUENCY",
2058
2061 "NAT",
2062 "ENABLE_IPSCAN");
2063
2065 NULL);
2067 cfg);
2070 NULL);
2071}
2072
2073
2082static void *
2084 struct GNUNET_SERVICE_Client *c,
2085 struct GNUNET_MQ_Handle *mq)
2086{
2087 struct ClientHandle *ch;
2088
2089 ch = GNUNET_new (struct ClientHandle);
2090 ch->mq = mq;
2091 ch->client = c;
2093 ch_tail,
2094 ch);
2095 return ch;
2096}
2097
2098
2106static void
2108 struct GNUNET_SERVICE_Client *c,
2109 void *internal_cls)
2110{
2111 struct ClientHandle *ch = internal_cls;
2112 struct LocalAddressList *lal;
2113
2115 ch_tail,
2116 ch);
2117 for (unsigned int i = 0; i < ch->num_caddrs; i++)
2118 {
2119 if (NULL != ch->caddrs[i].mh)
2120 {
2121 GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh);
2122 ch->caddrs[i].mh = NULL;
2123 }
2124 }
2125 GNUNET_free (ch->caddrs);
2126 while (NULL != (lal = ch->ext_addr_head))
2127 {
2128 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
2129 ch->ext_addr_tail,
2130 lal);
2131 GNUNET_free (lal);
2132 }
2133 if (NULL != ch->ext_dns_task)
2134 {
2135 GNUNET_SCHEDULER_cancel (ch->ext_dns_task);
2136 ch->ext_dns_task = NULL;
2137 }
2138 if (NULL != ch->external_monitor)
2139 {
2140 GN_external_ipv4_monitor_stop (ch->external_monitor);
2141 ch->external_monitor = NULL;
2142 }
2143 if (NULL != ch->ext_dns)
2144 {
2146 ch->ext_dns = NULL;
2147 }
2148 GNUNET_free (ch->hole_external);
2149 GNUNET_free (ch->section_name);
2150 GNUNET_free (ch);
2151}
2152
2153
2159 "nat",
2161 &run,
2164 NULL,
2165 GNUNET_MQ_hd_var_size (register,
2168 NULL),
2172 NULL),
2173 GNUNET_MQ_hd_var_size (request_connection_reversal,
2176 NULL),
2177 GNUNET_MQ_hd_var_size (add_global_address,
2180 NULL),
2182
2183
2184#if defined(__linux__) && defined(__GLIBC__)
2185#include <malloc.h>
2186
2187void __attribute__ ((constructor))
2188GNUNET_NATM_memory_init (void);
2189
2193void __attribute__ ((constructor))
2194GNUNET_NATM_memory_init (void)
2195{
2196 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2197 mallopt (M_TOP_PAD, 1 * 1024);
2198 malloc_trim (0);
2199}
2200
2201
2202#endif
2203
2204/* end of gnunet-service-nat.c */
struct GNUNET_MessageHeader * msg
Definition 005.c:2
struct GNUNET_MQ_Envelope * env
Definition 005.c:1
static int ret
Final status code.
Definition gnunet-arm.c:93
static uint16_t port
Port number.
Definition gnunet-bcd.c:146
static struct GNUNET_CADET_Channel * ch
Channel handle.
struct GNUNET_SCHEDULER_Task * shutdown_task
static char * name
Name (label) of the records to list.
static int add
Desired action is to add a record.
static int result
Global testing status.
static struct GNUNET_SERVICE_Handle * service
Handle to our service instance.
static unsigned long long payload
How much data are we currently storing in the database?
static void handle_stun(void *cls, const struct GNUNET_NAT_HandleStunMessage *message)
Handler for GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from client.
static int check_stun(void *cls, const struct GNUNET_NAT_HandleStunMessage *message)
Check validity of GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from client.
static struct ClientHandle * ch_head
Head of client DLL.
static struct StunExternalIP * se_head
Kept in a DLL.
static int return_local_addresses
Do we report addresses that are only meaningful on this host to clients that did not explicitly bind ...
static struct GNUNET_TIME_Relative dyndns_frequency
How often do we scan for changes in how our external (dyndns) hostname resolves?
static void upnp_addr_change_cb(void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen, enum GNUNET_NAT_StatusCode result)
Function called whenever our set of external addresses as created by upnpc changes.
static enum GNUNET_GenericReturnValue check_add_global_address(void *cls, const struct GNUNET_NAT_AddGlobalAddressMessage *message)
Check validity of GNUNET_MESSAGE_TYPE_NAT_ADD_GLOBAL_ADDRESS message from client.
int enable_ipscan
Is IP Scanning enabled? GNUNET_YES if enabled, GNUNET_NO if disabled, without, only explicitly specif...
static void notify_clients_stun_change(const struct sockaddr_in *ip, int add)
Notify all clients about our external IP address as reported by the STUN server.
static struct GNUNET_STATISTICS_Handle * stats
Handle to the statistics service.
static const struct GNUNET_CONFIGURATION_Handle * cfg
Handle to our current configuration.
static void destroy_lal()
Free the DLL starting at lal_head.
static void notify_client_external_ipv4_change(void *cls, const struct in_addr *v4, int add)
Tell relevant client about a change in our external IPv4 address.
static int check_register(void *cls, const struct GNUNET_NAT_RegisterMessage *message)
Check validity of GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
static void notify_client(enum GNUNET_NAT_AddressClass ac, struct ClientHandle *ch, int add, const void *addr, size_t addr_len)
Notify client about a change in the list of addresses this peer has.
static int match_ipv6(const char *network, const struct in6_addr *ip, uint8_t bits)
Check if ip is in network with bits netmask.
static void process_external_ip(void *cls, const struct sockaddr *addr, socklen_t addrlen)
Our (external) hostname was resolved.
static struct ClientHandle * ch_tail
Tail of client DLL.
static void notify_clients(struct LocalAddressList *delta, int add)
Notify all clients about a change in the list of addresses this peer has.
static void check_notify_client(struct LocalAddressList *delta, struct ClientHandle *ch, int add)
Check if we should bother to notify this client about this address change, and if so,...
static struct LocalAddressList * lal_head
Head of DLL of local addresses.
static void run_scan(void *cls)
Task we run periodically to scan for network interfaces.
static int match_ipv4(const char *network, const struct in_addr *ip, uint8_t bits)
Check if ip is in network with bits netmask.
static struct GNUNET_SCHEDULER_Task * scan_task
Task scheduled to periodically scan our network interfaces.
#define DYNDNS_FREQUENCY
How often do we scan for changes in how our external (dyndns) hostname resolves?
static void reversal_callback(void *cls, const struct sockaddr_in *ra)
We got a connection reversal request from another peer.
#define SCAN_FREQ
How often should we ask the OS about a list of active network interfaces?
static struct StunExternalIP * se_tail
Kept in a DLL.
static void handle_register(void *cls, const struct GNUNET_NAT_RegisterMessage *message)
Handler for GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
static void stun_ip_timeout(void *cls)
Function to be called when we decide that an external IP address as told to us by a STUN server has g...
static void run(void *cls, const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_SERVICE_Handle *service)
Setup NAT service.
static void lookup_hole_external(struct ClientHandle *ch)
Resolve the hole_external name to figure out our external address from a manually punched hole.
static int check_request_connection_reversal(void *cls, const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
Check validity of GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from client.
static int ifc_proc(void *cls, const char *name, int isDefault, const struct sockaddr *addr, const struct sockaddr *broadcast_addr, const struct sockaddr *netmask, socklen_t addrlen)
Callback function invoked for each interface found.
static void handle_request_connection_reversal(void *cls, const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
Handler for GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from client.
static void handle_add_global_address(void *cls, const struct GNUNET_NAT_AddGlobalAddressMessage *message)
Handle GNUNET_MESSAGE_TYPE_NAT_ADD_GLOBAL_ADDRESS message from client.
static void dyndns_lookup(void *cls)
Resolve the hole_external name to figure out our external address from a manually punched hole.
static void * client_connect_cb(void *cls, struct GNUNET_SERVICE_Client *c, struct GNUNET_MQ_Handle *mq)
Callback called when a client connects to the service.
static void client_disconnect_cb(void *cls, struct GNUNET_SERVICE_Client *c, void *internal_cls)
Callback called when a client disconnected from the service.
static int is_nat_v6(const struct in6_addr *ip)
Test if the given IPv6 address is in a known range for private networks.
static struct LocalAddressList * lal_tail
Tail of DLL of local addresses.
static void free_lal(struct LocalAddressList *lal)
Remove and free an entry from the lal_head DLL.
static int is_nat_v4(const struct in_addr *ip)
Test if the given IPv4 address is in a known range for private networks.
int enable_upnp
Is UPnP enabled? GNUNET_YES if enabled, GNUNET_NO if disabled, GNUNET_SYSERR if configuration enabled...
static struct GNUNET_TIME_Relative stun_stale_timeout
Timeout to use when STUN data is considered stale.
network address translation traversal service
void GN_external_ipv4_monitor_stop(struct GN_ExternalIPMonitor *mon)
Stop calling monitor.
void GN_nat_status_changed(int have_nat)
We have changed our opinion about being NATed in the first place.
struct GN_ExternalIPMonitor * GN_external_ipv4_monitor_start(GN_NotifyExternalIPv4Change cb, void *cb_cls)
Start monitoring external IPv4 addresses.
Code to figure out what our external IPv4 address(es) might be (external IPv4s are what is seen on th...
int GN_request_connection_reversal(const struct in_addr *internal_address, uint16_t internal_port, const struct in_addr *remote_v4, const struct GNUNET_CONFIGURATION_Handle *cfg)
We want to connect to a peer that is behind NAT.
struct HelperContext * GN_start_gnunet_nat_server_(const struct in_addr *internal_address, GN_ReversalCallback cb, void *cb_cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
Start the gnunet-helper-nat-server and process incoming requests.
void GN_stop_gnunet_nat_server_(struct HelperContext *h)
Start the gnunet-helper-nat-server and process incoming requests.
runs the gnunet-helper-nat-server
struct GNUNET_NAT_MiniHandle * GNUNET_NAT_mini_map_start(uint16_t port, int is_tcp, GNUNET_NAT_MiniAddressCallback ac, void *ac_cls)
Start mapping the given port using (mini)upnpc.
void GNUNET_NAT_mini_map_stop(struct GNUNET_NAT_MiniHandle *mini)
Remove a mapping created with (mini)upnpc.
int GNUNET_NAT_stun_handle_packet_(const void *data, size_t len, struct sockaddr_in *arg)
Handle an incoming STUN response.
This code provides some support for doing STUN transactions.
struct GNUNET_PQ_ResultSpec __attribute__
Constants for network protocols.
Functions related to doing DNS lookups.
API to create, modify and access statistics.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_yesno(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Get a configuration value that should be in a set of "YES" or "NO".
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_time(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, struct GNUNET_TIME_Relative *time)
Get a configuration value that should be a relative time.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
#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_memcmp(a, b)
Compare memory in a and b, where both must be of the same pointer type.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#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.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
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).
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_MESSAGE
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
#define GNUNET_strndup(a, length)
Wrapper around GNUNET_xstrndup_.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
void GNUNET_MQ_send(struct GNUNET_MQ_Handle *mq, struct GNUNET_MQ_Envelope *ev)
Send a message with the given message queue.
Definition mq.c:337
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
#define GNUNET_MQ_msg_extra(mvar, esize, type)
Allocate an envelope, with extra space allocated after the space needed by the message struct.
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
GNUNET_NAT_StatusCode
Error Types for the NAT subsystem (which can then later be converted/resolved to a string)
GNUNET_NAT_AddressClass
Some addresses contain sensitive information or are not suitable for global distribution.
@ GNUNET_NAT_ERROR_UPNPC_NOT_FOUND
upnpc command not found
@ GNUNET_NAT_ERROR_UPNPC_TIMEOUT
‘upnpc’ command took too long, process killed
@ GNUNET_NAT_ERROR_SUCCESS
Just the default.
@ GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID
‘external-ip’ command output invalid
@ GNUNET_NAT_ERROR_UPNPC_FAILED
Failed to run upnpc command.
@ GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED
Failed to run external-ip command.
@ GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED
‘upnpc’ command failed to establish port mapping
@ GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND
‘external-ip’ command not found
@ GNUNET_NAT_ERROR_IPC_FAILURE
IPC Failure.
@ GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID
"no valid address was returned by `external-ip'"
@ GNUNET_NAT_AC_LAN
Addresses useful in the local wired network, i.e.
@ GNUNET_NAT_AC_GLOBAL
Addresses that are global (i.e.
@ GNUNET_NAT_AC_PRIVATE
Flag for addresses that are highly sensitive (i.e.
@ GNUNET_NAT_AC_EXTERN
Addresses that should be our external IP address on the outside of a NAT.
@ GNUNET_NAT_AC_MANUAL
Addresses that were manually configured by the user.
@ GNUNET_NAT_AC_LOOPBACK
Loopback addresses, only useful under special circumstances.
const struct GNUNET_OS_ProjectData * GNUNET_OS_project_data_gnunet(void)
Return default project data used by 'libgnunetutil' for GNUnet.
void GNUNET_OS_network_interfaces_list(GNUNET_OS_NetworkInterfaceProcessor proc, void *proc_cls)
Enumerate all network interfaces.
Definition os_network.c:397
enum GNUNET_GenericReturnValue GNUNET_OS_check_helper_binary(const char *binary, bool check_suid, const char *params)
Check whether an executable exists and possibly if the suid bit is set on the file.
#define GNUNET_MESSAGE_TYPE_NAT_ADD_GLOBAL_ADDRESS
Message to ask NAT service to notify all clients about a new global address.
#define GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE
Message to from NAT service notifying us that one of our addresses changed.
#define GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED
Message to from NAT service notifying us that connection reversal was requested by another peer.
#define GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
Message to ask NAT service to request connection reversal.
#define GNUNET_MESSAGE_TYPE_NAT_REGISTER
Message to ask NAT service to register a client.
#define GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN
Message to ask NAT service to handle a STUN packet.
struct GNUNET_RESOLVER_RequestHandle * GNUNET_RESOLVER_ip_get(const char *hostname, int af, struct GNUNET_TIME_Relative timeout, GNUNET_RESOLVER_AddressCallback callback, void *callback_cls)
Convert a string to one or more IP addresses.
void GNUNET_RESOLVER_request_cancel(struct GNUNET_RESOLVER_RequestHandle *rh)
Cancel a request that is still pending with the resolver.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
Definition scheduler.c:1345
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition scheduler.c:986
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition scheduler.c:1310
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:1283
#define GNUNET_SERVICE_MAIN(pd, service_name, service_options, init_cb, connect_cb, disconnect_cb, cls,...)
Creates the "main" function for a GNUnet service.
void GNUNET_SERVICE_client_drop(struct GNUNET_SERVICE_Client *c)
Ask the server to disconnect from the given client.
Definition service.c:2463
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition service.c:2434
@ GNUNET_SERVICE_OPTION_NONE
Use defaults.
struct GNUNET_STATISTICS_Handle * GNUNET_STATISTICS_create(const char *subsystem, const struct GNUNET_CONFIGURATION_Handle *cfg)
Get handle for the statistics service.
void GNUNET_STATISTICS_destroy(struct GNUNET_STATISTICS_Handle *h, int sync_first)
Destroy a handle (free all state associated with it).
#define GNUNET_TIME_UNIT_HOURS
One hour.
#define GNUNET_TIME_UNIT_MINUTES
One minute.
GNUNET_NAT_RegisterFlags
Flags specifying the events this client would be interested in being told about.
Definition nat.h:72
@ GNUNET_NAT_RF_ADDRESSES
This client wants to be informed about changes to our applicable addresses.
Definition nat.h:82
#define _(String)
GNU gettext support macro.
Definition platform.h:179
static struct GNUNET_MQ_Handle * mq
Our connection to the resolver service, created on-demand, but then persists until error or shutdown.
static struct GNUNET_TIME_Relative delta
Definition speedup.c:36
Information we track per client address.
struct GNUNET_NAT_MiniHandle * mh
Handle to active UPnP request where we asked upnpc to open a port at the NAT.
struct sockaddr_storage ss
Network address used by the client.
Struct containing information about a client, handle to connect to it, and any pending messages that ...
uint16_t num_caddrs
Number of addresses that this service is bound to.
enum GNUNET_NAT_RegisterFlags flags
What does this client care about?
struct LocalAddressList * ext_addr_tail
DLL of external IP addresses as given in hole_external.
uint8_t proto
Client's IPPROTO, e.g.
char * section_name
Name of the configuration section this client cares about.
struct ClientHandle * prev
Kept in a DLL.
struct ClientHandle * next
Kept in a DLL.
char * hole_external
External DNS name and port given by user due to manual hole punching.
int natted_address
Is any of the caddrs in a reserved subnet for NAT?
struct GNUNET_SERVICE_Client * client
The handle to this client.
struct ClientAddress * caddrs
Array of addresses used by the service.
uint16_t ext_dns_port
Port number we found in hole_external.
struct GNUNET_MQ_Handle * mq
The message queue to this client.
struct GNUNET_RESOLVER_RequestHandle * ext_dns
Handle for (DYN)DNS lookup of our external IP as given in hole_external.
struct LocalAddressList * ext_addr_head
DLL of external IP addresses as given in hole_external.
struct GN_ExternalIPMonitor * external_monitor
Handle for monitoring external IP changes.
struct GNUNET_SCHEDULER_Task * ext_dns_task
Task for periodically re-running the ext_dns DNS lookup.
struct GNUNET_MQ_Handle * mq
Message Queue for the channel (which we are implementing).
Definition cadet.h:142
Handle to a message queue.
Definition mq.c:87
Message sent by client to add a global address.
Definition nat.h:225
struct GNUNET_MessageHeader header
Header with type GNUNET_MESSAGE_TYPE_NAT_ADD_GLOBAL_ADDRESS.
Definition nat.h:229
unsigned int address_length
Length of the address following the struct, in NBO.
Definition nat.h:234
Service notifying the client about changes in the set of addresses it has.
Definition nat.h:202
Service telling a client that connection reversal was requested.
Definition nat.h:187
Client telling the service to (possibly) handle a STUN message.
Definition nat.h:135
struct GNUNET_MessageHeader header
Header with type GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN.
Definition nat.h:139
uint16_t payload_size
Number of bytes of payload included, in NBO.
Definition nat.h:149
uint16_t sender_addr_size
Size of the sender address included, in NBO.
Definition nat.h:144
Handle to a mapping created with upnpc.
Message sent by a client to register with its addresses.
Definition nat.h:95
uint16_t num_addrs
Number of addresses that this service is bound to that follow.
Definition nat.h:122
uint16_t str_len
Number of bytes in the string that follow which specifies a section name in the configuration.
Definition nat.h:115
struct GNUNET_MessageHeader header
Header with type GNUNET_MESSAGE_TYPE_NAT_REGISTER.
Definition nat.h:99
uint8_t flags
An enum GNUNET_NAT_RegisterFlags.
Definition nat.h:104
uint8_t proto
Client's IPPROTO, e.g.
Definition nat.h:109
Client asking the service to initiate connection reversal.
Definition nat.h:161
struct GNUNET_MessageHeader header
Header with type GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL.
Definition nat.h:165
uint16_t local_addr_size
Size of the local address included, in NBO.
Definition nat.h:170
uint16_t remote_addr_size
Size of the remote address included, in NBO.
Definition nat.h:175
Handle to a request given to the resolver.
Entry in list of pending tasks.
Definition scheduler.c:141
Handle to a client that is connected to a service.
Definition service.c:249
Handle to a service.
Definition service.c:116
Handle for the service.
Time for relative time used by GNUnet, in microseconds.
Handle to monitor for external IP changes.
Information we keep per NAT helper process.
Closure for ifc_proc.
struct LocalAddressList * lal_head
Head of DLL of local addresses.
struct LocalAddressList * lal_tail
Tail of DLL of local addresses.
List of local addresses this system has.
struct LocalAddressList * prev
Previous entry.
int old
GNUNET_YES if we saw this one in the previous iteration, but not in the current iteration and thus mi...
struct HelperContext * hc
Context for a gnunet-helper-nat-server used to listen for ICMP messages to this client for connection...
struct LocalAddressList * next
This is a linked list.
int af
Address family.
enum GNUNET_NAT_AddressClass ac
What type of address is this?
struct sockaddr_storage addr
The address itself (i.e.
External IP address as given to us via some STUN server.
struct GNUNET_SCHEDULER_Task * timeout_task
Task we run to remove this entry when it is stale.
size_t stun_server_addr_len
Number of bytes used in stun_server_addr.
struct sockaddr_in external_addr
Our external IP address as reported by the STUN server.
struct sockaddr_storage stun_server_addr
Address of the reporting STUN server.
struct StunExternalIP * next
Kept in a DLL.
struct StunExternalIP * prev
Kept in a DLL.