GNUnet  0.19.5
gnunet-service-nat.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2016, 2017 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 
37 #include "platform.h"
38 #include <math.h>
39 #include "gnunet_util_lib.h"
40 #include "gnunet_protocols.h"
41 #include "gnunet_signatures.h"
44 #include "gnunet_nat_service.h"
45 #include "gnunet-service-nat.h"
50 #include "nat.h"
51 #include <gcrypt.h>
52 
53 
58 #define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
59 
63 #define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply ( \
64  GNUNET_TIME_UNIT_SECONDS, 5)
65 
69 #define DYNDNS_FREQUENCY GNUNET_TIME_relative_multiply ( \
70  GNUNET_TIME_UNIT_MINUTES, 7)
71 
72 
77 {
81  struct sockaddr_storage ss;
82 
89 };
90 
91 
96 {
101 
106 
111  struct HelperContext *hc;
112 
117  struct sockaddr_storage addr;
118 
122  int af;
123 
129  int old;
130 
135 };
136 
137 
141 struct ClientHandle
142 {
147 
152 
157 
161  struct GNUNET_MQ_Handle *mq;
162 
167 
177 
182 
187 
193 
198 
203 
208 
212  uint16_t ext_dns_port;
213 
218 
223 
228  uint16_t num_caddrs;
229 
233  uint8_t proto;
234 };
235 
236 
241 {
246 
251 
256 
261  struct sockaddr_in external_addr;
262 
268  struct sockaddr_storage stun_server_addr;
269 
274 };
275 
276 
281 
286 
290 static const struct GNUNET_CONFIGURATION_Handle *cfg;
291 
296 
301 
305 static struct ClientHandle *ch_head;
306 
310 static struct ClientHandle *ch_tail;
311 
315 static struct LocalAddressList *lal_head;
316 
320 static struct LocalAddressList *lal_tail;
321 
325 static struct StunExternalIP *se_head;
326 
330 static struct StunExternalIP *se_tail;
331 
337 
343 
349 static void
351 {
353  lal_tail,
354  lal);
355  if (NULL != lal->hc)
356  {
358  "Lost NATed local address %s, stopping NAT server\n",
359  GNUNET_a2s ((const struct sockaddr *) &lal->addr,
360  sizeof(struct sockaddr_in)));
361 
363  lal->hc = NULL;
364  }
365  GNUNET_free (lal);
366 }
367 
368 
372 static void
374 {
375  struct LocalAddressList *lal;
376 
377  while (NULL != (lal = lal_head))
378  free_lal (lal);
379 }
380 
381 
390 static int
391 check_register (void *cls,
392  const struct GNUNET_NAT_RegisterMessage *message)
393 {
394  uint16_t num_addrs = ntohs (message->num_addrs);
395  const char *off = (const char *) &message[1];
396  size_t left = ntohs (message->header.size) - sizeof(*message);
397 
398  for (unsigned int i = 0; i < num_addrs; i++)
399  {
400  size_t alen;
401  const struct sockaddr *sa = (const struct sockaddr *) off;
402 
403  if (sizeof(sa_family_t) > left)
404  {
405  GNUNET_break (0);
406  return GNUNET_SYSERR;
407  }
408  switch (sa->sa_family)
409  {
410  case AF_INET:
411  alen = sizeof(struct sockaddr_in);
412  break;
413 
414  case AF_INET6:
415  alen = sizeof(struct sockaddr_in6);
416  break;
417 
418 #if AF_UNIX
419  case AF_UNIX:
420  alen = sizeof(struct sockaddr_un);
421  break;
422 #endif
423  default:
424  GNUNET_break (0);
425  return GNUNET_SYSERR;
426  }
427  if (alen > left)
428  {
429  GNUNET_break (0);
430  return GNUNET_SYSERR;
431  }
432  off += alen;
433  left -= alen;
434  }
435  if (left != ntohs (message->str_len))
436  {
437  GNUNET_break (0);
438  return GNUNET_SYSERR;
439  }
440  return GNUNET_OK;
441 }
442 
443 
452 static int
453 match_ipv4 (const char *network,
454  const struct in_addr *ip,
455  uint8_t bits)
456 {
457  struct in_addr net;
458 
459  if (0 == ip->s_addr)
460  return GNUNET_YES;
461  if (0 == bits)
462  return GNUNET_YES;
463  GNUNET_assert (1 == inet_pton (AF_INET,
464  network,
465  &net));
466  return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
467 }
468 
469 
478 static int
479 match_ipv6 (const char *network,
480  const struct in6_addr *ip,
481  uint8_t bits)
482 {
483  struct in6_addr net;
484  struct in6_addr mask;
485  unsigned int off;
486 
487  if (0 == bits)
488  return GNUNET_YES;
489  GNUNET_assert (1 == inet_pton (AF_INET6,
490  network,
491  &net));
492  memset (&mask, 0, sizeof(mask));
493  if (0 == GNUNET_memcmp (&mask,
494  ip))
495  return GNUNET_YES;
496  off = 0;
497  while (bits > 8)
498  {
499  mask.s6_addr[off++] = 0xFF;
500  bits -= 8;
501  }
502  while (bits > 0)
503  {
504  mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
505  bits--;
506  }
507  for (unsigned j = 0; j < sizeof(struct in6_addr) / sizeof(uint32_t); j++)
508  if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
509  (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
510  return GNUNET_NO;
511  return GNUNET_YES;
512 }
513 
514 
522 static int
523 is_nat_v4 (const struct in_addr *ip)
524 {
525  return
526  match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
527  match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
528  match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
529  match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
530  match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
531 }
532 
533 
541 static int
542 is_nat_v6 (const struct in6_addr *ip)
543 {
544  return
545  match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
546  match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
547  match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
548 }
549 
550 
555 {
560 
565 };
566 
567 
581 static int
582 ifc_proc (void *cls,
583  const char *name,
584  int isDefault,
585  const struct sockaddr *addr,
586  const struct sockaddr *broadcast_addr,
587  const struct sockaddr *netmask,
588  socklen_t addrlen)
589 {
590  struct IfcProcContext *ifc_ctx = cls;
591  struct LocalAddressList *lal;
592  size_t alen;
593  const struct in_addr *ip4;
594  const struct in6_addr *ip6;
596 
597  switch (addr->sa_family)
598  {
599  case AF_INET:
600  alen = sizeof(struct sockaddr_in);
601  ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
602  if (match_ipv4 ("127.0.0.0", ip4, 8))
604  else if (is_nat_v4 (ip4))
606  else
608  break;
609 
610  case AF_INET6:
611  alen = sizeof(struct sockaddr_in6);
612  ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
613  if (match_ipv6 ("::1", ip6, 128))
615  else if (is_nat_v6 (ip6))
617  else
619  if ((ip6->s6_addr[11] == 0xFF) &&
620  (ip6->s6_addr[12] == 0xFE))
621  {
622  /* contains a MAC, be extra careful! */
624  }
625  break;
626 
627 #if AF_UNIX
628  case AF_UNIX:
629  GNUNET_break (0);
630  return GNUNET_OK;
631 #endif
632  default:
633  GNUNET_break (0);
634  return GNUNET_OK;
635  }
636  lal = GNUNET_malloc (sizeof(*lal));
637  lal->af = addr->sa_family;
638  lal->ac = ac;
639  GNUNET_memcpy (&lal->addr,
640  addr,
641  alen);
643  ifc_ctx->lal_tail,
644  lal);
645  return GNUNET_OK;
646 }
647 
648 
659 static void
661  struct ClientHandle *ch,
662  int add,
663  const void *addr,
664  size_t addr_len)
665 {
666  struct GNUNET_MQ_Envelope *env;
668 
670  "Notifying client about %s of IP %s\n",
671  add ? "addition" : "removal",
672  GNUNET_a2s (addr,
673  addr_len));
675  addr_len,
677  msg->add_remove = htonl (add);
678  msg->addr_class = htonl (ac);
679  GNUNET_memcpy (&msg[1],
680  addr,
681  addr_len);
682  GNUNET_MQ_send (ch->mq,
683  env);
684 }
685 
686 
695 static void
697  struct ClientHandle *ch,
698  int add)
699 {
700  size_t alen;
701  struct sockaddr_in v4;
702  struct sockaddr_in6 v6;
703 
704  if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
705  {
707  "Not notifying client as it does not care about addresses\n");
708  return;
709  }
710  switch (delta->af)
711  {
712  case AF_INET:
713  alen = sizeof(struct sockaddr_in);
714  GNUNET_memcpy (&v4,
715  &delta->addr,
716  alen);
717 
718  /* Check for client notifications */
719  for (unsigned int i = 0; i < ch->num_caddrs; i++)
720  {
721  const struct sockaddr_in *c4;
722 
723  if (AF_INET != ch->caddrs[i].ss.ss_family)
724  continue; /* IPv4 not relevant */
725  c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss;
726  if (match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) &&
727  (0 != c4->sin_addr.s_addr) &&
728  (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)))
729  continue; /* bound to loopback, but this is not loopback */
730  if ((! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8)) &&
731  match_ipv4 ("127.0.0.1", &v4.sin_addr, 8))
732  continue; /* bound to non-loopback, but this is loopback */
733  if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
734  (0 != c4->sin_addr.s_addr) &&
735  (! is_nat_v4 (&v4.sin_addr)))
736  continue; /* based on external-IP, but this IP is not
737  from private address range. */
738  if ((0 != GNUNET_memcmp (&v4.sin_addr,
739  &c4->sin_addr)) &&
740  (0 != c4->sin_addr.s_addr) &&
741  (! is_nat_v4 (&c4->sin_addr)))
742  continue; /* this IP is not from private address range,
743  and IP does not match. */
744 
745  /* OK, IP seems relevant, notify client */
746  if (0 == htons (v4.sin_port))
747  v4.sin_port = c4->sin_port;
748  notify_client (delta->ac,
749  ch,
750  add,
751  &v4,
752  alen);
753  }
754  break;
755 
756  case AF_INET6:
757  alen = sizeof(struct sockaddr_in6);
758  GNUNET_memcpy (&v6,
759  &delta->addr,
760  alen);
761  for (unsigned int i = 0; i < ch->num_caddrs; i++)
762  {
763  const struct sockaddr_in6 *c6;
764 
765  if (AF_INET6 != ch->caddrs[i].ss.ss_family)
766  continue; /* IPv4 not relevant */
767  c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss;
768  if (match_ipv6 ("::1", &c6->sin6_addr, 128) &&
769  (0 != GNUNET_memcmp (&c6->sin6_addr,
770  &in6addr_any)) &&
771  (! match_ipv6 ("::1", &v6.sin6_addr, 128)))
772  continue; /* bound to loopback, but this is not loopback */
773  if ((! match_ipv6 ("::1", &c6->sin6_addr, 128)) &&
774  match_ipv6 ("::1", &v6.sin6_addr, 128))
775  continue; /* bound to non-loopback, but this is loopback */
776  if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
777  (0 != GNUNET_memcmp (&c6->sin6_addr,
778  &in6addr_any)) &&
779  (! is_nat_v6 (&v6.sin6_addr)))
780  continue; /* based on external-IP, but this IP is not
781  from private address range. */
782  if ((0 != GNUNET_memcmp (&v6.sin6_addr,
783  &c6->sin6_addr)) &&
784  (0 != GNUNET_memcmp (&c6->sin6_addr,
785  &in6addr_any)) &&
786  (! is_nat_v6 (&c6->sin6_addr)))
787  continue; /* this IP is not from private address range,
788  and IP does not match. */
789  if ((match_ipv6 ("fe80::", &c6->sin6_addr, 10)) &&
790  (0 != GNUNET_memcmp (&c6->sin6_addr,
791  &in6addr_any)) &&
792  (0 != GNUNET_memcmp (&v6.sin6_addr,
793  &c6->sin6_addr)) &&
794  (0 == (delta->ac & GNUNET_NAT_AC_EXTERN)))
795  continue; /* client bound to link-local, and the other address
796  does not match and is not an external IP */
797 
798  /* OK, IP seems relevant, notify client */
799  if (0 == htons (v6.sin6_port))
800  v6.sin6_port = c6->sin6_port;
801  notify_client (delta->ac,
802  ch,
803  add,
804  &v6,
805  alen);
806  }
807  break;
808 
809  default:
810  GNUNET_break (0);
811  return;
812  }
813 }
814 
815 
823 static void
825  int add)
826 {
827  for (struct ClientHandle *ch = ch_head;
828  NULL != ch;
829  ch = ch->next)
831  ch,
832  add);
833 }
834 
835 
844 static void
846  const struct in_addr *v4,
847  int add)
848 {
849  struct ClientHandle *ch = cls;
850  struct sockaddr_in sa;
851  int have_v4;
852 
853  /* (0) check if this impacts 'hole_external' */
854  if ((NULL != ch->hole_external) &&
855  (0 == strcasecmp (ch->hole_external,
856  "AUTO")))
857  {
858  struct LocalAddressList lal;
859  struct sockaddr_in *s4;
860 
862  "Detected eternal IP, can now back-fill AUTO:%u in hole punching specification of `%s'\n",
863  (unsigned int) ch->ext_dns_port,
864  ch->section_name);
865  memset (&lal, 0, sizeof(lal));
866  s4 = (struct sockaddr_in *) &lal.addr;
867  s4->sin_family = AF_INET;
868  s4->sin_port = htons (ch->ext_dns_port);
869  s4->sin_addr = *v4;
870  lal.af = AF_INET;
872  check_notify_client (&lal,
873  ch,
874  add);
875  }
876 
877  /* (1) check if client cares. */
878  if (! ch->natted_address)
879  return;
880  have_v4 = GNUNET_NO;
881  for (unsigned int i = 0; i < ch->num_caddrs; i++)
882  {
883  const struct sockaddr_storage *ss = &ch->caddrs[i].ss;
884 
885  if (AF_INET != ss->ss_family)
886  continue;
887  have_v4 = GNUNET_YES;
888  break;
889  }
890  if (GNUNET_NO == have_v4)
891  return; /* IPv6-only */
892 
893  /* (2) build address info */
894  memset (&sa,
895  0,
896  sizeof(sa));
897  sa.sin_family = AF_INET;
898  sa.sin_addr = *v4;
899  sa.sin_port = htons (0);
900 
902  "Detected eternal IP %s, notifying client of external IP (without port)\n",
903  GNUNET_a2s ((const struct sockaddr *) &sa,
904  sizeof(sa)));
905  /* (3) notify client of change */
909  ch,
910  add,
911  &sa,
912  sizeof(sa));
913 }
914 
915 
923 static void
924 reversal_callback (void *cls,
925  const struct sockaddr_in *ra)
926 {
927  struct LocalAddressList *lal = cls;
928  const struct sockaddr_in *l4;
929 
930  GNUNET_assert (AF_INET == lal->af);
931  l4 = (const struct sockaddr_in *) &lal->addr;
932  for (struct ClientHandle *ch = ch_head;
933  NULL != ch;
934  ch = ch->next)
935  {
937  struct GNUNET_MQ_Envelope *env;
938  int match;
939 
940  /* Check if client is in applicable range for ICMP NAT traversal
941  for this local address */
942  if (! ch->natted_address)
943  continue;
944  match = GNUNET_NO;
945  for (unsigned int i = 0; i < ch->num_caddrs; i++)
946  {
947  struct ClientAddress *ca = &ch->caddrs[i];
948  const struct sockaddr_in *c4;
949 
950  if (AF_INET != ca->ss.ss_family)
951  continue;
952  c4 = (const struct sockaddr_in *) &ca->ss;
953  if ((0 != c4->sin_addr.s_addr) &&
954  (l4->sin_addr.s_addr != c4->sin_addr.s_addr))
955  continue;
956  match = GNUNET_YES;
957  break;
958  }
959  if (! match)
960  continue;
961 
962  /* Notify applicable client about connection reversal request */
963  env = GNUNET_MQ_msg_extra (crrm,
964  sizeof(struct sockaddr_in),
966  GNUNET_memcpy (&crrm[1],
967  ra,
968  sizeof(struct sockaddr_in));
969  GNUNET_MQ_send (ch->mq,
970  env);
971  }
972 }
973 
974 
980 static void
981 run_scan (void *cls)
982 {
983  struct IfcProcContext ifc_ctx;
984  int found;
985  int have_nat;
986  struct LocalAddressList *lnext;
987 
989  &run_scan,
990  NULL);
991  memset (&ifc_ctx,
992  0,
993  sizeof(ifc_ctx));
995  &ifc_ctx);
996  /* remove addresses that disappeared */
997  for (struct LocalAddressList *lal = lal_head;
998  NULL != lal;
999  lal = lnext)
1000  {
1001  lnext = lal->next;
1002  found = GNUNET_NO;
1003  for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1004  NULL != pos;
1005  pos = pos->next)
1006  {
1007  if ((pos->af == lal->af) &&
1008  (0 == memcmp (&lal->addr,
1009  &pos->addr,
1010  (AF_INET == lal->af)
1011  ? sizeof(struct sockaddr_in)
1012  : sizeof(struct sockaddr_in6))))
1013  {
1014  found = GNUNET_YES;
1015  }
1016  }
1017  if (GNUNET_NO == found)
1018  {
1019  notify_clients (lal,
1020  GNUNET_NO);
1021  free_lal (lal);
1022  }
1023  }
1024 
1025  /* add addresses that appeared */
1026  have_nat = GNUNET_NO;
1027  for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1028  NULL != pos;
1029  pos = ifc_ctx.lal_head)
1030  {
1031  found = GNUNET_NO;
1032  if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac))
1033  have_nat = GNUNET_YES;
1034  for (struct LocalAddressList *lal = lal_head;
1035  NULL != lal;
1036  lal = lal->next)
1037  {
1038  if ((pos->af == lal->af) &&
1039  (0 == memcmp (&lal->addr,
1040  &pos->addr,
1041  (AF_INET == lal->af)
1042  ? sizeof(struct sockaddr_in)
1043  : sizeof(struct sockaddr_in6))))
1044  found = GNUNET_YES;
1045  }
1047  ifc_ctx.lal_tail,
1048  pos);
1049  if (GNUNET_YES == found)
1050  {
1051  GNUNET_free (pos);
1052  }
1053  else
1054  {
1055  notify_clients (pos,
1056  GNUNET_YES);
1058  lal_tail,
1059  pos);
1060  if ((AF_INET == pos->af) &&
1061  (NULL == pos->hc) &&
1062  (0 != (GNUNET_NAT_AC_LAN & pos->ac)))
1063  {
1064  const struct sockaddr_in *s4
1065  = (const struct sockaddr_in *) &pos->addr;
1066 
1068  "Found NATed local address %s, starting NAT server\n",
1069  GNUNET_a2s ((const struct sockaddr *) &pos->addr,
1070  sizeof(*s4)));
1071  pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
1073  pos,
1074  cfg);
1075  }
1076  }
1077  }
1078  GN_nat_status_changed (have_nat);
1079 }
1080 
1081 
1093 static void
1095  int add_remove,
1096  const struct sockaddr *addr,
1097  socklen_t addrlen,
1099 {
1100  struct ClientHandle *ch = cls;
1102 
1103  switch (result)
1104  {
1106  GNUNET_assert (NULL != addr);
1107  break;
1108 
1113  "Running upnpc failed: %d\n",
1114  result);
1115  return;
1116 
1119  "external-ip binary not found\n");
1120  return;
1121 
1124  "upnpc binary not found\n");
1125  return;
1126 
1129  "external-ip binary could not be run\n");
1130  return;
1131 
1134  "upnpc failed to create port mapping\n");
1135  return;
1136 
1139  "Invalid output from upnpc\n");
1140  return;
1141 
1144  "Invalid address returned by upnpc\n");
1145  return;
1146 
1147  default:
1148  GNUNET_break (0); /* should not be possible */
1149  return;
1150  }
1151  switch (addr->sa_family)
1152  {
1153  case AF_INET:
1154  ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr)
1157  break;
1158 
1159  case AF_INET6:
1160  ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr)
1163  break;
1164 
1165  default:
1166  GNUNET_break (0);
1167  return;
1168  }
1170  "upnp external address %s: %s\n",
1171  add_remove ? "added" : "removed",
1172  GNUNET_a2s (addr,
1173  addrlen));
1174  notify_client (ac,
1175  ch,
1176  add_remove,
1177  addr,
1178  addrlen);
1179 }
1180 
1181 
1190 static void
1191 dyndns_lookup (void *cls);
1192 
1193 
1203 static void
1205  const struct sockaddr *addr,
1206  socklen_t addrlen)
1207 {
1208  struct ClientHandle *ch = cls;
1209  struct LocalAddressList *lal;
1210  struct sockaddr_storage ss;
1211  struct sockaddr_in *v4;
1212  struct sockaddr_in6 *v6;
1213 
1214  if (NULL == addr)
1215  {
1216  struct LocalAddressList *laln;
1217 
1218  ch->ext_dns = NULL;
1219  ch->ext_dns_task
1221  &dyndns_lookup,
1222  ch);
1223  /* Current iteration is over, remove 'old' IPs now */
1224  for (lal = ch->ext_addr_head; NULL != lal; lal = laln)
1225  {
1226  laln = lal->next;
1227  if (GNUNET_YES == lal->old)
1228  {
1229  GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
1230  ch->ext_addr_tail,
1231  lal);
1232  check_notify_client (lal,
1233  ch,
1234  GNUNET_NO);
1235  GNUNET_free (lal);
1236  }
1237  }
1238  return;
1239  }
1241  "Got IP `%s' for external address `%s'\n",
1242  GNUNET_a2s (addr,
1243  addrlen),
1244  ch->hole_external);
1245 
1246  /* build sockaddr storage with port number */
1247  memset (&ss,
1248  0,
1249  sizeof(ss));
1250  GNUNET_memcpy (&ss,
1251  addr,
1252  addrlen);
1253  switch (addr->sa_family)
1254  {
1255  case AF_INET:
1256  v4 = (struct sockaddr_in *) &ss;
1257  v4->sin_port = htons (ch->ext_dns_port);
1258  break;
1259 
1260  case AF_INET6:
1261  v6 = (struct sockaddr_in6 *) &ss;
1262  v6->sin6_port = htons (ch->ext_dns_port);
1263  break;
1264 
1265  default:
1266  GNUNET_break (0);
1267  return;
1268  }
1269  /* See if 'ss' matches any of our known addresses */
1270  for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1271  {
1272  if (GNUNET_NO == lal->old)
1273  continue; /* already processed, skip */
1274  if ((addr->sa_family == lal->addr.ss_family) &&
1275  (0 == memcmp (&ss,
1276  &lal->addr,
1277  addrlen)))
1278  {
1279  /* Address unchanged, remember so we do not remove */
1280  lal->old = GNUNET_NO;
1281  return; /* done here */
1282  }
1283  }
1284  /* notify client, and remember IP for later removal! */
1285  lal = GNUNET_new (struct LocalAddressList);
1286  lal->addr = ss;
1287  lal->af = ss.ss_family;
1289  GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1290  ch->ext_addr_tail,
1291  lal);
1292  check_notify_client (lal,
1293  ch,
1294  GNUNET_YES);
1295 }
1296 
1297 
1306 static void
1307 dyndns_lookup (void *cls)
1308 {
1309  struct ClientHandle *ch = cls;
1310  struct LocalAddressList *lal;
1311 
1313  "Performing DNS lookup for punched hole given for `%s' as `%s:%u'\n",
1314  ch->section_name,
1315  ch->hole_external,
1316  (unsigned int) ch->ext_dns_port);
1317  for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1318  lal->old = GNUNET_YES;
1319  ch->ext_dns_task = NULL;
1320  ch->ext_dns = GNUNET_RESOLVER_ip_get (ch->hole_external,
1321  AF_UNSPEC,
1324  ch);
1325 }
1326 
1327 
1339 static void
1341 {
1342  char *port;
1343  unsigned int pnum;
1344  struct sockaddr_in *s4;
1345  struct LocalAddressList *lal;
1346 
1347  port = strrchr (ch->hole_external, ':');
1348  if (NULL == port)
1349  {
1351  _ ("Malformed punched hole specification `%s' (lacks port)\n"),
1352  ch->hole_external);
1353  return;
1354  }
1355  if ((1 != sscanf (port + 1,
1356  "%u",
1357  &pnum)) ||
1358  (pnum > 65535))
1359  {
1361  _ (
1362  "Invalid port number in punched hole specification `%s' (lacks port)\n"),
1363  port + 1);
1364  return;
1365  }
1366  ch->ext_dns_port = (uint16_t) pnum;
1367  *port = '\0';
1368 
1369  lal = GNUNET_new (struct LocalAddressList);
1370  if ('[' == *ch->hole_external)
1371  {
1372  struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &lal->addr;
1373 
1374  s6->sin6_family = AF_INET6;
1375  if (']' != (ch->hole_external[strlen (ch->hole_external) - 1]))
1376  {
1378  _ ("Malformed punched hole specification `%s' (lacks `]')\n"),
1379  ch->hole_external);
1380  GNUNET_free (lal);
1381  return;
1382  }
1383  ch->hole_external[strlen (ch->hole_external) - 1] = '\0';
1384  if (1 != inet_pton (AF_INET6,
1385  ch->hole_external + 1,
1386  &s6->sin6_addr))
1387  {
1389  _ (
1390  "Malformed punched hole specification `%s' (IPv6 address invalid)"),
1391  ch->hole_external + 1);
1392  GNUNET_free (lal);
1393  return;
1394  }
1395  s6->sin6_port = htons (ch->ext_dns_port);
1396  lal->af = AF_INET6;
1398  GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1399  ch->ext_addr_tail,
1400  lal);
1401  check_notify_client (lal,
1402  ch,
1403  GNUNET_YES);
1404  return;
1405  }
1406 
1407  s4 = (struct sockaddr_in *) &lal->addr;
1408  s4->sin_family = AF_INET;
1409  if (1 == inet_pton (AF_INET,
1410  ch->hole_external,
1411  &s4->sin_addr))
1412  {
1414  "IPv4 punched hole given for `%s' via `%s:%u'\n",
1415  ch->section_name,
1416  ch->hole_external,
1417  (unsigned int) ch->ext_dns_port);
1418  s4->sin_port = htons (ch->ext_dns_port);
1419  lal->af = AF_INET;
1421  GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1422  ch->ext_addr_tail,
1423  lal);
1424  check_notify_client (lal,
1425  ch,
1426  GNUNET_YES);
1427  return;
1428  }
1429  if (0 == strcasecmp (ch->hole_external,
1430  "AUTO"))
1431  {
1432  /* handled in #notify_client_external_ipv4_change() */
1433  GNUNET_free (lal);
1434  return;
1435  }
1436  /* got a DNS name, trigger lookup! */
1437  GNUNET_free (lal);
1438  ch->ext_dns_task
1440  ch);
1441 }
1442 
1443 
1451 static void
1452 handle_register (void *cls,
1453  const struct GNUNET_NAT_RegisterMessage *message)
1454 {
1455  struct ClientHandle *ch = cls;
1456  const char *off;
1457  size_t left;
1458 
1459  if ((0 != ch->proto) ||
1460  (NULL != ch->caddrs))
1461  {
1462  /* double registration not allowed */
1463  GNUNET_break (0);
1464  GNUNET_SERVICE_client_drop (ch->client);
1465  return;
1466  }
1467  ch->flags = message->flags;
1468  ch->proto = message->proto;
1469  ch->num_caddrs = ntohs (message->num_addrs);
1470  ch->caddrs = GNUNET_new_array (ch->num_caddrs,
1471  struct ClientAddress);
1472  left = ntohs (message->header.size) - sizeof(*message);
1473  off = (const char *) &message[1];
1474  for (unsigned int i = 0; i < ch->num_caddrs; i++)
1475  {
1476  const struct sockaddr *sa = (const struct sockaddr *) off;
1477  size_t alen;
1478  uint16_t port;
1479  int is_nat;
1480 
1481  if (sizeof(sa_family_t) > left)
1482  {
1483  GNUNET_break (0);
1484  GNUNET_SERVICE_client_drop (ch->client);
1485  return;
1486  }
1487  is_nat = GNUNET_NO;
1488  switch (sa->sa_family)
1489  {
1490  case AF_INET:
1491  {
1492  struct sockaddr_in s4;
1493 
1494  GNUNET_memcpy (&s4,
1495  off,
1496  sizeof(struct sockaddr_in));
1497  alen = sizeof(struct sockaddr_in);
1498  if (is_nat_v4 (&s4.sin_addr))
1499  is_nat = GNUNET_YES;
1500  port = ntohs (s4.sin_port);
1501  }
1502  break;
1503 
1504  case AF_INET6:
1505  {
1506  struct sockaddr_in6 s6;
1507 
1508  GNUNET_memcpy (&s6,
1509  off,
1510  sizeof(struct sockaddr_in6));
1511  alen = sizeof(struct sockaddr_in6);
1512  if (is_nat_v6 (&s6.sin6_addr))
1513  is_nat = GNUNET_YES;
1514  port = ntohs (s6.sin6_port);
1515  }
1516  break;
1517 
1518 #if AF_UNIX
1519  case AF_UNIX:
1520  alen = sizeof(struct sockaddr_un);
1521  port = 0;
1522  break;
1523 #endif
1524  default:
1525  GNUNET_break (0);
1526  GNUNET_SERVICE_client_drop (ch->client);
1527  return;
1528  }
1529  /* store address */
1530  GNUNET_assert (alen <= left);
1531  GNUNET_assert (alen <= sizeof(struct sockaddr_storage));
1532  GNUNET_memcpy (&ch->caddrs[i].ss,
1533  off,
1534  alen);
1535 
1536  /* If applicable, try UPNPC NAT punching */
1537  if ((is_nat) &&
1538  (enable_upnp) &&
1539  ((IPPROTO_TCP == ch->proto) ||
1540  (IPPROTO_UDP == ch->proto)))
1541  {
1542  ch->natted_address = GNUNET_YES;
1543  ch->caddrs[i].mh
1545  IPPROTO_TCP == ch->proto,
1547  ch);
1548  }
1549 
1550  off += alen;
1551  }
1552 
1553  ch->section_name
1554  = GNUNET_strndup (off,
1555  ntohs (message->str_len));
1557  "Received REGISTER message from client for subsystem `%s'\n",
1558  ch->section_name);
1559  if (GNUNET_OK ==
1561  ch->section_name,
1562  "HOLE_EXTERNAL",
1563  &ch->hole_external))
1565 
1566  /* Actually send IP address list to client */
1567  for (struct LocalAddressList *lal = lal_head;
1568  NULL != lal;
1569  lal = lal->next)
1570  {
1571  check_notify_client (lal,
1572  ch,
1573  GNUNET_YES);
1574  }
1575  /* Also consider IPv4 determined by `external-ip` */
1576  ch->external_monitor
1578  ch);
1580 }
1581 
1582 
1591 static int
1592 check_stun (void *cls,
1593  const struct GNUNET_NAT_HandleStunMessage *message)
1594 {
1595  size_t sa_len = ntohs (message->sender_addr_size);
1596  size_t expect = sa_len + ntohs (message->payload_size);
1597 
1598  if (ntohs (message->header.size) - sizeof(*message) != expect)
1599  {
1600  GNUNET_break (0);
1601  return GNUNET_SYSERR;
1602  }
1603  if (sa_len < sizeof(sa_family_t))
1604  {
1605  GNUNET_break (0);
1606  return GNUNET_SYSERR;
1607  }
1608  return GNUNET_OK;
1609 }
1610 
1611 
1619 static void
1620 notify_clients_stun_change (const struct sockaddr_in *ip,
1621  int add)
1622 {
1623  for (struct ClientHandle *ch = ch_head;
1624  NULL != ch;
1625  ch = ch->next)
1626  {
1627  struct sockaddr_in v4;
1629  struct GNUNET_MQ_Envelope *env;
1630 
1631  if (! ch->natted_address)
1632  continue;
1633  v4 = *ip;
1634  v4.sin_port = htons (0);
1636  sizeof(v4),
1638  msg->add_remove = htonl ((int32_t) add);
1639  msg->addr_class = htonl (GNUNET_NAT_AC_EXTERN
1641  GNUNET_memcpy (&msg[1],
1642  &v4,
1643  sizeof(v4));
1644  GNUNET_MQ_send (ch->mq,
1645  env);
1646  }
1647 }
1648 
1649 
1657 static void
1658 stun_ip_timeout (void *cls)
1659 {
1660  struct StunExternalIP *se = cls;
1661 
1662  se->timeout_task = NULL;
1664  GNUNET_NO);
1666  se_tail,
1667  se);
1668  GNUNET_free (se);
1669 }
1670 
1671 
1679 static void
1680 handle_stun (void *cls,
1681  const struct GNUNET_NAT_HandleStunMessage *message)
1682 {
1683  struct ClientHandle *ch = cls;
1684  const char *buf = (const char *) &message[1];
1685  const struct sockaddr *sa;
1686  const void *payload;
1687  size_t sa_len;
1688  size_t payload_size;
1689  struct sockaddr_in external_addr;
1690 
1691  sa_len = ntohs (message->sender_addr_size);
1692  payload_size = ntohs (message->payload_size);
1693  sa = (const struct sockaddr *) &buf[0];
1694  payload = (const struct sockaddr *) &buf[sa_len];
1695  switch (sa->sa_family)
1696  {
1697  case AF_INET:
1698  if (sa_len != sizeof(struct sockaddr_in))
1699  {
1700  GNUNET_break (0);
1701  GNUNET_SERVICE_client_drop (ch->client);
1702  return;
1703  }
1704  break;
1705 
1706  case AF_INET6:
1707  if (sa_len != sizeof(struct sockaddr_in6))
1708  {
1709  GNUNET_break (0);
1710  GNUNET_SERVICE_client_drop (ch->client);
1711  return;
1712  }
1713  break;
1714  }
1716  "Received HANDLE_STUN message from client\n");
1717  if (GNUNET_OK ==
1719  payload_size,
1720  &external_addr))
1721  {
1722  /* We now know that a server at "sa" claims that
1723  we are visible at IP "external_addr".
1724 
1725  We should (for some fixed period of time) tell
1726  all of our clients that listen to a NAT'ed address
1727  that they might want to consider the given 'external_ip'
1728  as their public IP address (this includes TCP and UDP
1729  clients, even if only UDP sends STUN requests).
1730 
1731  If we do not get a renewal, the "external_addr" should be
1732  removed again. The timeout frequency should be configurable
1733  (with a sane default), so that the UDP plugin can tell how
1734  often to re-request STUN.
1735  */struct StunExternalIP *se;
1736 
1737  /* Check if we had a prior response from this STUN server */
1738  for (se = se_head; NULL != se; se = se->next)
1739  {
1740  if ((se->stun_server_addr_len != sa_len) ||
1741  (0 != memcmp (sa,
1742  &se->stun_server_addr,
1743  sa_len)))
1744  continue; /* different STUN server */
1745  if (0 != GNUNET_memcmp (&external_addr,
1746  &se->external_addr))
1747  {
1748  /* external IP changed, update! */
1750  GNUNET_NO);
1753  GNUNET_YES);
1754  }
1755  /* update timeout */
1757  se->timeout_task
1759  &stun_ip_timeout,
1760  se);
1761  return;
1762  }
1763  /* STUN server is completely new, create fresh entry */
1764  se = GNUNET_new (struct StunExternalIP);
1767  sa,
1768  sa_len);
1769  se->stun_server_addr_len = sa_len;
1771  &stun_ip_timeout,
1772  se);
1774  se_tail,
1775  se);
1777  GNUNET_NO);
1778  }
1780 }
1781 
1782 
1792 static int
1794  const struct
1796  message)
1797 {
1798  size_t expect;
1799 
1800  expect = ntohs (message->local_addr_size)
1801  + ntohs (message->remote_addr_size);
1802  if (ntohs (message->header.size) - sizeof(*message) != expect)
1803  {
1804  GNUNET_break (0);
1805  return GNUNET_SYSERR;
1806  }
1807  return GNUNET_OK;
1808 }
1809 
1810 
1818 static void
1820  const struct
1822  *message)
1823 {
1824  struct ClientHandle *ch = cls;
1825  const char *buf = (const char *) &message[1];
1826  size_t local_sa_len = ntohs (message->local_addr_size);
1827  size_t remote_sa_len = ntohs (message->remote_addr_size);
1828  struct sockaddr_in l4;
1829  struct sockaddr_in r4;
1830  int ret;
1831 
1833  "Received REQUEST CONNECTION REVERSAL message from client\n");
1834  if (local_sa_len != sizeof(struct sockaddr_in))
1835  {
1836  GNUNET_break_op (0);
1837  GNUNET_SERVICE_client_drop (ch->client);
1838  return;
1839  }
1840  if (remote_sa_len != sizeof(struct sockaddr_in))
1841  {
1842  GNUNET_break_op (0);
1843  GNUNET_SERVICE_client_drop (ch->client);
1844  return;
1845  }
1846  GNUNET_memcpy (&l4,
1847  buf,
1848  sizeof(struct sockaddr_in));
1849  GNUNET_break_op (AF_INET == l4.sin_family);
1850  buf += sizeof(struct sockaddr_in);
1851  GNUNET_memcpy (&r4,
1852  buf,
1853  sizeof(struct sockaddr_in));
1854  GNUNET_break_op (AF_INET == r4.sin_family);
1855  ret = GN_request_connection_reversal (&l4.sin_addr,
1856  ntohs (l4.sin_port),
1857  &r4.sin_addr,
1858  cfg);
1859  if (GNUNET_OK != ret)
1861  _ ("Connection reversal request failed\n"));
1863 }
1864 
1865 
1871 static void
1872 shutdown_task (void *cls)
1873 {
1874  struct StunExternalIP *se;
1875 
1876  while (NULL != (se = se_head))
1877  {
1879  se_tail,
1880  se);
1882  GNUNET_free (se);
1883  }
1885  if (NULL != scan_task)
1886  {
1888  scan_task = NULL;
1889  }
1890  if (NULL != stats)
1891  {
1893  GNUNET_NO);
1894  stats = NULL;
1895  }
1896  destroy_lal ();
1897 }
1898 
1899 
1907 static void
1908 run (void *cls,
1909  const struct GNUNET_CONFIGURATION_Handle *c,
1911 {
1912  cfg = c;
1913  if (GNUNET_OK !=
1915  "NAT",
1916  "STUN_STALE",
1919 
1920  /* Check for UPnP */
1921  enable_upnp
1923  "NAT",
1924  "ENABLE_UPNP");
1925  if (GNUNET_YES == enable_upnp)
1926  {
1927  /* check if it works */
1928  if (GNUNET_SYSERR ==
1930  GNUNET_NO,
1931  NULL))
1932  {
1934  _ (
1935  "UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
1937  }
1938  }
1939  if (GNUNET_OK !=
1941  "nat",
1942  "DYNDNS_FREQUENCY",
1943  &dyndns_frequency))
1945 
1948  "NAT",
1949  "ENABLE_IPSCAN");
1950 
1952  NULL);
1954  cfg);
1955  if (GNUNET_YES == enable_ipscan)
1957  NULL);
1958 }
1959 
1960 
1969 static void *
1971  struct GNUNET_SERVICE_Client *c,
1972  struct GNUNET_MQ_Handle *mq)
1973 {
1974  struct ClientHandle *ch;
1975 
1976  ch = GNUNET_new (struct ClientHandle);
1977  ch->mq = mq;
1978  ch->client = c;
1980  ch_tail,
1981  ch);
1982  return ch;
1983 }
1984 
1985 
1993 static void
1995  struct GNUNET_SERVICE_Client *c,
1996  void *internal_cls)
1997 {
1998  struct ClientHandle *ch = internal_cls;
1999  struct LocalAddressList *lal;
2000 
2002  ch_tail,
2003  ch);
2004  for (unsigned int i = 0; i < ch->num_caddrs; i++)
2005  {
2006  if (NULL != ch->caddrs[i].mh)
2007  {
2008  GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh);
2009  ch->caddrs[i].mh = NULL;
2010  }
2011  }
2012  GNUNET_free (ch->caddrs);
2013  while (NULL != (lal = ch->ext_addr_head))
2014  {
2015  GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
2016  ch->ext_addr_tail,
2017  lal);
2018  GNUNET_free (lal);
2019  }
2020  if (NULL != ch->ext_dns_task)
2021  {
2022  GNUNET_SCHEDULER_cancel (ch->ext_dns_task);
2023  ch->ext_dns_task = NULL;
2024  }
2025  if (NULL != ch->external_monitor)
2026  {
2027  GN_external_ipv4_monitor_stop (ch->external_monitor);
2028  ch->external_monitor = NULL;
2029  }
2030  if (NULL != ch->ext_dns)
2031  {
2033  ch->ext_dns = NULL;
2034  }
2035  GNUNET_free (ch->hole_external);
2036  GNUNET_free (ch->section_name);
2037  GNUNET_free (ch);
2038 }
2039 
2040 
2045  ("nat",
2047  &run,
2050  NULL,
2051  GNUNET_MQ_hd_var_size (register,
2054  NULL),
2055  GNUNET_MQ_hd_var_size (stun,
2058  NULL),
2059  GNUNET_MQ_hd_var_size (request_connection_reversal,
2062  NULL),
2064 
2065 
2066 #if defined(__linux__) && defined(__GLIBC__)
2067 #include <malloc.h>
2068 
2072 void __attribute__ ((constructor))
2073 GNUNET_ARM_memory_init ()
2074 {
2075  mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2076  mallopt (M_TOP_PAD, 1 * 1024);
2077  malloc_trim (0);
2078 }
2079 
2080 
2081 #endif
2082 
2083 /* end of gnunet-service-nat.c */
struct GNUNET_MQ_Handle * mq
Definition: 003.c:5
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
struct GNUNET_MQ_Envelope * env
Definition: 005.c:1
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static uint16_t port
Port number.
Definition: gnunet-bcd.c:147
static struct GNUNET_CADET_Channel * ch
Channel handle.
Definition: gnunet-cadet.c:117
enum RadiotapType __attribute__
static int add
Desired action is to add a record.
static struct GNUNET_MQ_Envelope * ac
Handle to current GNUNET_PEERINFO_add_peer() operation.
static int result
Global testing status.
static struct GNUNET_SERVICE_Handle * service
Handle to our service instance.
static unsigned long long payload
How much data are we currently storing in the database?
static void handle_stun(void *cls, const struct GNUNET_NAT_HandleStunMessage *message)
Handler for GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from client.
static int check_stun(void *cls, const struct GNUNET_NAT_HandleStunMessage *message)
Check validity of GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from client.
static struct ClientHandle * ch_head
Head of client DLL.
static struct StunExternalIP * se_head
Kept in a DLL.
static struct GNUNET_TIME_Relative dyndns_frequency
How often do we scan for changes in how our external (dyndns) hostname resolves?
static void upnp_addr_change_cb(void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen, enum GNUNET_NAT_StatusCode result)
Function called whenever our set of external addresses as created by upnpc changes.
int enable_ipscan
Is IP Scanning enabled? GNUNET_YES if enabled, GNUNET_NO if disabled, without, only explicitly specif...
static void notify_clients_stun_change(const struct sockaddr_in *ip, int add)
Notify all clients about our external IP address as reported by the STUN server.
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.
static struct GNUNET_STATISTICS_Handle * stats
Handle to the statistics service.
static const struct GNUNET_CONFIGURATION_Handle * cfg
Handle to our current configuration.
static void destroy_lal()
Free the DLL starting at lal_head.
static void notify_client_external_ipv4_change(void *cls, const struct in_addr *v4, int add)
Tell relevant client about a change in our external IPv4 address.
static void * client_connect_cb(void *cls, struct GNUNET_SERVICE_Client *c, struct GNUNET_MQ_Handle *mq)
Callback called when a client connects to the service.
static int check_register(void *cls, const struct GNUNET_NAT_RegisterMessage *message)
Check validity of GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
static void notify_client(enum GNUNET_NAT_AddressClass ac, struct ClientHandle *ch, int add, const void *addr, size_t addr_len)
Notify client about a change in the list of addresses this peer has.
static int match_ipv6(const char *network, const struct in6_addr *ip, uint8_t bits)
Check if ip is in network with bits netmask.
static void process_external_ip(void *cls, const struct sockaddr *addr, socklen_t addrlen)
Our (external) hostname was resolved.
static struct ClientHandle * ch_tail
Tail of client DLL.
static void notify_clients(struct LocalAddressList *delta, int add)
Notify all clients about a change in the list of addresses this peer has.
static void shutdown_task(void *cls)
Task run during shutdown.
static void check_notify_client(struct LocalAddressList *delta, struct ClientHandle *ch, int add)
Check if we should bother to notify this client about this address change, and if so,...
static struct LocalAddressList * lal_head
Head of DLL of local addresses.
static void run_scan(void *cls)
Task we run periodically to scan for network interfaces.
static int match_ipv4(const char *network, const struct in_addr *ip, uint8_t bits)
Check if ip is in network with bits netmask.
static struct GNUNET_SCHEDULER_Task * scan_task
Task scheduled to periodically scan our network interfaces.
#define DYNDNS_FREQUENCY
How often do we scan for changes in how our external (dyndns) hostname resolves?
static void reversal_callback(void *cls, const struct sockaddr_in *ra)
We got a connection reversal request from another peer.
#define SCAN_FREQ
How often should we ask the OS about a list of active network interfaces?
static struct StunExternalIP * se_tail
Kept in a DLL.
static void handle_register(void *cls, const struct GNUNET_NAT_RegisterMessage *message)
Handler for GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
static void stun_ip_timeout(void *cls)
Function to be called when we decide that an external IP address as told to us by a STUN server has g...
static void run(void *cls, const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_SERVICE_Handle *service)
Setup NAT service.
static void lookup_hole_external(struct ClientHandle *ch)
Resolve the hole_external name to figure out our external address from a manually punched hole.
static int check_request_connection_reversal(void *cls, const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
Check validity of GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from client.
static int ifc_proc(void *cls, const char *name, int isDefault, const struct sockaddr *addr, const struct sockaddr *broadcast_addr, const struct sockaddr *netmask, socklen_t addrlen)
Callback function invoked for each interface found.
static void handle_request_connection_reversal(void *cls, const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
Handler for GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from client.
static void dyndns_lookup(void *cls)
Resolve the hole_external name to figure out our external address from a manually punched hole.
static void client_disconnect_cb(void *cls, struct GNUNET_SERVICE_Client *c, void *internal_cls)
Callback called when a client disconnected from the service.
static int is_nat_v6(const struct in6_addr *ip)
Test if the given IPv6 address is in a known range for private networks.
static struct LocalAddressList * lal_tail
Tail of DLL of local addresses.
static void free_lal(struct LocalAddressList *lal)
Remove and free an entry from the lal_head DLL.
static int is_nat_v4(const struct in_addr *ip)
Test if the given IPv4 address is in a known range for private networks.
int enable_upnp
Is UPnP enabled? GNUNET_YES if enabled, GNUNET_NO if disabled, GNUNET_SYSERR if configuration enabled...
static struct GNUNET_TIME_Relative stun_stale_timeout
Timeout to use when STUN data is considered stale.
network address translation traversal service
void GN_external_ipv4_monitor_stop(struct GN_ExternalIPMonitor *mon)
Stop calling monitor.
void GN_nat_status_changed(int have_nat)
We have changed our opinion about being NATed in the first place.
struct GN_ExternalIPMonitor * GN_external_ipv4_monitor_start(GN_NotifyExternalIPv4Change cb, void *cb_cls)
Start monitoring external IPv4 addresses.
Code to figure out what our external IPv4 address(es) might be (external IPv4s are what is seen on th...
int GN_request_connection_reversal(const struct in_addr *internal_address, uint16_t internal_port, const struct in_addr *remote_v4, const struct GNUNET_CONFIGURATION_Handle *cfg)
We want to connect to a peer that is behind NAT.
void GN_stop_gnunet_nat_server_(struct HelperContext *h)
Start the gnunet-helper-nat-server and process incoming requests.
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.
runs the gnunet-helper-nat-server
void GNUNET_NAT_mini_map_stop(struct GNUNET_NAT_MiniHandle *mini)
Remove a mapping created with (mini)upnpc.
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.
int GNUNET_NAT_stun_handle_packet_(const void *data, size_t len, struct sockaddr_in *arg)
Handle an incoming STUN response.
This code provides some support for doing STUN transactions.
static char buf[2048]
Constants for network protocols.
Functions related to doing DNS lookups.
API to create, modify and access statistics.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_yesno(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Get a configuration value that should be in a set of "YES" or "NO".
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_time(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, struct GNUNET_TIME_Relative *time)
Get a configuration value that should be a relative time.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
#define GNUNET_log(kind,...)
#define GNUNET_memcmp(a, b)
Compare memory in a and b, where both must be of the same pointer type.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
const char * GNUNET_a2s(const struct sockaddr *addr, socklen_t addrlen)
Convert a "struct sockaddr*" (IPv4 or IPv6 address) to a string (for printing debug messages).
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_MESSAGE
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
#define GNUNET_strndup(a, length)
Wrapper around GNUNET_xstrndup_.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
void GNUNET_MQ_send(struct GNUNET_MQ_Handle *mq, struct GNUNET_MQ_Envelope *ev)
Send a message with the given message queue.
Definition: mq.c:304
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
#define GNUNET_MQ_msg_extra(mvar, esize, type)
Allocate an envelope, with extra space allocated after the space needed by the message struct.
Definition: gnunet_mq_lib.h:62
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
GNUNET_NAT_StatusCode
Error Types for the NAT subsystem (which can then later be converted/resolved to a string)
GNUNET_NAT_AddressClass
Some addresses contain sensitive information or are not suitable for global distribution.
@ GNUNET_NAT_ERROR_UPNPC_NOT_FOUND
upnpc command not found
@ GNUNET_NAT_ERROR_UPNPC_TIMEOUT
‘upnpc’ command took too long, process killed
@ GNUNET_NAT_ERROR_SUCCESS
Just the default.
@ GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID
‘external-ip’ command output invalid
@ GNUNET_NAT_ERROR_UPNPC_FAILED
Failed to run upnpc command.
@ GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED
Failed to run external-ip command.
@ GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED
‘upnpc’ command failed to establish port mapping
@ GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND
‘external-ip’ command not found
@ GNUNET_NAT_ERROR_IPC_FAILURE
IPC Failure.
@ GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID
"no valid address was returned by `external-ip'"
@ GNUNET_NAT_AC_LAN
Addresses useful in the local wired network, i.e.
@ GNUNET_NAT_AC_GLOBAL
Addresses that are global (i.e.
@ GNUNET_NAT_AC_PRIVATE
Flag for addresses that are highly sensitive (i.e.
@ GNUNET_NAT_AC_EXTERN
Addresses that should be our external IP address on the outside of a NAT.
@ GNUNET_NAT_AC_MANUAL
Addresses that were manually configured by the user.
@ GNUNET_NAT_AC_LOOPBACK
Loopback addresses, only useful under special circumstances.
void GNUNET_OS_network_interfaces_list(GNUNET_OS_NetworkInterfaceProcessor proc, void *proc_cls)
Enumerate all network interfaces.
Definition: os_network.c:397
enum GNUNET_GenericReturnValue GNUNET_OS_check_helper_binary(const char *binary, bool check_suid, const char *params)
Check whether an executable exists and possibly if the suid bit is set on the file.
#define GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE
Message to from NAT service notifying us that one of our addresses changed.
#define GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED
Message to from NAT service notifying us that connection reversal was requested by another peer.
#define GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
Message to ask NAT service to request connection reversal.
#define GNUNET_MESSAGE_TYPE_NAT_REGISTER
Message to ask NAT service to register a client.
#define GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN
Message to ask NAT service to handle a STUN packet.
void GNUNET_RESOLVER_request_cancel(struct GNUNET_RESOLVER_RequestHandle *rh)
Cancel a request that is still pending with the resolver.
struct GNUNET_RESOLVER_RequestHandle * GNUNET_RESOLVER_ip_get(const char *hostname, int af, struct GNUNET_TIME_Relative timeout, GNUNET_RESOLVER_AddressCallback callback, void *callback_cls)
Convert a string to one or more IP addresses.
Definition: resolver_api.c:940
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:1299
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
Definition: scheduler.c:1334
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:975
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:1272
void GNUNET_SERVICE_client_drop(struct GNUNET_SERVICE_Client *c)
Ask the server to disconnect from the given client.
Definition: service.c:2330
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition: service.c:2249
@ GNUNET_SERVICE_OPTION_NONE
Use defaults.
struct GNUNET_STATISTICS_Handle * GNUNET_STATISTICS_create(const char *subsystem, const struct GNUNET_CONFIGURATION_Handle *cfg)
Get handle for the statistics service.
void GNUNET_STATISTICS_destroy(struct GNUNET_STATISTICS_Handle *h, int sync_first)
Destroy a handle (free all state associated with it).
#define GNUNET_TIME_UNIT_HOURS
One hour.
#define GNUNET_TIME_UNIT_MINUTES
One minute.
Messages for interaction with gnunet-nat-server and gnunet-nat-service.
GNUNET_NAT_RegisterFlags
Flags specifying the events this client would be interested in being told about.
Definition: nat.h:72
@ GNUNET_NAT_RF_ADDRESSES
This client wants to be informed about changes to our applicable addresses.
Definition: nat.h:82
#define _(String)
GNU gettext support macro.
Definition: platform.h:178
const char * name
static struct GNUNET_TIME_Relative delta
Definition: speedup.c:36
Information we track per client address.
struct GNUNET_NAT_MiniHandle * mh
Handle to active UPnP request where we asked upnpc to open a port at the NAT.
struct sockaddr_storage ss
Network address used by the client.
Struct containing information about a client, handle to connect to it, and any pending messages that ...
uint16_t num_caddrs
Number of addresses that this service is bound to.
enum GNUNET_NAT_RegisterFlags flags
What does this client care about?
struct LocalAddressList * ext_addr_tail
DLL of external IP addresses as given in hole_external.
uint8_t proto
Client's IPPROTO, e.g.
char * section_name
Name of the configuration section this client cares about.
struct ClientHandle * prev
Kept in a DLL.
struct ClientHandle * next
Kept in a DLL.
char * hole_external
External DNS name and port given by user due to manual hole punching.
int natted_address
Is any of the caddrs in a reserved subnet for NAT?
struct GNUNET_SERVICE_Client * client
The handle to this client.
struct ClientAddress * caddrs
Array of addresses used by the service.
uint16_t ext_dns_port
Port number we found in hole_external.
struct GNUNET_MQ_Handle * mq
The message queue to this client.
struct GNUNET_RESOLVER_RequestHandle * ext_dns
Handle for (DYN)DNS lookup of our external IP as given in hole_external.
struct LocalAddressList * ext_addr_head
DLL of external IP addresses as given in hole_external.
struct GN_ExternalIPMonitor * external_monitor
Handle for monitoring external IP changes.
struct GNUNET_SCHEDULER_Task * ext_dns_task
Task for periodically re-running the ext_dns DNS lookup.
struct GNUNET_MQ_Handle * mq
Message Queue for the channel (which we are implementing).
Definition: cadet.h:142
Handle to a message queue.
Definition: mq.c:87
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
Service notifying the client about changes in the set of addresses it has.
Definition: nat.h:202
Service telling a client that connection reversal was requested.
Definition: nat.h:187
Client telling the service to (possibly) handle a STUN message.
Definition: nat.h:135
struct GNUNET_MessageHeader header
Header with type GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN.
Definition: nat.h:139
uint16_t payload_size
Number of bytes of payload included, in NBO.
Definition: nat.h:149
uint16_t sender_addr_size
Size of the sender address included, in NBO.
Definition: nat.h:144
Handle to a mapping created with upnpc.
Message sent by a client to register with its addresses.
Definition: nat.h:95
uint16_t num_addrs
Number of addresses that this service is bound to that follow.
Definition: nat.h:122
uint16_t str_len
Number of bytes in the string that follow which specifies a section name in the configuration.
Definition: nat.h:115
struct GNUNET_MessageHeader header
Header with type GNUNET_MESSAGE_TYPE_NAT_REGISTER.
Definition: nat.h:99
uint8_t flags
An enum GNUNET_NAT_RegisterFlags.
Definition: nat.h:104
uint8_t proto
Client's IPPROTO, e.g.
Definition: nat.h:109
Client asking the service to initiate connection reversal.
Definition: nat.h:161
struct GNUNET_MessageHeader header
Header with type GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL.
Definition: nat.h:165
uint16_t local_addr_size
Size of the local address included, in NBO.
Definition: nat.h:170
uint16_t remote_addr_size
Size of the remote address included, in NBO.
Definition: nat.h:175
Handle to a request given to the resolver.
Definition: resolver_api.c:104
Entry in list of pending tasks.
Definition: scheduler.c:136
Handle to a client that is connected to a service.
Definition: service.c:252
Handle to a service.
Definition: service.c:118
Handle for the service.
Time for relative time used by GNUnet, in microseconds.
Handle to monitor for external IP changes.
Information we keep per NAT helper process.
Closure for ifc_proc.
struct LocalAddressList * lal_head
Head of DLL of local addresses.
struct LocalAddressList * lal_tail
Tail of DLL of local addresses.
List of local addresses this system has.
struct LocalAddressList * prev
Previous entry.
int old
GNUNET_YES if we saw this one in the previous iteration, but not in the current iteration and thus mi...
struct HelperContext * hc
Context for a gnunet-helper-nat-server used to listen for ICMP messages to this client for connection...
struct LocalAddressList * next
This is a linked list.
int af
Address family.
enum GNUNET_NAT_AddressClass ac
What type of address is this?
struct sockaddr_storage addr
The address itself (i.e.
External IP address as given to us via some STUN server.
struct GNUNET_SCHEDULER_Task * timeout_task
Task we run to remove this entry when it is stale.
size_t stun_server_addr_len
Number of bytes used in stun_server_addr.
struct sockaddr_in external_addr
Our external IP address as reported by the STUN server.
struct sockaddr_storage stun_server_addr
Address of the reporting STUN server.
struct StunExternalIP * next
Kept in a DLL.
struct StunExternalIP * prev
Kept in a DLL.