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)
check_symbol_exists("memmem" "string.h" HAVE_MEMMEM)
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("vasprintf" "stdio.h" HAVE_VASPRINTF)
cmake_pop_check_state()

View File

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

View File

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

View File

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

View File

@ -528,6 +528,20 @@ ws_escape_string(wmem_allocator_t *alloc, const char *string, bool add_quotes)
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
*

View File

@ -195,6 +195,9 @@ char *format_size_wmem(wmem_allocator_t *allocator, int64_t size,
WS_DLL_PUBLIC
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 */
#define plurality(d,s,p) ((d) == 1 ? (s) : (p))

View File

@ -12,8 +12,66 @@
#include <glib.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)
{
@ -617,6 +675,11 @@ int main(int argc, char **argv)
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/escape_string", test_escape_string);
g_test_add_func("/str_util/strconcat", test_strconcat);