GNUnet 0.21.1
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 <math.h>
39#include "gnunet_util_lib.h"
40#include "gnunet_protocols.h"
41#include "gnunet_signatures.h"
44#include "gnunet_nat_service.h"
45#include "gnunet-service-nat.h"
50#include "nat.h"
51#include <gcrypt.h>
52
53
58#define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
59
63#define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply ( \
64 GNUNET_TIME_UNIT_SECONDS, 5)
65
69#define DYNDNS_FREQUENCY GNUNET_TIME_relative_multiply ( \
70 GNUNET_TIME_UNIT_MINUTES, 7)
71
72
77{
81 struct sockaddr_storage ss;
82
89};
90
91
96{
101
106
112
117 struct sockaddr_storage addr;
118
122 int af;
123
129 int old;
130
135};
136
137
141struct ClientHandle
142{
146 struct ClientHandle *next;
147
151 struct ClientHandle *prev;
152
157
161 struct GNUNET_MQ_Handle *mq;
162
167
177
182
187
193
198
203
208
212 uint16_t ext_dns_port;
213
218
223
228 uint16_t num_caddrs;
229
233 uint8_t proto;
234};
235
236
241{
246
251
256
261 struct sockaddr_in external_addr;
262
268 struct sockaddr_storage stun_server_addr;
269
274};
275
276
281
286
290static const struct GNUNET_CONFIGURATION_Handle *cfg;
291
296
301
305static struct ClientHandle *ch_head;
306
310static struct ClientHandle *ch_tail;
311
316
321
325static struct StunExternalIP *se_head;
326
330static struct StunExternalIP *se_tail;
331
337
343
349static void
351{
353 lal_tail,
354 lal);
355 if (NULL != lal->hc)
356 {
358 "Lost NATed local address %s, stopping NAT server\n",
359 GNUNET_a2s ((const struct sockaddr *) &lal->addr,
360 sizeof(struct sockaddr_in)));
361
363 lal->hc = NULL;
364 }
365 GNUNET_free (lal);
366}
367
368
372static void
374{
375 struct LocalAddressList *lal;
376
377 while (NULL != (lal = lal_head))
378 free_lal (lal);
379}
380
381
390static int
391check_register (void *cls,
392 const struct GNUNET_NAT_RegisterMessage *message)
393{
394 uint16_t num_addrs = ntohs (message->num_addrs);
395 const char *off = (const char *) &message[1];
396 size_t left = ntohs (message->header.size) - sizeof(*message);
397
398 for (unsigned int i = 0; i < num_addrs; i++)
399 {
400 size_t alen;
401 const struct sockaddr *sa = (const struct sockaddr *) off;
402
403 if (sizeof(sa_family_t) > left)
404 {
405 GNUNET_break (0);
406 return GNUNET_SYSERR;
407 }
408 switch (sa->sa_family)
409 {
410 case AF_INET:
411 alen = sizeof(struct sockaddr_in);
412 break;
413
414 case AF_INET6:
415 alen = sizeof(struct sockaddr_in6);
416 break;
417
418#if AF_UNIX
419 case AF_UNIX:
420 alen = sizeof(struct sockaddr_un);
421 break;
422#endif
423 default:
424 GNUNET_break (0);
425 return GNUNET_SYSERR;
426 }
427 if (alen > left)
428 {
429 GNUNET_break (0);
430 return GNUNET_SYSERR;
431 }
432 off += alen;
433 left -= alen;
434 }
435 if (left != ntohs (message->str_len))
436 {
437 GNUNET_break (0);
438 return GNUNET_SYSERR;
439 }
440 return GNUNET_OK;
441}
442
443
452static int
453match_ipv4 (const char *network,
454 const struct in_addr *ip,
455 uint8_t bits)
456{
457 struct in_addr net;
458
459 if (0 == ip->s_addr)
460 return GNUNET_YES;
461 if (0 == bits)
462 return GNUNET_YES;
463 GNUNET_assert (1 == inet_pton (AF_INET,
464 network,
465 &net));
466 return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
467}
468
469
478static int
479match_ipv6 (const char *network,
480 const struct in6_addr *ip,
481 uint8_t bits)
482{
483 struct in6_addr net;
484 struct in6_addr mask;
485 unsigned int off;
486
487 if (0 == bits)
488 return GNUNET_YES;
489 GNUNET_assert (1 == inet_pton (AF_INET6,
490 network,
491 &net));
492 memset (&mask, 0, sizeof(mask));
493 if (0 == GNUNET_memcmp (&mask,
494 ip))
495 return GNUNET_YES;
496 off = 0;
497 while (bits > 8)
498 {
499 mask.s6_addr[off++] = 0xFF;
500 bits -= 8;
501 }
502 while (bits > 0)
503 {
504 mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
505 bits--;
506 }
507 for (unsigned j = 0; j < sizeof(struct in6_addr) / sizeof(uint32_t); j++)
508 if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
509 (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
510 return GNUNET_NO;
511 return GNUNET_YES;
512}
513
514
522static int
523is_nat_v4 (const struct in_addr *ip)
524{
525 return
526 match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
527 match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
528 match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
529 match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
530 match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
531}
532
533
541static int
542is_nat_v6 (const struct in6_addr *ip)
543{
544 return
545 match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
546 match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
547 match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
548}
549
550
555{
560
565};
566
567
581static int
582ifc_proc (void *cls,
583 const char *name,
584 int isDefault,
585 const struct sockaddr *addr,
586 const struct sockaddr *broadcast_addr,
587 const struct sockaddr *netmask,
588 socklen_t addrlen)
589{
590 struct IfcProcContext *ifc_ctx = cls;
591 struct LocalAddressList *lal;
592 size_t alen;
593 const struct in_addr *ip4;
594 const struct in6_addr *ip6;
596
597 switch (addr->sa_family)
598 {
599 case AF_INET:
600 alen = sizeof(struct sockaddr_in);
601 ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
602 if (match_ipv4 ("127.0.0.0", ip4, 8))
604 else if (is_nat_v4 (ip4))
606 else
608 break;
609
610 case AF_INET6:
611 alen = sizeof(struct sockaddr_in6);
612 ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
613 if (match_ipv6 ("::1", ip6, 128))
615 else if (is_nat_v6 (ip6))
617 else
619 if ((ip6->s6_addr[11] == 0xFF) &&
620 (ip6->s6_addr[12] == 0xFE))
621 {
622 /* contains a MAC, be extra careful! */
624 }
625 break;
626
627#if AF_UNIX
628 case AF_UNIX:
629 GNUNET_break (0);
630 return GNUNET_OK;
631#endif
632 default:
633 GNUNET_break (0);
634 return GNUNET_OK;
635 }
636 lal = GNUNET_malloc (sizeof(*lal));
637 lal->af = addr->sa_family;
638 lal->ac = ac;
639 GNUNET_memcpy (&lal->addr,
640 addr,
641 alen);
643 ifc_ctx->lal_tail,
644 lal);
645 return GNUNET_OK;
646}
647
648
659static void
661 struct ClientHandle *ch,
662 int add,
663 const void *addr,
664 size_t addr_len)
665{
666 struct GNUNET_MQ_Envelope *env;
668
670 "Notifying client about %s of IP %s\n",
671 add ? "addition" : "removal",
672 GNUNET_a2s (addr,
673 addr_len));
675 addr_len,
677 msg->add_remove = htonl (add);
678 msg->addr_class = htonl (ac);
679 GNUNET_memcpy (&msg[1],
680 addr,
681 addr_len);
683 env);
684}
685
686
695static void
697 struct ClientHandle *ch,
698 int add)
699{
700 size_t alen;
701 struct sockaddr_in v4;
702 struct sockaddr_in6 v6;
703
704 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
705 {
707 "Not notifying client as it does not care about addresses\n");
708 return;
709 }
710 switch (delta->af)
711 {
712 case AF_INET:
713 alen = sizeof(struct sockaddr_in);
714 GNUNET_memcpy (&v4,
715 &delta->addr,
716 alen);
717
718 /* Check for client notifications */
719 for (unsigned int i = 0; i < ch->num_caddrs; i++)
720 {
721 const struct sockaddr_in *c4;
722
723 if (AF_INET != ch->caddrs[i].ss.ss_family)
724 continue; /* IPv4 not relevant */
725 c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss;
726 if (match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) &&
727 (0 != c4->sin_addr.s_addr) &&
728 (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)))
729 continue; /* bound to loopback, but this is not loopback */
730 if ((! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8)) &&
731 match_ipv4 ("127.0.0.1", &v4.sin_addr, 8))
732 continue; /* bound to non-loopback, but this is loopback */
733 if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
734 (0 != c4->sin_addr.s_addr) &&
735 (! is_nat_v4 (&v4.sin_addr)))
736 continue; /* based on external-IP, but this IP is not
737 from private address range. */
738 if ((0 != GNUNET_memcmp (&v4.sin_addr,
739 &c4->sin_addr)) &&
740 (0 != c4->sin_addr.s_addr) &&
741 (! is_nat_v4 (&c4->sin_addr)))
742 continue; /* this IP is not from private address range,
743 and IP does not match. */
744
745 /* OK, IP seems relevant, notify client */
746 if (0 == htons (v4.sin_port))
747 v4.sin_port = c4->sin_port;
748 notify_client (delta->ac,
749 ch,
750 add,
751 &v4,
752 alen);
753 }
754 break;
755
756 case AF_INET6:
757 alen = sizeof(struct sockaddr_in6);
758 GNUNET_memcpy (&v6,
759 &delta->addr,
760 alen);
761 for (unsigned int i = 0; i < ch->num_caddrs; i++)
762 {
763 const struct sockaddr_in6 *c6;
764
765 if (AF_INET6 != ch->caddrs[i].ss.ss_family)
766 continue; /* IPv4 not relevant */
767 c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss;
768 if (match_ipv6 ("::1", &c6->sin6_addr, 128) &&
769 (0 != GNUNET_memcmp (&c6->sin6_addr,
770 &in6addr_any)) &&
771 (! match_ipv6 ("::1", &v6.sin6_addr, 128)))
772 continue; /* bound to loopback, but this is not loopback */
773 if ((! match_ipv6 ("::1", &c6->sin6_addr, 128)) &&
774 match_ipv6 ("::1", &v6.sin6_addr, 128))
775 continue; /* bound to non-loopback, but this is loopback */
776 if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
777 (0 != GNUNET_memcmp (&c6->sin6_addr,
778 &in6addr_any)) &&
779 (! is_nat_v6 (&v6.sin6_addr)))
780 continue; /* based on external-IP, but this IP is not
781 from private address range. */
782 if ((0 != GNUNET_memcmp (&v6.sin6_addr,
783 &c6->sin6_addr)) &&
784 (0 != GNUNET_memcmp (&c6->sin6_addr,
785 &in6addr_any)) &&
786 (! is_nat_v6 (&c6->sin6_addr)))
787 continue; /* this IP is not from private address range,
788 and IP does not match. */
789 if ((match_ipv6 ("fe80::", &c6->sin6_addr, 10)) &&
790 (0 != GNUNET_memcmp (&c6->sin6_addr,
791 &in6addr_any)) &&
792 (0 != GNUNET_memcmp (&v6.sin6_addr,
793 &c6->sin6_addr)) &&
794 (0 == (delta->ac & GNUNET_NAT_AC_EXTERN)))
795 continue; /* client bound to link-local, and the other address
796 does not match and is not an external IP */
797
798 /* OK, IP seems relevant, notify client */
799 if (0 == htons (v6.sin6_port))
800 v6.sin6_port = c6->sin6_port;
801 notify_client (delta->ac,
802 ch,
803 add,
804 &v6,
805 alen);
806 }
807 break;
808
809 default:
810 GNUNET_break (0);
811 return;
812 }
813}
814
815
823static void
825 int add)
826{
827 for (struct ClientHandle *ch = ch_head;
828 NULL != ch;
829 ch = ch->next)
831 ch,
832 add);
833}
834
835
844static void
846 const struct in_addr *v4,
847 int add)
848{
849 struct ClientHandle *ch = cls;
850 struct sockaddr_in sa;
851 int have_v4;
852
853 /* (0) check if this impacts 'hole_external' */
854 if ((NULL != ch->hole_external) &&
855 (0 == strcasecmp (ch->hole_external,
856 "AUTO")))
857 {
858 struct LocalAddressList lal;
859 struct sockaddr_in *s4;
860
862 "Detected eternal IP, can now back-fill AUTO:%u in hole punching specification of `%s'\n",
863 (unsigned int) ch->ext_dns_port,
864 ch->section_name);
865 memset (&lal, 0, sizeof(lal));
866 s4 = (struct sockaddr_in *) &lal.addr;
867 s4->sin_family = AF_INET;
868 s4->sin_port = htons (ch->ext_dns_port);
869 s4->sin_addr = *v4;
870 lal.af = AF_INET;
873 ch,
874 add);
875 }
876
877 /* (1) check if client cares. */
878 if (! ch->natted_address)
879 return;
880 have_v4 = GNUNET_NO;
881 for (unsigned int i = 0; i < ch->num_caddrs; i++)
882 {
883 const struct sockaddr_storage *ss = &ch->caddrs[i].ss;
884
885 if (AF_INET != ss->ss_family)
886 continue;
887 have_v4 = GNUNET_YES;
888 break;
889 }
890 if (GNUNET_NO == have_v4)
891 return; /* IPv6-only */
892
893 /* (2) build address info */
894 memset (&sa,
895 0,
896 sizeof(sa));
897 sa.sin_family = AF_INET;
898 sa.sin_addr = *v4;
899 sa.sin_port = htons (0);
900
902 "Detected eternal IP %s, notifying client of external IP (without port)\n",
903 GNUNET_a2s ((const struct sockaddr *) &sa,
904 sizeof(sa)));
905 /* (3) notify client of change */
909 ch,
910 add,
911 &sa,
912 sizeof(sa));
913}
914
915
923static void
925 const struct sockaddr_in *ra)
926{
927 struct LocalAddressList *lal = cls;
928 const struct sockaddr_in *l4;
929
930 GNUNET_assert (AF_INET == lal->af);
931 l4 = (const struct sockaddr_in *) &lal->addr;
932 for (struct ClientHandle *ch = ch_head;
933 NULL != ch;
934 ch = ch->next)
935 {
937 struct GNUNET_MQ_Envelope *env;
938 int match;
939
940 /* Check if client is in applicable range for ICMP NAT traversal
941 for this local address */
942 if (! ch->natted_address)
943 continue;
944 match = GNUNET_NO;
945 for (unsigned int i = 0; i < ch->num_caddrs; i++)
946 {
947 struct ClientAddress *ca = &ch->caddrs[i];
948 const struct sockaddr_in *c4;
949
950 if (AF_INET != ca->ss.ss_family)
951 continue;
952 c4 = (const struct sockaddr_in *) &ca->ss;
953 if ((0 != c4->sin_addr.s_addr) &&
954 (l4->sin_addr.s_addr != c4->sin_addr.s_addr))
955 continue;
956 match = GNUNET_YES;
957 break;
958 }
959 if (! match)
960 continue;
961
962 /* Notify applicable client about connection reversal request */
963 env = GNUNET_MQ_msg_extra (crrm,
964 sizeof(struct sockaddr_in),
966 GNUNET_memcpy (&crrm[1],
967 ra,
968 sizeof(struct sockaddr_in));
970 env);
971 }
972}
973
974
980static void
981run_scan (void *cls)
982{
983 struct IfcProcContext ifc_ctx;
984 int found;
985 int have_nat;
986 struct LocalAddressList *lnext;
987
989 &run_scan,
990 NULL);
991 memset (&ifc_ctx,
992 0,
993 sizeof(ifc_ctx));
995 &ifc_ctx);
996 /* remove addresses that disappeared */
997 for (struct LocalAddressList *lal = lal_head;
998 NULL != lal;
999 lal = lnext)
1000 {
1001 lnext = lal->next;
1002 found = GNUNET_NO;
1003 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1004 NULL != pos;
1005 pos = pos->next)
1006 {
1007 if ((pos->af == lal->af) &&
1008 (0 == memcmp (&lal->addr,
1009 &pos->addr,
1010 (AF_INET == lal->af)
1011 ? sizeof(struct sockaddr_in)
1012 : sizeof(struct sockaddr_in6))))
1013 {
1014 found = GNUNET_YES;
1015 }
1016 }
1017 if (GNUNET_NO == found)
1018 {
1019 notify_clients (lal,
1020 GNUNET_NO);
1021 free_lal (lal);
1022 }
1023 }
1024
1025 /* add addresses that appeared */
1026 have_nat = GNUNET_NO;
1027 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1028 NULL != pos;
1029 pos = ifc_ctx.lal_head)
1030 {
1031 found = GNUNET_NO;
1032 if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac))
1033 have_nat = GNUNET_YES;
1034 for (struct LocalAddressList *lal = lal_head;
1035 NULL != lal;
1036 lal = lal->next)
1037 {
1038 if ((pos->af == lal->af) &&
1039 (0 == memcmp (&lal->addr,
1040 &pos->addr,
1041 (AF_INET == lal->af)
1042 ? sizeof(struct sockaddr_in)
1043 : sizeof(struct sockaddr_in6))))
1044 found = GNUNET_YES;
1045 }
1047 ifc_ctx.lal_tail,
1048 pos);
1049 if (GNUNET_YES == found)
1050 {
1051 GNUNET_free (pos);
1052 }
1053 else
1054 {
1055 notify_clients (pos,
1056 GNUNET_YES);
1058 lal_tail,
1059 pos);
1060 if ((AF_INET == pos->af) &&
1061 (NULL == pos->hc) &&
1062 (0 != (GNUNET_NAT_AC_LAN & pos->ac)))
1063 {
1064 const struct sockaddr_in *s4
1065 = (const struct sockaddr_in *) &pos->addr;
1066
1068 "Found NATed local address %s, starting NAT server\n",
1069 GNUNET_a2s ((const struct sockaddr *) &pos->addr,
1070 sizeof(*s4)));
1071 pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
1073 pos,
1074 cfg);
1075 }
1076 }
1077 }
1078 GN_nat_status_changed (have_nat);
1079}
1080
1081
1093static void
1095 int add_remove,
1096 const struct sockaddr *addr,
1097 socklen_t addrlen,
1099{
1100 struct ClientHandle *ch = cls;
1102
1103 switch (result)
1104 {
1106 GNUNET_assert (NULL != addr);
1107 break;
1108
1113 "Running upnpc failed: %d\n",
1114 result);
1115 return;
1116
1119 "external-ip binary not found\n");
1120 return;
1121
1124 "upnpc binary not found\n");
1125 return;
1126
1129 "external-ip binary could not be run\n");
1130 return;
1131
1134 "upnpc failed to create port mapping\n");
1135 return;
1136
1139 "Invalid output from upnpc\n");
1140 return;
1141
1144 "Invalid address returned by upnpc\n");
1145 return;
1146
1147 default:
1148 GNUNET_break (0); /* should not be possible */
1149 return;
1150 }
1151 switch (addr->sa_family)
1152 {
1153 case AF_INET:
1154 ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr)
1157 break;
1158
1159 case AF_INET6:
1160 ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr)
1163 break;
1164
1165 default:
1166 GNUNET_break (0);
1167 return;
1168 }
1170 "upnp external address %s: %s\n",
1171 add_remove ? "added" : "removed",
1172 GNUNET_a2s (addr,
1173 addrlen));
1174 notify_client (ac,
1175 ch,
1176 add_remove,
1177 addr,
1178 addrlen);
1179}
1180
1181
1190static void
1191dyndns_lookup (void *cls);
1192
1193
1203static void
1205 const struct sockaddr *addr,
1206 socklen_t addrlen)
1207{
1208 struct ClientHandle *ch = cls;
1209 struct LocalAddressList *lal;
1210 struct sockaddr_storage ss;
1211 struct sockaddr_in *v4;
1212 struct sockaddr_in6 *v6;
1213
1214 if (NULL == addr)
1215 {
1216 struct LocalAddressList *laln;
1217
1218 ch->ext_dns = NULL;
1219 ch->ext_dns_task
1222 ch);
1223 /* Current iteration is over, remove 'old' IPs now */
1224 for (lal = ch->ext_addr_head; NULL != lal; lal = laln)
1225 {
1226 laln = lal->next;
1227 if (GNUNET_YES == lal->old)
1228 {
1229 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
1230 ch->ext_addr_tail,
1231 lal);
1233 ch,
1234 GNUNET_NO);
1235 GNUNET_free (lal);
1236 }
1237 }
1238 return;
1239 }
1241 "Got IP `%s' for external address `%s'\n",
1243 addrlen),
1244 ch->hole_external);
1245
1246 /* build sockaddr storage with port number */
1247 memset (&ss,
1248 0,
1249 sizeof(ss));
1250 GNUNET_memcpy (&ss,
1251 addr,
1252 addrlen);
1253 switch (addr->sa_family)
1254 {
1255 case AF_INET:
1256 v4 = (struct sockaddr_in *) &ss;
1257 v4->sin_port = htons (ch->ext_dns_port);
1258 break;
1259
1260 case AF_INET6:
1261 v6 = (struct sockaddr_in6 *) &ss;
1262 v6->sin6_port = htons (ch->ext_dns_port);
1263 break;
1264
1265 default:
1266 GNUNET_break (0);
1267 return;
1268 }
1269 /* See if 'ss' matches any of our known addresses */
1270 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1271 {
1272 if (GNUNET_NO == lal->old)
1273 continue; /* already processed, skip */
1274 if ((addr->sa_family == lal->addr.ss_family) &&
1275 (0 == memcmp (&ss,
1276 &lal->addr,
1277 addrlen)))
1278 {
1279 /* Address unchanged, remember so we do not remove */
1280 lal->old = GNUNET_NO;
1281 return; /* done here */
1282 }
1283 }
1284 /* notify client, and remember IP for later removal! */
1285 lal = GNUNET_new (struct LocalAddressList);
1286 lal->addr = ss;
1287 lal->af = ss.ss_family;
1289 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1290 ch->ext_addr_tail,
1291 lal);
1293 ch,
1294 GNUNET_YES);
1295}
1296
1297
1306static void
1307dyndns_lookup (void *cls)
1308{
1309 struct ClientHandle *ch = cls;
1310 struct LocalAddressList *lal;
1311
1313 "Performing DNS lookup for punched hole given for `%s' as `%s:%u'\n",
1314 ch->section_name,
1315 ch->hole_external,
1316 (unsigned int) ch->ext_dns_port);
1317 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1318 lal->old = GNUNET_YES;
1319 ch->ext_dns_task = NULL;
1320 ch->ext_dns = GNUNET_RESOLVER_ip_get (ch->hole_external,
1321 AF_UNSPEC,
1324 ch);
1325}
1326
1327
1339static void
1341{
1342 char *port;
1343 unsigned int pnum;
1344 struct sockaddr_in *s4;
1345 struct LocalAddressList *lal;
1346
1347 port = strrchr (ch->hole_external, ':');
1348 if (NULL == port)
1349 {
1351 _ ("Malformed punched hole specification `%s' (lacks port)\n"),
1352 ch->hole_external);
1353 return;
1354 }
1355 if ((1 != sscanf (port + 1,
1356 "%u",
1357 &pnum)) ||
1358 (pnum > 65535))
1359 {
1361 _ (
1362 "Invalid port number in punched hole specification `%s' (lacks port)\n"),
1363 port + 1);
1364 return;
1365 }
1366 ch->ext_dns_port = (uint16_t) pnum;
1367 *port = '\0';
1368
1369 lal = GNUNET_new (struct LocalAddressList);
1370 if ('[' == *ch->hole_external)
1371 {
1372 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &lal->addr;
1373
1374 s6->sin6_family = AF_INET6;
1375 if (']' != (ch->hole_external[strlen (ch->hole_external) - 1]))
1376 {
1378 _ ("Malformed punched hole specification `%s' (lacks `]')\n"),
1379 ch->hole_external);
1380 GNUNET_free (lal);
1381 return;
1382 }
1383 ch->hole_external[strlen (ch->hole_external) - 1] = '\0';
1384 if (1 != inet_pton (AF_INET6,
1385 ch->hole_external + 1,
1386 &s6->sin6_addr))
1387 {
1389 _ (
1390 "Malformed punched hole specification `%s' (IPv6 address invalid)"),
1391 ch->hole_external + 1);
1392 GNUNET_free (lal);
1393 return;
1394 }
1395 s6->sin6_port = htons (ch->ext_dns_port);
1396 lal->af = AF_INET6;
1398 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1399 ch->ext_addr_tail,
1400 lal);
1402 ch,
1403 GNUNET_YES);
1404 return;
1405 }
1406
1407 s4 = (struct sockaddr_in *) &lal->addr;
1408 s4->sin_family = AF_INET;
1409 if (1 == inet_pton (AF_INET,
1410 ch->hole_external,
1411 &s4->sin_addr))
1412 {
1414 "IPv4 punched hole given for `%s' via `%s:%u'\n",
1415 ch->section_name,
1416 ch->hole_external,
1417 (unsigned int) ch->ext_dns_port);
1418 s4->sin_port = htons (ch->ext_dns_port);
1419 lal->af = AF_INET;
1421 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1422 ch->ext_addr_tail,
1423 lal);
1425 ch,
1426 GNUNET_YES);
1427 return;
1428 }
1429 if (0 == strcasecmp (ch->hole_external,
1430 "AUTO"))
1431 {
1432 /* handled in #notify_client_external_ipv4_change() */
1433 GNUNET_free (lal);
1434 return;
1435 }
1436 /* got a DNS name, trigger lookup! */
1437 GNUNET_free (lal);
1438 ch->ext_dns_task
1440 ch);
1441}
1442
1443
1451static void
1453 const struct GNUNET_NAT_RegisterMessage *message)
1454{
1455 struct ClientHandle *ch = cls;
1456 const char *off;
1457 size_t left;
1458
1459 if ((0 != ch->proto) ||
1460 (NULL != ch->caddrs))
1461 {
1462 /* double registration not allowed */
1463 GNUNET_break (0);
1465 return;
1466 }
1467 ch->flags = message->flags;
1468 ch->proto = message->proto;
1469 ch->num_caddrs = ntohs (message->num_addrs);
1470 ch->caddrs = GNUNET_new_array (ch->num_caddrs,
1471 struct ClientAddress);
1472 left = ntohs (message->header.size) - sizeof(*message);
1473 off = (const char *) &message[1];
1474 for (unsigned int i = 0; i < ch->num_caddrs; i++)
1475 {
1476 const struct sockaddr *sa = (const struct sockaddr *) off;
1477 size_t alen;
1478 uint16_t port;
1479 int is_nat;
1480
1481 if (sizeof(sa_family_t) > left)
1482 {
1483 GNUNET_break (0);
1485 return;
1486 }
1487 is_nat = GNUNET_NO;
1488 switch (sa->sa_family)
1489 {
1490 case AF_INET:
1491 {
1492 struct sockaddr_in s4;
1493
1494 GNUNET_memcpy (&s4,
1495 off,
1496 sizeof(struct sockaddr_in));
1497 alen = sizeof(struct sockaddr_in);
1498 if (is_nat_v4 (&s4.sin_addr))
1499 is_nat = GNUNET_YES;
1500 port = ntohs (s4.sin_port);
1501 }
1502 break;
1503
1504 case AF_INET6:
1505 {
1506 struct sockaddr_in6 s6;
1507
1508 GNUNET_memcpy (&s6,
1509 off,
1510 sizeof(struct sockaddr_in6));
1511 alen = sizeof(struct sockaddr_in6);
1512 if (is_nat_v6 (&s6.sin6_addr))
1513 is_nat = GNUNET_YES;
1514 port = ntohs (s6.sin6_port);
1515 }
1516 break;
1517
1518#if AF_UNIX
1519 case AF_UNIX:
1520 alen = sizeof(struct sockaddr_un);
1521 port = 0;
1522 break;
1523#endif
1524 default:
1525 GNUNET_break (0);
1527 return;
1528 }
1529 /* store address */
1530 GNUNET_assert (alen <= left);
1531 GNUNET_assert (alen <= sizeof(struct sockaddr_storage));
1532 GNUNET_memcpy (&ch->caddrs[i].ss,
1533 off,
1534 alen);
1535
1536 /* If applicable, try UPNPC NAT punching */
1537 if ((is_nat) &&
1538 (enable_upnp) &&
1539 ((IPPROTO_TCP == ch->proto) ||
1540 (IPPROTO_UDP == ch->proto)))
1541 {
1542 ch->natted_address = GNUNET_YES;
1543 ch->caddrs[i].mh
1545 IPPROTO_TCP == ch->proto,
1547 ch);
1548 }
1549
1550 off += alen;
1551 }
1552
1553 ch->section_name
1554 = GNUNET_strndup (off,
1555 ntohs (message->str_len));
1557 "Received REGISTER message from client for subsystem `%s'\n",
1558 ch->section_name);
1559 if (GNUNET_OK ==
1561 ch->section_name,
1562 "HOLE_EXTERNAL",
1563 &ch->hole_external))
1565
1566 /* Actually send IP address list to client */
1567 for (struct LocalAddressList *lal = lal_head;
1568 NULL != lal;
1569 lal = lal->next)
1570 {
1572 ch,
1573 GNUNET_YES);
1574 }
1575 /* Also consider IPv4 determined by `external-ip` */
1576 ch->external_monitor
1578 ch);
1580}
1581
1582
1591static int
1592check_stun (void *cls,
1593 const struct GNUNET_NAT_HandleStunMessage *message)
1594{
1595 size_t sa_len = ntohs (message->sender_addr_size);
1596 size_t expect = sa_len + ntohs (message->payload_size);
1597
1598 if (ntohs (message->header.size) - sizeof(*message) != expect)
1599 {
1600 GNUNET_break (0);
1601 return GNUNET_SYSERR;
1602 }
1603 if (sa_len < sizeof(sa_family_t))
1604 {
1605 GNUNET_break (0);
1606 return GNUNET_SYSERR;
1607 }
1608 return GNUNET_OK;
1609}
1610
1611
1619static void
1620notify_clients_stun_change (const struct sockaddr_in *ip,
1621 int add)
1622{
1623 for (struct ClientHandle *ch = ch_head;
1624 NULL != ch;
1625 ch = ch->next)
1626 {
1627 struct sockaddr_in v4;
1629 struct GNUNET_MQ_Envelope *env;
1630
1631 if (! ch->natted_address)
1632 continue;
1633 v4 = *ip;
1634 v4.sin_port = htons (0);
1636 sizeof(v4),
1638 msg->add_remove = htonl ((int32_t) add);
1639 msg->addr_class = htonl (GNUNET_NAT_AC_EXTERN
1641 GNUNET_memcpy (&msg[1],
1642 &v4,
1643 sizeof(v4));
1645 env);
1646 }
1647}
1648
1649
1657static void
1659{
1660 struct StunExternalIP *se = cls;
1661
1662 se->timeout_task = NULL;
1664 GNUNET_NO);
1666 se_tail,
1667 se);
1668 GNUNET_free (se);
1669}
1670
1671
1679static void
1680handle_stun (void *cls,
1681 const struct GNUNET_NAT_HandleStunMessage *message)
1682{
1683 struct ClientHandle *ch = cls;
1684 const char *buf = (const char *) &message[1];
1685 const struct sockaddr *sa;
1686 const void *payload;
1687 size_t sa_len;
1688 size_t payload_size;
1689 struct sockaddr_in external_addr;
1690
1691 sa_len = ntohs (message->sender_addr_size);
1692 payload_size = ntohs (message->payload_size);
1693 sa = (const struct sockaddr *) &buf[0];
1694 payload = (const struct sockaddr *) &buf[sa_len];
1695 switch (sa->sa_family)
1696 {
1697 case AF_INET:
1698 if (sa_len != sizeof(struct sockaddr_in))
1699 {
1700 GNUNET_break (0);
1702 return;
1703 }
1704 break;
1705
1706 case AF_INET6:
1707 if (sa_len != sizeof(struct sockaddr_in6))
1708 {
1709 GNUNET_break (0);
1711 return;
1712 }
1713 break;
1714 }
1716 "Received HANDLE_STUN message from client\n");
1717 if (GNUNET_OK ==
1719 payload_size,
1720 &external_addr))
1721 {
1722 /* We now know that a server at "sa" claims that
1723 we are visible at IP "external_addr".
1724
1725 We should (for some fixed period of time) tell
1726 all of our clients that listen to a NAT'ed address
1727 that they might want to consider the given 'external_ip'
1728 as their public IP address (this includes TCP and UDP
1729 clients, even if only UDP sends STUN requests).
1730
1731 If we do not get a renewal, the "external_addr" should be
1732 removed again. The timeout frequency should be configurable
1733 (with a sane default), so that the UDP plugin can tell how
1734 often to re-request STUN.
1735 */struct StunExternalIP *se;
1736
1737 /* Check if we had a prior response from this STUN server */
1738 for (se = se_head; NULL != se; se = se->next)
1739 {
1740 if ((se->stun_server_addr_len != sa_len) ||
1741 (0 != memcmp (sa,
1742 &se->stun_server_addr,
1743 sa_len)))
1744 continue; /* different STUN server */
1745 if (0 != GNUNET_memcmp (&external_addr,
1746 &se->external_addr))
1747 {
1748 /* external IP changed, update! */
1750 GNUNET_NO);
1753 GNUNET_YES);
1754 }
1755 /* update timeout */
1757 se->timeout_task
1760 se);
1761 return;
1762 }
1763 /* STUN server is completely new, create fresh entry */
1764 se = GNUNET_new (struct StunExternalIP);
1767 sa,
1768 sa_len);
1769 se->stun_server_addr_len = sa_len;
1772 se);
1774 se_tail,
1775 se);
1777 GNUNET_NO);
1778 }
1780}
1781
1782
1792static int
1794 const struct
1796 message)
1797{
1798 size_t expect;
1799
1800 expect = ntohs (message->local_addr_size)
1801 + ntohs (message->remote_addr_size);
1802 if (ntohs (message->header.size) - sizeof(*message) != expect)
1803 {
1804 GNUNET_break (0);
1805 return GNUNET_SYSERR;
1806 }
1807 return GNUNET_OK;
1808}
1809
1810
1818static void
1820 const struct
1822 *message)
1823{
1824 struct ClientHandle *ch = cls;
1825 const char *buf = (const char *) &message[1];
1826 size_t local_sa_len = ntohs (message->local_addr_size);
1827 size_t remote_sa_len = ntohs (message->remote_addr_size);
1828 struct sockaddr_in l4;
1829 struct sockaddr_in r4;
1830 int ret;
1831
1833 "Received REQUEST CONNECTION REVERSAL message from client\n");
1834 if (local_sa_len != sizeof(struct sockaddr_in))
1835 {
1836 GNUNET_break_op (0);
1838 return;
1839 }
1840 if (remote_sa_len != sizeof(struct sockaddr_in))
1841 {
1842 GNUNET_break_op (0);
1844 return;
1845 }
1846 GNUNET_memcpy (&l4,
1847 buf,
1848 sizeof(struct sockaddr_in));
1849 GNUNET_break_op (AF_INET == l4.sin_family);
1850 buf += sizeof(struct sockaddr_in);
1851 GNUNET_memcpy (&r4,
1852 buf,
1853 sizeof(struct sockaddr_in));
1854 GNUNET_break_op (AF_INET == r4.sin_family);
1855 ret = GN_request_connection_reversal (&l4.sin_addr,
1856 ntohs (l4.sin_port),
1857 &r4.sin_addr,
1858 cfg);
1859 if (GNUNET_OK != ret)
1861 _ ("Connection reversal request failed\n"));
1863}
1864
1865
1874static int
1876 const struct GNUNET_NAT_AddGlobalAddressMessage *message)
1877{
1878 char *addr = GNUNET_malloc (ntohs (message->address_length));
1879 size_t left = ntohs (message->header.size) - sizeof(*message);
1880
1881 GNUNET_memcpy (addr, (const char *) &message[1], ntohs (message->address_length));
1883 "message size %u natting address %s length %u left %u\n",
1884 ntohs (message->header.size),
1885 addr,
1886 ntohs (message->address_length),
1887 left);
1888
1889 if (left != ntohs (message->address_length))
1890 {
1891 GNUNET_break (0);
1892 return GNUNET_SYSERR;
1893 }
1894 GNUNET_free (addr);
1895 return GNUNET_OK;
1896}
1897
1898
1899static int
1900is_nat_v4 (const struct in_addr *ip);
1901
1902
1903static int
1904is_nat_v6 (const struct in6_addr *ip);
1905
1906
1907static void
1909 struct ClientHandle *ch,
1910 int add,
1911 const void *addr,
1912 size_t addr_len);
1913
1914
1922static void
1924 const struct GNUNET_NAT_AddGlobalAddressMessage *message)
1925{
1926 struct ClientHandle *ch = cls;
1927 char *buf = GNUNET_malloc (ntohs (message->address_length));
1928 //= (const char *) &message[1];
1929 struct sockaddr *sockaddr = NULL;
1930 socklen_t addr_len;
1931 struct sockaddr_in *sockaddr_ipv4 = GNUNET_malloc(sizeof(struct sockaddr_in));
1933
1934 GNUNET_memcpy (buf, (const char *) &message[1], ntohs (message->address_length));
1935 memset(sockaddr_ipv4, 0, sizeof(struct sockaddr_in));
1936 sockaddr_ipv4->sin_family = AF_INET;
1937
1938 if (1 == inet_pton(AF_INET, buf, &(sockaddr_ipv4->sin_addr)))
1939 {
1940 sockaddr = (struct sockaddr *)sockaddr_ipv4;
1941 addr_len = sizeof(struct sockaddr_in);
1942 ac = is_nat_v4 (&((const struct sockaddr_in *)sockaddr_ipv4)->sin_addr)
1945 }
1946 else
1947 {
1948 GNUNET_free(sockaddr_ipv4);
1949 sockaddr_ipv4 = NULL;
1950 }
1951
1952 if (NULL == sockaddr)
1953 {
1954 struct sockaddr_in6 *sockaddr_ipv6 = malloc(sizeof(struct sockaddr_in6));
1955
1956 if (sockaddr_ipv6 != NULL)
1957 {
1958 memset(sockaddr_ipv6, 0, sizeof(struct sockaddr_in6));
1959 sockaddr_ipv6->sin6_family = AF_INET6;
1960
1961 if (1 == inet_pton(AF_INET6, buf, &(sockaddr_ipv6->sin6_addr)))
1962 {
1963 GNUNET_break (0);
1965 GNUNET_free (buf);
1966 return;
1967 }
1968 else
1969 {
1970 GNUNET_free(sockaddr_ipv6);
1971 sockaddr_ipv6 = NULL;
1972 }
1973 }
1974 }
1975
1977 "3 natting address %s\n",
1978 buf);
1979 if (NULL == sockaddr)
1980 {
1981 GNUNET_break (0);
1983 GNUNET_free (buf);
1984 return;
1985 }
1986 notify_clients_stun_change (sockaddr_ipv4, GNUNET_YES);
1988 GNUNET_free (buf);
1989}
1990
1991
1997static void
1998shutdown_task (void *cls)
1999{
2000 struct StunExternalIP *se;
2001
2002 while (NULL != (se = se_head))
2003 {
2005 se_tail,
2006 se);
2008 GNUNET_free (se);
2009 }
2011 if (NULL != scan_task)
2012 {
2014 scan_task = NULL;
2015 }
2016 if (NULL != stats)
2017 {
2019 GNUNET_NO);
2020 stats = NULL;
2021 }
2022 destroy_lal ();
2023}
2024
2025
2033static void
2034run (void *cls,
2035 const struct GNUNET_CONFIGURATION_Handle *c,
2037{
2038 cfg = c;
2039 if (GNUNET_OK !=
2041 "NAT",
2042 "STUN_STALE",
2045
2046 /* Check for UPnP */
2049 "NAT",
2050 "ENABLE_UPNP");
2051 if (GNUNET_YES == enable_upnp)
2052 {
2053 /* check if it works */
2054 if (GNUNET_SYSERR ==
2056 GNUNET_NO,
2057 NULL))
2058 {
2060 _ (
2061 "UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
2063 }
2064 }
2065 if (GNUNET_OK !=
2067 "nat",
2068 "DYNDNS_FREQUENCY",
2071
2074 "NAT",
2075 "ENABLE_IPSCAN");
2076
2078 NULL);
2080 cfg);
2083 NULL);
2084}
2085
2086
2095static void *
2097 struct GNUNET_SERVICE_Client *c,
2098 struct GNUNET_MQ_Handle *mq)
2099{
2100 struct ClientHandle *ch;
2101
2102 ch = GNUNET_new (struct ClientHandle);
2103 ch->mq = mq;
2104 ch->client = c;
2106 ch_tail,
2107 ch);
2108 return ch;
2109}
2110
2111
2119static void
2121 struct GNUNET_SERVICE_Client *c,
2122 void *internal_cls)
2123{
2124 struct ClientHandle *ch = internal_cls;
2125 struct LocalAddressList *lal;
2126
2128 ch_tail,
2129 ch);
2130 for (unsigned int i = 0; i < ch->num_caddrs; i++)
2131 {
2132 if (NULL != ch->caddrs[i].mh)
2133 {
2134 GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh);
2135 ch->caddrs[i].mh = NULL;
2136 }
2137 }
2138 GNUNET_free (ch->caddrs);
2139 while (NULL != (lal = ch->ext_addr_head))
2140 {
2141 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
2142 ch->ext_addr_tail,
2143 lal);
2144 GNUNET_free (lal);
2145 }
2146 if (NULL != ch->ext_dns_task)
2147 {
2148 GNUNET_SCHEDULER_cancel (ch->ext_dns_task);
2149 ch->ext_dns_task = NULL;
2150 }
2151 if (NULL != ch->external_monitor)
2152 {
2153 GN_external_ipv4_monitor_stop (ch->external_monitor);
2154 ch->external_monitor = NULL;
2155 }
2156 if (NULL != ch->ext_dns)
2157 {
2159 ch->ext_dns = NULL;
2160 }
2161 GNUNET_free (ch->hole_external);
2162 GNUNET_free (ch->section_name);
2163 GNUNET_free (ch);
2164}
2165
2166
2171 ("nat",
2173 &run,
2176 NULL,
2177 GNUNET_MQ_hd_var_size (register,
2180 NULL),
2184 NULL),
2185 GNUNET_MQ_hd_var_size (request_connection_reversal,
2188 NULL),
2189 GNUNET_MQ_hd_var_size (add_global_address,
2192 NULL),
2194
2195
2196#if defined(__linux__) && defined(__GLIBC__)
2197#include <malloc.h>
2198
2202void __attribute__ ((constructor))
2203GNUNET_NATM_memory_init ()
2204{
2205 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2206 mallopt (M_TOP_PAD, 1 * 1024);
2207 malloc_trim (0);
2208}
2209
2210
2211#endif
2212
2213/* end of gnunet-service-nat.c */
struct GNUNET_MQ_Handle * mq
Definition: 003.c:5
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:94
static uint16_t port
Port number.
Definition: gnunet-bcd.c:147
static struct GNUNET_CADET_Channel * ch
Channel handle.
Definition: gnunet-cadet.c:117
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 struct GNUNET_TIME_Relative dyndns_frequency
How often do we scan for changes in how our external (dyndns) hostname resolves?
GNUNET_SERVICE_MAIN("nat", GNUNET_SERVICE_OPTION_NONE, &run, &client_connect_cb, &client_disconnect_cb, NULL, GNUNET_MQ_hd_var_size(register, GNUNET_MESSAGE_TYPE_NAT_REGISTER, struct GNUNET_NAT_RegisterMessage, NULL), GNUNET_MQ_hd_var_size(stun, GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN, struct GNUNET_NAT_HandleStunMessage, NULL), GNUNET_MQ_hd_var_size(request_connection_reversal, GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL, struct GNUNET_NAT_RequestConnectionReversalMessage, NULL), GNUNET_MQ_hd_var_size(add_global_address, GNUNET_MESSAGE_TYPE_NAT_ADD_GLOBAL_ADDRESS, struct GNUNET_NAT_AddGlobalAddressMessage, NULL), GNUNET_MQ_handler_end())
Define "main" method using service macro.
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.
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_add_global_address(void *cls, const struct GNUNET_NAT_AddGlobalAddressMessage *message)
Check validity of GNUNET_MESSAGE_TYPE_NAT_ADD_GLOBAL_ADDRESS message from client.
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 shutdown_task(void *cls)
Task run during shutdown.
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_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:304
#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.
Definition: gnunet_mq_lib.h:63
#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.
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.
Definition: resolver_api.c:940
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:1340
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:981
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:1305
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:1278
void GNUNET_SERVICE_client_drop(struct GNUNET_SERVICE_Client *c)
Ask the server to disconnect from the given client.
Definition: service.c:2489
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition: service.c:2408
@ 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:178
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
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
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.
Definition: resolver_api.c:104
Entry in list of pending tasks.
Definition: scheduler.c:136
Handle to a client that is connected to a service.
Definition: service.c:252
Handle to a service.
Definition: service.c:118
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.