move external IP logic to separate file
authorChristian Grothoff <christian@grothoff.org>
Thu, 5 Jan 2017 17:51:02 +0000 (18:51 +0100)
committerChristian Grothoff <christian@grothoff.org>
Thu, 5 Jan 2017 17:51:02 +0000 (18:51 +0100)
src/nat/Makefile.am
src/nat/gnunet-service-nat.c
src/nat/gnunet-service-nat.h [new file with mode: 0644]
src/nat/gnunet-service-nat_externalip.c [new file with mode: 0644]
src/nat/gnunet-service-nat_externalip.h [new file with mode: 0644]

index 767cf8d826753da674f00d40ea437d81f5f77cb4..b2b9c4f50e0078df27b851f7b20d0b99ea67daa0 100644 (file)
@@ -97,7 +97,8 @@ libgnunetnatnew_la_LDFLAGS = \
   -version-info 2:0:0
 
 gnunet_service_nat_SOURCES = \
- gnunet-service-nat.c \
+ gnunet-service-nat.c gnunet-service-nat.h \
+ gnunet-service-nat_externalip.c gnunet-service-nat_externalip.h \
  gnunet-service-nat_stun.c gnunet-service-nat_stun.h \
  gnunet-service-nat_mini.c gnunet-service-nat_mini.h \
  gnunet-service-nat_helper.c gnunet-service-nat_helper.h
index ffc0f6742990d1c9c7c985d7886a3c33a43b0fb7..7edee9f5b30be0859d9b1ad5165848d6504fdb9a 100644 (file)
@@ -29,9 +29,6 @@
  *
  * TODO:
  * - test and document (!) ICMP based NAT traversal
- * - implement NEW logic for external IP detection;
- *   => introduce higher-level abstraction for external-IPs 
- *      for subsystems to hook into!
  * - implement manual hole punching support (AUTO missing)
  * - test manual hole punching support
  * - implement "more" autoconfig:
@@ -49,6 +46,8 @@
 #include "gnunet_statistics_service.h"
 #include "gnunet_resolver_service.h"
 #include "gnunet_nat_service.h"
+#include "gnunet-service-nat.h"
+#include "gnunet-service-nat_externalip.h"
 #include "gnunet-service-nat_stun.h"
 #include "gnunet-service-nat_mini.h"
 #include "gnunet-service-nat_helper.h"
  */
 #define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
 
-/**
- * How long do we wait until we re-try running `external-ip` if the
- * command failed to terminate nicely?
- */
-#define EXTERN_IP_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
-
-/**
- * How long do we wait until we re-try running `external-ip` if the
- * command failed (but terminated)?
- */
-#define EXTERN_IP_RETRY_FAILURE GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
-
-/**
- * How long do we wait until we re-try running `external-ip` if the
- * command succeeded?
- */
-#define EXTERN_IP_RETRY_SUCCESS GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
-
 /**
  * How often do we scan for changes in how our external (dyndns) hostname resolves?
  */
@@ -210,6 +191,11 @@ struct ClientHandle
    */
   struct GNUNET_RESOLVER_RequestHandle *ext_dns;
 
+  /**
+   * Handle for monitoring external IP changes.
+   */
+  struct GN_ExternalIPMonitor *external_monitor;
+  
   /**
    * DLL of external IP addresses as given in @e hole_external.
    */
@@ -422,24 +408,7 @@ static struct StunExternalIP *se_tail;
  * Is UPnP enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled,
  * #GNUNET_SYSERR if configuration enabled but binary is unavailable.
  */
-static int enable_upnp;
-
-/**
- * Task run to obtain our external IP (if #enable_upnp is set
- * and if we find we have a NATed IP address).
- */
-static struct GNUNET_SCHEDULER_Task *probe_external_ip_task;
-
-/**
- * Handle to our operation to run `external-ip`.
- */
-static struct GNUNET_NAT_ExternalHandle *probe_external_ip_op;
-
-/**
- * What is our external IP address as claimed by `external-ip`?
- * 0 for unknown.
- */
-static struct in_addr mini_external_ipv4;
+int enable_upnp;
 
 
 /**
@@ -936,15 +905,16 @@ notify_clients (struct LocalAddressList *delta,
  * Tell relevant client about a change in our external
  * IPv4 address.
  * 
+ * @param cls client to check if it cares and possibly notify
  * @param v4 the external address that changed
- * @param ch client to check if it cares and possibly notify
  * @param add #GNUNET_YES to add, #GNUNET_NO to remove
  */
 static void
