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 
75 {
79  struct sockaddr_storage ss;
80 
87 
88 };
89 
90 
95 {
100 
105 
110  struct HelperContext *hc;
111 
116  struct sockaddr_storage addr;
117 
121  int af;
122 
128  int old;
129 
134 
135 };
136 
137 
141 struct ClientHandle
142 {
143 
148 
153 
157  struct GNUNET_SERVICE_Client *client;
158 
162  struct GNUNET_MQ_Handle *mq;
163 
168 
178 
183 
188 
194 
199 
204 
209 
213  uint16_t ext_dns_port;
214 
219 
224 
229  uint16_t num_caddrs;
230 
234  uint8_t proto;
235 
236 };
237 
238 
243 {
248 
253 
258 
263  struct sockaddr_in external_addr;
264 
270  struct sockaddr_storage stun_server_addr;
271 
276 };
277 
278 
283 
288 
292 static const struct GNUNET_CONFIGURATION_Handle *cfg;
293 
298 
303 
307 static struct ClientHandle *ch_head;
308 
312 static struct ClientHandle *ch_tail;
313 
317 static struct LocalAddressList *lal_head;
318 
322 static struct LocalAddressList *lal_tail;
323 
327 static struct StunExternalIP *se_head;
328 
332 static struct StunExternalIP *se_tail;
333 
339 
340 
346 static void
348 {
349  GNUNET_CONTAINER_DLL_remove (lal_head,
350  lal_tail,
351  lal);
352  if (NULL != lal->hc)
353  {
355  "Lost NATed local address %s, stopping NAT server\n",
356  GNUNET_a2s ((const struct sockaddr *) &lal->addr,
357  sizeof (struct sockaddr_in)));
358 
360  lal->hc = NULL;
361  }
362  GNUNET_free (lal);
363 }
364 
365 
369 static void
371 {
372  struct LocalAddressList *lal;
373 
374  while (NULL != (lal = lal_head))
375  free_lal (lal);
376 }
377 
378 
387 static int
388 check_register (void *cls,
389  const struct GNUNET_NAT_RegisterMessage *message)
390 {
391  uint16_t num_addrs = ntohs (message->num_addrs);
392  const char *off = (const char *) &message[1];
393  size_t left = ntohs (message->header.size) - sizeof (*message);
394 
395  for (unsigned int i=0;i<num_addrs;i++)
396  {
397  size_t alen;
398  const struct sockaddr *sa = (const struct sockaddr *) off;
399 
400  if (sizeof (sa_family_t) > left)
401  {
402  GNUNET_break (0);
403  return GNUNET_SYSERR;
404  }
405  switch (sa->sa_family)
406  {
407  case AF_INET:
408  alen = sizeof (struct sockaddr_in);
409  break;
410  case AF_INET6:
411  alen = sizeof (struct sockaddr_in6);
412  break;
413 #if AF_UNIX
414  case AF_UNIX:
415  alen = sizeof (struct sockaddr_un);
416  break;
417 #endif
418  default:
419  GNUNET_break (0);
420  return GNUNET_SYSERR;
421  }
422  if (alen > left)
423  {
424  GNUNET_break (0);
425  return GNUNET_SYSERR;
426  }
427  off += alen;
428  left -= alen;
429  }
430  if (left != ntohs (message->str_len))
431  {
432  GNUNET_break (0);
433  return GNUNET_SYSERR;
434  }
435  return GNUNET_OK;
436 }
437 
438 
447 static int
448 match_ipv4 (const char *network,
449  const struct in_addr *ip,
450  uint8_t bits)
451 {
452  struct in_addr net;
453 
454  if (0 == ip->s_addr)
455  return GNUNET_YES;
456  if (0 == bits)
457  return GNUNET_YES;
458  GNUNET_assert (1 == inet_pton (AF_INET,
459  network,
460  &net));
461  return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
462 }
463 
464 
473 static int
474 match_ipv6 (const char *network,
475  const struct in6_addr *ip,
476  uint8_t bits)
477 {
478  struct in6_addr net;
479  struct in6_addr mask;
480  unsigned int off;
481 
482  if (0 == bits)
483  return GNUNET_YES;
484  GNUNET_assert (1 == inet_pton (AF_INET6,
485  network,
486  &net));
487  memset (&mask, 0, sizeof (mask));
488  if (0 == GNUNET_memcmp (&mask,
489  ip))
490  return GNUNET_YES;
491  off = 0;
492  while (bits > 8)
493  {
494  mask.s6_addr[off++] = 0xFF;
495  bits -= 8;
496  }
497  while (bits > 0)
498  {
499  mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
500  bits--;
501  }
502  for (unsigned j = 0; j < sizeof (struct in6_addr) / sizeof (uint32_t); j++)
503  if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
504  (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
505  return GNUNET_NO;
506  return GNUNET_YES;
507 }
508 
509 
517 static int
518 is_nat_v4 (const struct in_addr *ip)
519 {
520  return
521  match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
522  match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
523  match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
524  match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
525  match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
526 }
527 
528 
536 static int
537 is_nat_v6 (const struct in6_addr *ip)
538 {
539  return
540  match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
541  match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
542  match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
543 }
544 
545 
550 {
551 
556 
561 
562 };
563 
564 
578 static int
579 ifc_proc (void *cls,
580  const char *name,
581  int isDefault,
582  const struct sockaddr *addr,
583  const struct sockaddr *broadcast_addr,
584  const struct sockaddr *netmask,
585  socklen_t addrlen)
586 {
587  struct IfcProcContext *ifc_ctx = cls;
588  struct LocalAddressList *lal;
589  size_t alen;
590  const struct in_addr *ip4;
591  const struct in6_addr *ip6;
593 
594  switch (addr->sa_family)
595  {
596  case AF_INET:
597  alen = sizeof (struct sockaddr_in);
598  ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
599  if (match_ipv4 ("127.0.0.0", ip4, 8))
601  else if (is_nat_v4 (ip4))
602  ac = GNUNET_NAT_AC_LAN;
603  else
605  break;
606  case AF_INET6:
607  alen = sizeof (struct sockaddr_in6);
608  ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
609  if (match_ipv6 ("::1", ip6, 128))
611  else if (is_nat_v6 (ip6))
612  ac = GNUNET_NAT_AC_LAN;
613  else
615  if ( (ip6->s6_addr[11] == 0xFF) &&
616  (ip6->s6_addr[12] == 0xFE) )
617  {
618  /* contains a MAC, be extra careful! */
619  ac |= GNUNET_NAT_AC_PRIVATE;
620  }
621  break;
622 #if AF_UNIX
623  case AF_UNIX:
624  GNUNET_break (0);
625  return GNUNET_OK;
626 #endif
627  default:
628  GNUNET_break (0);
629  return GNUNET_OK;
630  }
631  lal = GNUNET_malloc (sizeof (*lal));
632  lal->af = addr->sa_family;
633  lal->ac = ac;
634  GNUNET_memcpy (&lal->addr,
635  addr,
636  alen);
638  ifc_ctx->lal_tail,
639  lal);
640  return GNUNET_OK;
641 }
642 
643 
654 static void
656  struct ClientHandle *ch,
657  int add,
658  const void *addr,
659  size_t addr_len)
660 {
661  struct GNUNET_MQ_Envelope *env;
663 
665  "Notifying client about %s of IP %s\n",
666  add ? "addition" : "removal",
667  GNUNET_a2s (addr,
668  addr_len));
669  env = GNUNET_MQ_msg_extra (msg,
670  addr_len,
672  msg->add_remove = htonl (add);
673  msg->addr_class = htonl (ac);
674  GNUNET_memcpy (&msg[1],
675  addr,
676  addr_len);
677  GNUNET_MQ_send (ch->mq,
678  env);
679 }
680 
681 
690 static void
692  struct ClientHandle *ch,
693  int add)
694 {
695  size_t alen;
696  struct sockaddr_in v4;
697  struct sockaddr_in6 v6;
698 
699  if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
700  {
702  "Not notifying client as it does not care about addresses\n");
703  return;
704  }
705  switch (delta->af)
706  {
707  case AF_INET:
708  alen = sizeof (struct sockaddr_in);
709  GNUNET_memcpy (&v4,
710  &delta->addr,
711  alen);
712 
713  /* Check for client notifications */
714  for (unsigned int i=0;i<ch->num_caddrs;i++)
715  {
716  const struct sockaddr_in *c4;
717 
718  if (AF_INET != ch->caddrs[i].ss.ss_family)
719  continue; /* IPv4 not relevant */
720  c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss;
721  if ( match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) &&
722  (0 != c4->sin_addr.s_addr) &&
723  (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)) )
724  continue; /* bound to loopback, but this is not loopback */
725  if ( (! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) ) &&
726  match_ipv4 ("127.0.0.1", &v4.sin_addr, 8) )
727  continue; /* bound to non-loopback, but this is loopback */
728  if ( (0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
729  (0 != c4->sin_addr.s_addr) &&
730  (! is_nat_v4 (&v4.sin_addr)) )
731  continue; /* based on external-IP, but this IP is not
732  from private address range. */
733  if ( (0 != GNUNET_memcmp (&v4.sin_addr,
734  &c4->sin_addr)) &&
735  (0 != c4->sin_addr.s_addr) &&
736  (! is_nat_v4 (&c4->sin_addr)) )
737  continue; /* this IP is not from private address range,
738  and IP does not match. */
739 
740  /* OK, IP seems relevant, notify client */
741  if (0 == htons (v4.sin_port))
742  v4.sin_port = c4->sin_port;
743  notify_client (delta->ac,
744  ch,
745  add,
746  &v4,
747  alen);
748  }
749  break;
750  case AF_INET6:
751  alen = sizeof (struct sockaddr_in6);
752  GNUNET_memcpy (&v6,
753  &delta->addr,
754  alen);
755  for (unsigned int i=0;i<ch->num_caddrs;i++)
756  {
757  const struct sockaddr_in6 *c6;
758 
759  if (AF_INET6 != ch->caddrs[i].ss.ss_family)
760  continue; /* IPv4 not relevant */
761  c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss;
762  if ( match_ipv6 ("::1", &c6->sin6_addr, 128) &&
763  (0 != GNUNET_memcmp (&c6->sin6_addr,
764  &in6addr_any)) &&
765  (! match_ipv6 ("::1", &v6.sin6_addr, 128)) )
766  continue; /* bound to loopback, but this is not loopback */
767  if ( (! match_ipv6 ("::1", &c6->sin6_addr, 128) ) &&
768  match_ipv6 ("::1", &v6.sin6_addr, 128) )
769  continue; /* bound to non-loopback, but this is loopback */
770  if ( (0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
771  (0 != GNUNET_memcmp (&c6->sin6_addr,
772  &in6addr_any)) &&
773  (! is_nat_v6 (&v6.sin6_addr)) )
774  continue; /* based on external-IP, but this IP is not
775  from private address range. */
776  if ( (0 != GNUNET_memcmp (&v6.sin6_addr,
777  &c6->sin6_addr)) &&
778  (0 != GNUNET_memcmp (&c6->sin6_addr,
779  &in6addr_any)) &&
780  (! is_nat_v6 (&c6->sin6_addr)) )
781  continue; /* this IP is not from private address range,
782  and IP does not match. */
783  if ( (match_ipv6 ("fe80::", &c6->sin6_addr, 10)) &&
784  (0 != GNUNET_memcmp (&c6->sin6_addr,
785  &in6addr_any)) &&
786  (0 != GNUNET_memcmp (&v6.sin6_addr,
787  &c6->sin6_addr)) &&
788  (0 == (delta->ac & GNUNET_NAT_AC_EXTERN)) )
789  continue; /* client bound to link-local, and the other address
790  does not match and is not an external IP */
791 
792  /* OK, IP seems relevant, notify client */
793  if (0 == htons (v6.sin6_port))
794  v6.sin6_port = c6->sin6_port;
795  notify_client (delta->ac,
796  ch,
797  add,
798  &v6,
799  alen);
800  }
801  break;
802  default:
803  GNUNET_break (0);
804  return;
805  }
806 }
807 
808 
816 static void
818  int add)
819 {
820  for (struct ClientHandle *ch = ch_head;
821  NULL != ch;
822  ch = ch->next)
823  check_notify_client (delta,
824  ch,
825  add);
826 }
827 
828 
837 static void
839  const struct in_addr *v4,
840  int add)
841 {
842  struct ClientHandle *ch = cls;
843  struct sockaddr_in sa;
844  int have_v4;
845 
846  /* (0) check if this impacts 'hole_external' */
847  if ( (NULL != ch->hole_external) &&
848  (0 == strcasecmp (ch->hole_external,
849  "AUTO")) )
850  {
851  struct LocalAddressList lal;
852  struct sockaddr_in *s4;
853 
855  "Detected eternal IP, can now back-fill AUTO:%u in hole punching specification of `%s'\n",
856  (unsigned int) ch->ext_dns_port,
857  ch->section_name);
858  memset (&lal, 0, sizeof (lal));
859  s4 = (struct sockaddr_in *) &lal.addr;
860  s4->sin_family = AF_INET;
861  s4->sin_port = htons (ch->ext_dns_port);
862  s4->sin_addr = *v4;
863  lal.af = AF_INET;
865  check_notify_client (&lal,
866  ch,
867  add);
868  }
869 
870  /* (1) check if client cares. */
871  if (! ch->natted_address)
872  return;
873  have_v4 = GNUNET_NO;
874  for (unsigned int i=0;i<ch->num_caddrs;i++)
875  {
876  const struct sockaddr_storage *ss = &ch->caddrs[i].ss;
877 
878  if (AF_INET != ss->ss_family)
879  continue;
880  have_v4 = GNUNET_YES;
881  break;
882  }
883  if (GNUNET_NO == have_v4)
884  return; /* IPv6-only */
885 
886  /* (2) build address info */
887  memset (&sa,
888  0,
889  sizeof (sa));
890  sa.sin_family = AF_INET;
891  sa.sin_addr = *v4;
892  sa.sin_port = htons (0);
893 
895  "Detected eternal IP %s, notifying client of external IP (without port)\n",
896  GNUNET_a2s ((const struct sockaddr *) &sa,
897  sizeof (sa)));
898  /* (3) notify client of change */
902  ch,
903  add,
904  &sa,
905  sizeof (sa));
906 }
907 
908 
916 static void
917 reversal_callback (void *cls,
918  const struct sockaddr_in *ra)
919 {
920  struct LocalAddressList *lal = cls;
921  const struct sockaddr_in *l4;
922 
923  GNUNET_assert (AF_INET == lal->af);
924  l4 = (const struct sockaddr_in *) &lal->addr;
925  for (struct ClientHandle *ch = ch_head;
926  NULL != ch;
927  ch = ch->next)
928  {
930  struct GNUNET_MQ_Envelope *env;
931  int match;
932 
933  /* Check if client is in applicable range for ICMP NAT traversal
934  for this local address */
935  if (! ch->natted_address)
936  continue;
937  match = GNUNET_NO;
938  for (unsigned int i=0;i<ch->num_caddrs;i++)
939  {
940  struct ClientAddress *ca = &ch->caddrs[i];
941  const struct sockaddr_in *c4;
942 
943  if (AF_INET != ca->ss.ss_family)
944  continue;
945  c4 = (const struct sockaddr_in *) &ca->ss;
946  if ( (0 != c4->sin_addr.s_addr) &&
947  (l4->sin_addr.s_addr != c4->sin_addr.s_addr) )
948  continue;
949  match = GNUNET_YES;
950  break;
951  }
952  if (! match)
953  continue;
954 
955  /* Notify applicable client about connection reversal request */
956  env = GNUNET_MQ_msg_extra (crrm,
957  sizeof (struct sockaddr_in),
959  GNUNET_memcpy (&crrm[1],
960  ra,
961  sizeof (struct sockaddr_in));
962  GNUNET_MQ_send (ch->mq,
963  env);
964  }
965 }
966 
967 
973 static void
974 run_scan (void *cls)
975 {
976  struct IfcProcContext ifc_ctx;
977  int found;
978  int have_nat;
979  struct LocalAddressList *lnext;
980 
982  &run_scan,
983  NULL);
984  memset (&ifc_ctx,
985  0,
986  sizeof (ifc_ctx));
988  &ifc_ctx);
989  /* remove addresses that disappeared */
990  for (struct LocalAddressList *lal = lal_head;
991  NULL != lal;
992  lal = lnext)
993  {
994  lnext = lal->next;
995  found = GNUNET_NO;
996  for (struct LocalAddressList *pos = ifc_ctx.lal_head;
997  NULL != pos;
998  pos = pos->next)
999  {
1000  if ( (pos->af == lal->af) &&
1001  (0 == memcmp (&lal->addr,
1002  &pos->addr,
1003  (AF_INET == lal->af)
1004  ? sizeof (struct sockaddr_in)
1005  : sizeof (struct sockaddr_in6))) )
1006  {
1007  found = GNUNET_YES;
1008  }
1009  }
1010  if (GNUNET_NO == found)
1011  {
1012  notify_clients (lal,
1013  GNUNET_NO);
1014  free_lal (lal);
1015  }
1016  }
1017 
1018  /* add addresses that appeared */
1019  have_nat = GNUNET_NO;
1020  for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1021  NULL != pos;
1022  pos = ifc_ctx.lal_head)
1023  {
1024  found = GNUNET_NO;
1025  if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac))
1026  have_nat = GNUNET_YES;
1027  for (struct LocalAddressList *lal = lal_head;
1028  NULL != lal;
1029  lal = lal->next)
1030  {
1031  if ( (pos->af == lal->af) &&
1032  (0 == memcmp (&lal->addr,
1033  &pos->addr,
1034  (AF_INET == lal->af)
1035  ? sizeof (struct sockaddr_in)
1036  : sizeof (struct sockaddr_in6))) )
1037  found = GNUNET_YES;
1038  }
1040  ifc_ctx.lal_tail,
1041  pos);
1042  if (GNUNET_YES == found)
1043  {
1044  GNUNET_free (pos);
1045  }
1046  else
1047  {
1048  notify_clients (pos,
1049  GNUNET_YES);
1050  GNUNET_CONTAINER_DLL_insert (lal_head,
1051  lal_tail,
1052  pos);
1053  if ( (AF_INET == pos->af) &&
1054  (NULL == pos->hc) &&
1055  (0 != (GNUNET_NAT_AC_LAN & pos->ac)) )
1056  {
1057  const struct sockaddr_in *s4
1058  = (const struct sockaddr_in *) &pos->addr;
1059 
1061  "Found NATed local address %s, starting NAT server\n",
1062  GNUNET_a2s ((const struct sockaddr *) &pos->addr,
1063  sizeof (*s4)));
1064  pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
1066  pos,
1067  cfg);
1068  }
1069  }
1070  }
1071  GN_nat_status_changed (have_nat);
1072 }
1073 
1074 
1086 static void
1088  int add_remove,
1089  const struct sockaddr *addr,
1090  socklen_t addrlen,
1092 {
1093  struct ClientHandle *ch = cls;
1095 
1096  switch (result)
1097  {
1099  GNUNET_assert (NULL != addr);
1100  break;
1105  "Running upnpc failed: %d\n",
1106  result);
1107  return;
1110  "external-ip binary not found\n");
1111  return;
1114  "upnpc binary not found\n");
1115  return;
1118  "external-ip binary could not be run\n");
1119  return;
1122  "upnpc failed to create port mapping\n");
1123  return;
1126  "Invalid output from upnpc\n");
1127  return;
1130  "Invalid address returned by upnpc\n");
1131  return;
1132  default:
1133  GNUNET_break (0); /* should not be possible */
1134  return;
1135  }
1136  switch (addr->sa_family)
1137  {
1138  case AF_INET:
1139  ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr)
1142  break;
1143  case AF_INET6:
1144  ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr)
1147  break;
1148  default:
1149  GNUNET_break (0);
1150  return;
1151  }
1153  "upnp external address %s: %s\n",
1154  add_remove ? "added" : "removed",
1155  GNUNET_a2s (addr,
1156  addrlen));
1157  notify_client (ac,
1158  ch,
1159  add_remove,
1160  addr,
1161  addrlen);
1162 }
1163 
1164 
1173 static void
1174 dyndns_lookup (void *cls);
1175 
1176 
1186 static void
1188  const struct sockaddr *addr,
1189  socklen_t addrlen)
1190 {
1191  struct ClientHandle *ch = cls;
1192  struct LocalAddressList *lal;
1193  struct sockaddr_storage ss;
1194  struct sockaddr_in *v4;
1195  struct sockaddr_in6 *v6;
1196 
1197  if (NULL == addr)
1198  {
1199  struct LocalAddressList *laln;
1200 
1201  ch->ext_dns = NULL;
1202  ch->ext_dns_task
1204  &dyndns_lookup,
1205  ch);
1206  /* Current iteration is over, remove 'old' IPs now */
1207  for (lal = ch->ext_addr_head; NULL != lal; lal = laln)
1208  {
1209  laln = lal->next;
1210  if (GNUNET_YES == lal->old)
1211  {
1213  ch->ext_addr_tail,
1214  lal);
1215  check_notify_client (lal,
1216  ch,
1217  GNUNET_NO);
1218  GNUNET_free (lal);
1219  }
1220  }
1221  return;
1222  }
1224  "Got IP `%s' for external address `%s'\n",
1225  GNUNET_a2s (addr,
1226  addrlen),
1227  ch->hole_external);
1228 
1229  /* build sockaddr storage with port number */
1230  memset (&ss,
1231  0,
1232  sizeof (ss));
1233  GNUNET_memcpy (&ss,
1234  addr,
1235  addrlen);
1236  switch (addr->sa_family)
1237  {
1238  case AF_INET:
1239  v4 = (struct sockaddr_in *) &ss;
1240  v4->sin_port = htons (ch->ext_dns_port);
1241  break;
1242  case AF_INET6:
1243  v6 = (struct sockaddr_in6 *) &ss;
1244  v6->sin6_port = htons (ch->ext_dns_port);
1245  break;
1246  default:
1247  GNUNET_break (0);
1248  return;
1249  }
1250  /* See if 'ss' matches any of our known addresses */
1251  for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1252  {
1253  if (GNUNET_NO == lal->old)
1254  continue; /* already processed, skip */
1255  if ( (addr->sa_family == lal->addr.ss_family) &&
1256  (0 == memcmp (&ss,
1257  &lal->addr,
1258  addrlen)) )
1259  {
1260  /* Address unchanged, remember so we do not remove */
1261  lal->old = GNUNET_NO;
1262  return; /* done here */
1263  }
1264  }
1265  /* notify client, and remember IP for later removal! */
1266  lal = GNUNET_new (struct LocalAddressList);
1267  lal->addr = ss;
1268  lal->af = ss.ss_family;
1271  ch->ext_addr_tail,
1272  lal);
1273  check_notify_client (lal,
1274  ch,
1275  GNUNET_YES);
1276 }
1277 
1278 
1287 static void
1288 dyndns_lookup (void *cls)
1289 {
1290  struct ClientHandle *ch = cls;
1291  struct LocalAddressList *lal;
1292 
1294  "Performing DNS lookup for punched hole given for `%s' as `%s:%u'\n",
1295  ch->section_name,
1296  ch->hole_external,
1297  (unsigned int) ch->ext_dns_port);
1298  for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1299  lal->old = GNUNET_YES;
1300  ch->ext_dns_task = NULL;
1302  AF_UNSPEC,
1305  ch);
1306 }
1307 
1308 
1320 static void
1322 {
1323  char *port;
1324  unsigned int pnum;
1325  struct sockaddr_in *s4;
1326  struct LocalAddressList *lal;
1327 
1328  port = strrchr (ch->hole_external, ':');
1329  if (NULL == port)
1330  {
1332  _("Malformed punched hole specification `%s' (lacks port)\n"),
1333  ch->hole_external);
1334  return;
1335  }
1336  if ( (1 != sscanf (port + 1,
1337  "%u",
1338  &pnum)) ||
1339  (pnum > 65535) )
1340  {
1342  _("Invalid port number in punched hole specification `%s' (lacks port)\n"),
1343  port + 1);
1344  return;
1345  }
1346  ch->ext_dns_port = (uint16_t) pnum;
1347  *port = '\0';
1348 
1349  lal = GNUNET_new (struct LocalAddressList);
1350  if ('[' == *ch->hole_external)
1351  {
1352  struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &lal->addr;
1353 
1354  s6->sin6_family = AF_INET6;
1355  if (']' != (ch->hole_external[strlen(ch->hole_external)-1]))
1356  {
1358  _("Malformed punched hole specification `%s' (lacks `]')\n"),
1359  ch->hole_external);
1360  GNUNET_free (lal);
1361  return;
1362  }
1363  ch->hole_external[strlen(ch->hole_external)-1] = '\0';
1364  if (1 != inet_pton (AF_INET6,
1365  ch->hole_external + 1,
1366  &s6->sin6_addr))
1367  {
1369  _("Malformed punched hole specification `%s' (IPv6 address invalid)"),
1370  ch->hole_external + 1);
1371  GNUNET_free (lal);
1372  return;
1373  }
1374  s6->sin6_port = htons (ch->ext_dns_port);
1375  lal->af = AF_INET6;
1378  ch->ext_addr_tail,
1379  lal);
1380  check_notify_client (lal,
1381  ch,
1382  GNUNET_YES);
1383  return;
1384  }
1385 
1386  s4 = (struct sockaddr_in *) &lal->addr;
1387  s4->sin_family = AF_INET;
1388  if (1 == inet_pton (AF_INET,
1389  ch->hole_external,
1390  &s4->sin_addr))
1391  {
1393  "IPv4 punched hole given for `%s' via `%s:%u'\n",
1394  ch->section_name,
1395  ch->hole_external,
1396  (unsigned int) ch->ext_dns_port);
1397  s4->sin_port = htons (ch->ext_dns_port);
1398  lal->af = AF_INET;
1401  ch->ext_addr_tail,
1402  lal);
1403  check_notify_client (lal,
1404  ch,
1405  GNUNET_YES);
1406  return;
1407  }
1408  if (0 == strcasecmp (ch->hole_external,
1409  "AUTO"))
1410  {
1411  /* handled in #notify_client_external_ipv4_change() */
1412  GNUNET_free (lal);
1413  return;
1414  }
1415  /* got a DNS name, trigger lookup! */
1416  GNUNET_free (lal);
1417  ch->ext_dns_task
1419  ch);
1420 }
1421 
1422 
1430 static void
1431 handle_register (void *cls,
1432  const struct GNUNET_NAT_RegisterMessage *message)
1433 {
1434  struct ClientHandle *ch = cls;
1435  const char *off;
1436  size_t left;
1437 
1438  if ( (0 != ch->proto) ||
1439  (NULL != ch->caddrs) )
1440  {
1441  /* double registration not allowed */
1442  GNUNET_break (0);
1444  return;
1445  }
1446  ch->flags = message->flags;
1447  ch->proto = message->proto;
1448  ch->num_caddrs = ntohs (message->num_addrs);
1449  ch->caddrs = GNUNET_new_array (ch->num_caddrs,
1450  struct ClientAddress);
1451  left = ntohs (message->header.size) - sizeof (*message);
1452  off = (const char *) &message[1];
1453  for (unsigned int i=0;i<ch->num_caddrs;i++)
1454  {
1455  const struct sockaddr *sa = (const struct sockaddr *) off;
1456  size_t alen;
1457  uint16_t port;
1458  int is_nat;
1459 
1460  if (sizeof (sa_family_t) > left)
1461  {
1462  GNUNET_break (0);
1464  return;
1465  }
1466  is_nat = GNUNET_NO;
1467  switch (sa->sa_family)
1468  {
1469  case AF_INET:
1470  {
1471  struct sockaddr_in s4;
1472 
1473  GNUNET_memcpy (&s4,
1474  off,
1475  sizeof (struct sockaddr_in));
1476  alen = sizeof (struct sockaddr_in);
1477  if (is_nat_v4 (&s4.sin_addr))
1478  is_nat = GNUNET_YES;
1479  port = ntohs (s4.sin_port);
1480  }
1481  break;
1482  case AF_INET6:
1483  {
1484  struct sockaddr_in6 s6;
1485 
1486  GNUNET_memcpy (&s6,
1487  off,
1488  sizeof (struct sockaddr_in6));
1489  alen = sizeof (struct sockaddr_in6);
1490  if (is_nat_v6 (&s6.sin6_addr))
1491  is_nat = GNUNET_YES;
1492  port = ntohs (s6.sin6_port);
1493  }
1494  break;
1495 #if AF_UNIX
1496  case AF_UNIX:
1497  alen = sizeof (struct sockaddr_un);
1498  port = 0;
1499  break;
1500 #endif
1501  default:
1502  GNUNET_break (0);
1504  return;
1505  }
1506  /* store address */
1507  GNUNET_assert (alen <= left);
1508  GNUNET_assert (alen <= sizeof (struct sockaddr_storage));
1509  GNUNET_memcpy (&ch->caddrs[i].ss,
1510  off,
1511  alen);
1512 
1513  /* If applicable, try UPNPC NAT punching */
1514  if ( (is_nat) &&
1515  (enable_upnp) &&
1516  ( (IPPROTO_TCP == ch->proto) ||
1517  (IPPROTO_UDP == ch->proto) ) )
1518  {
1519  ch->natted_address = GNUNET_YES;
1520  ch->caddrs[i].mh
1521  = GNUNET_NAT_mini_map_start (port,
1522  IPPROTO_TCP == ch->proto,
1524  ch);
1525  }
1526 
1527  off += alen;
1528  }
1529 
1530  ch->section_name
1531  = GNUNET_strndup (off,
1532  ntohs (message->str_len));
1534  "Received REGISTER message from client for subsystem `%s'\n",
1535  ch->section_name);
1536  if (GNUNET_OK ==
1538  ch->section_name,
1539  "HOLE_EXTERNAL",
1540  &ch->hole_external))
1541  lookup_hole_external (ch);
1542 
1543  /* Actually send IP address list to client */
1544  for (struct LocalAddressList *lal = lal_head;
1545  NULL != lal;
1546  lal = lal->next)
1547  {
1548  check_notify_client (lal,
1549  ch,
1550  GNUNET_YES);
1551  }
1552  /* Also consider IPv4 determined by `external-ip` */
1553  ch->external_monitor
1555  ch);
1557 }
1558 
1559 
1568 static int
1569 check_stun (void *cls,
1570  const struct GNUNET_NAT_HandleStunMessage *message)
1571 {
1572  size_t sa_len = ntohs (message->sender_addr_size);
1573  size_t expect = sa_len + ntohs (message->payload_size);
1574 
1575  if (ntohs (message->header.size) - sizeof (*message) != expect)
1576  {
1577  GNUNET_break (0);
1578  return GNUNET_SYSERR;
1579  }
1580  if (sa_len < sizeof (sa_family_t))
1581  {
1582  GNUNET_break (0);
1583  return GNUNET_SYSERR;
1584  }
1585  return GNUNET_OK;
1586 }
1587 
1588 
1596 static void
1597 notify_clients_stun_change (const struct sockaddr_in *ip,
1598  int add)
1599 {
1600  for (struct ClientHandle *ch = ch_head;
1601  NULL != ch;
1602  ch = ch->next)
1603  {
1604  struct sockaddr_in v4;
1606  struct GNUNET_MQ_Envelope *env;
1607 
1608  if (! ch->natted_address)
1609  continue;
1610  v4 = *ip;
1611  v4.sin_port = htons (0);
1612  env = GNUNET_MQ_msg_extra (msg,
1613  sizeof (v4),
1615  msg->add_remove = htonl ((int32_t) add);
1616  msg->addr_class = htonl (GNUNET_NAT_AC_EXTERN |
1618  GNUNET_memcpy (&msg[1],
1619  &v4,
1620  sizeof (v4));
1621  GNUNET_MQ_send (ch->mq,
1622  env);
1623  }
1624 }
1625 
1626 
1634 static void
1635 stun_ip_timeout (void *cls)
1636 {
1637  struct StunExternalIP *se = cls;
1638 
1639  se->timeout_task = NULL;
1641  GNUNET_NO);
1642  GNUNET_CONTAINER_DLL_remove (se_head,
1643  se_tail,
1644  se);
1645  GNUNET_free (se);
1646 }
1647 
1648 
1656 static void
1657 handle_stun (void *cls,
1658  const struct GNUNET_NAT_HandleStunMessage *message)
1659 {
1660  struct ClientHandle *ch = cls;
1661  const char *buf = (const char *) &message[1];
1662  const struct sockaddr *sa;
1663  const void *payload;
1664  size_t sa_len;
1665  size_t payload_size;
1666  struct sockaddr_in external_addr;
1667 
1668  sa_len = ntohs (message->sender_addr_size);
1669  payload_size = ntohs (message->payload_size);
1670  sa = (const struct sockaddr *) &buf[0];
1671  payload = (const struct sockaddr *) &buf[sa_len];
1672  switch (sa->sa_family)
1673  {
1674  case AF_INET:
1675  if (sa_len != sizeof (struct sockaddr_in))
1676  {
1677  GNUNET_break (0);
1679  return;
1680  }
1681  break;
1682  case AF_INET6:
1683  if (sa_len != sizeof (struct sockaddr_in6))
1684  {
1685  GNUNET_break (0);
1687  return;
1688  }
1689  break;
1690  }
1692  "Received HANDLE_STUN message from client\n");
1693  if (GNUNET_OK ==
1695  payload_size,
1696  &external_addr))
1697  {
1698  /* We now know that a server at "sa" claims that
1699  we are visible at IP "external_addr".
1700 
1701  We should (for some fixed period of time) tell
1702  all of our clients that listen to a NAT'ed address
1703  that they might want to consider the given 'external_ip'
1704  as their public IP address (this includes TCP and UDP
1705  clients, even if only UDP sends STUN requests).
1706 
1707  If we do not get a renewal, the "external_addr" should be
1708  removed again. The timeout frequency should be configurable
1709  (with a sane default), so that the UDP plugin can tell how
1710  often to re-request STUN.
1711  */
1712  struct StunExternalIP *se;
1713 
1714  /* Check if we had a prior response from this STUN server */
1715  for (se = se_head; NULL != se; se = se->next)
1716  {
1717  if ( (se->stun_server_addr_len != sa_len) ||
1718  (0 != memcmp (sa,
1719  &se->stun_server_addr,
1720  sa_len)) )
1721  continue; /* different STUN server */
1722  if (0 != GNUNET_memcmp (&external_addr,
1723  &se->external_addr))
1724  {
1725  /* external IP changed, update! */
1727  GNUNET_NO);
1730  GNUNET_YES);
1731  }
1732  /* update timeout */
1734  se->timeout_task
1736  &stun_ip_timeout,
1737  se);
1738  return;
1739  }
1740  /* STUN server is completely new, create fresh entry */
1741  se = GNUNET_new (struct StunExternalIP);
1744  sa,
1745  sa_len);
1746  se->stun_server_addr_len = sa_len;
1748  &stun_ip_timeout,
1749  se);
1750  GNUNET_CONTAINER_DLL_insert (se_head,
1751  se_tail,
1752  se);
1754  GNUNET_NO);
1755  }
1757 }
1758 
1759 
1769 static int
1771  const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1772 {
1773  size_t expect;
1774 
1775  expect = ntohs (message->local_addr_size)
1776  + ntohs (message->remote_addr_size);
1777  if (ntohs (message->header.size) - sizeof (*message) != expect)
1778  {
1779  GNUNET_break (0);
1780  return GNUNET_SYSERR;
1781  }
1782  return GNUNET_OK;
1783 }
1784 
1785 
1793 static void
1795  const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1796 {
1797  struct ClientHandle *ch = cls;
1798  const char *buf = (const char *) &message[1];
1799  size_t local_sa_len = ntohs (message->local_addr_size);
1800  size_t remote_sa_len = ntohs (message->remote_addr_size);
1801  struct sockaddr_in l4;
1802  struct sockaddr_in r4;
1803  int ret;
1804 
1806  "Received REQUEST CONNECTION REVERSAL message from client\n");
1807  if (local_sa_len != sizeof (struct sockaddr_in))
1808  {
1809  GNUNET_break_op (0);
1811  return;
1812  }
1813  if (remote_sa_len != sizeof (struct sockaddr_in))
1814  {
1815  GNUNET_break_op (0);
1817  return;
1818  }
1819  GNUNET_memcpy (&l4,
1820  buf,
1821  sizeof (struct sockaddr_in));
1822  GNUNET_break_op (AF_INET == l4.sin_family);
1823  buf += sizeof (struct sockaddr_in);
1824  GNUNET_memcpy (&r4,
1825  buf,
1826  sizeof (struct sockaddr_in));
1827  GNUNET_break_op (AF_INET == r4.sin_family);
1828  ret = GN_request_connection_reversal (&l4.sin_addr,
1829  ntohs (l4.sin_port),
1830  &r4.sin_addr,
1831  cfg);
1832  if (GNUNET_OK != ret)
1834  _("Connection reversal request failed\n"));
1836 }
1837 
1838 
1844 static void
1845 shutdown_task (void *cls)
1846 {
1847  struct StunExternalIP *se;
1848 
1849  while (NULL != (se = se_head))
1850  {
1851  GNUNET_CONTAINER_DLL_remove (se_head,
1852  se_tail,
1853  se);
1855  GNUNET_free (se);
1856  }
1858  if (NULL != scan_task)
1859  {
1860  GNUNET_SCHEDULER_cancel (scan_task);
1861  scan_task = NULL;
1862  }
1863  if (NULL != stats)
1864  {
1866  GNUNET_NO);
1867  stats = NULL;
1868  }
1869  destroy_lal ();
1870 }
1871 
1872 
1880 static void
1881 run (void *cls,
1882  const struct GNUNET_CONFIGURATION_Handle *c,
1884 {
1885  cfg = c;
1886  if (GNUNET_OK !=
1888  "NAT",
1889  "STUN_STALE",
1892 
1893  /* Check for UPnP */
1894  enable_upnp
1896  "NAT",
1897  "ENABLE_UPNP");
1898  if (GNUNET_YES == enable_upnp)
1899  {
1900  /* check if it works */
1901  if (GNUNET_SYSERR ==
1903  GNUNET_NO,
1904  NULL))
1905  {
1907  _("UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
1909  }
1910  }
1911  if (GNUNET_OK !=
1913  "nat",
1914  "DYNDNS_FREQUENCY",
1915  &dyndns_frequency))
1917 
1919  NULL);
1920  stats = GNUNET_STATISTICS_create ("nat",
1921  cfg);
1922  scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
1923  NULL);
1924 }
1925 
1926 
1935 static void *
1937  struct GNUNET_SERVICE_Client *c,
1938  struct GNUNET_MQ_Handle *mq)
1939 {
1940  struct ClientHandle *ch;
1941 
1942  ch = GNUNET_new (struct ClientHandle);
1943  ch->mq = mq;
1944  ch->client = c;
1945  GNUNET_CONTAINER_DLL_insert (ch_head,
1946  ch_tail,
1947  ch);
1948  return ch;
1949 }
1950 
1951 
1959 static void
1961  struct GNUNET_SERVICE_Client *c,
1962  void *internal_cls)
1963 {
1964  struct ClientHandle *ch = internal_cls;
1965  struct LocalAddressList *lal;
1966 
1967  GNUNET_CONTAINER_DLL_remove (ch_head,
1968  ch_tail,
1969  ch);
1970  for (unsigned int i=0;i<ch->num_caddrs;i++)
1971  {
1972  if (NULL != ch->caddrs[i].mh)
1973  {
1975  ch->caddrs[i].mh = NULL;
1976  }
1977  }
1979  while (NULL != (lal = ch->ext_addr_head))
1980  {
1982  ch->ext_addr_tail,
1983  lal);
1984  GNUNET_free (lal);
1985  }
1986  if (NULL != ch->ext_dns_task)
1987  {
1989  ch->ext_dns_task = NULL;
1990  }
1991  if (NULL != ch->external_monitor)
1992  {
1994  ch->external_monitor = NULL;
1995  }
1996  if (NULL != ch->ext_dns)
1997  {
1999  ch->ext_dns = NULL;
2000  }
2003  GNUNET_free (ch);
2004 }
2005 
2006 
2011 ("nat",
2013  &run,
2016  NULL,
2017  GNUNET_MQ_hd_var_size (register,
2020  NULL),
2021  GNUNET_MQ_hd_var_size (stun,
2024  NULL),
2025  GNUNET_MQ_hd_var_size (request_connection_reversal,
2028  NULL),
2030 
2031 
2032 #if defined(LINUX) && defined(__GLIBC__)
2033 #include <malloc.h>
2034 
2038 void __attribute__ ((constructor))
2039 GNUNET_ARM_memory_init ()
2040 {
2041  mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2042  mallopt (M_TOP_PAD, 1 * 1024);
2043  malloc_trim (0);
2044 }
2045 #endif
2046 
2047 /* 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:137
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:206
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:116
uint16_t remote_addr_size
Size of the remote address included, in NBO.
Definition: nat.h:178
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:1293
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:168
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:96
#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:163
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:111
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.
uint16_t payload_size
Number of bytes of payload included, in NBO.
Definition: nat.h:152
`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:117
uint16_t local_addr_size
Size of the local address included, in NBO.
Definition: nat.h:173
#define GNUNET_NO
Definition: gnunet_common.h:81
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:927
static struct StunExternalIP * se_tail
Kept in a DLL.
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
#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:208
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:249
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:1246
static int is_nat_v4(const struct in_addr *ip)
Test if the given IPv4 address is in a known range for private networks.
#define GNUNET_memcpy(dst, src, n)
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:147
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:1273
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.
GUID ip4
uint16_t num_addrs
Number of addresses that this service is bound to that follow.
Definition: nat.h:124
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:106
void GNUNET_SERVICE_client_drop(struct GNUNET_SERVICE_Client *c)
Ask the server to disconnect from the given client.
Definition: service.c:2618
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:221
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:190
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:79
struct GNUNET_MQ_Handle * mq
Message Queue for the channel (which we are implementing).
Definition: cadet_api.c:107
struct GNUNET_MessageHeader header
Header with type GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN.
Definition: nat.h:142
int32_t add_remove
GNUNET_YES to add, GNUNET_NO to remove the address from the list.
Definition: nat.h:216
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:85
#define GNUNET_strndup(a, length)
Wrapper around GNUNET_xstrndup_.
struct GNUNET_MessageHeader header
Header with type GNUNET_MESSAGE_TYPE_NAT_REGISTER.
Definition: nat.h:101
#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:79
configuration data
Definition: configuration.c:85
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
static int inet_pton(int af, const char *cp, struct in_addr *buf)
Convert IPv4 address from text to binary form.
#define GNUNET_log(kind,...)
Entry in list of pending tasks.
Definition: scheduler.c:134
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:80
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:353
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.
GUID ip6
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:84
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:2533
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:73
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:965
static int check_stun(void *cls, const struct GNUNET_NAT_HandleStunMessage *message)
Check validity of GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from client.