wsutil/inet_addr: Refactor to use C99/POSIX types

Rewrite ws_inet_pton{4,6} and ws_inet_ntop{4,6} without
GLib types.

Check for strerrorname_np() and use that is available,
to simplify error handling.

Add some minimal tests.
This commit is contained in:
João Valverde 2021-12-27 13:28:29 +00:00 committed by Wireshark GitLab Utility
parent 6343967eef
commit 14a1dfbe10
8 changed files with 131 additions and 64 deletions

View File

@ -98,6 +98,7 @@ if(UNIX)
list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
check_symbol_exists("memmem" "string.h" HAVE_MEMMEM) check_symbol_exists("memmem" "string.h" HAVE_MEMMEM)
check_symbol_exists("strcasestr" "string.h" HAVE_STRCASESTR) check_symbol_exists("strcasestr" "string.h" HAVE_STRCASESTR)
check_symbol_exists("strerrorname_np" "string.h" HAVE_STRERRORNAME_NP)
check_symbol_exists("strptime" "time.h" HAVE_STRPTIME) check_symbol_exists("strptime" "time.h" HAVE_STRPTIME)
check_symbol_exists("vasprintf" "stdio.h" HAVE_VASPRINTF) check_symbol_exists("vasprintf" "stdio.h" HAVE_VASPRINTF)
cmake_pop_check_state() cmake_pop_check_state()

View File

@ -256,6 +256,9 @@
/* Define if you have the 'strcasestr' function. */ /* Define if you have the 'strcasestr' function. */
#cmakedefine HAVE_STRCASESTR 1 #cmakedefine HAVE_STRCASESTR 1
/* Define if you have the 'strerrorname_np' function. */
#cmakedefine HAVE_STRERRORNAME_NP 1
/* Define if you have the 'vasprintf' function. */ /* Define if you have the 'vasprintf' function. */
#cmakedefine HAVE_VASPRINTF 1 #cmakedefine HAVE_VASPRINTF 1

View File

@ -428,6 +428,7 @@ libwsutil.so.0 libwsutil0 #MINVER#
ws_regex_pattern@Base 3.7.0 ws_regex_pattern@Base 3.7.0
ws_socket_ptoa@Base 3.1.1 ws_socket_ptoa@Base 3.1.1
ws_strcasestr@Base 3.7.0 ws_strcasestr@Base 3.7.0
ws_strerrorname_r@Base 3.7.0
ws_strptime@Base 3.7.0 ws_strptime@Base 3.7.0
ws_strtoi16@Base 2.3.0 ws_strtoi16@Base 2.3.0
ws_strtoi32@Base 2.3.0 ws_strtoi32@Base 2.3.0

View File