-check_notify_client_external_ipv4_change (const struct in_addr *v4,
-                                         struct ClientHandle *ch,
-                                         int add)
+notify_client_external_ipv4_change (void *cls,
+                                   const struct in_addr *v4,
+                                   int add)
 {
+  struct ClientHandle *ch = cls;
   struct sockaddr_in sa;
   int have_v4;
 
@@ -985,112 +955,6 @@ check_notify_client_external_ipv4_change (const struct in_addr *v4,
 }
 
 
-/**
- * Tell relevant clients about a change in our external
- * IPv4 address.
- * 
- * @param add #GNUNET_YES to add, #GNUNET_NO to remove
- * @param v4 the external address that changed
- */
-static void
-notify_clients_external_ipv4_change (int add,
-                                    const struct in_addr *v4)
-{
-  for (struct ClientHandle *ch = ch_head;
-       NULL != ch;
-       ch = ch->next)
-    check_notify_client_external_ipv4_change (v4,
-                                             ch,
-                                             add);
-}
-
-
-/**
- * Task used to run `external-ip` to get our external IPv4
- * address and pass it to NATed clients if possible.
- *
- * @param cls NULL
- */
-static void
-run_external_ip (void *cls);
-
-
-/**
- * We learn our current external IP address.  If it changed,
- * notify all of our applicable clients. Also re-schedule
- * #run_external_ip with an appropriate timeout.
- * 
- * @param cls NULL
- * @param addr the address, NULL on errors
- * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
- */
-static void
-handle_external_ip (void *cls,
-                   const struct in_addr *addr,
-                   enum GNUNET_NAT_StatusCode result)
-{
-  char buf[INET_ADDRSTRLEN];
-  
-  probe_external_ip_op = NULL;
-  GNUNET_SCHEDULER_cancel (probe_external_ip_task);
-  probe_external_ip_task
-    = GNUNET_SCHEDULER_add_delayed ((NULL == addr)
-                                   ? EXTERN_IP_RETRY_FAILURE
-                                   : EXTERN_IP_RETRY_SUCCESS,
-                                   &run_external_ip,
-                                   NULL);
-  switch (result)
-  {
-  case GNUNET_NAT_ERROR_SUCCESS:
-    if (addr->s_addr == mini_external_ipv4.s_addr)
-      return; /* not change */
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-               "Our external IP is now %s\n",
-               inet_ntop (AF_INET,
-                          addr,
-                          buf,
-                          sizeof (buf)));
-    if (0 != mini_external_ipv4.s_addr)
-      notify_clients_external_ipv4_change (GNUNET_NO,
-                                          &mini_external_ipv4);
-    mini_external_ipv4 = *addr;
-    notify_clients_external_ipv4_change (GNUNET_YES,
-                                        &mini_external_ipv4);
-    break;
-  default:
-    if (0 != mini_external_ipv4.s_addr)
-      notify_clients_external_ipv4_change (GNUNET_NO,
-                                          &mini_external_ipv4);
-    mini_external_ipv4.s_addr = 0; 
-    break;
-  }
-}
-
-
-/**
- * Task used to run `external-ip` to get our external IPv4
- * address and pass it to NATed clients if possible.
- *
- * @param cls NULL
- */
-static void
-run_external_ip (void *cls)
-{
-  probe_external_ip_task
-    = GNUNET_SCHEDULER_add_delayed (EXTERN_IP_RETRY_TIMEOUT,
-                                   &run_external_ip,
-                                   NULL);
-  if (NULL != probe_external_ip_op)
-  {
-    GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
-    probe_external_ip_op = NULL;
-  }
-  probe_external_ip_op
-    = GNUNET_NAT_mini_get_external_ipv4_ (&handle_external_ip,
-                                         NULL);
-}
-
-
 /**
  * We got a connection reversal request from another peer.
  * Notify applicable clients.
@@ -1251,29 +1115,7 @@ run_scan (void *cls)
       }
     }
   }
-  if ( (GNUNET_YES == have_nat) &&
-       (GNUNET_YES == enable_upnp) &&
-       (NULL == probe_external_ip_task) &&
-       (NULL == probe_external_ip_op) )
-  {
-    probe_external_ip_task
-      = GNUNET_SCHEDULER_add_now (&run_external_ip,
-                                 NULL);
-  }
-  if ( (GNUNET_NO == have_nat) &&
-       (GNUNET_YES == enable_upnp) )
-  {
-    if (NULL != probe_external_ip_task)
-    {
-      GNUNET_SCHEDULER_cancel (probe_external_ip_task);
-      probe_external_ip_task = NULL;
-    }
-    if (NULL != probe_external_ip_op)
-    {
-      GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
-      probe_external_ip_op = NULL;
-    }
-  }
+  GN_nat_status_changed (have_nat);
 }
 
 
@@ -1727,12 +1569,9 @@ handle_register (void *cls,
                         GNUNET_YES);
   }
   /* Also consider IPv4 determined by `external-ip` */
