GNUnet  0.10.x
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(GNUNET_TIME_UNIT_SECONDS, 5)
64 
68 #define DYNDNS_FREQUENCY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 7)
69 
70 
74 struct ClientAddress {
78  struct sockaddr_storage ss;
79 
86 };
87 
88 
97 
102 
107  struct HelperContext *hc;
108 
113  struct sockaddr_storage addr;
114 
118  int af;
119 
125  int old;
126 
131 };
132 
133 
137 struct ClientHandle {
142 
147 
151  struct GNUNET_SERVICE_Client *client;
152 
156  struct GNUNET_MQ_Handle *mq;
157 
162 
172 
177 
182 
188 
193 
198 
203 
207  uint16_t ext_dns_port;
208 
213 
218 
223  uint16_t num_caddrs;
224 
228  uint8_t proto;
229 };
230 
231 
240 
245 
250 
255  struct sockaddr_in external_addr;
256 
262  struct sockaddr_storage stun_server_addr;
263 
268 };
269 
270 
275 
280 
284 static const struct GNUNET_CONFIGURATION_Handle *cfg;
285 
290 
295 
299 static struct ClientHandle *ch_head;
300 
304 static struct ClientHandle *ch_tail;
305 
309 static struct LocalAddressList *lal_head;
310 
314 static struct LocalAddressList *lal_tail;
315 
319 static struct StunExternalIP *se_head;
320 
324 static struct StunExternalIP *se_tail;
325 
331 
332 
338 static void
340 {
342  lal_tail,
343  lal);
344  if (NULL != lal->hc)
345  {
347  "Lost NATed local address %s, stopping NAT server\n",
348  GNUNET_a2s((const struct sockaddr *)&lal->addr,
349  sizeof(struct sockaddr_in)));
350 
352  lal->hc = NULL;
353  }
354  GNUNET_free(lal);
355 }
356 
357 
361 static void
363 {
364  struct LocalAddressList *lal;
365 
366  while (NULL != (lal = lal_head))
367  free_lal(lal);
368 }
369 
370 
379 static int
380 check_register(void *cls,
381  const struct GNUNET_NAT_RegisterMessage *message)
382 {
383  uint16_t num_addrs = ntohs(message->num_addrs);
384  const char *off = (const char *)&message[1];
385  size_t left = ntohs(message->header.size) - sizeof(*message);
386 
387  for (unsigned int i = 0; i < num_addrs; i++)
388  {
389  size_t alen;
390  const struct sockaddr *sa = (const struct sockaddr *)off;
391 
392  if (sizeof(sa_family_t) > left)
393  {
394  GNUNET_break(0);
395  return GNUNET_SYSERR;
396  }
397  switch (sa->sa_family)
398  {
399  case AF_INET:
400  alen = sizeof(struct sockaddr_in);
401  break;
402 
403  case AF_INET6:
404  alen = sizeof(struct sockaddr_in6);
405  break;
406 
407 #if AF_UNIX
408  case AF_UNIX:
409  alen = sizeof(struct sockaddr_un);
410  break;
411 #endif
412  default:
413  GNUNET_break(0);
414  return GNUNET_SYSERR;
415  }
416  if (alen > left)
417  {
418  GNUNET_break(0);
419  return GNUNET_SYSERR;
420  }
421  off += alen;
422  left -= alen;
423  }
424  if (left != ntohs(message->str_len))
425  {
426  GNUNET_break(0);
427  return GNUNET_SYSERR;
428  }
429  return GNUNET_OK;
430 }
431 
432 
441 static int
442 match_ipv4(const char *network,
443  const struct in_addr *ip,
444  uint8_t bits)
445 {
446  struct in_addr net;
447 
448  if (0 == ip->s_addr)
449  return GNUNET_YES;
450  if (0 == bits)
451  return GNUNET_YES;
452  GNUNET_assert(1 == inet_pton(AF_INET,
453  network,
454  &net));
455  return !((ip->s_addr ^ net.s_addr) & htonl(0xFFFFFFFFu << (32 - bits)));
456 }
457 
458 
467 static int
468 match_ipv6(const char *network,
469  const struct in6_addr *ip,
470  uint8_t bits)
471 {
472  struct in6_addr net;
473  struct in6_addr mask;
474  unsigned int off;
475 
476  if (0 == bits)
477  return GNUNET_YES;
478  GNUNET_assert(1 == inet_pton(AF_INET6,
479  network,
480  &net));
481  memset(&mask, 0, sizeof(mask));
482  if (0 == GNUNET_memcmp(&mask,
483  ip))
484  return GNUNET_YES;
485  off = 0;
486  while (bits > 8)
487  {
488  mask.s6_addr[off++] = 0xFF;
489  bits -= 8;
490  }
491  while (bits > 0)
492  {
493  mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
494  bits--;
495  }
496  for (unsigned j = 0; j < sizeof(struct in6_addr) / sizeof(uint32_t); j++)
497  if (((((uint32_t *)ip)[j] & ((uint32_t *)&mask)[j])) !=
498  (((uint32_t *)&net)[j] & ((int *)&mask)[j]))
499  return GNUNET_NO;
500  return GNUNET_YES;
501 }
502 
503 
511 static int
512 is_nat_v4(const struct in_addr *ip)
513 {
514  return
515  match_ipv4("10.0.0.0", ip, 8) || /* RFC 1918 */
516  match_ipv4("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
517  match_ipv4("192.168.0.0", ip, 12) || /* RFC 1918 */
518  match_ipv4("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
519  match_ipv4("172.16.0.0", ip, 16); /* RFC 1918 */
520 }
521 
522 
530 static int
531 is_nat_v6(const struct in6_addr *ip)
532 {
533  return
534  match_ipv6("fc00::", ip, 7) || /* RFC 4193 */
535  match_ipv6("fec0::", ip, 10) || /* RFC 3879 */
536  match_ipv6("fe80::", ip, 10); /* RFC 4291, link-local */
537 }
538 
539 
548 
553 };
554 
555 
569 static int
570 ifc_proc(void *cls,
571  const char *name,
572  int isDefault,
573  const struct sockaddr *addr,
574  const struct sockaddr *broadcast_addr,
575  const struct sockaddr *netmask,
576  socklen_t addrlen)
577 {
578  struct IfcProcContext *ifc_ctx = cls;
579  struct LocalAddressList *lal;
580  size_t alen;
581  const struct in_addr *ip4;
582  const struct in6_addr *ip6;
584 
585  switch (addr->sa_family)
586  {
587  case AF_INET:
588  alen = sizeof(struct sockaddr_in);
589  ip4 = &((const struct sockaddr_in *)addr)->sin_addr;
590  if (match_ipv4("127.0.0.0", ip4, 8))
592  else if (is_nat_v4(ip4))
593  ac = GNUNET_NAT_AC_LAN;
594  else
596  break;
597 
598  case AF_INET6:
599  alen = sizeof(struct sockaddr_in6);
600  ip6 = &((const struct sockaddr_in6 *)addr)->sin6_addr;
601  if (match_ipv6("::1", ip6, 128))
603  else if (is_nat_v6(ip6))
604  ac = GNUNET_NAT_AC_LAN;
605  else
607  if ((ip6->s6_addr[11] == 0xFF) &&
608  (ip6->s6_addr[12] == 0xFE))
609  {
610  /* contains a MAC, be extra careful! */
611  ac |= GNUNET_NAT_AC_PRIVATE;
612  }
613  break;
614 
615 #if AF_UNIX
616  case AF_UNIX:
617  GNUNET_break(0);
618  return GNUNET_OK;
619 #endif
620  default:
621  GNUNET_break(0);
622  return GNUNET_OK;
623  }
624  lal = GNUNET_malloc(sizeof(*lal));
625  lal->af = addr->sa_family;
626  lal->ac = ac;
627  GNUNET_memcpy(&lal->addr,
628  addr,
629  alen);
631  ifc_ctx->lal_tail,
632  lal);
633  return GNUNET_OK;
634 }
635 
636 
647 static void
649  struct ClientHandle *ch,
650  int add,
651  const void *addr,
652  size_t addr_len)
653 {
654  struct GNUNET_MQ_Envelope *env;
656 
658  "Notifying client about %s of IP %s\n",
659  add ? "addition" : "removal",
660  GNUNET_a2s(addr,
661  addr_len));
662  env = GNUNET_MQ_msg_extra(msg,
663  addr_len,
665  msg->add_remove = htonl(add);
666  msg->addr_class = htonl(ac);
667  GNUNET_memcpy(&msg[1],
668  addr,
669  addr_len);
670  GNUNET_MQ_send(ch->mq,
671  env);
672 }
673 
674 
683 static void
685  struct ClientHandle *ch,
686  int add)
687 {
688  size_t alen;
689  struct sockaddr_in v4;
690  struct sockaddr_in6 v6;
691 
692  if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
693  {
695  "Not notifying client as it does not care about addresses\n");
696  return;
697  }
698  switch (delta->af)
699  {
700  case AF_INET:
701  alen = sizeof(struct sockaddr_in);
702  GNUNET_memcpy(&v4,
703  &delta->addr,
704  alen);
705 
706  /* Check for client notifications */
707  for (unsigned int i = 0; i < ch->num_caddrs; i++)
708  {
709  const struct sockaddr_in *c4;
710 
711  if (AF_INET != ch->caddrs[i].ss.ss_family)
712  continue; /* IPv4 not relevant */
713  c4 = (const struct sockaddr_in *)&ch->caddrs[i].ss;
714  if (match_ipv4("127.0.0.1", &c4->sin_addr, 8) &&
715  (0 != c4->sin_addr.s_addr) &&
716  (!match_ipv4("127.0.0.1", &v4.sin_addr, 8)))
717  continue; /* bound to loopback, but this is not loopback */
718  if ((!match_ipv4("127.0.0.1", &c4->sin_addr, 8)) &&
719  match_ipv4("127.0.0.1", &v4.sin_addr, 8))
720  continue; /* bound to non-loopback, but this is loopback */
721  if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
722  (0 != c4->sin_addr.s_addr) &&
723  (!is_nat_v4(&v4.sin_addr)))
724  continue; /* based on external-IP, but this IP is not
725  from private address range. */
726  if ((0 != GNUNET_memcmp(&v4.sin_addr,
727  &c4->sin_addr)) &&
728  (0 != c4->sin_addr.s_addr) &&
729  (!is_nat_v4(&c4->sin_addr)))
730  continue; /* this IP is not from private address range,
731  and IP does not match. */
732 
733  /* OK, IP seems relevant, notify client */
734  if (0 == htons(v4.sin_port))
735  v4.sin_port = c4->sin_port;
736  notify_client(delta->ac,
737  ch,
738  add,
739  &v4,
740  alen);
741  }
742  break;
743 
744  case AF_INET6:
745  alen = sizeof(struct sockaddr_in6);
746  GNUNET_memcpy(&v6,
747  &delta->addr,
748  alen);
749  for (unsigned int i = 0; i < ch->num_caddrs; i++)
750  {
751  const struct sockaddr_in6 *c6;
752 
753  if (AF_INET6 != ch->caddrs[i].ss.ss_family)
754  continue; /* IPv4 not relevant */
755  c6 = (const struct sockaddr_in6 *)&ch->caddrs[i].ss;
756  if (match_ipv6("::1", &c6->sin6_addr, 128) &&
757  (0 != GNUNET_memcmp(&c6->sin6_addr,
758  &in6addr_any)) &&
759  (!match_ipv6("::1", &v6.sin6_addr, 128)))
760  continue; /* bound to loopback, but this is not loopback */
761  if ((!match_ipv6("::1", &c6->sin6_addr, 128)) &&
762  match_ipv6("::1", &v6.sin6_addr, 128))
763  continue; /* bound to non-loopback, but this is loopback */
764  if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
765  (0 != GNUNET_memcmp(&c6->sin6_addr,
766  &in6addr_any)) &&
767  (!is_nat_v6(&v6.sin6_addr)))
768  continue; /* based on external-IP, but this IP is not
769  from private address range. */
770  if ((0 != GNUNET_memcmp(&v6.sin6_addr,
771  &c6->sin6_addr)) &&
772  (0 != GNUNET_memcmp(&c6->sin6_addr,
773  &in6addr_any)) &&
774  (!is_nat_v6(&c6->sin6_addr)))
775  continue; /* this IP is not from private address range,
776  and IP does not match. */
777  if ((match_ipv6("fe80::", &c6->sin6_addr, 10)) &&
778  (0 != GNUNET_memcmp(&c6->sin6_addr,
779  &in6addr_any)) &&
780  (0 != GNUNET_memcmp(&v6.sin6_addr,
781  &c6->sin6_addr)) &&
782  (0 == (delta->ac & GNUNET_NAT_AC_EXTERN)))
783  continue; /* client bound to link-local, and the other address
784  does not match and is not an external IP */
785 
786  /* OK, IP seems relevant, notify client */
787  if (0 == htons(v6.sin6_port))
788  v6.sin6_port = c6->sin6_port;
789  notify_client(delta->ac,
790  ch,
791  add,
792  &v6,
793  alen);
794  }
795  break;
796 
797  default:
798  GNUNET_break(0);
799  return;
800  }
801 }
802 
803 
811 static void
813  int add)
814 {
815  for (struct ClientHandle *ch = ch_head;
816  NULL != ch;
817  ch = ch->next)
818  check_notify_client(delta,
819  ch,
820  add);
821 }
822 
823 
832 static void
834  const struct in_addr *v4,
835  int add)
836 {
837  struct ClientHandle *ch = cls;
838  struct sockaddr_in sa;
839  int have_v4;
840 
841  /* (0) check if this impacts 'hole_external' */
842  if ((NULL != ch->hole_external) &&
843  (0 == strcasecmp(ch->hole_external,
844  "AUTO")))
845  {
846  struct LocalAddressList lal;
847  struct sockaddr_in *s4;
848 
850  "Detected eternal IP, can now back-fill AUTO:%u in hole punching specification of `%s'\n",
851  (unsigned int)ch->ext_dns_port,
852  ch->section_name);
853  memset(&lal, 0, sizeof(lal));
854  s4 = (struct sockaddr_in *)&lal.addr;
855  s4->sin_family = AF_INET;
856  s4->sin_port = htons(ch->ext_dns_port);
857  s4->sin_addr = *v4;
858  lal.af = AF_INET;
860  check_notify_client(&lal,
861  ch,
862  add);
863  }
864 
865  /* (1) check if client cares. */
866  if (!ch->natted_address)
867  return;
868  have_v4 = GNUNET_NO;
869  for (unsigned int i = 0; i < ch->num_caddrs; i++)
870  {
871  const struct sockaddr_storage *ss = &ch->caddrs[i].ss;
872 
873  if (AF_INET != ss->ss_family)
874  continue;
875  have_v4 = GNUNET_YES;
876  break;
877  }
878  if (GNUNET_NO == have_v4)
879  return; /* IPv6-only */
880 
881  /* (2) build address info */
882  memset(&sa,
883  0,
884  sizeof(sa));
885  sa.sin_family = AF_INET;
886  sa.sin_addr = *v4;
887  sa.sin_port = htons(0);
888 
890  "Detected eternal IP %s, notifying client of external IP (without port)\n",
891  GNUNET_a2s((const struct sockaddr *)&sa,
892  sizeof(sa)));
893  /* (3) notify client of change */
897  ch,
898  add,
899  &sa,
900  sizeof(sa));
901 }
902 
903 
911 static void
913  const struct sockaddr_in *ra)
914 {
915  struct LocalAddressList *lal = cls;
916  const struct sockaddr_in *l4;
917 
918  GNUNET_assert(AF_INET == lal->af);
919  l4 = (const struct sockaddr_in *)&lal->addr;
920  for (struct ClientHandle *ch = ch_head;
921  NULL != ch;
922  ch = ch->next)
923  {
925  struct GNUNET_MQ_Envelope *env;
926  int match;
927 
928  /* Check if client is in applicable range for ICMP NAT traversal
929  for this local address */
930  if (!ch->natted_address)
931  continue;
932  match = GNUNET_NO;
933  for (unsigned int i = 0; i < ch->num_caddrs; i++)
934  {
935  struct ClientAddress *ca = &ch->caddrs[i];
936  const struct sockaddr_in *c4;
937 
938  if (AF_INET != ca->ss.ss_family)
939  continue;
940  c4 = (const struct sockaddr_in *)&ca->ss;
941  if ((0 != c4->sin_addr.s_addr) &&
942  (l4->sin_addr.s_addr != c4->sin_addr.s_addr))
943  continue;
944  match = GNUNET_YES;
945  break;
946  }
947  if (!match)
948  continue;
949 
950  /* Notify applicable client about connection reversal request */
951  env = GNUNET_MQ_msg_extra(crrm,
952  sizeof(struct sockaddr_in),
954  GNUNET_memcpy(&crrm[1],
955  ra,
956  sizeof(struct sockaddr_in));
958  env);
959  }
960 }
961 
962 
968 static void
969 run_scan(void *cls)
970 {
971  struct IfcProcContext ifc_ctx;
972  int found;
973  int have_nat;
974  struct LocalAddressList *lnext;
975 
977  &run_scan,
978  NULL);
979  memset(&ifc_ctx,
980  0,
981  sizeof(ifc_ctx));
983  &ifc_ctx);
984  /* remove addresses that disappeared */
985  for (struct LocalAddressList *lal = lal_head;
986  NULL != lal;
987  lal = lnext)
988  {
989  lnext = lal->next;
990  found = GNUNET_NO;
991  for (struct LocalAddressList *pos = ifc_ctx.lal_head;
992  NULL != pos;
993  pos = pos->next)
994  {
995  if ((pos->af == lal->af) &&
996  (0 == memcmp(&lal->addr,
997  &pos->addr,
998  (AF_INET == lal->af)
999  ? sizeof(struct sockaddr_in)
1000  : sizeof(struct sockaddr_in6))))
1001  {
1002  found = GNUNET_YES;
1003  }
1004  }
1005  if (GNUNET_NO == found)
1006  {
1007  notify_clients(lal,
1008  GNUNET_NO);
1009  free_lal(lal);
1010  }
1011  }
1012 
1013  /* add addresses that appeared */
1014  have_nat = GNUNET_NO;
1015  for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1016  NULL != pos;
1017  pos = ifc_ctx.lal_head)
1018  {
1019  found = GNUNET_NO;
1020  if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac))
1021  have_nat = GNUNET_YES;
1022  for (struct LocalAddressList *lal = lal_head;
1023  NULL != lal;
1024  lal = lal->next)
1025  {
1026  if ((pos->af == lal->af) &&
1027  (0 == memcmp(&lal->addr,
1028  &pos->addr,
1029  (AF_INET == lal->af)
1030  ? sizeof(struct sockaddr_in)
1031  : sizeof(struct sockaddr_in6))))
1032  found = GNUNET_YES;
1033  }
1035  ifc_ctx.lal_tail,
1036  pos);
1037  if (GNUNET_YES == found)
1038  {
1039  GNUNET_free(pos);
1040  }
1041  else
1042  {
1043  notify_clients(pos,
1044  GNUNET_YES);
1045  GNUNET_CONTAINER_DLL_insert(lal_head,
1046  lal_tail,
1047  pos);
1048  if ((AF_INET == pos->af) &&
1049  (NULL == pos->hc) &&
1050  (0 != (GNUNET_NAT_AC_LAN & pos->ac)))
1051  {
1052  const struct sockaddr_in *s4
1053  = (const struct sockaddr_in *)&pos->addr;
1054 
1056  "Found NATed local address %s, starting NAT server\n",
1057  GNUNET_a2s((const struct sockaddr *)&pos->addr,
1058  sizeof(*s4)));
1059  pos->hc = GN_start_gnunet_nat_server_(&s4->sin_addr,
1061  pos,
1062  cfg);
1063  }
1064  }
1065  }
1066  GN_nat_status_changed(have_nat);
1067 }
1068 
1069 
1081 static void
1083  int add_remove,
1084  const struct sockaddr *addr,
1085  socklen_t addrlen,
1087 {
1088  struct ClientHandle *ch = cls;
1090 
1091  switch (result)
1092  {
1094  GNUNET_assert(NULL != addr);
1095  break;
1096 
1101  "Running upnpc failed: %d\n",
1102  result);
1103  return;
1104 
1107  "external-ip binary not found\n");
1108  return;
1109 
1112  "upnpc binary not found\n");
1113  return;
1114 
1117  "external-ip binary could not be run\n");
1118  return;
1119 
1122  "upnpc failed to create port mapping\n");
1123  return;
1124 
1127  "Invalid output from upnpc\n");
1128  return;
1129 
1132  "Invalid address returned by upnpc\n");
1133  return;
1134 
1135  default:
1136  GNUNET_break(0); /* should not be possible */
1137  return;
1138  }
1139  switch (addr->sa_family)
1140  {
1141  case AF_INET:
1142  ac = is_nat_v4(&((const struct sockaddr_in *)addr)->sin_addr)
1145  break;
1146 
1147  case AF_INET6:
1148  ac = is_nat_v6(&((const struct sockaddr_in6 *)addr)->sin6_addr)
1151  break;
1152 
1153  default:
1154  GNUNET_break(0);
1155  return;
1156  }
1158  "upnp external address %s: %s\n",
1159  add_remove ? "added" : "removed",
1160  GNUNET_a2s(addr,
1161  addrlen));
1162  notify_client(ac,
1163  ch,
1164  add_remove,
1165  addr,
1166  addrlen);
1167 }
1168 
1169 
1178 static void
1179 dyndns_lookup(void *cls);
1180 
1181 
1191 static void
1193  const struct sockaddr *addr,
1194  socklen_t addrlen)
1195 {
1196  struct ClientHandle *ch = cls;
1197  struct LocalAddressList *lal;
1198  struct sockaddr_storage ss;
1199  struct sockaddr_in *v4;
1200  struct sockaddr_in6 *v6;
1201 
1202  if (NULL == addr)
1203  {
1204  struct LocalAddressList *laln;
1205 
1206  ch->ext_dns = NULL;
1207  ch->ext_dns_task
1209  &dyndns_lookup,
1210  ch);
1211  /* Current iteration is over, remove 'old' IPs now */
1212  for (lal = ch->ext_addr_head; NULL != lal; lal = laln)
1213  {
1214  laln = lal->next;
1215  if (GNUNET_YES == lal->old)
1216  {
1218  ch->ext_addr_tail,
1219  lal);
1220  check_notify_client(lal,
1221  ch,
1222  GNUNET_NO);
1223  GNUNET_free(lal);
1224  }
1225  }
1226  return;
1227  }
1229  "Got IP `%s' for external address `%s'\n",
1230  GNUNET_a2s(addr,
1231  addrlen),
1232  ch->hole_external);
1233 
1234  /* build sockaddr storage with port number */
1235  memset(&ss,
1236  0,
1237  sizeof(ss));
1238  GNUNET_memcpy(&ss,
1239  addr,
1240  addrlen);
1241  switch (addr->sa_family)
1242  {
1243  case AF_INET:
1244  v4 = (struct sockaddr_in *)&ss;
1245  v4->sin_port = htons(ch->ext_dns_port);
1246  break;
1247 
1248  case AF_INET6:
1249  v6 = (struct sockaddr_in6 *)&ss;
1250  v6->sin6_port = htons(ch->ext_dns_port);
1251  break;
1252 
1253  default:
1254  GNUNET_break(0);
1255  return;
1256  }
1257  /* See if 'ss' matches any of our known addresses */
1258  for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1259  {
1260  if (GNUNET_NO == lal->old)
1261  continue; /* already processed, skip */
1262  if ((addr->sa_family == lal->addr.ss_family) &&
1263  (0 == memcmp(&ss,
1264  &lal->addr,
1265  addrlen)))
1266  {
1267  /* Address unchanged, remember so we do not remove */
1268  lal->old = GNUNET_NO;
1269  return; /* done here */
1270  }
1271  }
1272  /* notify client, and remember IP for later removal! */
1273  lal = GNUNET_new(struct LocalAddressList);
1274  lal->addr = ss;
1275  lal->af = ss.ss_family;
1278  ch->ext_addr_tail,
1279  lal);
1280  check_notify_client(lal,
1281  ch,
1282  GNUNET_YES);
1283 }
1284 
1285 
1294 static void
1295 dyndns_lookup(void *cls)
1296 {
1297  struct ClientHandle *ch = cls;
1298  struct LocalAddressList *lal;
1299 
1301  "Performing DNS lookup for punched hole given for `%s' as `%s:%u'\n",
1302  ch->section_name,
1303  ch->hole_external,
1304  (unsigned int)ch->ext_dns_port);
1305  for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1306  lal->old = GNUNET_YES;
1307  ch->ext_dns_task = NULL;
1309  AF_UNSPEC,
1312  ch);
1313 }
1314 
1315 
1327 static void
1329 {
1330  char *port;
1331  unsigned int pnum;
1332  struct sockaddr_in *s4;
1333  struct LocalAddressList *lal;
1334 
1335  port = strrchr(ch->hole_external, ':');
1336  if (NULL == port)
1337  {
1339  _("Malformed punched hole specification `%s' (lacks port)\n"),
1340  ch->hole_external);
1341  return;
1342  }
1343  if ((1 != sscanf(port + 1,
1344  "%u",
1345  &pnum)) ||
1346  (pnum > 65535))
1347  {
1349  _("Invalid port number in punched hole specification `%s' (lacks port)\n"),
1350  port + 1);
1351  return;
1352  }
1353  ch->ext_dns_port = (uint16_t)pnum;
1354  *port = '\0';
1355 
1356  lal = GNUNET_new(struct LocalAddressList);
1357  if ('[' == *ch->hole_external)
1358  {
1359  struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)&lal->addr;
1360 
1361  s6->sin6_family = AF_INET6;
1362  if (']' != (ch->hole_external[strlen(ch->hole_external) - 1]))
1363  {
1365  _("Malformed punched hole specification `%s' (lacks `]')\n"),
1366  ch->hole_external);
1367  GNUNET_free(lal);
1368  return;
1369  }
1370  ch->hole_external[strlen(ch->hole_external) - 1] = '\0';
1371  if (1 != inet_pton(AF_INET6,
1372  ch->hole_external + 1,
1373  &s6->sin6_addr))
1374  {
1376  _("Malformed punched hole specification `%s' (IPv6 address invalid)"),
1377  ch->hole_external + 1);
1378  GNUNET_free(lal);
1379  return;
1380  }
1381  s6->sin6_port = htons(ch->ext_dns_port);
1382  lal->af = AF_INET6;
1385  ch->ext_addr_tail,
1386  lal);
1387  check_notify_client(lal,
1388  ch,
1389  GNUNET_YES);
1390  return;
1391  }
1392 
1393  s4 = (struct sockaddr_in *)&lal->addr;
1394  s4->sin_family = AF_INET;
1395  if (1 == inet_pton(AF_INET,
1396  ch->hole_external,
1397  &s4->sin_addr))
1398  {
1400  "IPv4 punched hole given for `%s' via `%s:%u'\n",
1401  ch->section_name,
1402  ch->hole_external,
1403  (unsigned int)ch->ext_dns_port);
1404  s4->sin_port = htons(ch->ext_dns_port);
1405  lal->af = AF_INET;
1408  ch->ext_addr_tail,
1409  lal);
1410  check_notify_client(lal,
1411  ch,
1412  GNUNET_YES);
1413  return;
1414  }
1415  if (0 == strcasecmp(ch->hole_external,
1416  "AUTO"))
1417  {
1418  /* handled in #notify_client_external_ipv4_change() */
1419  GNUNET_free(lal);
1420  return;
1421  }
1422  /* got a DNS name, trigger lookup! */
1423  GNUNET_free(lal);
1424  ch->ext_dns_task
1426  ch);
1427 }
1428 
1429 
1437 static void
1439  const struct GNUNET_NAT_RegisterMessage *message)
1440 {
1441  struct ClientHandle *ch = cls;
1442  const char *off;
1443  size_t left;
1444 
1445  if ((0 != ch->proto) ||
1446  (NULL != ch->caddrs))
1447  {
1448  /* double registration not allowed */
1449  GNUNET_break(0);
1451  return;
1452  }
1453  ch->flags = message->flags;
1454  ch->proto = message->proto;
1455  ch->num_caddrs = ntohs(message->num_addrs);
1457  struct ClientAddress);
1458  left = ntohs(message->header.size) - sizeof(*message);
1459  off = (const char *)&message[1];
1460  for (unsigned int i = 0; i < ch->num_caddrs; i++)
1461  {
1462  const struct sockaddr *sa = (const struct sockaddr *)off;
1463  size_t alen;
1464  uint16_t port;
1465  int is_nat;
1466 
1467  if (sizeof(sa_family_t) > left)
1468  {
1469  GNUNET_break(0);
1471  return;
1472  }
1473  is_nat = GNUNET_NO;
1474  switch (sa->sa_family)
1475  {
1476  case AF_INET:
1477  {
1478  struct sockaddr_in s4;
1479 
1480  GNUNET_memcpy(&s4,
1481  off,
1482  sizeof(struct sockaddr_in));
1483  alen = sizeof(struct sockaddr_in);
1484  if (is_nat_v4(&s4.sin_addr))
1485  is_nat = GNUNET_YES;
1486  port = ntohs(s4.sin_port);
1487  }
1488  break;
1489 
1490  case AF_INET6:
1491  {
1492  struct sockaddr_in6 s6;
1493 
1494  GNUNET_memcpy(&s6,
1495  off,
1496  sizeof(struct sockaddr_in6));
1497  alen = sizeof(struct sockaddr_in6);
1498  if (is_nat_v6(&s6.sin6_addr))
1499  is_nat = GNUNET_YES;
1500  port = ntohs(s6.sin6_port);
1501  }
1502  break;
1503 
1504 #if AF_UNIX
1505  case AF_UNIX:
1506  alen = sizeof(struct sockaddr_un);
1507  port = 0;
1508  break;
1509 #endif
1510  default:
1511  GNUNET_break(0);
1513  return;
1514  }
1515  /* store address */
1516  GNUNET_assert(alen <= left);
1517  GNUNET_assert(alen <= sizeof(struct sockaddr_storage));
1518  GNUNET_memcpy(&ch->caddrs[i].ss,
1519  off,
1520  alen);
1521 
1522  /* If applicable, try UPNPC NAT punching */
1523  if ((is_nat) &&
1524  (enable_upnp) &&
1525  ((IPPROTO_TCP == ch->proto) ||
1526  (IPPROTO_UDP == ch->proto)))
1527  {
1528  ch->natted_address = GNUNET_YES;
1529  ch->caddrs[i].mh
1531  IPPROTO_TCP == ch->proto,
1533  ch);
1534  }
1535 
1536  off += alen;
1537  }
1538 
1539  ch->section_name
1540  = GNUNET_strndup(off,
1541  ntohs(message->str_len));
1543  "Received REGISTER message from client for subsystem `%s'\n",
1544  ch->section_name);
1545  if (GNUNET_OK ==
1547  ch->section_name,
1548  "HOLE_EXTERNAL",
1549  &ch->hole_external))
1551 
1552  /* Actually send IP address list to client */
1553  for (struct LocalAddressList *lal = lal_head;
1554  NULL != lal;
1555  lal = lal->next)
1556  {
1557  check_notify_client(lal,
1558  ch,
1559  GNUNET_YES);
1560  }
1561  /* Also consider IPv4 determined by `external-ip` */
1562  ch->external_monitor
1564  ch);
1566 }
1567 
1568 
1577 static int
1578 check_stun(void *cls,
1579  const struct GNUNET_NAT_HandleStunMessage *message)
1580 {
1581  size_t sa_len = ntohs(message->sender_addr_size);
1582  size_t expect = sa_len + ntohs(message->payload_size);
1583 
1584  if (ntohs(message->header.size) - sizeof(*message) != expect)
1585  {
1586  GNUNET_break(0);
1587  return GNUNET_SYSERR;
1588  }
1589  if (sa_len < sizeof(sa_family_t))
1590  {
1591  GNUNET_break(0);
1592  return GNUNET_SYSERR;
1593  }
1594  return GNUNET_OK;
1595 }
1596 
1597 
1605 static void
1606 notify_clients_stun_change(const struct sockaddr_in *ip,
1607  int add)
1608 {
1609  for (struct ClientHandle *ch = ch_head;
1610  NULL != ch;
1611  ch = ch->next)
1612  {
1613  struct sockaddr_in v4;
1615  struct GNUNET_MQ_Envelope *env;
1616 
1617  if (!ch->natted_address)
1618  continue;
1619  v4 = *ip;
1620  v4.sin_port = htons(0);
1621  env = GNUNET_MQ_msg_extra(msg,
1622  sizeof(v4),
1624  msg->add_remove = htonl((int32_t)add);
1625  msg->addr_class = htonl(GNUNET_NAT_AC_EXTERN |
1627  GNUNET_memcpy(&msg[1],
1628  &v4,
1629  sizeof(v4));
1630  GNUNET_MQ_send(ch->mq,
1631  env);
1632  }
1633 }
1634 
1635 
1643 static void
1645 {
1646  struct StunExternalIP *se = cls;
1647 
1648  se->timeout_task = NULL;
1650  GNUNET_NO);
1652  se_tail,
1653  se);
1654  GNUNET_free(se);
1655 }
1656 
1657 
1665 static void
1666 handle_stun(void *cls,
1667  const struct GNUNET_NAT_HandleStunMessage *message)
1668 {
1669  struct ClientHandle *ch = cls;
1670  const char *buf = (const char *)&message[1];
1671  const struct sockaddr *sa;
1672  const void *payload;
1673  size_t sa_len;
1674  size_t payload_size;
1675  struct sockaddr_in external_addr;
1676 
1677  sa_len = ntohs(message->sender_addr_size);
1678  payload_size = ntohs(message->payload_size);
1679  sa = (const struct sockaddr *)&buf[0];
1680  payload = (const struct sockaddr *)&buf[sa_len];
1681  switch (sa->sa_family)
1682  {
1683  case AF_INET:
1684  if (sa_len != sizeof(struct sockaddr_in))
1685  {
1686  GNUNET_break(0);
1688  return;
1689  }
1690  break;
1691 
1692  case AF_INET6:
1693  if (sa_len != sizeof(struct sockaddr_in6))
1694  {
1695  GNUNET_break(0);
1697  return;
1698  }
1699  break;
1700  }
1702  "Received HANDLE_STUN message from client\n");
1703  if (GNUNET_OK ==
1705  payload_size,
1706  &external_addr))
1707  {
1708  /* We now know that a server at "sa" claims that
1709  we are visible at IP "external_addr".
1710 
1711  We should (for some fixed period of time) tell
1712  all of our clients that listen to a NAT'ed address
1713  that they might want to consider the given 'external_ip'
1714  as their public IP address (this includes TCP and UDP
1715  clients, even if only UDP sends STUN requests).
1716 
1717  If we do not get a renewal, the "external_addr" should be
1718  removed again. The timeout frequency should be configurable
1719  (with a sane default), so that the UDP plugin can tell how
1720  often to re-request STUN.
1721  */
1722  struct StunExternalIP *se;
1723 
1724  /* Check if we had a prior response from this STUN server */
1725  for (se = se_head; NULL != se; se = se->next)
1726  {
1727  if ((se->stun_server_addr_len != sa_len) ||
1728  (0 != memcmp(sa,
1729  &se->stun_server_addr,
1730  sa_len)))
1731  continue; /* different STUN server */
1732  if (0 != GNUNET_memcmp(&external_addr,
1733  &se->external_addr))
1734  {
1735  /* external IP changed, update! */
1737  GNUNET_NO);
1740  GNUNET_YES);
1741  }
1742  /* update timeout */
1744  se->timeout_task
1746  &stun_ip_timeout,
1747  se);
1748  return;
1749  }
1750  /* STUN server is completely new, create fresh entry */
1751  se = GNUNET_new(struct StunExternalIP);
1754  sa,
1755  sa_len);
1756  se->stun_server_addr_len = sa_len;
1758  &stun_ip_timeout,
1759  se);
1761  se_tail,
1762  se);
1764  GNUNET_NO);
1765  }
1767 }
1768 
1769 
1779 static int
1781  const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1782 {
1783  size_t expect;
1784 
1785  expect = ntohs(message->local_addr_size)
1786  + ntohs(message->remote_addr_size);
1787  if (ntohs(message->header.size) - sizeof(*message) != expect)
1788  {
1789  GNUNET_break(0);
1790  return GNUNET_SYSERR;
1791  }
1792  return GNUNET_OK;
1793 }
1794 
1795 
1803 static void
1805  const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1806 {
1807  struct ClientHandle *ch = cls;
1808  const char *buf = (const char *)&message[1];
1809  size_t local_sa_len = ntohs(message->local_addr_size);
1810  size_t remote_sa_len = ntohs(message->remote_addr_size);
1811  struct sockaddr_in l4;
1812  struct sockaddr_in r4;
1813  int ret;
1814 
1816  "Received REQUEST CONNECTION REVERSAL message from client\n");
1817  if (local_sa_len != sizeof(struct sockaddr_in))
1818  {
1819  GNUNET_break_op(0);
1821  return;
1822  }
1823  if (remote_sa_len != sizeof(struct sockaddr_in))
1824  {
1825  GNUNET_break_op(0);
1827  return;
1828  }
1829  GNUNET_memcpy(&l4,
1830  buf,
1831  sizeof(struct sockaddr_in));
1832  GNUNET_break_op(AF_INET == l4.sin_family);
1833  buf += sizeof(struct sockaddr_in);
1834  GNUNET_memcpy(&r4,
1835  buf,
1836  sizeof(struct sockaddr_in));
1837  GNUNET_break_op(AF_INET == r4.sin_family);
1838  ret = GN_request_connection_reversal(&l4.sin_addr,
1839  ntohs(l4.sin_port),
1840  &r4.sin_addr,
1841  cfg);
1842  if (GNUNET_OK != ret)
1844  _("Connection reversal request failed\n"));
1846 }
1847 
1848 
1854 static void
1855 shutdown_task(void *cls)
1856 {
1857  struct StunExternalIP *se;
1858 
1859  while (NULL != (se = se_head))
1860  {
1862  se_tail,
1863  se);
1865  GNUNET_free(se);
1866  }
1868  if (NULL != scan_task)
1869  {
1870  GNUNET_SCHEDULER_cancel(scan_task);
1871  scan_task = NULL;
1872  }
1873  if (NULL != stats)
1874  {
1876  GNUNET_NO);
1877  stats = NULL;
1878  }
1879  destroy_lal();
1880 }
1881 
1882 
1890 static void
1891 run(void *cls,
1892  const struct GNUNET_CONFIGURATION_Handle *c,
1894 {
1895  cfg = c;
1896  if (GNUNET_OK !=
1898  "NAT",
1899  "STUN_STALE",
1902 
1903  /* Check for UPnP */
1904  enable_upnp
1906  "NAT",
1907  "ENABLE_UPNP");
1908  if (GNUNET_YES == enable_upnp)
1909  {
1910  /* check if it works */
1911  if (GNUNET_SYSERR ==
1913  GNUNET_NO,
1914  NULL))
1915  {
1917  _("UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
1919  }
1920  }
1921  if (GNUNET_OK !=
1923  "nat",
1924  "DYNDNS_FREQUENCY",
1925  &dyndns_frequency))
1927 
1929  NULL);
1930  stats = GNUNET_STATISTICS_create("nat",
1931  cfg);
1932  scan_task = GNUNET_SCHEDULER_add_now(&run_scan,
1933  NULL);
1934 }
1935 
1936 
1945 static void *
1947  struct GNUNET_SERVICE_Client *c,
1948  struct GNUNET_MQ_Handle *mq)
1949 {
1950  struct ClientHandle *ch;
1951 
1952  ch = GNUNET_new(struct ClientHandle);
1953  ch->mq = mq;
1954  ch->client = c;
1956  ch_tail,
1957  ch);
1958  return ch;
1959 }
1960 
1961 
1969 static void
1971  struct GNUNET_SERVICE_Client *c,
1972  void *internal_cls)
1973 {
1974  struct ClientHandle *ch = internal_cls;
1975  struct LocalAddressList *lal;
1976 
1978  ch_tail,
1979  ch);
1980  for (unsigned int i = 0; i < ch->num_caddrs; i++)
1981  {
1982  if (NULL != ch->caddrs[i].mh)
1983  {
1985  ch->caddrs[i].mh = NULL;
1986  }
1987  }
1989  while (NULL != (lal = ch->ext_addr_head))
1990  {
1992  ch->ext_addr_tail,
1993  lal);
1994  GNUNET_free(lal);
1995  }
1996  if (NULL != ch->ext_dns_task)
1997  {
1999  ch->ext_dns_task = NULL;
2000  }
2001  if (NULL != ch->external_monitor)
2002  {
2004  ch->external_monitor = NULL;
2005  }
2006  if (NULL != ch->ext_dns)
2007  {
2009  ch->ext_dns = NULL;
2010  }
2013  GNUNET_free(ch);
2014 }
2015 
2016 
2021  ("nat",
2023  &run,
2026  NULL,
2027  GNUNET_MQ_hd_var_size(register,
2030  NULL),
2031  GNUNET_MQ_hd_var_size(stun,
2034  NULL),
2035  GNUNET_MQ_hd_var_size(request_connection_reversal,
2038  NULL),
2040 
2041 
2042 #if defined(LINUX) && defined(__GLIBC__)
2043 #include <malloc.h>
2044 
2048 void __attribute__ ((constructor))
2049 GNUNET_ARM_memory_init()
2050 {
2051  mallopt(M_TRIM_THRESHOLD, 4 * 1024);
2052  mallopt(M_TOP_PAD, 1 * 1024);
2053  malloc_trim(0);
2054 }
2055 #endif
2056 
2057 /* end of gnunet-service-nat.c */
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
Client telling the service to (possibly) handle a STUN message.
Definition: nat.h:132
static struct GNUNET_TIME_Relative stun_stale_timeout
Timeout to use when STUN data is considered stale.
Service notifying the client about changes in the set of addresses it has.
Definition: nat.h:196
External IP address as given to us via some STUN server.
static struct GNUNET_CADET_Channel * ch
Channel handle.
Definition: gnunet-cadet.c:117
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 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 GNUNET_SERVICE_Handle * service
Handle to our service instance.
static void free_lal(struct LocalAddressList *lal)
Remove and free an entry from the lal_head DLL.
static void run_scan(void *cls)
Task we run periodically to scan for network interfaces.
size_t stun_server_addr_len
Number of bytes used in stun_server_addr.
int 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.
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
Addresses that were manually configured by the user.
void GNUNET_RESOLVER_request_cancel(struct GNUNET_RESOLVER_RequestHandle *rh)
Cancel a request that is still pending with the resolver.
#define GNUNET_TIME_UNIT_HOURS
One hour.
GNUNET_NAT_AddressClass
Some addresses contain sensitive information or are not suitable for global distribution.
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.
static struct GNUNET_TIME_Relative delta
Definition: speedup.c:35
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
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.
struct ClientHandle * prev
Kept in a DLL.
Handle to a service.
Definition: service.c:114
uint16_t remote_addr_size
Size of the remote address included, in NBO.
Definition: nat.h:171
Handle to a mapping created with upnpc.
`upnpc&#39; command failed to establish port mapping
static struct LocalAddressList * lal_tail
Tail of DLL of local addresses.
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, or when GNUNET_SCHEDULER_shutdown() is being invoked.
Definition: scheduler.c:1284
uint16_t ext_dns_port
Port number we found in hole_external.
#define GNUNET_TIME_UNIT_MINUTES
One minute.
struct GNUNET_MessageHeader header
Header with type GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL.
Definition: nat.h:161
struct GNUNET_STATISTICS_Handle * GNUNET_STATISTICS_create(const char *subsystem, const struct GNUNET_CONFIGURATION_Handle *cfg)
Get handle for the statistics service.
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.
int natted_address
Is any of the caddrs in a reserved subnet for NAT?
Message sent by a client to register with its addresses.
Definition: nat.h:93
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
Closure for ifc_proc.
Client asking the service to initiate connection reversal.
Definition: nat.h:157
char * hole_external
External DNS name and port given by user due to manual hole punching.
#define GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED
Message to from NAT service notifying us that connection reversal was requested by another peer...
void GN_external_ipv4_monitor_stop(struct GN_ExternalIPMonitor *mon)
Stop calling monitor.
uint8_t proto
Client&#39;s IPPROTO, e.g.
Definition: nat.h:107
struct LocalAddressList * prev
Previous entry.
static struct GNUNET_STATISTICS_Handle * stats
Handle to the statistics service.
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.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
uint16_t payload_size
Number of bytes of payload included, in NBO.
Definition: nat.h:146
`upnpc&#39; command took too long, process killed
Addresses that should be our external IP address on the outside of a NAT.
static struct ClientHandle * ch_head
Head of client DLL.
void GN_stop_gnunet_nat_server_(struct HelperContext *h)
Start the gnunet-helper-nat-server and process incoming requests.
uint16_t str_len
Number of bytes in the string that follow which specifies a section name in the configuration.
Definition: nat.h:113
uint16_t local_addr_size
Size of the local address included, in NBO.
Definition: nat.h:166
#define GNUNET_NO
Definition: gnunet_common.h:78
struct GNUNET_SCHEDULER_Task * ext_dns_task
Task for periodically re-running the ext_dns DNS lookup.
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:933
static struct StunExternalIP * se_tail
Kept in a DLL.
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
int GNUNET_OS_check_helper_binary(const char *binary, int check_suid, const char *params)
Check whether an executable exists and possibly if the suid bit is set on the file.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
void GNUNET_OS_network_interfaces_list(GNUNET_OS_NetworkInterfaceProcessor proc, void *proc_cls)
Enumerate all network interfaces.
Definition: os_network.c:388
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format...
static void process_external_ip(void *cls, const struct sockaddr *addr, socklen_t addrlen)
Our (external) hostname was resolved.
void GNUNET_STATISTICS_destroy(struct GNUNET_STATISTICS_Handle *h, int sync_first)
Destroy a handle (free all state associated with it).
static int ret
Final status code.
Definition: gnunet-arm.c:89
Handle for the service.
struct sockaddr_in external_addr
Our external IP address as reported by the STUN server.
char * section_name
Name of the configuration section this client cares about.
List of local addresses this system has.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
static struct GNUNET_SCHEDULER_Task * scan_task
Task scheduled to periodically scan our network interfaces.
runs the gnunet-helper-nat-server
static void handle_stun(void *cls, const struct GNUNET_NAT_HandleStunMessage *message)
Handler for GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from client.
`external-ip&#39; command output invalid
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
struct sockaddr_storage addr
The address itself (i.e.
Handle to monitor for external IP changes.
Handle to a client that is connected to a service.
Definition: service.c:246
static struct ClientHandle * ch_tail
Tail of client DLL.
void GNUNET_NAT_mini_map_stop(struct GNUNET_NAT_MiniHandle *mini)
Remove a mapping created with (mini)upnpc.
int old
GNUNET_YES if we saw this one in the previous iteration, but not in the current iteration and thus mi...
#define GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
Message to ask NAT service to request connection reversal.
#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:52
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:1237
static int is_nat_v4(const struct in_addr *ip)
Test if the given IPv4 address is in a known range for private networks.
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 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 int match_ipv4(const char *network, const struct in_addr *ip, uint8_t bits)
Check if ip is in network with bits netmask.
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_handler_end())
Define "main" method using service macro.
struct GNUNET_RESOLVER_RequestHandle * ext_dns
Handle for (DYN)DNS lookup of our external IP as given in hole_external.
static void handle_register(void *cls, const struct GNUNET_NAT_RegisterMessage *message)
Handler for GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
uint16_t sender_addr_size
Size of the sender address included, in NBO.
Definition: nat.h:141
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:1264
int GNUNET_NAT_stun_handle_packet_(const void *data, size_t len, struct sockaddr_in *arg)
Handle an incoming STUN response.
network address translation traversal service
GNUNET_NAT_StatusCode
Error Types for the NAT subsystem (which can then later be converted/resolved to a string) ...
static void destroy_lal()
Free the DLL starting at lal_head.
static char buf[2048]
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
#define DYNDNS_FREQUENCY
How often do we scan for changes in how our external (dyndns) hostname resolves?
static int result
Global testing status.
uint16_t num_caddrs
Number of addresses that this service is bound to.
uint16_t num_addrs
Number of addresses that this service is bound to that follow.
Definition: nat.h:120
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)...
Code to figure out what our external IPv4 address(es) might be (external IPv4s are what is seen on th...
Loopback addresses, only useful under special cirumstances.
struct LocalAddressList * ext_addr_tail
DLL of external IP addresses as given in hole_external.
static void shutdown_task(void *cls)
Task run during shutdown.
uint8_t flags
An enum GNUNET_NAT_RegisterFlags.
Definition: nat.h:102
void GNUNET_SERVICE_client_drop(struct GNUNET_SERVICE_Client *c)
Ask the server to disconnect from the given client.
Definition: service.c:2315
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.
struct GNUNET_SERVICE_Client * client
The handle to this client.
uint32_t addr_class
Type of the address, an enum GNUNET_NAT_AddressClass in NBO.
Definition: nat.h:210
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...
int 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.
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...
Service telling a client that connection reversal was requested.
Definition: nat.h:182
Struct containing information about a client, handle to connect to it, and any pending messages that ...
#define GNUNET_MESSAGE_TYPE_NAT_REGISTER
Message to ask NAT service to register a client.
struct GN_ExternalIPMonitor * external_monitor
Handle for monitoring external IP changes.
Addresses that are global (i.e.
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
struct GNUNET_MQ_Handle * mq
Message Queue for the channel (which we are implementing).
Definition: cadet_api.c:104
struct GNUNET_MessageHeader header
Header with type GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN.
Definition: nat.h:136
int32_t add_remove
GNUNET_YES to add, GNUNET_NO to remove the address from the list.
Definition: nat.h:205
Handle to a request given to the resolver.
Definition: resolver_api.c:100
const char * name
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 struct GNUNET_MQ_Envelope * ac
Handle to current GNUNET_PEERINFO_add_peer() operation.
struct GNUNET_MQ_Envelope * env
Definition: 005.c:1
struct GNUNET_MQ_Handle * mq
The message queue to this client.
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.
#define GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE
Message to from NAT service notifying us that one of our addresses changed.
`external-ip&#39; command not found
struct ClientAddress * caddrs
Array of addresses used by the service.
struct GNUNET_NAT_MiniHandle * mh
Handle to active UPnP request where we asked upnpc to open a port at the NAT.
static unsigned long long payload
How much data are we currently storing in the database?
static int add
Desired action is to add a record.
Addresses useful in the local wired network, i.e.
#define GNUNET_memcmp(a, b)
Compare memory in a and b, where both must be of the same pointer type.
static const struct GNUNET_CONFIGURATION_Handle * cfg
Handle to our current configuration.
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.
Flag for addresses that are highly sensitive (i.e.
Handle to a message queue.
Definition: mq.c:84
#define GNUNET_strndup(a, length)
Wrapper around GNUNET_xstrndup_.
struct GNUNET_MessageHeader header
Header with type GNUNET_MESSAGE_TYPE_NAT_REGISTER.
Definition: nat.h:97
#define GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN
Message to ask NAT service to handle a STUN packet.
enum RadiotapType __attribute__
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 LocalAddressList * lal_tail
Tail of DLL of local addresses.
int enable_upnp
Is UPnP enabled? GNUNET_YES if enabled, GNUNET_NO if disabled, GNUNET_SYSERR if configuration enabled...
Messages for interaction with gnunet-nat-server and gnunet-nat-service.
struct LocalAddressList * ext_addr_head
DLL of external IP addresses as given in hole_external.
uint8_t proto
Client&#39;s IPPROTO, e.g.
Information we track per client address.
static uint16_t port
Port number.
Definition: gnunet-bcd.c:81
configuration data
Definition: configuration.c:83
static void run(void *cls, const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_SERVICE_Handle *service)
Setup NAT service.
Failed to run upnpc command.
struct GNUNET_MQ_Handle * mq
Definition: 003.c:5
#define GNUNET_log(kind,...)
Entry in list of pending tasks.
Definition: scheduler.c:131
int af
Address family.
struct StunExternalIP * prev
Kept in a DLL.
"no valid address was returned by `external-ip&#39;"
enum GNUNET_NAT_AddressClass ac
What type of address is this?
struct GNUNET_SCHEDULER_Task * timeout_task
Task we run to remove this entry when it is stale.
#define GNUNET_YES
Definition: gnunet_common.h:77
static struct GNUNET_TIME_Relative dyndns_frequency
How often do we scan for changes in how our external (dyndns) hostname resolves?
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:351
This code provides some support for doing STUN transactions.
static void dyndns_lookup(void *cls)
Resolve the hole_external name to figure out our external address from a manually punched hole...
struct GN_ExternalIPMonitor * GN_external_ipv4_monitor_start(GN_NotifyExternalIPv4Change cb, void *cb_cls)
Start monitoring external IPv4 addresses.
static void lookup_hole_external(struct ClientHandle *ch)
Resolve the hole_external name to figure out our external address from a manually punched hole...
void GN_nat_status_changed(int have_nat)
We have changed our opinion about being NATed in the first place.
enum GNUNET_NAT_RegisterFlags flags
What does this client care about?
struct LocalAddressList * lal_head
Head of DLL of local addresses.
int 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".
struct ClientHandle * next
Kept in a DLL.
struct HelperContext * hc
Context for a gnunet-helper-nat-server used to listen for ICMP messages to this client for connection...
struct sockaddr_storage ss
Network address used by the client.
static void client_disconnect_cb(void *cls, struct GNUNET_SERVICE_Client *c, void *internal_cls)
Callback called when a client disconnected from the service.
Information we keep per NAT helper process.
This client wants to be informed about changes to our applicable addresses.
Definition: nat.h:81
struct StunExternalIP * next
Kept in a DLL.
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition: service.c:2234
Failed to run external-ip command.
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
#define GNUNET_malloc(size)
Wrapper around malloc.
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 void notify_clients(struct LocalAddressList *delta, int add)
Notify all clients about a change in the list of addresses this peer has.
static struct LocalAddressList * lal_head
Head of DLL of local addresses.
static struct StunExternalIP * se_head
Kept in a DLL.
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.
#define GNUNET_free(ptr)
Wrapper around free.
Time for relative time used by GNUnet, in microseconds.
struct sockaddr_storage stun_server_addr
Address of the reporting STUN server.
struct LocalAddressList * next
This is a linked list.
GNUNET_NAT_RegisterFlags
Flags specifying the events this client would be interested in being told about.
Definition: nat.h:71
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:956
static int check_stun(void *cls, const struct GNUNET_NAT_HandleStunMessage *message)
Check validity of GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from client.