/** * Main function run with scheduler. */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_NAT_Handle *nat; struct addr_cls data; struct sockaddr *addr; data.addr = NULL; GNUNET_OS_network_interfaces_list (process_if, &data); if (NULL == data.addr) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not find a valid interface address!\n"); exit (77); /* marks test as skipped */ } addr = data.addr; GNUNET_assert (addr->sa_family == AF_INET || addr->sa_family == AF_INET6); if (addr->sa_family == AF_INET) ((struct sockaddr_in *) addr)->sin_port = htons (2086); else ((struct sockaddr_in6 *) addr)->sin6_port = htons (2086); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Requesting NAT redirection from address %s...\n", GNUNET_a2s (addr, data.addrlen)); nat = GNUNET_NAT_register (cfg, GNUNET_YES /* tcp */ , 2086, 1, (const struct sockaddr **) &addr, &data.addrlen, &addr_callback, NULL, NULL, NULL); GNUNET_free (addr); GNUNET_SCHEDULER_add_delayed (TIMEOUT, &stop, nat); }
static void start_report_addresses (struct Plugin *plugin) { int res = GNUNET_OK; struct sockaddr **addrs; socklen_t *addrlens; res = http_get_addresses (plugin, plugin->name, plugin->env->cfg, &addrs, &addrlens); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, _("Found %u addresses to report to NAT service\n"), res); if (res != GNUNET_SYSERR) { plugin->nat = GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, plugin->port, (unsigned int) res, (const struct sockaddr **) addrs, addrlens, &nat_port_map_callback, NULL, plugin); while (res > 0) { res--; #if 0 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, _("FREEING %s\n"), GNUNET_a2s (addrs[res], addrlens[res])); #endif GNUNET_assert (addrs[res] != NULL); GNUNET_free (addrs[res]); } GNUNET_free_non_null (addrs); GNUNET_free_non_null (addrlens); } else { plugin->nat = GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, 0, 0, NULL, NULL, NULL, NULL, plugin); } }
/** * Try contacting the peer using autonomous * NAT traveral method. * * @param dst_ipv4 IPv4 address to send the fake ICMP message * @param dport destination port to include in ICMP message * @param is_tcp mark for TCP (GNUNET_YES) or UDP (GNUNET_NO) */ static void try_anat (uint32_t dst_ipv4, uint16_t dport, int is_tcp) { struct GNUNET_NAT_Handle *h; struct sockaddr_in sa; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking for connection reversal with %x and code %u\n", (unsigned int) dst_ipv4, (unsigned int) dport); h = GNUNET_NAT_register (cfg, is_tcp, dport, 0, NULL, NULL, NULL, NULL, NULL); memset (&sa, 0, sizeof (sa)); sa.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN sa.sin_len = sizeof (sa); #endif sa.sin_addr.s_addr = dst_ipv4; GNUNET_NAT_run_client (h, &sa); GNUNET_NAT_unregister (h); }
/** * Main function that will be run. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param c configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { uint8_t af; struct sockaddr *local_sa; struct sockaddr *remote_sa; socklen_t local_len; size_t remote_len; if (use_tcp && use_udp) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Cannot use TCP and UDP\n"); global_ret = 1; return; } proto = 0; if (use_tcp) proto = IPPROTO_TCP; if (use_udp) proto = IPPROTO_UDP; GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); if (0 == proto) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Must specify either TCP or UDP\n"); global_ret = 1; return; } if (NULL != local_addr) { local_len = (socklen_t) GNUNET_STRINGS_parse_socket_addr (local_addr, &af, &local_sa); if (0 == local_len) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Invalid socket address `%s'\n", local_addr); global_ret = 1; return; } } if (NULL != remote_addr) { remote_len = GNUNET_STRINGS_parse_socket_addr (remote_addr, &af, &remote_sa); if (0 == remote_len) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Invalid socket address `%s'\n", remote_addr); global_ret = 1; return; } } if (NULL != local_addr) { if (NULL == section_name) section_name = GNUNET_strdup ("undefined"); nh = GNUNET_NAT_register (c, section_name, proto, 1, (const struct sockaddr **) &local_sa, &local_len, &address_cb, (listen_reversal) ? &reversal_cb : NULL, NULL); } else if (listen_reversal) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Use of `-W` only effective in combination with `-i`\n"); global_ret = 1; GNUNET_SCHEDULER_shutdown (); return; } if (NULL != remote_addr) { int ret; if ( (NULL == nh) || (sizeof (struct sockaddr_in) != local_len) ) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Require IPv4 local address to initiate connection reversal\n"); global_ret = 1; GNUNET_SCHEDULER_shutdown (); return; } if (sizeof (struct sockaddr_in) != remote_len) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Require IPv4 reversal target address\n"); global_ret = 1; GNUNET_SCHEDULER_shutdown (); return; } GNUNET_assert (AF_INET == local_sa->sa_family); GNUNET_assert (AF_INET == remote_sa->sa_family); ret = GNUNET_NAT_request_reversal (nh, (const struct sockaddr_in *) local_sa, (const struct sockaddr_in *) remote_sa); switch (ret) { case GNUNET_SYSERR: GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Connection reversal internal error\n"); break; case GNUNET_NO: GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Connection reversal unavailable\n"); break; case GNUNET_OK: /* operation in progress */ break; } } if (do_stun) { if (NULL == local_addr) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Require local address to support STUN requests\n"); global_ret = 1; GNUNET_SCHEDULER_shutdown (); return; } if (IPPROTO_UDP != proto) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "STUN only supported over UDP\n"); global_ret = 1; GNUNET_SCHEDULER_shutdown (); return; } ls = GNUNET_NETWORK_socket_create (af, SOCK_DGRAM, IPPROTO_UDP); if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ls, local_sa, local_len)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to bind to %s: %s\n", GNUNET_a2s (local_sa, local_len), STRERROR (errno)); global_ret = 1; GNUNET_SCHEDULER_shutdown (); return; } rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, ls, &stun_read_task, NULL); } test_finished (); }
/** * Start testing if NAT traversal works using the * given configuration (IPv4-only). * * ALL failures are reported directly to the report callback * * @param cfg configuration for the NAT traversal * @param is_tcp #GNUNET_YES to test TCP, #GNUNET_NO to test UDP * @param bnd_port port to bind to, 0 for connection reversal * @param adv_port externally advertised port to use * @param timeout delay after which the test should be aborted * @param report function to call with the result of the test * @param report_cls closure for @a report * @return handle to cancel NAT test or NULL. The error is always indicated via the report callback */ struct GNUNET_NAT_Test * GNUNET_NAT_test_start (const struct GNUNET_CONFIGURATION_Handle *cfg, int is_tcp, uint16_t bnd_port, uint16_t adv_port, struct GNUNET_TIME_Relative timeout, GNUNET_NAT_TestCallback report, void *report_cls) { struct GNUNET_NAT_Test *nh; struct sockaddr_in sa; const struct sockaddr *addrs[] = { (const struct sockaddr *) &sa }; const socklen_t addrlens[] = { sizeof (sa) }; memset (&sa, 0, sizeof (sa)); sa.sin_family = AF_INET; sa.sin_port = htons (bnd_port); #if HAVE_SOCKADDR_IN_SIN_LEN sa.sin_len = sizeof (sa); #endif nh = GNUNET_new (struct GNUNET_NAT_Test); nh->cfg = cfg; nh->is_tcp = is_tcp; nh->data = bnd_port; nh->adv_port = adv_port; nh->report = report; nh->report_cls = report_cls; nh->status = GNUNET_NAT_ERROR_SUCCESS; if (0 == bnd_port) { nh->nat = GNUNET_NAT_register (cfg, is_tcp, 0, 0, NULL, NULL, &addr_cb, &reversal_cb, nh, NULL); } else { nh->lsock = GNUNET_NETWORK_socket_create (AF_INET, (is_tcp == GNUNET_YES) ? SOCK_STREAM : SOCK_DGRAM, 0); if ((nh->lsock == NULL) || (GNUNET_OK != GNUNET_NETWORK_socket_bind (nh->lsock, (const struct sockaddr *) &sa, sizeof (sa)))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to create listen socket bound to `%s' for NAT test: %s\n"), GNUNET_a2s ((const struct sockaddr *) &sa, sizeof (sa)), STRERROR (errno)); if (NULL != nh->lsock) { GNUNET_NETWORK_socket_close (nh->lsock); nh->lsock = NULL; } nh->status = GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR; nh->ttask = GNUNET_SCHEDULER_add_now (&do_timeout, nh); return nh; } if (GNUNET_YES == is_tcp) { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_listen (nh->lsock, 5)); nh->ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, nh->lsock, &do_accept, nh); } else { nh->ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, nh->lsock, &do_udp_read, nh); } LOG (GNUNET_ERROR_TYPE_INFO, "NAT test listens on port %u (%s)\n", bnd_port, (GNUNET_YES == is_tcp) ? "tcp" : "udp"); nh->nat = GNUNET_NAT_register (cfg, is_tcp, adv_port, 1, addrs, addrlens, &addr_cb, NULL, nh, NULL); if (NULL == nh->nat) { LOG (GNUNET_ERROR_TYPE_INFO, _("NAT test failed to start NAT library\n")); if (NULL != nh->ltask) { GNUNET_SCHEDULER_cancel (nh->ltask); nh->ltask = NULL; } if (NULL != nh->lsock) { GNUNET_NETWORK_socket_close (nh->lsock); nh->lsock = NULL; } nh->status = GNUNET_NAT_ERROR_NAT_REGISTER_FAILED; nh->ttask = GNUNET_SCHEDULER_add_now (&do_timeout, nh); return nh; } } nh->ttask = GNUNET_SCHEDULER_add_delayed (timeout, &do_timeout, nh); return nh; }