@ -8,8 +8,8 @@
*/ */
#include "config.h" #include "config.h"
#include "inet_addr.h"
#define WS_LOG_DOMAIN LOG_DOMAIN_WSUTIL #define WS_LOG_DOMAIN LOG_DOMAIN_WSUTIL
#include "inet_addr.h"
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
@ -35,82 +35,66 @@
#define _NTOP_SRC_CAST_ #define _NTOP_SRC_CAST_
#endif #endif
#include <wsutil/ws_assert.h> #include "str_util.h"
#include <wsutil/wslog.h>
/* /*
* We assume and require an inet_pton/inet_ntop that supports AF_INET * We assume and require an inet_pton/inet_ntop that supports AF_INET
* and AF_INET6. * and AF_INET6.
*/ */
static inline gboolean static inline bool
_inet_pton(int af, const gchar *src, gpointer dst) inet_pton_internal(int af, const char *src, void *dst, size_t dst_size,
const char *af_str)
{ {
gint ret = inet_pton(af, src, dst); int ret = inet_pton(af, src, dst);
if (G_UNLIKELY(ret < 0)) { if (ret < 0) {
/* EAFNOSUPPORT */ int err = errno;
if (af == AF_INET) { ws_log(WS_LOG_DOMAIN, LOG_LEVEL_CRITICAL, "inet_pton: %s (%d): %s", af_str, af, g_strerror(err));
memset(dst, 0, sizeof(struct in_addr)); memset(dst, 0, dst_size);
ws_critical("ws_inet_pton4: EAFNOSUPPORT"); errno = err;
} return false;
else if (af == AF_INET6) {
memset(dst, 0, sizeof(struct in6_addr));
ws_critical("ws_inet_pton6: EAFNOSUPPORT");
}
else {
ws_assert_not_reached();
}
errno = EAFNOSUPPORT;
} }
/* ret == 0 invalid src representation, ret == 1 success. */
return ret == 1; return ret == 1;
} }
static inline const gchar * static inline const char *
_inet_ntop(int af, gconstpointer src, gchar *dst, guint dst_size) inet_ntop_internal(int af, const void *src, char *dst, size_t dst_size,
const char *af_str)
{ {
const gchar *ret = inet_ntop(af, _NTOP_SRC_CAST_ src, dst, dst_size); const char *ret = inet_ntop(af, _NTOP_SRC_CAST_ src, dst, dst_size);
if (G_UNLIKELY(ret == NULL)) { if (ret == NULL) {
int saved_errno = errno; int err = errno;
gchar *errmsg = "<<ERROR>>"; char errbuf[16];
switch (errno) { ws_log(WS_LOG_DOMAIN, LOG_LEVEL_CRITICAL, "inet_ntop: %s (%d): %s", af_str, af, g_strerror(err));
case EAFNOSUPPORT:
errmsg = "<<EAFNOSUPPORT>>";
ws_critical("ws_inet_ntop: EAFNOSUPPORT");
break;
case ENOSPC:
errmsg = "<<ENOSPC>>";
break;
default:
break;
}
/* set result to something that can't be confused with a valid conversion */ /* set result to something that can't be confused with a valid conversion */
(void) g_strlcpy(dst, errmsg, dst_size); (void)g_strlcpy(dst, ws_strerrorname_r(err, errbuf, sizeof(errbuf)), dst_size);
/* set errno for caller */ errno = err;
errno = saved_errno; return dst;
} }
return dst; return dst;
} }
const gchar * const char *
ws_inet_ntop4(gconstpointer src, gchar *dst, guint dst_size) ws_inet_ntop4(const void *src, char *dst, size_t dst_size)
{ {
return _inet_ntop(AF_INET, src, dst, dst_size); return inet_ntop_internal(AF_INET, src, dst, dst_size, "AF_INET");
} }
gboolean bool
ws_inet_pton4(const gchar *src, guint32 *dst) ws_inet_pton4(const char *src, ws_in4_addr *dst)
{ {
return _inet_pton(AF_INET, src, dst); return inet_pton_internal(AF_INET, src, dst, sizeof(*dst), "AF_INET");
} }
const gchar * const char *
ws_inet_ntop6(gconstpointer src, gchar *dst, guint dst_size) ws_inet_ntop6(const void *src, char *dst, size_t dst_size)
{ {
return _inet_ntop(AF_INET6, src, dst, dst_size); return inet_ntop_internal(AF_INET6, src, dst, dst_size, "AF_INET6");
} }
gboolean bool
ws_inet_pton6(const gchar *src, ws_in6_addr *dst) ws_inet_pton6(const char *src, ws_in6_addr *dst)
{ {
return _inet_pton(AF_INET6, src, dst); return inet_pton_internal(AF_INET6, src, dst, sizeof(*dst), "AF_INET6");
} }

View File

@ -10,10 +10,8 @@
#ifndef __WS_INET_ADDR_H__ #ifndef __WS_INET_ADDR_H__
#define __WS_INET_ADDR_H__ #define __WS_INET_ADDR_H__
#include "ws_symbol_export.h" #include <wireshark.h>
#include "ws_attributes.h"
#include <glib.h>
#include "inet_ipv4.h" #include "inet_ipv4.h"
#include "inet_ipv6.h" #include "inet_ipv6.h"
@ -58,17 +56,17 @@ extern "C" {
* To check for errors set errno to zero before calling ws_inet_ntop{4,6}. * To check for errors set errno to zero before calling ws_inet_ntop{4,6}.
* ENOSPC is set if the result exceeds the given buffer size. * ENOSPC is set if the result exceeds the given buffer size.
*/ */
WS_DLL_PUBLIC WS_RETNONNULL const gchar * WS_DLL_PUBLIC WS_RETNONNULL const char *
ws_inet_ntop4(gconstpointer src, gchar *dst, guint dst_size); ws_inet_ntop4(const void *src, char *dst, size_t dst_size);
WS_DLL_PUBLIC WS_RETNONNULL const gchar * WS_DLL_PUBLIC WS_RETNONNULL const char *
ws_inet_ntop6(gconstpointer src, gchar *dst, guint dst_size); ws_inet_ntop6(const void *src, char *dst, size_t dst_size);
WS_DLL_PUBLIC gboolean WS_DLL_PUBLIC bool
ws_inet_pton4(const gchar *src, ws_in4_addr *dst); ws_inet_pton4(const char *src, ws_in4_addr *dst);
WS_DLL_PUBLIC gboolean WS_DLL_PUBLIC bool
ws_inet_pton6(const gchar *src, ws_in6_addr *dst); ws_inet_pton6(const char *src, ws_in6_addr *dst);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -528,6 +528,20 @@ ws_escape_string(wmem_allocator_t *alloc, const char *string, bool add_quotes)
return buf; return buf;
} }
const char *
ws_strerrorname_r(int errnum, char *buf, size_t buf_size)
{
#ifdef HAVE_STRERRORNAME_NP
const char *errstr = strerrorname_np(errnum);
if (errstr != NULL) {
(void)g_strlcpy(buf, errstr, buf_size);
return buf;
}
#endif
snprintf(buf, buf_size, "Errno(%d)", errnum);
return buf;
}
/* /*
* Editor modelines - https://www.wireshark.org/tools/modelines.html * Editor modelines - https://www.wireshark.org/tools/modelines.html
* *

View File

@ -195,6 +195,9 @@ char *format_size_wmem(wmem_allocator_t *allocator, int64_t size,
WS_DLL_PUBLIC WS_DLL_PUBLIC
gchar printable_char_or_period(gchar c); gchar printable_char_or_period(gchar c);
WS_DLL_PUBLIC WS_RETNONNULL
const char *ws_strerrorname_r(int errnum, char *buf, size_t buf_size);
/* To pass one of two strings, singular or plural */ /* To pass one of two strings, singular or plural */
#define plurality(d,s,p) ((d) == 1 ? (s) : (p)) #define plurality(d,s,p) ((d) == 1 ? (s) : (p))

