From: Christian Grothoff Date: Sun, 27 Nov 2016 13:43:02 +0000 (+0100) Subject: largely completing gnunet-nat tool, using new service API (but untested) X-Git-Tag: taler-0.2.1~583 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=c30f9fe5daf92a89849f7d6d22eacb603918b42d;p=oweals%2Fgnunet.git largely completing gnunet-nat tool, using new service API (but untested) --- diff --git a/src/include/gnunet_strings_lib.h b/src/include/gnunet_strings_lib.h index 15d4f57ac..0328882dd 100644 --- a/src/include/gnunet_strings_lib.h +++ b/src/include/gnunet_strings_lib.h @@ -349,25 +349,27 @@ GNUNET_STRINGS_base64_encode (const char *data, size_t len, char **output); * * @param data the data to encode * @param len the length of the input - * @param output where to write the output (*output should be NULL, + * @param[out] output where to write the output (*output should be NULL, * is allocated) * @return the size of the output */ size_t -GNUNET_STRINGS_base64_decode (const char *data, size_t len, char **output); +GNUNET_STRINGS_base64_decode (const char *data, + size_t len, + char **output); /** * Parse a path that might be an URI. * * @param path path to parse. Must be NULL-terminated. - * @param scheme_part a pointer to 'char *' where a pointer to a string that + * @param[out] scheme_part pointer to a string that * represents the URI scheme will be stored. Can be NULL. The string is * allocated by the function, and should be freed by GNUNET_free() when * it is no longer needed. * @param path_part a pointer to 'const char *' where a pointer to the path * part of the URI will be stored. Can be NULL. Points to the same block - * of memory as 'path', and thus must not be freed. Might point to '\0', + * of memory as @a path, and thus must not be freed. Might point to '\0', * if path part is zero-length. * @return #GNUNET_YES if it's an URI, #GNUNET_NO otherwise. If 'path' is not * an URI, '* scheme_part' and '*path_part' will remain unchanged @@ -474,6 +476,21 @@ GNUNET_STRINGS_to_address_ipv4 (const char *zt_addr, struct sockaddr_in *r_buf); +/** + * Parse an address given as a string into a + * `struct sockaddr`. + * + * @param addr the address + * @param[out] af set to the parsed address family (i.e. AF_INET) + * @param[out] sa set to the parsed address + * @return 0 on error, otherwise number of bytes in @a sa + */ +size_t +GNUNET_STRINGS_parse_socket_addr (const char *addr, + uint8_t *af, + struct sockaddr **sa); + + /** * Tries to convert @a addr string to an IP (v4 or v6) address. * Will automatically decide whether to treat 'addr' as v4 or v6 address. diff --git a/src/nat/Makefile.am b/src/nat/Makefile.am index d8d50e1a4..c3477930d 100644 --- a/src/nat/Makefile.am +++ b/src/nat/Makefile.am @@ -58,7 +58,7 @@ gnunet_helper_nat_client_SOURCES = \ gnunet_nat_SOURCES = \ gnunet-nat.c nat.h gnunet_nat_LDADD = \ - libgnunetnat.la \ + libgnunetnatnew.la \ $(top_builddir)/src/util/libgnunetutil.la diff --git a/src/nat/gnunet-nat.c b/src/nat/gnunet-nat.c index 10d5aef8e..6be3319b5 100644 --- a/src/nat/gnunet-nat.c +++ b/src/nat/gnunet-nat.c @@ -39,9 +39,9 @@ static int global_ret; static struct GNUNET_NAT_AutoHandle *ah; /** - * Port we use. + * Port we advertise. */ -static unsigned int port; +static unsigned int adv_port; /** * Flag set to 1 if we use IPPROTO_UDP. @@ -197,6 +197,68 @@ auto_config_cb (void *cls, } +/** + * Function called to report success or failure for + * NAT configuration test. + * + * @param cls closure + * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code + */ +static void +test_report_cb (void *cls, + enum GNUNET_NAT_StatusCode result) +{ + nt = NULL; + PRINTF ("NAT test result: %s\n", + GNUNET_NAT_status2string (result)); + test_finished (); +} + + +/** + * Signature of the callback passed to #GNUNET_NAT_register() for + * a function to call whenever our set of 'valid' addresses changes. + * + * @param cls closure + * @param add_remove #GNUNET_YES to add a new public IP address, + * #GNUNET_NO to remove a previous (now invalid) one + * @param ac address class the address belongs to + * @param addr either the previous or the new public IP address + * @param addrlen actual length of the @a addr + */ +static void +address_cb (void *cls, + int add_remove, + enum GNUNET_NAT_AddressClass ac, + const struct sockaddr *addr, + socklen_t addrlen) +{ + // FIXME: print! +} + + +/** + * Signature of the callback passed to #GNUNET_NAT_register(). + * for a function to call whenever someone asks us to do connection + * reversal. + * + * @param cls closure + * @param local_addr address where we received the request + * @param local_addrlen actual length of the @a local_addr + * @param remote_addr public IP address of the other peer + * @param remote_addrlen actual length of the @a remote_addr + */ +static void +reversal_cb (void *cls, + const struct sockaddr *local_addr, + socklen_t local_addrlen, + const struct sockaddr *remote_addr, + socklen_t remote_addrlen) +{ + // FIXME: print! +} + + /** * Task run on shutdown. * @@ -237,6 +299,14 @@ run (void *cls, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { + uint8_t af; + struct sockaddr_in bind_sa; + struct sockaddr_in extern_sa; + struct sockaddr *local_sa; + struct sockaddr *remote_sa; + size_t local_len; + size_t remote_len; + if (use_tcp && use_udp) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, @@ -256,6 +326,130 @@ run (void *cls, global_ret = 1; return; } + if (NULL != bind_addr) + { + if (GNUNET_OK != + GNUNET_STRINGS_to_address_ipv4 (bind_addr, + strlen (bind_addr), + &bind_sa)) + { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Invalid socket address `%s'\n", + bind_addr); + global_ret = 1; + return; + } + } + if (NULL != extern_addr) + { + if (GNUNET_OK != + GNUNET_STRINGS_to_address_ipv4 (extern_addr, + strlen (extern_addr), + &extern_sa)) + { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Invalid socket address `%s'\n", + extern_addr); + global_ret = 1; + return; + } + } + if (NULL != local_addr) + { + local_len = 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 != bind_addr) + { + if (NULL == extern_addr) + extern_sa = bind_sa; + nt = GNUNET_NAT_test_start (c, + proto, + bind_sa.sin_addr, + ntohs (bind_sa.sin_port), + extern_sa.sin_addr, + ntohs (extern_sa.sin_port), + &test_report_cb, + NULL); + } + + if (NULL != local_addr) + { + nh = GNUNET_NAT_register (c, + proto, + (uint16_t) adv_port, + 1, + (const struct sockaddr **) &local_sa, + &local_len, + &address_cb, + (listen_reversal) ? &reversal_cb : NULL, + NULL); + } + + 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; + } + 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_auto) { ah = GNUNET_NAT_autoconfig_start (c, @@ -285,22 +479,22 @@ main (int argc, GNUNET_NO, &GNUNET_GETOPT_set_one, &do_auto }, {'b', "bind", "ADDRESS", gettext_noop ("which IP and port are we bound to"), - GNUNET_YES, &GNUNET_GETOPT_set_string, &bind_addr}, + GNUNET_YES, &GNUNET_GETOPT_set_string, &bind_addr }, {'e', "external", "ADDRESS", gettext_noop ("which external IP and port should be used to test"), - GNUNET_YES, &GNUNET_GETOPT_set_string, &extern_addr}, + GNUNET_YES, &GNUNET_GETOPT_set_string, &extern_addr }, {'l', "local", "ADDRESS", gettext_noop ("which IP and port are we locally using to listen to for connection reversals"), - GNUNET_YES, &GNUNET_GETOPT_set_string, &local_addr}, + GNUNET_YES, &GNUNET_GETOPT_set_string, &local_addr }, {'r', "remote", "ADDRESS", gettext_noop ("which remote IP and port should be asked for connection reversal"), - GNUNET_YES, &GNUNET_GETOPT_set_string, &remote_addr}, + GNUNET_YES, &GNUNET_GETOPT_set_string, &remote_addr }, {'L', "listen", NULL, gettext_noop ("listen for connection reversal requests"), GNUNET_NO, &GNUNET_GETOPT_set_one, &listen_reversal }, {'p', "port", NULL, - gettext_noop ("port to use"), - GNUNET_YES, &GNUNET_GETOPT_set_uint, &port}, + gettext_noop ("port to use to advertise"), + GNUNET_YES, &GNUNET_GETOPT_set_uint, &adv_port }, {'s', "stun", NULL, gettext_noop ("enable STUN processing"), GNUNET_NO, &GNUNET_GETOPT_set_one, &do_stun }, diff --git a/src/util/strings.c b/src/util/strings.c index 6a6cad6fe..46eab856f 100644 --- a/src/util/strings.c +++ b/src/util/strings.c @@ -1209,7 +1209,7 @@ GNUNET_STRINGS_check_filename (const char *filename, /** - * Tries to convert 'zt_addr' string to an IPv6 address. + * Tries to convert @a zt_addr string to an IPv6 address. * The string is expected to have the format "[ABCD::01]:80". * * @param zt_addr 0-terminated string. May be mangled by the function. @@ -1292,7 +1292,8 @@ GNUNET_STRINGS_to_address_ipv6 (const char *zt_addr, * the contents of @a r_buf are undefined. */ int -GNUNET_STRINGS_to_address_ipv4 (const char *zt_addr, uint16_t addrlen, +GNUNET_STRINGS_to_address_ipv4 (const char *zt_addr, + uint16_t addrlen, struct sockaddr_in *r_buf) { unsigned int temps[4]; @@ -1301,7 +1302,13 @@ GNUNET_STRINGS_to_address_ipv4 (const char *zt_addr, uint16_t addrlen, if (addrlen < 9) return GNUNET_SYSERR; - cnt = SSCANF (zt_addr, "%u.%u.%u.%u:%u", &temps[0], &temps[1], &temps[2], &temps[3], &port); + cnt = SSCANF (zt_addr, + "%u.%u.%u.%u:%u", + &temps[0], + &temps[1], + &temps[2], + &temps[3], + &port); if (5 != cnt) return GNUNET_SYSERR; for (cnt = 0; cnt < 4; cnt++) @@ -1328,8 +1335,8 @@ GNUNET_STRINGS_to_address_ipv4 (const char *zt_addr, uint16_t addrlen, * @param addrlen number of bytes in @a addr (if addr is 0-terminated, * 0-terminator should not be counted towards addrlen). * @param r_buf a buffer to fill. - * @return #GNUNET_OK if conversion succeded. GNUNET_SYSERR otherwise, in which - * case the contents of r_buf are undefined. + * @return #GNUNET_OK if conversion succeded. #GNUNET_SYSERR otherwise, in which + * case the contents of @a r_buf are undefined. */ int GNUNET_STRINGS_to_address_ip (const char *addr, @@ -1346,6 +1353,62 @@ GNUNET_STRINGS_to_address_ip (const char *addr, } +/** + * Parse an address given as a string into a + * `struct sockaddr`. + * + * @param addr the address + * @param[out] af set to the parsed address family (i.e. AF_INET) + * @param[out] sa set to the parsed address + * @return 0 on error, otherwise number of bytes in @a sa + */ +size_t +GNUNET_STRINGS_parse_socket_addr (const char *addr, + uint8_t *af, + struct sockaddr **sa) +{ + char *cp = GNUNET_strdup (addr); + + *af = AF_UNSPEC; + if ('[' == *addr) + { + /* IPv6 */ + *sa = GNUNET_malloc (sizeof (struct sockaddr_in6)); + if (GNUNET_OK != + GNUNET_STRINGS_to_address_ipv6 (cp, + strlen (cp), + (struct sockaddr_in6 *) *sa)) + { + GNUNET_free (*sa); + *sa = NULL; + GNUNET_free (cp); + return 0; + } + *af = AF_INET6; + GNUNET_free (cp); + return sizeof (struct sockaddr_in6); + } + else + { + /* IPv4 */ + *sa = GNUNET_malloc (sizeof (struct sockaddr_in)); + if (GNUNET_OK != + GNUNET_STRINGS_to_address_ipv4 (cp, + strlen (cp), + (struct sockaddr_in *) *sa)) + { + GNUNET_free (*sa); + *sa = NULL; + GNUNET_free (cp); + return 0; + } + *af = AF_INET; + GNUNET_free (cp); + return sizeof (struct sockaddr_in); + } +} + + /** * Makes a copy of argv that consists of a single memory chunk that can be * freed with a single call to GNUNET_free(); @@ -1388,7 +1451,10 @@ _make_continuous_arg_copy (int argc, * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure */ int -GNUNET_STRINGS_get_utf8_args (int argc, char *const *argv, int *u8argc, char *const **u8argv) +GNUNET_STRINGS_get_utf8_args (int argc, + char *const *argv, + int *u8argc, + char *const **u8argv) { #if WINDOWS wchar_t *wcmd;