GNUnet 0.22.2
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
347static void
349{
351 lal_tail,
352 lal);
353 if (NULL != lal->hc)
354 {
356 "Lost NATed local address %s, stopping NAT server\n",
357 GNUNET_a2s ((const struct sockaddr *) &lal->addr,
358 sizeof(struct sockaddr_in)));
359
361 lal->hc = NULL;
362 }
363 GNUNET_free (lal);
364}
365
366
370static void
372{
373 struct LocalAddressList *lal;
374
375 while (NULL != (lal = lal_head))
376 free_lal (lal);
377}
378
379
388static int
389check_register (void *cls,
390 const struct GNUNET_NAT_RegisterMessage *message)
391{
392 uint16_t num_addrs = ntohs (message->num_addrs);
393 const char *off = (const char *) &message[1];
394 size_t left = ntohs (message->header.size) - sizeof(*message);
395
396 for (unsigned int i = 0; i < num_addrs; i++)
397 {
398 size_t alen;
399 const struct sockaddr *sa = (const struct sockaddr *) off;
400
401 if (sizeof(sa_family_t) > left)
402 {
403 GNUNET_break (0);
404 return GNUNET_SYSERR;
405 }
406 switch (sa->sa_family)
407 {
408 case AF_INET:
409 alen = sizeof(struct sockaddr_in);
410 break;
411
412 case AF_INET6:
413 alen = sizeof(struct sockaddr_in6);
414 break;
415
416#if AF_UNIX
417 case AF_UNIX:
418 alen = sizeof(struct sockaddr_un);
419 break;
420#endif
421 default:
422 GNUNET_break (0);
423 return GNUNET_SYSERR;
424 }
425 if (alen > left)
426 {
427 GNUNET_break (0);
428 return GNUNET_SYSERR;
429 }
430 off += alen;
431 left -= alen;
432 }
433 if (left != ntohs (message->str_len))
434 {
435 GNUNET_break (0);
436 return GNUNET_SYSERR;
437 }
438 return GNUNET_OK;
439}
440
441
450static int
451match_ipv4 (const char *network,
452 const struct in_addr *ip,
453 uint8_t bits)
454{
455 struct in_addr net;
456
457 if (0 == ip->s_addr)
458 return GNUNET_YES;
459 if (0 == bits)
460 return GNUNET_YES;
461 GNUNET_assert (1 == inet_pton (AF_INET,
462 network,
463 &net));
464 return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
465}
466
467
476static int
477match_ipv6 (const char *network,
478 const struct in6_addr *ip,
479 uint8_t bits)
480{
481 struct in6_addr net;
482 struct in6_addr mask;
483 unsigned int off;
484
485 if (0 == bits)
486 return GNUNET_YES;
487 GNUNET_assert (1 == inet_pton (AF_INET6,
488 network,
489 &net));
490 memset (&mask, 0, sizeof(mask));
491 if (0 == GNUNET_memcmp (&mask,
492 ip))
493 return GNUNET_YES;
494 off = 0;
495 while (bits > 8)
496 {
497 mask.s6_addr[off++] = 0xFF;
498 bits -= 8;
499 }
500 while (bits > 0)
501 {
502 mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
503 bits--;
504 }
505 for (unsigned j = 0; j < sizeof(struct in6_addr) / sizeof(uint32_t); j++)
506 if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
507 (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
508 return GNUNET_NO;
509 return GNUNET_YES;
510}
511
512
520static int
521is_nat_v4 (const struct in_addr *ip)
522{
523 return
524 match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
525 match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
526 match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
527 match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
528 match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
529}
530
531
539static int
540is_nat_v6 (const struct in6_addr *ip)
541{
542 return
543 match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
544 match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
545 match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
546}
547
548
553{
558
563};
564
565
579static int
580ifc_proc (void *cls,
581 const char *name,
582 int isDefault,
583 const struct sockaddr *addr,
584 const struct sockaddr *broadcast_addr,
585 const struct sockaddr *netmask,
586 socklen_t addrlen)
587{
588 struct IfcProcContext *ifc_ctx = cls;
589 struct LocalAddressList *lal;
590 size_t alen;
591 const struct in_addr *ip4;
592 const struct in6_addr *ip6;
594
595 switch (addr->sa_family)
596 {
597 case AF_INET:
598 alen = sizeof(struct sockaddr_in);
599 ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
600 if (match_ipv4 ("127.0.0.0", ip4, 8))
602 else if (is_nat_v4 (ip4))
604 else
606 break;
607
608 case AF_INET6:
609 alen = sizeof(struct sockaddr_in6);
610 ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
611 if (match_ipv6 ("::1", ip6, 128))
613 else if (is_nat_v6 (ip6))
615 else
617 if ((ip6->s6_addr[11] == 0xFF) &&
618 (ip6->s6_addr[12] == 0xFE))
619 {
620 /* contains a MAC, be extra careful! */
622 }
623 break;
624
625#if AF_UNIX
626 case AF_UNIX:
627 GNUNET_break (0);
628 return GNUNET_OK;
629#endif
630 default:
631 GNUNET_break (0);
632 return GNUNET_OK;
633 }
634 lal = GNUNET_malloc (sizeof(*lal));
635 lal->af = addr->sa_family;
636 lal->ac = ac;
637 GNUNET_memcpy (&lal->addr,
638 addr,
639 alen);
641 ifc_ctx->lal_tail,
642 lal);
643 return GNUNET_OK;
644}
645
646
657static void
659 struct ClientHandle *ch,
660 int add,
661 const void *addr,
662 size_t addr_len)
663{
664 struct GNUNET_MQ_Envelope *env;
666
668 "Notifying client about %s of IP %s\n",
669 add ? "addition" : "removal",
670 GNUNET_a2s (addr,
671 addr_len));
673 addr_len,
675 msg->add_remove = htonl (add);
676 msg->addr_class = htonl (ac);
677 GNUNET_memcpy (&msg[1],
678 addr,
679 addr_len);
681 env);
682}
683
684
693static void
695 struct ClientHandle *ch,
696 int add)
697{
698 size_t alen;
699 struct sockaddr_in v4;
700 struct sockaddr_in6 v6;
701
702 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
703 {
705 "Not notifying client as it does not care about addresses\n");
706 return;
707 }
708 switch (delta->af)
709 {
710 case AF_INET:
711 alen = sizeof(struct sockaddr_in);
712 GNUNET_memcpy (&v4,
713 &delta->addr,
714 alen);
715
716 /* Check for client notifications */
717 for (unsigned int i = 0; i < ch->num_caddrs; i++)
718 {
719 const struct sockaddr_in *c4;
720
721 if (AF_INET != ch->caddrs[i].ss.ss_family)
722 continue; /* IPv4 not relevant */
723 c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss;
724 if (match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) &&
725 (0 != c4->sin_addr.s_addr) &&
726 (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)))
727 continue; /* bound to loopback, but this is not loopback */
728 if ((! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8)) &&
729 match_ipv4 ("127.0.0.1", &v4.sin_addr, 8))
730 continue; /* bound to non-loopback, but this is loopback */
731 if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
732 (0 != c4->sin_addr.s_addr) &&
733 (! is_nat_v4 (&v4.sin_addr)))
734 continue; /* based on external-IP, but this IP is not
735 from private address range. */
736 if ((0 != GNUNET_memcmp (&v4.sin_addr,
737 &c4->sin_addr)) &&
738 (0 != c4->sin_addr.s_addr) &&
739 (! is_nat_v4 (&c4->sin_addr)))
740 continue; /* this IP is not from private address range,
741 and IP does not match. */
742
743 /* OK, IP seems relevant, notify client */
744 if (0 == htons (v4.sin_port))
745 v4.sin_port = c4->sin_port;
746 notify_client (delta->ac,
747 ch,
748 add,
749 &v4,
750 alen);
751 }
752 break;
753
754 case AF_INET6:
755 alen = sizeof(struct sockaddr_in6);
756 GNUNET_memcpy (&v6,
757 &delta->addr,
758 alen);
759 for (unsigned int i = 0; i < ch->num_caddrs; i++)
760 {
761 const struct sockaddr_in6 *c6;
762
763 if (AF_INET6 != ch->caddrs[i].ss.ss_family)
764 continue; /* IPv4 not relevant */
765 c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss;
766 if (match_ipv6 ("::1", &c6->sin6_addr, 128) &&
767 (0 != GNUNET_memcmp (&c6->sin6_addr,
768 &in6addr_any)) &&
769 (! match_ipv6 ("::1", &v6.sin6_addr, 128)))
770 continue; /* bound to loopback, but this is not loopback */
771 if ((! match_ipv6 ("::1", &c6->sin6_addr, 128)) &&
772 match_ipv6 ("::1", &v6.sin6_addr, 128))
773 continue; /* bound to non-loopback, but this is loopback */
774 if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
775 (0 != GNUNET_memcmp (&c6->sin6_addr,
776 &in6addr_any)) &&
777 (! is_nat_v6 (&v6.sin6_addr)))
778 continue; /* based on external-IP, but this IP is not
779 from private address range. */
780 if ((0 != GNUNET_memcmp (&v6.sin6_addr,
781 &c6->sin6_addr)) &&
782 (0 != GNUNET_memcmp (&c6->sin6_addr,
783 &in6addr_any)) &&
784 (! is_nat_v6 (&c6->sin6_addr)))
785 continue; /* this IP is not from private address range,
786 and IP does not match. */
787 if ((match_ipv6 ("fe80::", &c6->sin6_addr, 10)) &&
788 (0 != GNUNET_memcmp (&c6->sin6_addr,
789 &in6addr_any)) &&
790 (0 != GNUNET_memcmp (&v6.sin6_addr,
791 &c6->sin6_addr)) &&
792 (0 == (delta->ac & GNUNET_NAT_AC_EXTERN)))
793 continue; /* client bound to link-local, and the other address
794 does not match and is not an external IP */
795
796 /* OK, IP seems relevant, notify client */
797 if (0 == htons (v6.sin6_port))
798 v6.sin6_port = c6->sin6_port;
799 notify_client (delta->ac,
800 ch,
801 add,
802 &v6,
803 alen);
804 }
805 break;
806
807 default:
808 GNUNET_break (0);
809 return;
810 }
811}
812
813
821static void
823 int add)
824{
825 for (struct ClientHandle *ch = ch_head;
826 NULL != ch;
827 ch = ch->next)
829 ch,
830 add);
831}
832
833
842static void
844 const struct in_addr *v4,
845 int add)
846{
847 struct ClientHandle *ch = cls;
848 struct sockaddr_in sa;
849 int have_v4;
850
851 /* (0) check if this impacts 'hole_external' */
852 if ((NULL != ch->hole_external) &&
853 (0 == strcasecmp (ch->hole_external,
854 "AUTO")))
855 {
856 struct LocalAddressList lal;
857 struct sockaddr_in *s4;
858
860 "Detected eternal IP, can now back-fill AUTO:%u in hole punching specification of `%s'\n",
861 (unsigned int) ch->ext_dns_port,
862 ch->section_name);
863 memset (&lal, 0, sizeof(lal));
864 s4 = (struct sockaddr_in *) &lal.addr;
865 s4->sin_family = AF_INET;
866 s4->sin_port = htons (ch->ext_dns_port);
867 s4->sin_addr = *v4;
868 lal.af = AF_INET;
871 ch,
872 add);
873 }
874
875 /* (1) check if client cares. */
876 if (! ch->natted_address)
877 return;
878 have_v4 = GNUNET_NO;
879 for (unsigned int i = 0; i < ch->num_caddrs; i++)
880 {
881 const struct sockaddr_storage *ss = &ch->caddrs[i].ss;
882
883 if (AF_INET != ss->ss_family)
884 continue;
885 have_v4 = GNUNET_YES;
886 break;
887 }
888 if (GNUNET_NO == have_v4)
889 return; /* IPv6-only */
890
891 /* (2) build address info */
892 memset (&sa,
893 0,
894 sizeof(sa));
895 sa.sin_family = AF_INET;
896 sa.sin_addr = *v4;
897 sa.sin_port = htons (0);
898
900 "Detected eternal IP %s, notifying client of external IP (without port)\n",
901 GNUNET_a2s ((const struct sockaddr *) &sa,
902 sizeof(sa)));
903 /* (3) notify client of change */
907 ch,
908 add,
909 &sa,
910 sizeof(sa));
911}
912
913
921static void
923 const struct sockaddr_in *ra)
924{
925 struct LocalAddressList *lal = cls;
926 const struct sockaddr_in *l4;
927
928 GNUNET_assert (AF_INET == lal->af);
929 l4 = (const struct sockaddr_in *) &lal->addr;
930 for (struct ClientHandle *ch = ch_head;
931 NULL != ch;
932 ch = ch->next)
933 {
935 struct GNUNET_MQ_Envelope *env;
936 int match;
937
938 /* Check if client is in applicable range for ICMP NAT traversal
939 for this local address */
940 if (! ch->natted_address)
941 continue;
942 match = GNUNET_NO;
943 for (unsigned int i = 0; i < ch->num_caddrs; i++)
944 {
945 struct ClientAddress *ca = &ch->caddrs[i];
946 const struct sockaddr_in *c4;
947
948 if (AF_INET != ca->ss.ss_family)
949 continue;
950 c4 = (const struct sockaddr_in *) &ca->ss;
951 if ((0 != c4->sin_addr.s_addr) &&
952 (l4->sin_addr.s_addr != c4->sin_addr.s_addr))
953 continue;
954 match = GNUNET_YES;
955 break;
956 }
957 if (! match)
958 continue;
959
960 /* Notify applicable client about connection reversal request */
961 env = GNUNET_MQ_msg_extra (crrm,
962 sizeof(struct sockaddr_in),
964 GNUNET_memcpy (&crrm[1],
965 ra,
966 sizeof(struct sockaddr_in));
968 env);
969 }
970}
971
972
978static void
979run_scan (void *cls)
980{
981 struct IfcProcContext ifc_ctx;
982 int found;
983 int have_nat;
984 struct LocalAddressList *lnext;
985
987 &run_scan,
988 NULL);
989 memset (&ifc_ctx,
990 0,
991 sizeof(ifc_ctx));
993 &ifc_ctx);
994 /* remove addresses that disappeared */
995 for (struct LocalAddressList *lal = lal_head;
996 NULL != lal;
997 lal = lnext)
998 {
999 lnext = lal->next;
1000 found = GNUNET_NO;
1001 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1002 NULL != pos;
1003 pos = pos->next)
1004 {
1005 if ((pos->af == lal->af) &&
1006 (0 == memcmp (&lal->addr,
1007 &pos->addr,
1008 (AF_INET == lal->af)
1009 ? sizeof(struct sockaddr_in)
1010 : sizeof(struct sockaddr_in6))))
1011 {
1012 found = GNUNET_YES;
1013 }
1014 }
1015 if (GNUNET_NO == found)
1016 {
1017 notify_clients (lal,
1018 GNUNET_NO);
1019 free_lal (lal);
1020 }
1021 }
1022
1023 /* add addresses that appeared */
1024 have_nat = GNUNET_NO;
1025 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1026 NULL != pos;
1027 pos = ifc_ctx.lal_head)
1028 {
1029 found = GNUNET_NO;
1030 if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac))
1031 have_nat = GNUNET_YES;
1032 for (struct LocalAddressList *lal = lal_head;
1033 NULL != lal;
1034 lal = lal->next)
1035 {
1036 if ((pos->af == lal->af) &&
1037 (0 == memcmp (&lal->addr,
1038 &pos->addr,
1039 (AF_INET == lal->af)
1040 ? sizeof(struct sockaddr_in)
1041 : sizeof(struct sockaddr_in6))))
1042 found = GNUNET_YES;
1043 }
1045 ifc_ctx.lal_tail,
1046 pos);
1047 if (GNUNET_YES == found)
1048 {
1049 GNUNET_free (pos);
1050 }
1051 else
1052 {
1053 notify_clients (pos,
1054 GNUNET_YES);
1056 lal_tail,
1057 pos);
1058 if ((AF_INET == pos->af) &&
1059 (NULL == pos->hc) &&
1060 (0 != (GNUNET_NAT_AC_LAN & pos->ac)))
1061 {
1062 const struct sockaddr_in *s4
1063 = (const struct sockaddr_in *) &pos->addr;
1064
1066 "Found NATed local address %s, starting NAT server\n",
1067 GNUNET_a2s ((const struct sockaddr *) &pos->addr,
1068 sizeof(*s4)));
1069 pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
1071 pos,
1072 cfg);
1073 }
1074 }
1075 }
1076 GN_nat_status_changed (have_nat);
1077}
1078
1079
1091static void
1093 int add_remove,
1094 const struct sockaddr *addr,
1095 socklen_t addrlen,
1097{
1098 struct ClientHandle *ch = cls;
1100
1101 switch (result)
1102 {
1104 GNUNET_assert (NULL != addr);
1105 break;
1106
1111 "Running upnpc failed: %d\n",
1112 result);
1113 return;
1114
1117 "external-ip binary not found\n");
1118 return;
1119
1122 "upnpc binary not found\n");
1123 return;
1124
1127 "external-ip binary could not be run\n");
1128 return;
1129
1132 "upnpc failed to create port mapping\n");
1133 return;
1134
1137 "Invalid output from upnpc\n");
1138 return;
1139
1142 "Invalid address returned by upnpc\n");
1143 return;
1144
1145 default:
1146 GNUNET_break (0); /* should not be possible */
1147 return;
1148 }
1149 switch (addr->sa_family)
1150 {
1151 case AF_INET:
1152 ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr)
1155 break;
1156
1157 case AF_INET6:
1158 ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr)
1161 break;
1162
1163 default:
1164 GNUNET_break (0);
1165 return;
1166 }
1168 "upnp external address %s: %s\n",
1169 add_remove ? "added" : "removed",
1170 GNUNET_a2s (addr,
1171 addrlen));
1172 notify_client (ac,
1173 ch,
1174 add_remove,
1175 addr,
1176 addrlen);
1177}
1178
1179
1188static void
1189dyndns_lookup (void *cls);
1190
1191
1201static void
1203 const struct sockaddr *addr,
1204 socklen_t addrlen)
1205{
1206 struct ClientHandle *ch = cls;
1207 struct LocalAddressList *lal;
1208 struct sockaddr_storage ss;
1209 struct sockaddr_in *v4;
1210 struct sockaddr_in6 *v6;
1211
1212 if (NULL == addr)
1213 {
1214 struct LocalAddressList *laln;
1215
1216 ch->ext_dns = NULL;
1217 ch->ext_dns_task
1220 ch);
1221 /* Current iteration is over, remove 'old' IPs now */
1222 for (lal = ch->ext_addr_head; NULL != lal; lal = laln)
1223 {
1224 laln = lal->next;
1225 if (GNUNET_YES == lal->old)
1226 {
1227 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
1228 ch->ext_addr_tail,
1229 lal);
1231 ch,
1232 GNUNET_NO);
1233 GNUNET_free (lal);
1234 }
1235 }
1236 return;
1237 }
1239 "Got IP `%s' for external address `%s'\n",
1241 addrlen),
1242 ch->hole_external);
1243
1244 /* build sockaddr storage with port number */
1245 memset (&ss,
1246 0,
1247 sizeof(ss));
1248 GNUNET_memcpy (&ss,
1249 addr,
1250 addrlen);
1251 switch (addr->sa_family)
1252 {
1253 case AF_INET:
1254 v4 = (struct sockaddr_in *) &ss;
1255 v4->sin_port = htons (ch->ext_dns_port);
1256 break;
1257
1258 case AF_INET6:
1259 v6 = (struct sockaddr_in6 *) &ss;
1260 v6->sin6_port = htons (ch->ext_dns_port);
1261 break;
1262
1263 default:
1264 GNUNET_break (0);
1265 return;
1266 }
1267 /* See if 'ss' matches any of our known addresses */
1268 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1269 {
1270 if (GNUNET_NO == lal->old)
1271 continue; /* already processed, skip */
1272 if ((addr->sa_family == lal->addr.ss_family) &&
1273 (0 == memcmp (&ss,
1274 &lal->addr,
1275 addrlen)))
1276 {
1277 /* Address unchanged, remember so we do not remove */
1278 lal->old = GNUNET_NO;
1279 return; /* done here */
1280 }
1281 }
1282 /* notify client, and remember IP for later removal! */
1283 lal = GNUNET_new (struct LocalAddressList);
1284 lal->addr = ss;
1285 lal->af = ss.ss_family;
1287 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1288 ch->ext_addr_tail,
1289 lal);
1291 ch,
1292 GNUNET_YES);
1293}
1294
1295
1304static void
1305dyndns_lookup (void *cls)
1306{
1307 struct ClientHandle *ch = cls;
1308 struct LocalAddressList *lal;
1309
1311 "Performing DNS lookup for punched hole given for `%s' as `%s:%u'\n",
1312 ch->section_name,
1313 ch->hole_external,
1314 (unsigned int) ch->ext_dns_port);
1315 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1316 lal->old = GNUNET_YES;
1317 ch->ext_dns_task = NULL;
1318 ch->ext_dns = GNUNET_RESOLVER_ip_get (ch->hole_external,
1319 AF_UNSPEC,
1322 ch);
1323}
1324
1325
1337static void
1339{
1340 char *port;
1341 unsigned int pnum;
1342 struct sockaddr_in *s4;
1343 struct LocalAddressList *lal;
1344
1345 port = strrchr (ch->hole_external, ':');
1346 if (NULL == port)
1347 {
1349 _ ("Malformed punched hole specification `%s' (lacks port)\n"),
1350 ch->hole_external);
1351 return;
1352 }
1353 if ((1 != sscanf (port + 1,
1354 "%u",
1355 &pnum)) ||
1356 (pnum > 65535))
1357 {
1359 _ (
1360 "Invalid port number in punched hole specification `%s' (lacks port)\n"),
1361 port + 1);
1362 return;
1363 }
1364 ch->ext_dns_port = (uint16_t) pnum;
1365 *port = '\0';
1366
1367 lal = GNUNET_new (struct LocalAddressList);
1368 if ('[' == *ch->hole_external)
1369 {
1370 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &lal->addr;
1371
1372 s6->sin6_family = AF_INET6;
1373 if (']' != (ch->hole_external[strlen (ch->hole_external) - 1]))
1374 {
1376 _ ("Malformed punched hole specification `%s' (lacks `]')\n"),
1377 ch->hole_external);
1378 GNUNET_free (lal);
1379 return;
1380 }
1381 ch->hole_external[strlen (ch->hole_external) - 1] = '\0';
1382 if (1 != inet_pton (AF_INET6,
1383 ch->hole_external + 1,
1384 &s6->sin6_addr))
1385 {
1387 _ (
1388 "Malformed punched hole specification `%s' (IPv6 address invalid)"),
1389 ch->hole_external + 1);
1390 GNUNET_free (lal);
1391 return;
1392 }
1393 s6->sin6_port = htons (ch->ext_dns_port);
1394 lal->af = AF_INET6;
1396 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1397 ch->ext_addr_tail,
1398 lal);
1400 ch,
1401 GNUNET_YES);
1402 return;
1403 }
1404
1405 s4 = (struct sockaddr_in *) &lal->addr;
1406 s4->sin_family = AF_INET;
1407 if (1 == inet_pton (AF_INET,
1408 ch->hole_external,
1409 &s4->sin_addr))
1410 {
1412 "IPv4 punched hole given for `%s' via `%s:%u'\n",
1413 ch->section_name,
1414 ch->hole_external,
1415 (unsigned int) ch->ext_dns_port);
1416 s4->sin_port = htons (ch->ext_dns_port);
1417 lal->af = AF_INET;
1419 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1420 ch->ext_addr_tail,
1421 lal);
1423 ch,
1424 GNUNET_YES);
1425 return;
1426 }
1427 if (0 == strcasecmp (ch->hole_external,
1428 "AUTO"))
1429 {
1430 /* handled in #notify_client_external_ipv4_change() */
1431 GNUNET_free (lal);
1432 return;
1433 }
1434 /* got a DNS name, trigger lookup! */
1435 GNUNET_free (lal);
1436 ch->ext_dns_task
1438 ch);
1439}
1440
1441
1449static void
1451 const struct GNUNET_NAT_RegisterMessage *message)
1452{
1453 struct ClientHandle *ch = cls;
1454 const char *off;
1455 size_t left;
1456
1457 if ((0 != ch->proto) ||
1458 (NULL != ch->caddrs))
1459 {
1460 /* double registration not allowed */
1461 GNUNET_break (0);
1463 return;
1464 }
1465 ch->flags = message->flags;
1466 ch->proto = message->proto;
1467 ch->num_caddrs = ntohs (message->num_addrs);
1468 ch->caddrs = GNUNET_new_array (ch->num_caddrs,
1469 struct ClientAddress);
1470 left = ntohs (message->header.size) - sizeof(*message);
1471 off = (const char *) &message[1];
1472 for (unsigned int i = 0; i < ch->num_caddrs; i++)
1473 {
1474 const struct sockaddr *sa = (const struct sockaddr *) off;
1475 size_t alen;
1476 uint16_t port;
1477 int is_nat;
1478
1479 if (sizeof(sa_family_t) > left)
1480 {
1481 GNUNET_break (0);
1483 return;
1484 }
1485 is_nat = GNUNET_NO;
1486 switch (sa->sa_family)
1487 {
1488 case AF_INET:
1489 {
1490 struct sockaddr_in s4;
1491
1492 GNUNET_memcpy (&s4,
1493 off,
1494 sizeof(struct sockaddr_in));
1495 alen = sizeof(struct sockaddr_in);
1496 if (is_nat_v4 (&s4.sin_addr))
1497 is_nat = GNUNET_YES;
1498 port = ntohs (s4.sin_port);
1499 }
1500 break;
1501
1502 case AF_INET6:
1503 {
1504 struct sockaddr_in6 s6;
1505
1506 GNUNET_memcpy (&s6,
1507 off,
1508 sizeof(struct sockaddr_in6));
1509 alen = sizeof(struct sockaddr_in6);
1510 if (is_nat_v6 (&s6.sin6_addr))
1511 is_nat = GNUNET_YES;
1512 port = ntohs (s6.sin6_port);
1513 }
1514 break;
1515
1516#if AF_UNIX
1517 case AF_UNIX:
1518 alen = sizeof(struct sockaddr_un);
1519 port = 0;
1520 break;
1521#endif
1522 default:
1523 GNUNET_break (0);
1525 return;
1526 }
1527 /* store address */
1528 GNUNET_assert (alen <= left);
1529 GNUNET_assert (alen <= sizeof(struct sockaddr_storage));
1530 GNUNET_memcpy (&ch->caddrs[i].ss,
1531 off,
1532 alen);
1533
1534 /* If applicable, try UPNPC NAT punching */
1535 if ((is_nat) &&
1536 (enable_upnp) &&
1537 ((IPPROTO_TCP == ch->proto) ||
1538 (IPPROTO_UDP == ch->proto)))
1539 {
1540 ch->natted_address = GNUNET_YES;
1541 ch->caddrs[i].mh
1543 IPPROTO_TCP == ch->proto,
1545 ch);
1546 }
1547
1548 off += alen;
1549 }
1550
1551 ch->section_name
1552 = GNUNET_strndup (off,
1553 ntohs (message->str_len));
1555 "Received REGISTER message from client for subsystem `%s'\n",
1556 ch->section_name);
1557 if (GNUNET_OK ==
1559 ch->section_name,
1560 "HOLE_EXTERNAL",
1561 &ch->hole_external))
1563
1564 /* Actually send IP address list to client */
1565 for (struct LocalAddressList *lal = lal_head;
1566 NULL != lal;
1567 lal = lal->next)
1568 {
1570 ch,
1571 GNUNET_YES);
1572 }
1573 /* Also consider IPv4 determined by `external-ip` */
1574 ch->external_monitor
1576 ch);
1578}
1579
1580
1589static int
1590check_stun (void *cls,
1591 const struct GNUNET_NAT_HandleStunMessage *message)
1592{
1593 size_t sa_len = ntohs (message->sender_addr_size);
1594 size_t expect = sa_len + ntohs (message->payload_size);
1595
1596 if (ntohs (message->header.size) - sizeof(*message) != expect)
1597 {
1598 GNUNET_break (0);
1599 return GNUNET_SYSERR;
1600 }
1601 if (sa_len < sizeof(sa_family_t))
1602 {
1603 GNUNET_break (0);
1604 return GNUNET_SYSERR;
1605 }
1606 return GNUNET_OK;
1607}
1608
1609
1617static void
1618notify_clients_stun_change (const struct sockaddr_in *ip,
1619 int add)
1620{
1621 for (struct ClientHandle *ch = ch_head;
1622 NULL != ch;
1623 ch = ch->next)
1624 {
1625 struct sockaddr_in v4;
1627 struct GNUNET_MQ_Envelope *env;
1628
1629 if (! ch->natted_address)
1630 continue;
1631 v4 = *ip;
1632 v4.sin_port = htons (0);
1634 sizeof(v4),
1636 msg->add_remove = htonl ((int32_t) add);
1637 msg->addr_class = htonl (GNUNET_NAT_AC_EXTERN
1639 GNUNET_memcpy (&msg[1],
1640 &v4,
1641 sizeof(v4));
1643 env);
1644 }
1645}
1646
1647
1655static void
1657{
1658 struct StunExternalIP *se = cls;
1659
1660 se->timeout_task = NULL;
1662 GNUNET_NO);
1664 se_tail,
1665 se);
1666 GNUNET_free (se);
1667}
1668
1669
1677static void
1678handle_stun (void *cls,
1679 const struct GNUNET_NAT_HandleStunMessage *message)
1680{
1681 struct ClientHandle *ch = cls;
1682 const char *buf = (const char *) &message[1];
1683 const struct sockaddr *sa;
1684 const void *payload;
1685 size_t sa_len;
1686 size_t payload_size;
1687 struct sockaddr_in external_addr;
1688
1689 sa_len = ntohs (message->sender_addr_size);
1690 payload_size = ntohs (message->payload_size);
1691 sa = (const struct sockaddr *) &buf[0];
1692 payload = (const struct sockaddr *) &buf[sa_len];
1693 switch (sa->sa_family)
1694 {
1695 case AF_INET:
1696 if (sa_len != sizeof(struct sockaddr_in))
1697 {
1698 GNUNET_break (0);
1700 return;
1701 }
1702 break;
1703
1704 case AF_INET6:
1705 if (sa_len != sizeof(struct sockaddr_in6))
1706 {
1707 GNUNET_break (0);
1709 return;
1710 }
1711 break;
1712 }
1714 "Received HANDLE_STUN message from client\n");
1715 if (GNUNET_OK ==
1717 payload_size,
1718 &external_addr))
1719 {
1720 /* We now know that a server at "sa" claims that
1721 we are visible at IP "external_addr".
1722
1723 We should (for some fixed period of time) tell
1724 all of our clients that listen to a NAT'ed address
1725 that they might want to consider the given 'external_ip'
1726 as their public IP address (this includes TCP and UDP
1727 clients, even if only UDP sends STUN requests).
1728
1729 If we do not get a renewal, the "external_addr" should be
1730 removed again. The timeout frequency should be configurable
1731 (with a sane default), so that the UDP plugin can tell how
1732 often to re-request STUN.
1733 */struct StunExternalIP *se;
1734
1735 /* Check if we had a prior response from this STUN server */
1736 for (se = se_head; NULL != se; se = se->next)
1737 {
1738 if ((se->stun_server_addr_len != sa_len) ||
1739 (0 != memcmp (sa,
1740 &se->stun_server_addr,
1741 sa_len)))
1742 continue; /* different STUN server */
1743 if (0 != GNUNET_memcmp (&external_addr,
1744 &se->external_addr))
1745 {
1746 /* external IP changed, update! */
1748 GNUNET_NO);
1751 GNUNET_YES);
1752 }
1753 /* update timeout */
1755 se->timeout_task
1758 se);
1759 return;
1760 }
1761 /* STUN server is completely new, create fresh entry */
1762 se = GNUNET_new (struct StunExternalIP);
1765 sa,
1766 sa_len);
1767 se->stun_server_addr_len = sa_len;
1770 se);
1772 se_tail,
1773 se);
1775 GNUNET_NO);
1776 }
1778}
1779
1780
1790static int
1792 const struct
1794 message)
1795{
1796 size_t expect;
1797
1798 expect = ntohs (message->local_addr_size)
1799 + ntohs (message->remote_addr_size);
1800 if (ntohs (message->header.size) - sizeof(*message) != expect)
1801 {
1802 GNUNET_break (0);
1803 return GNUNET_SYSERR;
1804 }
1805 return GNUNET_OK;
1806}
1807
1808
1816static void
1818 void *cls,
1819 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1820{
1821 struct ClientHandle *ch = cls;
1822 const char *buf = (const char *) &message[1];
1823 size_t local_sa_len = ntohs (message->local_addr_size);
1824 size_t remote_sa_len = ntohs (message->remote_addr_size);
1825 struct sockaddr_in l4;
1826 struct sockaddr_in r4;
1827 int ret;
1828
1830 "Received REQUEST CONNECTION REVERSAL message from client\n");
1831 if (local_sa_len != sizeof(struct sockaddr_in))
1832 {
1833 GNUNET_break_op (0);
1835 return;
1836 }
1837 if (remote_sa_len != sizeof(struct sockaddr_in))
1838 {
1839 GNUNET_break_op (0);
1841 return;
1842 }
1843 GNUNET_memcpy (&l4,
1844 buf,
1845 sizeof(struct sockaddr_in));
1846 GNUNET_break_op (AF_INET == l4.sin_family);
1847 buf += sizeof(struct sockaddr_in);
1848 GNUNET_memcpy (&r4,
1849 buf,
1850 sizeof(struct sockaddr_in));
1851 GNUNET_break_op (AF_INET == r4.sin_family);
1852 ret = GN_request_connection_reversal (&l4.sin_addr,
1853 ntohs (l4.sin_port),
1854 &r4.sin_addr,
1855 cfg);
1856 if (GNUNET_OK != ret)
1858 _ ("Connection reversal request failed\n"));
1860}
1861
1862
1871static enum GNUNET_GenericReturnValue
1873 void *cls,
1874 const struct GNUNET_NAT_AddGlobalAddressMessage *message)
1875{
1876 //const char *buf = (const char *) &message[1];
1877 //uint16_t blen = ntohs (message->address_length);
1878 size_t left = ntohs (message->header.size) - sizeof(*message);
1879
1880 if (left != ntohs (message->address_length))
1881 {
1882 GNUNET_break_op (0);
1883 return GNUNET_SYSERR;
1884 }
1885 /* if ('\0' != buf[blen - 1]) */
1886 /* { */
1887 /* GNUNET_break_op (0); */
1888 /* return GNUNET_SYSERR; */
1889 /* } */
1890 return GNUNET_OK;
1891}
1892
1893
1901static void
1903 void *cls,
1904 const struct GNUNET_NAT_AddGlobalAddressMessage *message)
1905{
1906 struct ClientHandle *ch = cls;
1907 const char *buf = (const char *) &message[1];
1908 //uint16_t blen = ntohs (message->address_length);
1909 struct sockaddr_in sockaddr_ipv4 = {
1910 .sin_family = AF_INET
1911 };
1912
1913 //GNUNET_assert ('\0' == buf[blen - 1]);
1914 if (1 != inet_pton (AF_INET,
1915 buf,
1916 &sockaddr_ipv4.sin_addr))
1917 {
1919 "natting address %s length %u no ipv4\n",
1920 buf,
1921 message->address_length);
1922 GNUNET_break (0);
1924 return;
1925 }
1926 notify_clients_stun_change (&sockaddr_ipv4,
1927 GNUNET_YES);
1929}
1930
1931
1937static void
1938shutdown_task (void *cls)
1939{
1940 struct StunExternalIP *se;
1941
1942 while (NULL != (se = se_head))
1943 {
1945 se_tail,
1946 se);
1948 GNUNET_free (se);
1949 }
1951 if (NULL != scan_task)
1952 {
1954 scan_task = NULL;
1955 }
1956 if (NULL != stats)
1957 {
1959 GNUNET_NO);
1960 stats = NULL;
1961 }
1962 destroy_lal ();
1963}
1964
1965
1973static void
1974run (void *cls,
1975 const struct GNUNET_CONFIGURATION_Handle *c,
1977{
1978 cfg = c;
1979 if (GNUNET_OK !=
1981 "NAT",
1982 "STUN_STALE",
1985
1986 /* Check for UPnP */
1989 "NAT",
1990 "ENABLE_UPNP");
1991 if (GNUNET_YES == enable_upnp)
1992 {
1993 /* check if it works */
1994 if (GNUNET_SYSERR ==
1996 GNUNET_NO,
1997 NULL))
1998 {
2000 _ (
2001 "UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
2003 }
2004 }
2005 if (GNUNET_OK !=
2007 "nat",
2008 "DYNDNS_FREQUENCY",
2011
2014 "NAT",
2015 "ENABLE_IPSCAN");
2016
2018 NULL);
2020 cfg);
2023 NULL);
2024}
2025
2026
2035static void *
2037 struct GNUNET_SERVICE_Client *c,
2038 struct GNUNET_MQ_Handle *mq)
2039{
2040 struct ClientHandle *ch;
2041
2042 ch = GNUNET_new (struct ClientHandle);
2043 ch->mq = mq;
2044 ch->client = c;
2046 ch_tail,
2047 ch);
2048 return ch;
2049}
2050
2051
2059static void
2061 struct GNUNET_SERVICE_Client *c,
2062 void *internal_cls)
2063{
2064 struct ClientHandle *ch = internal_cls;
2065 struct LocalAddressList *lal;
2066
2068 ch_tail,
2069 ch);
2070 for (unsigned int i = 0; i < ch->num_caddrs; i++)
2071 {
2072 if (NULL != ch->caddrs[i].mh)
2073 {
2074 GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh);
2075 ch->caddrs[i].mh = NULL;
2076 }
2077 }
2078 GNUNET_free (ch->caddrs);
2079 while (NULL != (lal = ch->ext_addr_head))
2080 {
2081 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
2082 ch->ext_addr_tail,
2083 lal);
2084 GNUNET_free (lal);
2085 }
2086 if (NULL != ch->ext_dns_task)
2087 {
2088 GNUNET_SCHEDULER_cancel (ch->ext_dns_task);
2089 ch->ext_dns_task = NULL;
2090 }
2091 if (NULL != ch->external_monitor)
2092 {
2093 GN_external_ipv4_monitor_stop (ch->external_monitor);
2094 ch->external_monitor = NULL;
2095 }
2096 if (NULL != ch->ext_dns)
2097 {
2099 ch->ext_dns = NULL;
2100 }
2101 GNUNET_free (ch->hole_external);
2102 GNUNET_free (ch->section_name);
2103 GNUNET_free (ch);
2104}
2105
2106
2112 "nat",
2114 &run,
2117 NULL,
2118 GNUNET_MQ_hd_var_size (register,
2121 NULL),
2125 NULL),
2126 GNUNET_MQ_hd_var_size (request_connection_reversal,
2129 NULL),
2130 GNUNET_MQ_hd_var_size (add_global_address,
2133 NULL),
2135
2136
2137#if defined(__linux__) && defined(__GLIBC__)
2138#include <malloc.h>
2139
2140void __attribute__ ((constructor))
2141GNUNET_NATM_memory_init (void);
2142
2146void __attribute__ ((constructor))
2147GNUNET_NATM_memory_init (void)
2148{
2149 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2150 mallopt (M_TOP_PAD, 1 * 1024);
2151 malloc_trim (0);
2152}
2153
2154
2155#endif
2156
2157/* 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:93
static uint16_t port
Port number.
Definition: gnunet-bcd.c:146
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(GNUNET_OS_project_data_gnunet(), "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.
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 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_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:305
#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:61
#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.
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:1339
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:980
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:1304
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:1277
void GNUNET_SERVICE_client_drop(struct GNUNET_SERVICE_Client *c)
Ask the server to disconnect from the given client.
Definition: service.c:2418
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition: service.c:2389
@ 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_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.
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: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.