View File

@ -12,8 +12,66 @@
#include <glib.h> #include <glib.h>
#include <wsutil/utf8_entities.h> #include <wsutil/utf8_entities.h>
#include "str_util.h" #include "inet_addr.h"
static void test_inet_pton4_test1(void)
{
const char *str;
bool ok;
ws_in4_addr result, expect;
str = "198.51.100.200";
expect = g_htonl(3325256904);
ok = ws_inet_pton4(str, &result);
g_assert_true(ok);
g_assert_cmpint(result, ==, expect);
}
static void test_inet_ntop4_test1(void)
{
char result[WS_INET_ADDRSTRLEN];
const char *expect, *ptr;
ws_in4_addr addr;
addr = g_htonl(3325256904);
expect = "198.51.100.200";
ptr = ws_inet_ntop4(&addr, result, sizeof(result));
g_assert_true(ptr == result);
g_assert_cmpstr(result, ==, expect);
}
struct in6_test {
char str[WS_INET6_ADDRSTRLEN];
ws_in6_addr addr;
};
static struct in6_test in6_test1 = {
.str = "2001:db8:ffaa:ddbb:1199:2288:3377:1",
.addr = { { 0x20, 0x01, 0x0d, 0xb8, 0xff, 0xaa, 0xdd, 0xbb,
0x11, 0x99, 0x22, 0x88, 0x33, 0x77, 0x00, 0x01 } }
};
static void test_inet_pton6_test1(void)
{
bool ok;
ws_in6_addr result;
ok = ws_inet_pton6(in6_test1.str, &result);
g_assert_true(ok);
g_assert_cmpmem(&result, sizeof(result), &in6_test1.addr, sizeof(in6_test1.addr));
}
static void test_inet_ntop6_test1(void)
{
char result[WS_INET6_ADDRSTRLEN];
const char *ptr;
ptr = ws_inet_ntop6(&in6_test1.addr, result, sizeof(result));
g_assert_true(ptr == result);
g_assert_cmpstr(result, ==, in6_test1.str);
}
#include "str_util.h"
static void test_format_size(void) static void test_format_size(void)
{ {
@ -617,6 +675,11 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL); g_test_init(&argc, &argv, NULL);
g_test_add_func("/inet_addr/inet_pton4", test_inet_pton4_test1);
g_test_add_func("/inet_addr/inet_ntop4", test_inet_ntop4_test1);
g_test_add_func("/inet_addr/inet_pton6", test_inet_pton6_test1);
g_test_add_func("/inet_addr/inet_ntop6", test_inet_ntop6_test1);
g_test_add_func("/str_util/format_size", test_format_size); g_test_add_func("/str_util/format_size", test_format_size);
g_test_add_func("/str_util/escape_string", test_escape_string); g_test_add_func("/str_util/escape_string", test_escape_string);
g_test_add_func("/str_util/strconcat", test_strconcat); g_test_add_func("/str_util/strconcat", test_strconcat);