From 0746baa7c3e4924ac6a687d0d1fff3b33138eca0 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 11 Mar 2012 22:45:56 +0000 Subject: [PATCH] -LRN: Generalize ip-address str->addr conversion --- src/include/gnunet_strings_lib.h | 44 +++++++++ src/transport/plugin_transport_tcp.c | 108 ++++++---------------- src/util/strings.c | 132 +++++++++++++++++++++++++++ 3 files changed, 202 insertions(+), 82 deletions(-) diff --git a/src/include/gnunet_strings_lib.h b/src/include/gnunet_strings_lib.h index 385b6c042..2beaa9534 100644 --- a/src/include/gnunet_strings_lib.h +++ b/src/include/gnunet_strings_lib.h @@ -315,6 +315,50 @@ GNUNET_STRINGS_check_filename (const char *filename, enum GNUNET_STRINGS_FilenameCheck checks); +/** + * Tries to convert @zt_addr string to an IPv6 address. + * + * @param zt_addr 0-terminated string. May be mangled by the function. + * @param addrlen length of zt_addr (not counting 0-terminator). + * @param r_buf a buffer to fill. Initially gets filled with zeroes, + * then its sin6_port, sin6_family and sin6_addr are set appropriately. + * @return GNUNET_OK if conversion succeded. GNUNET_SYSERR otherwise, in which + * case the contents of r_buf are undefined. + */ +int +GNUNET_STRINGS_to_address_ipv6 (char *zt_addr, uint16_t addrlen, + struct sockaddr_in6 *r_buf); + +/** + * Tries to convert @zt_addr string to an IPv4 address. + * + * @param zt_addr 0-terminated string. May be mangled by the function. + * @param addrlen length of zt_addr (not counting 0-terminator). + * @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. + */ +int +GNUNET_STRINGS_to_address_ipv4 (char *zt_addr, uint16_t addrlen, + struct sockaddr_in *r_buf); + +/** + * Tries to convert @addr string to an IP (v4 or v6) address. + * IPv6 address must have its address part enclosed in '()' parens + * instead of '[]'. + * Will automatically decide whether to treat @addr as v4 or v6 address. + * + * @param addr a string, may not be 0-terminated. + * @param addrlen number of bytes in 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. + */ +int +GNUNET_STRINGS_to_address_ip (const char *addr, uint16_t addrlen, + struct sockaddr_storage *r_buf); + /* ifndef GNUNET_UTIL_STRING_H */ #endif /* end of gnunet_util_string.h */ diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c index e10dd74c1..e5d3014bc 100644 --- a/src/transport/plugin_transport_tcp.c +++ b/src/transport/plugin_transport_tcp.c @@ -537,82 +537,6 @@ tcp_address_to_string (void *cls, const void *addr, size_t addrlen) return rbuf; } -#define MAX_IPV6_ADDRLEN 47 - -int -tcp_string_to_address_ipv6 (void *cls, const char *addr, uint16_t addrlen, - void **buf, size_t *added) -{ - char zt_addr[MAX_IPV6_ADDRLEN + 1]; - int ret; - char *port_colon; - unsigned int port; - struct IPv6TcpAddress *ipv6addr; - - if (addrlen < 6) - return GNUNET_SYSERR; - - memset (zt_addr, 0, MAX_IPV6_ADDRLEN + 1); - strncpy (zt_addr, addr, addrlen <= MAX_IPV6_ADDRLEN ? addrlen : MAX_IPV6_ADDRLEN); - - port_colon = strrchr (zt_addr, ':'); - if (port_colon == NULL) - return GNUNET_SYSERR; - ret = sscanf (port_colon, ":%u", &port); - if (ret != 1 || port > 65535) - return GNUNET_SYSERR; - port_colon[0] = '\0'; - - ipv6addr = GNUNET_malloc (sizeof (struct IPv6TcpAddress)); - ret = inet_pton (AF_INET6, zt_addr, &ipv6addr->ipv6_addr); - if (ret <= 0) - { - GNUNET_free (ipv6addr); - return GNUNET_SYSERR; - } - ipv6addr->t6_port = port; - *buf = ipv6addr; - *added = sizeof (struct IPv6TcpAddress); - return GNUNET_OK; -} - -#define MAX_IPV4_ADDRLEN 21 - -int -tcp_string_to_address_ipv4 (void *cls, const char *addr, uint16_t addrlen, - void **buf, size_t *added) -{ - unsigned int temps[5]; - unsigned int port; - int cnt; - char zt_addr[MAX_IPV4_ADDRLEN + 1]; - struct IPv4TcpAddress *ipv4addr; - - if (addrlen < 9) - return GNUNET_SYSERR; - - memset (zt_addr, 0, MAX_IPV4_ADDRLEN + 1); - strncpy (zt_addr, addr, addrlen <= MAX_IPV4_ADDRLEN ? addrlen : MAX_IPV4_ADDRLEN); - - cnt = sscanf (zt_addr, "%u.%u.%u.%u:%u", &temps[0], &temps[1], &temps[2], &temps[3], &port); - if (cnt != 5) - return GNUNET_SYSERR; - - for (cnt = 0; cnt < 4; cnt++) - if (temps[cnt] > 0xFF) - return GNUNET_SYSERR; - if (port > 65535) - return GNUNET_SYSERR; - - ipv4addr = GNUNET_malloc (sizeof (struct IPv4TcpAddress)); - ipv4addr->ipv4_addr = - htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) + - temps[3]); - ipv4addr->t4_port = htonl (port); - *buf = ipv4addr; - *added = sizeof (struct IPv4TcpAddress); - return GNUNET_OK; -} /** * Function called to convert a string address to @@ -622,7 +546,6 @@ tcp_string_to_address_ipv4 (void *cls, const char *addr, uint16_t addrlen, * @param addr string address * @param addrlen length of the address * @param buf location to store the buffer - * @param max size of the buffer * @param added location to store the number of bytes in the buffer. * If the function returns GNUNET_SYSERR, its contents are undefined. * @return GNUNET_OK on success, GNUNET_SYSERR on failure @@ -631,13 +554,34 @@ int tcp_string_to_address (void *cls, const char *addr, uint16_t addrlen, void **buf, size_t *added) { - if (addrlen < 1) + struct sockaddr_storage socket_address; + int ret = GNUNET_STRINGS_to_address_ip (addr, addrlen, + &socket_address); + + if (ret != GNUNET_OK) return GNUNET_SYSERR; - if (addr[0] == '(') - return tcp_string_to_address_ipv6 (cls, addr, addrlen, buf, added); - else - return tcp_string_to_address_ipv4 (cls, addr, addrlen, buf, added); + if (socket_address.ss_family == AF_INET) + { + struct IPv4TcpAddress *t4; + struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address; + t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress)); + t4->ipv4_addr = in4->sin_addr.s_addr; + t4->t4_port = in4->sin_port; + *buf = t4; + *added = sizeof (struct IPv4TcpAddress); + } + else if (socket_address.ss_family == AF_INET6) + { + struct IPv6TcpAddress *t6; + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address; + t6 = GNUNET_malloc (sizeof (struct IPv6TcpAddress)); + t6->ipv6_addr = in6->sin6_addr; + t6->t6_port = in6->sin6_port; + *buf = t6; + *added = sizeof (struct IPv6TcpAddress); + } + return GNUNET_SYSERR; } diff --git a/src/util/strings.c b/src/util/strings.c index abc763b88..a6a5c7542 100644 --- a/src/util/strings.c +++ b/src/util/strings.c @@ -950,4 +950,136 @@ GNUNET_STRINGS_check_filename (const char *filename, return GNUNET_YES; } +#define MAX_IPV6_ADDRLEN 47 +#define MAX_IPV4_ADDRLEN 21 +#define MAX_IP_ADDRLEN MAX_IPV6_ADDRLEN + +/** + * Tries to convert @zt_addr string to an IPv6 address. + * + * @param zt_addr 0-terminated string. May be mangled by the function. + * @param addrlen length of zt_addr (not counting 0-terminator). + * @param r_buf a buffer to fill. Initially gets filled with zeroes, + * then its sin6_port, sin6_family and sin6_addr are set appropriately. + * @return GNUNET_OK if conversion succeded. GNUNET_SYSERR otherwise, in which + * case the contents of r_buf are undefined. + */ +int +GNUNET_STRINGS_to_address_ipv6 (char *zt_addr, uint16_t addrlen, + struct sockaddr_in6 *r_buf) +{ + int ret; + char *port_colon; + unsigned int port; + + if (addrlen < 6) + return GNUNET_SYSERR; + + port_colon = strrchr (zt_addr, ':'); + if (port_colon == NULL) + return GNUNET_SYSERR; + ret = sscanf (port_colon, ":%u", &port); + if (ret != 1 || port > 65535) + return GNUNET_SYSERR; + port_colon[0] = '\0'; + + memset (r_buf, 0, sizeof (struct sockaddr_in6)); + ret = inet_pton (AF_INET6, zt_addr, &r_buf->sin6_addr); + if (ret <= 0) + return GNUNET_SYSERR; + r_buf->sin6_port = htonl (port); + r_buf->sin6_family = AF_INET6; + return GNUNET_OK; +} + +/** + * Tries to convert @zt_addr string to an IPv4 address. + * + * @param zt_addr 0-terminated string. May be mangled by the function. + * @param addrlen length of zt_addr (not counting 0-terminator). + * @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. + */ +int +GNUNET_STRINGS_to_address_ipv4 (char *zt_addr, uint16_t addrlen, + struct sockaddr_in *r_buf) +{ + unsigned int temps[5]; + unsigned int port; + int cnt; + + if (addrlen < 9) + return GNUNET_SYSERR; + + cnt = sscanf (zt_addr, "%u.%u.%u.%u:%u", &temps[0], &temps[1], &temps[2], &temps[3], &port); + if (cnt != 5) + return GNUNET_SYSERR; + + for (cnt = 0; cnt < 4; cnt++) + if (temps[cnt] > 0xFF) + return GNUNET_SYSERR; + if (port > 65535) + return GNUNET_SYSERR; + + r_buf->sin_family = AF_INET; + r_buf->sin_port = htonl (port); + r_buf->sin_addr.s_addr = htonl ((temps[0] << 24) + (temps[1] << 16) + + (temps[2] << 8) + temps[3]); + return GNUNET_OK; +} + +/** + * Tries to convert @addr string to an IP (v4 or v6) address. + * IPv6 address must have its address part enclosed in '()' parens + * instead of '[]'. + * Will automatically decide whether to treat @addr as v4 or v6 address. + * + * @param addr a string, may not be 0-terminated. + * @param addrlen number of bytes in 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. + */ +int +GNUNET_STRINGS_to_address_ip (const char *addr, uint16_t addrlen, + struct sockaddr_storage *r_buf) +{ + uint16_t i; + char zt_addr[MAX_IP_ADDRLEN + 1]; + uint16_t zt_len = addrlen <= MAX_IP_ADDRLEN ? addrlen : MAX_IP_ADDRLEN; + + if (addrlen < 1) + return GNUNET_SYSERR; + + memset (zt_addr, 0, MAX_IP_ADDRLEN + 1); + strncpy (zt_addr, addr, zt_len); + + /* For URIs we use '(' and ')' instead of '[' and ']'. Do the substitution + * now, as GNUNET_STRINGS_to_address_ipv6() takes a proper []-enclosed IPv6 + * address. + */ + if (zt_addr[0] == '(') + { + for (i = 0; i < zt_len; i++) + { + switch (zt_addr[i]) + { + case '(': + zt_addr[i] = '['; + break; + case ')': + zt_addr[i] = ']'; + break; + default: + break; + } + } + return GNUNET_STRINGS_to_address_ipv6 (zt_addr, zt_len, (struct sockaddr_in6 *) r_buf); + } + else + return GNUNET_STRINGS_to_address_ipv4 (zt_addr, zt_len, (struct sockaddr_in *) r_buf); +} + /* end of strings.c */ -- 2.25.1