-  if (0 != mini_external_ipv4.s_addr)
-  {
-    check_notify_client_external_ipv4_change (&mini_external_ipv4,
-                                             ch,
-                                             GNUNET_YES);
-  }
+  ch->external_monitor
+    = GN_external_ipv4_monitor_start (&notify_client_external_ipv4_change,
+                                     ch);
   GNUNET_SERVICE_client_continue (ch->client);
 }
 
@@ -2346,16 +2185,7 @@ shutdown_task (void *cls)
     GNUNET_SCHEDULER_cancel (se->timeout_task);
     GNUNET_free (se);
   }
-  if (NULL != probe_external_ip_task)
-  {
-    GNUNET_SCHEDULER_cancel (probe_external_ip_task);
-    probe_external_ip_task = NULL;
-  }
-  if (NULL != probe_external_ip_op)
-  {
-    GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
-    probe_external_ip_op = NULL;
-  }
+  GN_nat_status_changed (GNUNET_NO);
   if (NULL != scan_task)
   {
     GNUNET_SCHEDULER_cancel (scan_task);
@@ -2489,6 +2319,11 @@ client_disconnect_cb (void *cls,
     GNUNET_SCHEDULER_cancel (ch->ext_dns_task);
     ch->ext_dns_task = NULL;
   }
+  if (NULL != ch->external_monitor)
+  {
+    GN_external_ipv4_monitor_stop (ch->external_monitor);
+    ch->external_monitor = NULL;
+  }
   if (NULL != ch->ext_dns)
   {
     GNUNET_RESOLVER_request_cancel (ch->ext_dns);
diff --git a/src/nat/gnunet-service-nat.h b/src/nat/gnunet-service-nat.h
new file mode 100644 (file)
index 0000000..96eb9f7
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+  This file is part of GNUnet.
+  Copyright (C) 2016, 2017 GNUnet e.V.
+
+  GNUnet is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 3, or (at your
+  option) any later version.
+
+  GNUnet is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with GNUnet; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * @file nat/gnunet-service-nat.h
+ * @brief network address translation traversal service
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_NAT_H
+#define GNUNET_SERVICE_NAT_H
+
+/**
+ * Is UPnP enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled,
+ * #GNUNET_SYSERR if configuration enabled but binary is unavailable.
+ */
+extern int enable_upnp;
+
+#endif
diff --git a/src/nat/gnunet-service-nat_externalip.c b/src/nat/gnunet-service-nat_externalip.c
new file mode 100644 (file)
index 0000000..979d2f0
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2009, 2015, 2016, 2017 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+/**
+ * Code to figure out what our external IPv4 address(es) might
+ * be (external IPv4s are what is seen on the rest of the Internet).
+ *
+ * This can be implemented using different methods, and we allow
+ * the main service to be notified about changes to what we believe
+ * is our external IPv4 address.  
+ *
+ * Note that this is explicitly only about NATed systems; if one
+ * of our network interfaces has a global IP address this does
+ * not count as "external".
+ *
+ * TODO:
+ * - implement NEW logic for external IP detection based on traceroute!
+ *
+ * @file nat/gnunet-service-nat_externalip.c
+ * @brief Functions for monitoring external IPv4 addresses
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <math.h>
+#include "gnunet_util_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_signatures.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_resolver_service.h"
+#include "gnunet_nat_service.h"
+#include "gnunet-service-nat.h"
+#include "gnunet-service-nat_externalip.h"
+#include "gnunet-service-nat_stun.h"
+#include "gnunet-service-nat_mini.h"
+#include "gnunet-service-nat_helper.h"
+#include "nat.h"
+#include <gcrypt.h>
+
+
+/**
+ * How long do we wait until we re-try running `external-ip` if the
+ * command failed to terminate nicely?
+ */
+#define EXTERN_IP_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
+
+/**
+ * How long do we wait until we re-try running `external-ip` if the
+ * command failed (but terminated)?
+ */
+#define EXTERN_IP_RETRY_FAILURE GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
+
+/**
+ * How long do we wait until we re-try running `external-ip` if the
+ * command succeeded?
+ */
+#define EXTERN_IP_RETRY_SUCCESS GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
+
+
+/**
+ * Handle to monitor for external IP changes.
+ */
+struct GN_ExternalIPMonitor
+{
+  /**
+   * Kept in DLL.
+   */
+  struct GN_ExternalIPMonitor *next;
+
+  /**
+   * Kept in DLL.
+   */
+  struct GN_ExternalIPMonitor *prev;
+  
+  /**
+   * Function to call when we believe our external IPv4 address changed.
+   */
+  GN_NotifyExternalIPv4Change cb;
+
+  /**
+   * Closure for @e cb.
+   */
+  void *cb_cls;
+
+};
+
+
+/**
+ * List of monitors, kept in DLL.
+ */
+static struct GN_ExternalIPMonitor *mon_head;
+
+/**
+ * List of monitors, kept in DLL.
+ */
+static struct GN_ExternalIPMonitor *mon_tail;
+
+/**
+ * Task run to obtain our external IP (if #enable_upnp is set
+ * and if we find we have a NATed IP address).
+ */
+static struct GNUNET_SCHEDULER_Task *probe_external_ip_task;
+
+/**
+ * Handle to our operation to run `external-ip`.
+ */
+static struct GNUNET_NAT_ExternalHandle *probe_external_ip_op;
+
+/**
+ * What is our external IP address as claimed by `external-ip`?
+ * 0 for unknown.
+ */
+static struct in_addr mini_external_ipv4;
+
+
+/**
+ * Tell relevant clients about a change in our external
+ * IPv4 address.
+ * 
+ * @param add #GNUNET_YES to add, #GNUNET_NO to remove
+ * @param v4 the external address that changed
+ */
+static void
+notify_monitors_external_ipv4_change (int add,
+                                     const struct in_addr *v4)
+{
+  for (struct GN_ExternalIPMonitor *mon = mon_head;
+       NULL != mon;
+       mon = mon->next)
+    mon->cb (mon->cb_cls,
+            v4,
+            add);
+}
+
+
+/**
+ * Task used to run `external-ip` to get our external IPv4
+ * address and pass it to NATed clients if possible.
+ *
+ * @param cls NULL
+ */
+static void
+run_external_ip (void *cls);
+
+
+/**
+ * We learn our current external IP address.  If it changed,
+ * notify all of our applicable clients. Also re-schedule
+ * #run_external_ip with an appropriate timeout.
+ * 
+ * @param cls NULL
+ * @param addr the address, NULL on errors
+ * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
+ */
+static void
+handle_external_ip (void *cls,
+                   const struct in_addr *addr,
+                   enum GNUNET_NAT_StatusCode result)
+{
+  char buf[INET_ADDRSTRLEN];
+  
+  probe_external_ip_op = NULL;
+  GNUNET_SCHEDULER_cancel (probe_external_ip_task);
+  probe_external_ip_task
+    = GNUNET_SCHEDULER_add_delayed ((NULL == addr)
+                                   ? EXTERN_IP_RETRY_FAILURE
+                                   : EXTERN_IP_RETRY_SUCCESS,
+                                   &run_external_ip,
+                                   NULL);
+  switch (result)
+  {
+  case GNUNET_NAT_ERROR_SUCCESS:
+    if (addr->s_addr == mini_external_ipv4.s_addr)
+      return; /* not change */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               "Our external IP is now %s\n",
+               inet_ntop (AF_INET,
+                          addr,
+                          buf,
+                          sizeof (buf)));
+    if (0 != mini_external_ipv4.s_addr)
+      notify_monitors_external_ipv4_change (GNUNET_NO,
+                                           &mini_external_ipv4);
+    mini_external_ipv4 = *addr;
+    notify_monitors_external_ipv4_change (GNUNET_YES,
+                                         &mini_external_ipv4);
+    break;
+  default:
+    if (0 != mini_external_ipv4.s_addr)
+      notify_monitors_external_ipv4_change (GNUNET_NO,
+                                           &mini_external_ipv4);
+    mini_external_ipv4.s_addr = 0; 
+    break;
+  }
+}
+
+
+/**
+ * Task used to run `external-ip` to get our external IPv4
+ * address and pass it to NATed clients if possible.
+ *
+ * @param cls NULL
+ */
+static void
+run_external_ip (void *cls)
+{
+  probe_external_ip_task
+    = GNUNET_SCHEDULER_add_delayed (EXTERN_IP_RETRY_TIMEOUT,
+                                   &run_external_ip,
+                                   NULL);
+  if (NULL != probe_external_ip_op)
+  {
+    GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
+    probe_external_ip_op = NULL;
+  }
+  probe_external_ip_op
+    = GNUNET_NAT_mini_get_external_ipv4_ (&handle_external_ip,
+                                         NULL);
+}
+
+
+/**
+ * We have changed our opinion about being NATed in the first
+ * place. Adapt our probing.
+ *
+ * @param have_nat #GNUNET_YES if we believe we are behind NAT
+ */
+void
+GN_nat_status_changed (int have_nat)
+{
+  if (GNUNET_YES != enable_upnp)
+    return;
+  if ( (GNUNET_YES == have_nat) &&
+       (NULL == probe_external_ip_task) &&
+       (NULL == probe_external_ip_op) )
+  {
+    probe_external_ip_task
+      = GNUNET_SCHEDULER_add_now (&run_external_ip,
+                                 NULL);
+    return;
+  }
+  if (GNUNET_NO == have_nat) 
+  {
+    if (NULL != probe_external_ip_task)
+    {
+      GNUNET_SCHEDULER_cancel (probe_external_ip_task);
+      probe_external_ip_task = NULL;
+    }
+    if (NULL != probe_external_ip_op)
+    {
+      GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
+      probe_external_ip_op = NULL;
+    }
+  }
+}
+
+
+/**
+ * Start monitoring external IPv4 addresses.
+ *
+ * @param cb function to call on changes
+ * @param cb_cls closure for @a cb
+ * @return handle to cancel
+ */
+struct GN_ExternalIPMonitor *
+GN_external_ipv4_monitor_start (GN_NotifyExternalIPv4Change cb,
+                               void *cb_cls)
+{
+  struct GN_ExternalIPMonitor *mon;
+
+  mon = GNUNET_new (struct GN_ExternalIPMonitor);
+  mon->cb = cb;
+  mon->cb_cls = cb_cls;
+  GNUNET_CONTAINER_DLL_insert (mon_head,
+                              mon_tail,
+                              mon);
+  if (0 != mini_external_ipv4.s_addr)
+    cb (cb_cls,
+       &mini_external_ipv4,
+       GNUNET_YES);
+  return mon;
+}
+
+
+/**
+ * Stop calling monitor.
+ *
+ * @param mon monitor to call
+ */
+void
+GN_external_ipv4_monitor_stop (struct GN_ExternalIPMonitor *mon)
+{
+  GNUNET_CONTAINER_DLL_remove (mon_head,
+                              mon_tail,
+                              mon);
+  GNUNET_free (mon);
+}
+
+/* end of gnunet-service-nat_externalip.c */
diff --git a/src/nat/gnunet-service-nat_externalip.h b/src/nat/gnunet-service-nat_externalip.h
new file mode 100644 (file)
index 0000000..3191055
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2009, 2015, 2016, 2017 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+/**
+ * Code to figure out what our external IPv4 address(es) might
+ * be (external IPv4s are what is seen on the rest of the Internet).
+ *
+ * This can be implemented using different methods, and we allow
+ * the main service to be notified about changes to what we believe
+ * is our external IPv4 address.  
+ *
+ * Note that this is explicitly only about NATed systems; if one
+ * of our network interfaces has a global IP address this does
+ * not count as "external".
+ *
+ * @file nat/gnunet-service-nat_externalip.h
+ * @brief Functions for monitoring external IPv4 addresses
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_NAT_EXTERNALIP_H
+#define GNUNET_SERVICE_NAT_EXTERNALIP_H
+
+#include "platform.h"
+
+
+/**
+ * We have changed our opinion about being NATed in the first
+ * place. Adapt our probing.
+ *
+ * @param have_nat #GNUNET_YES if we believe we are behind NAT
+ */
+void
+GN_nat_status_changed (int have_nat);
+
+
+/**
+ * Function we call when we believe our external IPv4 address changed.
+ *
+ * @param cls closure
+ * @param ip address to add/remove
+ * @param add_remove #GNUNET_YES to add, #GNUNET_NO to remove
+ */
+typedef void
+(*GN_NotifyExternalIPv4Change)(void *cls,
+                              const struct in_addr *ip,
+                              int add_remove);
+
+
+/**
+ * Handle to monitor for external IP changes.
+ */
+struct GN_ExternalIPMonitor;
+
+
+/**
+ * Start monitoring external IPv4 addresses.
+ *
+ * @param cb function to call on changes
+ * @param cb_cls closure for @a cb
+ * @return handle to cancel
+ */
+struct GN_ExternalIPMonitor *
+GN_external_ipv4_monitor_start (GN_NotifyExternalIPv4Change cb,
+                               void *cb_cls);
+
+
+/**
+ * Stop calling monitor.
+ *
+ * @param mon monitor to call
+ */
+void
+GN_external_ipv4_monitor_stop (struct GN_ExternalIPMonitor *mon);
+
+
+#endif