+GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *h)
+{
+ unsigned int i;
+ struct LocalAddressList *lal;
+ struct MiniList *ml;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "NAT unregister called\n");
+ while (NULL != (ml = h->mini_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (h->mini_head,
+ h->mini_tail,
+ ml);
+ if (NULL != ml->mini)
+ GNUNET_NAT_mini_map_stop (ml->mini);
+ GNUNET_free (ml);
+ }
+ if (NULL != h->ext_dns)
+ {
+ GNUNET_RESOLVER_request_cancel (h->ext_dns);
+ h->ext_dns = NULL;
+ }
+ if (NULL != h->hostname_dns)
+ {
+ GNUNET_RESOLVER_request_cancel (h->hostname_dns);
+ h->hostname_dns = NULL;
+ }
+ if (NULL != h->server_read_task)
+ {
+ GNUNET_SCHEDULER_cancel (h->server_read_task);
+ h->server_read_task = NULL;
+ }
+ if (NULL != h->ifc_task)
+ {
+ GNUNET_SCHEDULER_cancel (h->ifc_task);
+ h->ifc_task = NULL;
+ }
+ if (NULL != h->hostname_task)
+ {
+ GNUNET_SCHEDULER_cancel (h->hostname_task);
+ h->hostname_task = NULL;
+ }
+ if (NULL != h->dns_task)
+ {
+ GNUNET_SCHEDULER_cancel (h->dns_task);
+ h->dns_task = NULL;
+ }
+ if (NULL != h->server_proc)
+ {
+ if (0 != GNUNET_OS_process_kill (h->server_proc, GNUNET_TERM_SIG))
+ GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING, "nat", "kill");
+ GNUNET_OS_process_wait (h->server_proc);
+ GNUNET_OS_process_destroy (h->server_proc);
+ h->server_proc = NULL;
+ GNUNET_DISK_pipe_close (h->server_stdout);
+ h->server_stdout = NULL;
+ h->server_stdout_handle = NULL;
+ }
+ if (NULL != h->server_stdout)
+ {
+ GNUNET_DISK_pipe_close (h->server_stdout);
+ h->server_stdout = NULL;
+ h->server_stdout_handle = NULL;
+ }
+ while (NULL != (lal = h->lal_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (h->lal_head, h->lal_tail, lal);
+ if (NULL != h->address_callback)
+ h->address_callback (h->callback_cls, GNUNET_NO,
+ (const struct sockaddr *) &lal[1], lal->addrlen);
+ GNUNET_free (lal);
+ }
+ for (i = 0; i < h->num_local_addrs; i++)
+ GNUNET_free (h->local_addrs[i]);
+ GNUNET_free_non_null (h->local_addrs);
+ GNUNET_free_non_null (h->local_addrlens);
+ GNUNET_free_non_null (h->external_address);
+ GNUNET_free_non_null (h->internal_address);
+ GNUNET_free (h);
+}
+
+
+/**
+ * We learned about a peer (possibly behind NAT) so run the
+ * gnunet-helper-nat-client to send dummy ICMP responses to cause
+ * that peer to connect to us (connection reversal).
+ *
+ * @param h handle (used for configuration)
+ * @param sa the address of the peer (IPv4-only)
+ * @return #GNUNET_SYSERR on error, #GNUNET_NO if nat client is disabled,
+ * #GNUNET_OK otherwise
+ */
+int
+GNUNET_NAT_run_client (struct GNUNET_NAT_Handle *h,
+ const struct sockaddr_in *sa)
+
+
+{
+ char inet4[INET_ADDRSTRLEN];
+ char port_as_string[6];
+ struct GNUNET_OS_Process *proc;
+ char *binary;
+
+ if (GNUNET_YES != h->enable_nat_client)
+ return GNUNET_NO; /* not permitted / possible */
+
+ if (h->internal_address == NULL)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING, "nat",
+ _("Internal IP address not known, cannot use ICMP NAT traversal method\n"));
+ return GNUNET_SYSERR;
+ }
+ GNUNET_assert (sa->sin_family == AF_INET);
+ if (NULL == inet_ntop (AF_INET, &sa->sin_addr, inet4, INET_ADDRSTRLEN))
+ {
+ GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING,
+ "nat",
+ "inet_ntop");
+ return GNUNET_SYSERR;
+ }
+ GNUNET_snprintf (port_as_string,
+ sizeof (port_as_string),
+ "%d",
+ h->adv_port);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ _("Running gnunet-helper-nat-client %s %s %u\n"),
+ h->internal_address,
+ inet4,
+ (unsigned int) h->adv_port);
+ binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-client");
+ proc =
+ GNUNET_OS_start_process (GNUNET_NO, 0, NULL, NULL, NULL,
+ binary,
+ "gnunet-helper-nat-client",
+ h->internal_address,
+ inet4, port_as_string, NULL);
+ GNUNET_free (binary);
+ if (NULL == proc)
+ return GNUNET_SYSERR;
+ /* we know that the gnunet-helper-nat-client will terminate virtually
+ * instantly */
+ GNUNET_OS_process_wait (proc);
+ GNUNET_OS_process_destroy (proc);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Test if the given address is (currently) a plausible IP address for this peer.
+ *
+ * @param h the handle returned by register
+ * @param addr IP address to test (IPv4 or IPv6)
+ * @param addrlen number of bytes in @a addr
+ * @return #GNUNET_YES if the address is plausible,
+ * #GNUNET_NO if the address is not plausible,
+ * #GNUNET_SYSERR if the address is malformed
+ */
+int
+GNUNET_NAT_test_address (struct GNUNET_NAT_Handle *h,
+ const void *addr,
+ socklen_t addrlen)
+{
+ struct LocalAddressList *pos;
+ const struct sockaddr_in *in4;
+ const struct sockaddr_in6 *in6;
+
+ if ((addrlen != sizeof (struct in_addr)) &&
+ (addrlen != sizeof (struct in6_addr)))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ for (pos = h->lal_head; NULL != pos; pos = pos->next)
+ {
+ if (pos->addrlen == sizeof (struct sockaddr_in))
+ {
+ in4 = (struct sockaddr_in *) &pos[1];
+ if ((addrlen == sizeof (struct in_addr)) &&
+ (0 == memcmp (&in4->sin_addr, addr, sizeof (struct in_addr))))
+ return GNUNET_YES;
+ }
+ else if (pos->addrlen == sizeof (struct sockaddr_in6))
+ {
+ in6 = (struct sockaddr_in6 *) &pos[1];
+ if ((addrlen == sizeof (struct in6_addr)) &&
+ (0 == memcmp (&in6->sin6_addr, addr, sizeof (struct in6_addr))))
+ return GNUNET_YES;
+ }
+ else
+ {
+ GNUNET_assert (0);
+ }
+ }
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Asked to validate one of my addresses and validation failed!\n");
+ return GNUNET_NO;
+}
+
+/**
+ * Converts enum GNUNET_NAT_StatusCode to a string
+ *
+ * @param err error code to resolve to a string
+ * @return pointer to a static string containing the error code
+ */
+const char *
+GNUNET_NAT_status2string (enum GNUNET_NAT_StatusCode err)