diff options
Diffstat (limited to 'src/libnm-glib-aux')
-rw-r--r-- | src/libnm-glib-aux/meson.build | 1 | ||||
-rw-r--r-- | src/libnm-glib-aux/nm-default-glib.h | 1 | ||||
-rw-r--r-- | src/libnm-glib-aux/nm-inet-utils.c | 529 | ||||
-rw-r--r-- | src/libnm-glib-aux/nm-inet-utils.h | 359 | ||||
-rw-r--r-- | src/libnm-glib-aux/nm-shared-utils.c | 525 | ||||
-rw-r--r-- | src/libnm-glib-aux/nm-shared-utils.h | 364 | ||||
-rw-r--r-- | src/libnm-glib-aux/nm-test-utils.h | 10 | ||||
-rw-r--r-- | src/libnm-glib-aux/tests/test-shared-general.c | 53 |
8 files changed, 934 insertions, 908 deletions
diff --git a/src/libnm-glib-aux/meson.build b/src/libnm-glib-aux/meson.build index 4f13fd0b17..d5e88e6b7a 100644 --- a/src/libnm-glib-aux/meson.build +++ b/src/libnm-glib-aux/meson.build @@ -8,6 +8,7 @@ libnm_glib_aux = static_library( 'nm-enum-utils.c', 'nm-errno.c', 'nm-hash-utils.c', + 'nm-inet-utils.c', 'nm-io-utils.c', 'nm-json-aux.c', 'nm-keyfile-aux.c', diff --git a/src/libnm-glib-aux/nm-default-glib.h b/src/libnm-glib-aux/nm-default-glib.h index f39e16cc5b..18460de8ff 100644 --- a/src/libnm-glib-aux/nm-default-glib.h +++ b/src/libnm-glib-aux/nm-default-glib.h @@ -67,6 +67,7 @@ #include "libnm-glib-aux/nm-shared-utils.h" #include "libnm-glib-aux/nm-errno.h" #include "libnm-glib-aux/nm-hash-utils.h" +#include "libnm-glib-aux/nm-inet-utils.h" /*****************************************************************************/ diff --git a/src/libnm-glib-aux/nm-inet-utils.c b/src/libnm-glib-aux/nm-inet-utils.c new file mode 100644 index 0000000000..2ede87baf9 --- /dev/null +++ b/src/libnm-glib-aux/nm-inet-utils.c @@ -0,0 +1,529 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "libnm-glib-aux/nm-default-glib-i18n-lib.h" + +#include "nm-inet-utils.h" + +#include <netinet/in.h> +#include <arpa/inet.h> + +/*****************************************************************************/ + +const NMIPAddr nm_ip_addr_zero = {}; + +/* We use _nm_alignas(NMIPAddr) to ensure that fields for in_addr_t and + * struct in6_addr have all the same alignment. Ensure that this is suitable. */ +G_STATIC_ASSERT(_nm_alignof(in_addr_t) <= _nm_alignof(NMIPAddr)); +G_STATIC_ASSERT(_nm_alignof(struct in_addr) <= _nm_alignof(NMIPAddr)); +G_STATIC_ASSERT(_nm_alignof(struct in6_addr) <= _nm_alignof(NMIPAddr)); +G_STATIC_ASSERT(_nm_alignof(NMEtherAddr) <= _nm_alignof(NMIPAddr)); + +int +nm_ip_addr_cmp_for_sort(gconstpointer a, gconstpointer b, gpointer user_data) +{ + /* This is a compare function that can be used for sorting IP addresses. + * Essentially, it calls memcmp(). @user_data must be GINT_TO_POINTER(addr_family). + * @a and @b must be either pointers to in_addr_t, struct in6_addr or NMIPAddr. */ + return nm_ip_addr_cmp(GPOINTER_TO_INT(user_data), a, b); +} + +/* this initializes a struct in_addr/in6_addr and allows for untrusted + * arguments (like unsuitable @addr_family or @src_len). It's almost safe + * in the sense that it verifies input arguments strictly. Also, it + * uses memcpy() to access @src, so alignment is not an issue. + * + * Only potential pitfalls: + * + * - it allows for @addr_family to be AF_UNSPEC. If that is the case (and the + * caller allows for that), the caller MUST provide @out_addr_family. + * - when setting @dst to an IPv4 address, the trailing bytes are not touched. + * Meaning, if @dst is an NMIPAddr union, only the first bytes will be set. + * If that matter to you, clear @dst before. */ +gboolean +nm_ip_addr_set_from_untrusted(int addr_family, + gpointer dst, + gconstpointer src, + gsize src_len, + int *out_addr_family) +{ + nm_assert(dst); + + switch (addr_family) { + case AF_UNSPEC: + if (!out_addr_family) { + /* when the callers allow undefined @addr_family, they must provide + * an @out_addr_family argument. */ + nm_assert_not_reached(); + return FALSE; + } + switch (src_len) { + case sizeof(struct in_addr): + addr_family = AF_INET; + break; + case sizeof(struct in6_addr): + addr_family = AF_INET6; + break; + default: + return FALSE; + } + break; + case AF_INET: + if (src_len != sizeof(struct in_addr)) + return FALSE; + break; + case AF_INET6: + if (src_len != sizeof(struct in6_addr)) + return FALSE; + break; + default: + /* when the callers allow undefined @addr_family, they must provide + * an @out_addr_family argument. */ + nm_assert(out_addr_family); + return FALSE; + } + + nm_assert(src); + + memcpy(dst, src, src_len); + NM_SET_OUT(out_addr_family, addr_family); + return TRUE; +} + +gboolean +nm_ip_addr_set_from_variant(int addr_family, gpointer dst, GVariant *variant, int *out_addr_family) +{ + gconstpointer bytes; + gsize len; + + g_return_val_if_fail(dst, FALSE); + g_return_val_if_fail(variant, FALSE); + + /* This function always expects IP addressea a byte arrays ("ay"). Note that + * several NetworkManager API uses "u" (32 bit unsigned intergers) for IPv4 addresses. + * So this function won't work in those cases. + * + * Btw, using "u" for IPv4 address messes badly with the endianness (host + * vs network byte order). Don't do that. + */ + g_return_val_if_fail(g_variant_is_of_type(variant, G_VARIANT_TYPE("ay")), FALSE); + + bytes = g_variant_get_fixed_array(variant, &len, sizeof(guint8)); + + return nm_ip_addr_set_from_untrusted(addr_family, dst, bytes, len, out_addr_family); +} + +/*****************************************************************************/ + +guint32 +nm_ip4_addr_get_default_prefix0(in_addr_t ip) +{ + /* The function is originally from ipcalc.c of Red Hat's initscripts. */ + switch (ntohl(ip) >> 24) { + case 0 ... 127: + return 8; /* Class A */ + case 128 ... 191: + return 16; /* Class B */ + case 192 ... 223: + return 24; /* Class C */ + } + return 0; +} + +guint32 +nm_ip4_addr_get_default_prefix(in_addr_t ip) +{ + return nm_ip4_addr_get_default_prefix0(ip) ?: 24; +} + +gboolean +nm_ip_addr_is_site_local(int addr_family, const void *address) +{ + NMIPAddr a; + + nm_ip_addr_set(addr_family, &a, address); + + switch (addr_family) { + case AF_INET: + /* RFC1918 private addresses + * 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 */ + return (a.addr4 & htonl(0xff000000)) == htonl(0x0a000000) + || (a.addr4 & htonl(0xfff00000)) == htonl(0xac100000) + || (a.addr4 & htonl(0xffff0000)) == htonl(0xc0a80000); + case AF_INET6: + /* IN6_IS_ADDR_SITELOCAL() is for deprecated fec0::/10 addresses (see rfc3879, 4.). + * Note that for unique local IPv6 addresses (ULA, fc00::/7) this returns false. + * This may or may not be a bug of this function. */ + return IN6_IS_ADDR_SITELOCAL(&a.addr6); + default: + g_return_val_if_reached(FALSE); + } +} + +gboolean +nm_ip6_addr_is_ula(const struct in6_addr *address) +{ + /* Unique local IPv6 address (ULA) fc00::/7 */ + return (address->s6_addr32[0] & htonl(0xfe000000u)) == htonl(0xfc000000u); +} + +/*****************************************************************************/ + +gconstpointer +nm_ip_addr_clear_host_address(int family, gpointer dst, gconstpointer src, guint32 plen) +{ + NMIPAddr a; + NMIPAddr a2; + + g_return_val_if_fail(dst, NULL); + + if (!src) { + /* allow "self-assignment", by specifying %NULL as source. */ + src = dst; + } + + nm_ip_addr_set(family, &a, src); + + switch (family) { + case AF_INET: + g_return_val_if_fail(plen <= 32, NULL); + + a2.addr4 = nm_ip4_addr_clear_host_address(a.addr4, plen); + break; + case AF_INET6: + nm_ip6_addr_clear_host_address(&a2.addr6, &a.addr6, plen); + break; + default: + g_return_val_if_reached(NULL); + } + + nm_ip_addr_set(family, dst, &a2); + + return dst; +} + +/* nm_ip6_addr_clear_host_address: + * @dst: destination output buffer, will contain the network part of the @src address + * @src: source ip6 address. If NULL, this does an in-place update of @dst. + * Also, @src and @dst are allowed to be the same pointers. + * @plen: prefix length of network + * + * Note: this function is self assignment safe, to update @src inplace, set both + * @dst and @src to the same destination or set @src NULL. + */ +const struct in6_addr * +nm_ip6_addr_clear_host_address(struct in6_addr *dst, const struct in6_addr *src, guint32 plen) +{ + g_return_val_if_fail(plen <= 128, NULL); + g_return_val_if_fail(dst, NULL); + + if (!src) + src = dst; + + if (plen < 128) { + guint nbytes = plen / 8; + guint nbits = plen % 8; + + if (nbytes && dst != src) + memcpy(dst, src, nbytes); + if (nbits) { + dst->s6_addr[nbytes] = (src->s6_addr[nbytes] & (0xFF << (8 - nbits))); + nbytes++; + } + if (nbytes <= 15) + memset(&dst->s6_addr[nbytes], 0, 16 - nbytes); + } else if (src != dst) + *dst = *src; + + return dst; +} + +int +nm_ip6_addr_same_prefix_cmp(const struct in6_addr *addr_a, + const struct in6_addr *addr_b, + guint32 plen) +{ + int nbytes; + guint8 va, vb, m; + + if (plen >= 128) { + nm_assert(plen == 128); + NM_CMP_DIRECT_MEMCMP(addr_a, addr_b, sizeof(struct in6_addr)); + } else { + nbytes = plen / 8; + if (nbytes) + NM_CMP_DIRECT_MEMCMP(addr_a, addr_b, nbytes); + + plen = plen % 8; + if (plen != 0) { + m = ~((1 << (8 - plen)) - 1); + va = ((((const guint8 *) addr_a))[nbytes]) & m; + vb = ((((const guint8 *) addr_b))[nbytes]) & m; + NM_CMP_DIRECT(va, vb); + } + } + return 0; +} + +/*****************************************************************************/ + +static gboolean +_parse_legacy_addr4(const char *text, in_addr_t *out_addr, GError **error) +{ + gs_free char *s_free = NULL; + struct in_addr a1; + guint8 bin[sizeof(a1)]; + char *s; + int i; + + if (inet_aton(text, &a1) != 1) { + g_set_error_literal(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_INVALID_ARGUMENT, + "address invalid according to inet_aton()"); + return FALSE; + } + + /* OK, inet_aton() accepted the format. That's good, because we want + * to accept IPv4 addresses in octal format, like 255.255.000.000. + * That's what "legacy" means here. inet_pton() doesn't accept those. + * + * But inet_aton() also ignores trailing garbage and formats with fewer than + * 4 digits. That is just too crazy and we don't do that. Perform additional checks + * and reject some forms that inet_aton() accepted. + * + * Note that we still should (of course) accept everything that inet_pton() + * accepts. However this code never gets called if inet_pton() succeeds + * (see below, aside the assertion code). */ + + if (NM_STRCHAR_ANY(text, ch, (!(ch >= '0' && ch <= '9') && !NM_IN_SET(ch, '.', 'x')))) { + /* We only accepts '.', digits, and 'x' for "0x". */ + g_set_error_literal(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_INVALID_ARGUMENT, + "contains an invalid character"); + return FALSE; + } + + s = nm_memdup_maybe_a(300, text, strlen(text) + 1, &s_free); + + for (i = 0; i < G_N_ELEMENTS(bin); i++) { + char *current_token = s; + gint32 v; + + s = strchr(s, '.'); + if (s) { + s[0] = '\0'; + s++; + } + + if ((i == G_N_ELEMENTS(bin) - 1) != (s == NULL)) { + /* Exactly for the last digit, we expect to have no more following token. + * But this isn't the case. Abort. */ + g_set_error(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_INVALID_ARGUMENT, + "wrong number of tokens (index %d, token '%s')", + i, + s); + return FALSE; + } + + v = _nm_utils_ascii_str_to_int64(current_token, 0, 0, 0xFF, -1); + if (v == -1) { + int errsv = errno; + + /* we do accept octal and hex (even with leading "0x"). But something + * about this token is wrong. */ + g_set_error(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_INVALID_ARGUMENT, + "invalid token '%s': %s (%d)", + current_token, + nm_strerror_native(errsv), + errsv); + return FALSE; + } + + bin[i] = v; + } + + if (memcmp(bin, &a1, sizeof(bin)) != 0) { + /* our parsing did not agree with what inet_aton() gave. Something + * is wrong. Abort. */ + g_set_error( + error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_INVALID_ARGUMENT, + "inet_aton() result 0x%08x differs from computed value 0x%02hhx%02hhx%02hhx%02hhx", + a1.s_addr, + bin[0], + bin[1], + bin[2], + bin[3]); + return FALSE; + } + + *out_addr = a1.s_addr; + return TRUE; +} + +gboolean +nm_inet_parse_bin_full(int addr_family, + gboolean accept_legacy, + const char *text, + int *out_addr_family, + gpointer out_addr) +{ + NMIPAddr addrbin; + + g_return_val_if_fail(text, FALSE); + + if (addr_family == AF_UNSPEC) { + g_return_val_if_fail(!out_addr || out_addr_family, FALSE); + addr_family = strchr(text, ':') ? AF_INET6 : AF_INET; + } else + g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), FALSE); + + if (inet_pton(addr_family, text, &addrbin) != 1) { + if (accept_legacy && addr_family == AF_INET + && _parse_legacy_addr4(text, &addrbin.addr4, NULL)) { + /* The address is in some legacy format which inet_aton() accepts, but not inet_pton(). + * Most likely octal digits (leading zeros). We accept the address. */ + } else + return FALSE; + } + +#if NM_MORE_ASSERTS > 10 + if (addr_family == AF_INET) { + NM_PRAGMA_WARNING_DISABLE_DANGLING_POINTER + gs_free_error GError *error = NULL; + in_addr_t a; + + /* The legacy parser should accept everything that inet_pton() accepts too. Meaning, + * it should strictly parse *more* formats. And of course, parse it the same way. */ + if (!_parse_legacy_addr4(text, &a, &error)) { + char buf[INET_ADDRSTRLEN]; + + g_error("unexpected assertion failure: could parse \"%s\" as %s, but not accepted by " + "legacy parser: %s", + text, + nm_inet4_ntop(addrbin.addr4, buf), + error->message); + } + nm_assert(addrbin.addr4 == a); + NM_PRAGMA_WARNING_REENABLE + } +#endif + + NM_SET_OUT(out_addr_family, addr_family); + if (out_addr) + nm_ip_addr_set(addr_family, out_addr, &addrbin); + return TRUE; +} + +gboolean +nm_inet_parse_str(int addr_family, const char *text, char **out_addr) +{ + NMIPAddr addrbin; + + if (!nm_inet_parse_bin(addr_family, text, &addr_family, &addrbin)) + return FALSE; + + NM_SET_OUT(out_addr, nm_inet_ntop_dup(addr_family, &addrbin)); + return TRUE; +} + +gboolean +nm_inet_parse_with_prefix_bin(int addr_family, + const char *text, + int *out_addr_family, + gpointer out_addr, + int *out_prefix) +{ + gs_free char *addrstr_free = NULL; + int prefix = -1; + const char *slash; + const char *addrstr; + NMIPAddr addrbin; + + g_return_val_if_fail(text, FALSE); + + if (addr_family == AF_UNSPEC) { + g_return_val_if_fail(!out_addr || out_addr_family, FALSE); + addr_family = strchr(text, ':') ? AF_INET6 : AF_INET; + } else + g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), FALSE); + + slash = strchr(text, '/'); + if (slash) + addrstr = nm_strndup_a(300, text, slash - text, &addrstr_free); + else + addrstr = text; + + if (inet_pton(addr_family, addrstr, &addrbin) != 1) + return FALSE; + + if (slash) { + /* For IPv4, `ip addr add` supports the prefix-length as a netmask. We don't + * do that. */ + prefix = + _nm_utils_ascii_str_to_int64(&slash[1], 10, 0, addr_family == AF_INET ? 32 : 128, -1); + if (prefix == -1) + return FALSE; + } + + NM_SET_OUT(out_addr_family, addr_family); + if (out_addr) + nm_ip_addr_set(addr_family, out_addr, &addrbin); + NM_SET_OUT(out_prefix, prefix); + return TRUE; +} + +gboolean +nm_inet_parse_with_prefix_str(int addr_family, const char *text, char **out_addr, int *out_prefix) +{ + NMIPAddr addrbin; + + if (!nm_inet_parse_with_prefix_bin(addr_family, text, &addr_family, &addrbin, out_prefix)) + return FALSE; + + NM_SET_OUT(out_addr, nm_inet_ntop_dup(addr_family, &addrbin)); + return TRUE; +} + +/*****************************************************************************/ + +gboolean +nm_inet_is_valid(int addr_family, const char *str_addr) +{ + nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6)); + + return str_addr && nm_inet_parse_bin(addr_family, str_addr, NULL, NULL); +} + +gboolean +nm_inet_is_normalized(int addr_family, const char *str_addr) +{ + NMIPAddr addr; + char sbuf[NM_INET_ADDRSTRLEN]; + + nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6)); + + if (!str_addr) + return FALSE; + + if (!nm_inet_parse_bin(addr_family, str_addr, &addr_family, &addr)) + return FALSE; + + nm_inet_ntop(addr_family, &addr, sbuf); + return nm_streq(sbuf, str_addr); +} + +/*****************************************************************************/ + +NM_UTILS_ENUM2STR_DEFINE(nm_icmpv6_router_pref_to_string, + NMIcmpv6RouterPref, + NM_UTILS_ENUM2STR(NM_ICMPV6_ROUTER_PREF_LOW, "low"), + NM_UTILS_ENUM2STR(NM_ICMPV6_ROUTER_PREF_MEDIUM, "medium"), + NM_UTILS_ENUM2STR(NM_ICMPV6_ROUTER_PREF_HIGH, "high"), + NM_UTILS_ENUM2STR(NM_ICMPV6_ROUTER_PREF_INVALID, "invalid"), ); diff --git a/src/libnm-glib-aux/nm-inet-utils.h b/src/libnm-glib-aux/nm-inet-utils.h new file mode 100644 index 0000000000..d9246d459b --- /dev/null +++ b/src/libnm-glib-aux/nm-inet-utils.h @@ -0,0 +1,359 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#ifndef __NM_INET_UTILS_H__ +#define __NM_INET_UTILS_H__ + +typedef struct _NMIPAddr { + union { + guint8 addr_ptr[sizeof(struct in6_addr)]; + in_addr_t addr4; + struct in_addr addr4_struct; + struct in6_addr addr6; + + /* NMIPAddr is really a union for IP addresses. + * However, as ethernet addresses fit in here nicely, use + * it also for an ethernet MAC address. */ + guint8 ether_addr_octet[6 /*ETH_ALEN*/]; + NMEtherAddr ether_addr; + + guint8 array[sizeof(struct in6_addr)]; + }; +} NMIPAddr; + +#define NM_IP_ADDR_INIT \ + { \ + .array = { 0 } \ + } + +extern const NMIPAddr nm_ip_addr_zero; + +/* This doesn't really belong here, but since it's convenient to re-use nm_ip_addr_zero.ether_addr + * for NMEtherAddr, it is. */ +#define nm_ether_addr_zero (nm_ip_addr_zero.ether_addr) + +static inline int +nm_ip_addr_cmp(int addr_family, gconstpointer a, gconstpointer b) +{ + /* Note that @a and @b are not required to be full NMIPAddr unions. + * Depending on @addr_family, they can also be only in_addr_t or + * struct in6_addr. */ + NM_CMP_SELF(a, b); + NM_CMP_DIRECT_MEMCMP(a, b, nm_utils_addr_family_to_size(addr_family)); + return 0; +} + +int nm_ip_addr_cmp_for_sort(gconstpointer a, gconstpointer b, gpointer user_data); + +static inline gboolean +nm_ip_addr_equal(int addr_family, gconstpointer a, gconstpointer b) +{ + return nm_ip_addr_cmp(addr_family, a, b) == 0; +} + +static inline void +nm_ip_addr_set(int addr_family, gpointer dst, gconstpointer src) +{ + nm_assert(dst); + nm_assert(src); + + /* this MUST use memcpy() to support unaligned src/dst pointers. */ + memcpy(dst, src, nm_utils_addr_family_to_size(addr_family)); + + /* Note that @dst is not necessarily a NMIPAddr, it could also be just + * an in_addr_t/struct in6_addr. We thus can only set the bytes that + * we know are present based on the address family. + * + * Using this function to initialize an NMIPAddr union (for IPv4) leaves + * uninitalized bytes. Avoid that by using nm_ip_addr_init() instead. */ +} + +static inline gboolean +nm_ip_addr_is_null(int addr_family, gconstpointer addr) +{ + NMIPAddr a; + + nm_ip_addr_set(addr_family, &a, addr); + + if (NM_IS_IPv4(addr_family)) + return a.addr4 == 0; + + return IN6_IS_ADDR_UNSPECIFIED(&a.addr6); +} + +static inline NMIPAddr +nm_ip_addr_init(int addr_family, gconstpointer src) +{ + NMIPAddr a; + + nm_assert_addr_family(addr_family); + nm_assert(src); + + G_STATIC_ASSERT_EXPR(sizeof(NMIPAddr) == sizeof(struct in6_addr)); + + /* this MUST use memcpy() to support unaligned src/dst pointers. */ + + if (NM_IS_IPv4(addr_family)) { + memcpy(&a, src, sizeof(in_addr_t)); + + /* ensure all bytes of the union are initialized. If only to make + * valgrind happy. */ + memset(&a.array[sizeof(in_addr_t)], 0, sizeof(a) - sizeof(in_addr_t)); + } else + memcpy(&a, src, sizeof(struct in6_addr)); + + return a; +} + +gboolean nm_ip_addr_set_from_untrusted(int addr_family, + gpointer dst, + gconstpointer src, + gsize src_len, + int *out_addr_family); + +gboolean +nm_ip_addr_set_from_variant(int addr_family, gpointer dst, GVariant *variant, int *out_addr_family); + +static inline gconstpointer +nm_ip_addr_from_packed_array(int addr_family, gconstpointer ipaddr_arr, gsize idx) +{ + return NM_IS_IPv4(addr_family) + ? ((gconstpointer) & (((const struct in_addr *) ipaddr_arr)[idx])) + : ((gconstpointer) & (((const struct in6_addr *) ipaddr_arr)[idx])); +} + +/*****************************************************************************/ + +static inline guint32 +nm_ip4_addr_netmask_to_prefix(in_addr_t subnetmask) +{ + G_STATIC_ASSERT_EXPR(__SIZEOF_INT__ == 4); + G_STATIC_ASSERT_EXPR(sizeof(int) == 4); + G_STATIC_ASSERT_EXPR(sizeof(guint) == 4); + G_STATIC_ASSERT_EXPR(sizeof(subnetmask) == 4); + + return ((subnetmask != 0u) ? (guint32) (32 - __builtin_ctz(ntohl(subnetmask))) : 0u); +} + +/** + * nm_ip4_addr_netmask_from_prefix: + * @prefix: a CIDR prefix + * + * Returns: the netmask represented by the prefix, in network byte order + **/ +static inline in_addr_t +nm_ip4_addr_netmask_from_prefix(guint32 prefix) +{ + nm_assert(prefix <= 32); + return prefix < 32 ? ~htonl(0xFFFFFFFFu >> prefix) : 0xFFFFFFFFu; +} + +guint32 nm_ip4_addr_get_default_prefix0(in_addr_t ip); +guint32 nm_ip4_addr_get_default_prefix(in_addr_t ip); + +gconstpointer +nm_ip_addr_clear_host_address(int family, gpointer dst, gconstpointer src, guint32 plen); + +/* nm_ip4_addr_clear_host_address: + * @addr: source ip6 address + * @plen: prefix length of network + * + * returns: the input address, with the host address set to 0. + */ +static inline in_addr_t +nm_ip4_addr_clear_host_address(in_addr_t addr, guint32 plen) +{ + return addr & nm_ip4_addr_netmask_from_prefix(plen); +} + +const struct in6_addr * +nm_ip6_addr_clear_host_address(struct in6_addr *dst, const struct in6_addr *src, guint32 plen); + +/*****************************************************************************/ + +static inline int +nm_ip4_addr_same_prefix_cmp(in_addr_t addr_a, in_addr_t addr_b, guint32 plen) +{ + NM_CMP_DIRECT(htonl(nm_ip4_addr_clear_host_address(addr_a, plen)), + htonl(nm_ip4_addr_clear_host_address(addr_b, plen))); + return 0; +} + +int nm_ip6_addr_same_prefix_cmp(const struct in6_addr *addr_a, + const struct in6_addr *addr_b, + guint32 plen); + +static inline gboolean +nm_ip4_addr_same_prefix(in_addr_t addr_a, in_addr_t addr_b, guint32 plen) +{ + return nm_ip4_addr_same_prefix_cmp(addr_a, addr_b, plen) == 0; +} + +static inline gboolean +nm_ip6_addr_same_prefix(const struct in6_addr *addr_a, const struct in6_addr *addr_b, guint8 plen) +{ + return nm_ip6_addr_same_prefix_cmp(addr_a, addr_b, plen) == 0; +} + +static inline int +nm_ip_addr_same_prefix_cmp(int addr_family, gconstpointer addr_a, gconstpointer addr_b, guint8 plen) +{ + NMIPAddr a; + NMIPAddr b; + + NM_CMP_SELF(addr_a, addr_b); + + nm_ip_addr_set(addr_family, &a, addr_a); + nm_ip_addr_set(addr_family, &b, addr_b); + + if (NM_IS_IPv4(addr_family)) + return nm_ip4_addr_same_prefix_cmp(a.addr4, b.addr4, plen); + + return nm_ip6_addr_same_prefix_cmp(&a.addr6, &b.addr6, plen); +} + +static inline gboolean +nm_ip_addr_same_prefix(int addr_family, gconstpointer addr_a, gconstpointer addr_b, guint8 plen) +{ + return nm_ip_addr_same_prefix_cmp(addr_family, addr_a, addr_b, plen) == 0; +} + +#define NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX(a, b, plen) \ + NM_CMP_RETURN(nm_ip4_addr_same_prefix_cmp((a), (b), (plen))) + +#define NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX(a, b, plen) \ + NM_CMP_RETURN(nm_ip6_addr_same_prefix_cmp((a), (b), (plen))) + +/*****************************************************************************/ + +gboolean nm_ip_addr_is_site_local(int addr_family, const void *address); +gboolean nm_ip6_addr_is_ula(const struct in6_addr *address); + +/*****************************************************************************/ + +#define NM_IPV4LL_NETWORK ((in_addr_t) htonl(0xA9FE0000lu)) +#define NM_IPV4LL_NETMASK ((in_addr_t) htonl(0xFFFF0000lu)) + +static inline gboolean +nm_ip4_addr_is_loopback(in_addr_t addr) +{ + /* There is also IN_LOOPBACK() in <linux/in.h>, but there the + * argument is in host order not `in_addr_t`. */ + return (addr & htonl(0xFF000000u)) == htonl(0x7F000000u); +} + +static inline gboolean +nm_ip4_addr_is_link_local(in_addr_t addr) +{ + return (addr & NM_IPV4LL_NETMASK) == NM_IPV4LL_NETWORK; +} + +static inline gboolean +nm_ip4_addr_is_zeronet(in_addr_t network) +{ + /* Same as ipv4_is_zeronet() from kernel's include/linux/in.h. */ + return (network & htonl(0xFF000000u)) == htonl(0x00000000u); +} + +/*****************************************************************************/ + +#define NM_INET_ADDRSTRLEN INET6_ADDRSTRLEN + +/* Forward declare function so we don't have to drag in <arpa/inet.h>. */ +const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); + +static inline const char * +nm_inet_ntop(int addr_family, gconstpointer addr, char *dst) +{ + const char *s; + + nm_assert_addr_family(addr_family); + nm_assert(addr); + nm_assert(dst); + + s = inet_ntop(addr_family, + addr, + dst, + addr_family == AF_INET6 ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN); + nm_assert(s); + return s; +} + +static inline const char * +nm_inet4_ntop(in_addr_t addr, char dst[static INET_ADDRSTRLEN]) +{ + return nm_inet_ntop(AF_INET, &addr, dst); +} + +static inline const char * +nm_inet6_ntop(const struct in6_addr *addr, char dst[static INET6_ADDRSTRLEN]) +{ + return nm_inet_ntop(AF_INET6, addr, dst); +} + +static inline char * +nm_inet_ntop_dup(int addr_family, gconstpointer addr) +{ + char buf[NM_INET_ADDRSTRLEN]; + + return g_strdup(nm_inet_ntop(addr_family, addr, buf)); +} + +static inline char * +nm_inet4_ntop_dup(in_addr_t addr) +{ + return nm_inet_ntop_dup(AF_INET, &addr); +} + +static inline char * +nm_inet6_ntop_dup(const struct in6_addr *addr) +{ + return nm_inet_ntop_dup(AF_INET6, addr); +} + +/*****************************************************************************/ + +gboolean nm_inet_parse_bin_full(int addr_family, + gboolean accept_legacy, + const char *text, + int *out_addr_family, + gpointer out_addr); +static inline gboolean +nm_inet_parse_bin(int addr_family, const char *text, int *out_addr_family, gpointer out_addr) +{ + return nm_inet_parse_bin_full(addr_family, FALSE, text, out_addr_family, out_addr); +} + +gboolean nm_inet_parse_str(int addr_family, const char *text, char **out_addr); + +gboolean nm_inet_parse_with_prefix_bin(int addr_family, + const char *text, + int *out_addr_family, + gpointer out_addr, + int *out_prefix); + +gboolean +nm_inet_parse_with_prefix_str(int addr_family, const char *text, char **out_addr, int *out_prefix); + +/*****************************************************************************/ + +gboolean nm_inet_is_valid(int addr_family, const char *str_addr); + +gboolean nm_inet_is_normalized(int addr_family, const char *str_addr); + +/*****************************************************************************/ + +/* this enum is compatible with ICMPV6_ROUTER_PREF_* (from <linux/icmpv6.h>, + * the values for netlink attribute RTA_PREF) and "enum ndp_route_preference" + * from <ndp.h>. */ +typedef enum _nm_packed { + NM_ICMPV6_ROUTER_PREF_MEDIUM = 0x0, /* ICMPV6_ROUTER_PREF_MEDIUM */ + NM_ICMPV6_ROUTER_PREF_LOW = 0x3, /* ICMPV6_ROUTER_PREF_LOW */ + NM_ICMPV6_ROUTER_PREF_HIGH = 0x1, /* ICMPV6_ROUTER_PREF_HIGH */ + NM_ICMPV6_ROUTER_PREF_INVALID = 0x2, /* ICMPV6_ROUTER_PREF_INVALID */ +} NMIcmpv6RouterPref; + +const char *nm_icmpv6_router_pref_to_string(NMIcmpv6RouterPref pref, char *buf, gsize len); + +/*****************************************************************************/ + +#endif /* __NM_INET_UTILS_H__ */ diff --git a/src/libnm-glib-aux/nm-shared-utils.c b/src/libnm-glib-aux/nm-shared-utils.c index 624f9a3e97..524f0c31b1 100644 --- a/src/libnm-glib-aux/nm-shared-utils.c +++ b/src/libnm-glib-aux/nm-shared-utils.c @@ -35,111 +35,6 @@ const void *const _NM_PTRARRAY_EMPTY[1] = {NULL}; /*****************************************************************************/ -const NMIPAddr nm_ip_addr_zero = {}; - -/* We use _nm_alignas(NMIPAddr) to ensure that fields for in_addr_t and - * struct in6_addr have all the same alignment. Ensure that this is suitable. */ -G_STATIC_ASSERT(_nm_alignof(in_addr_t) <= _nm_alignof(NMIPAddr)); -G_STATIC_ASSERT(_nm_alignof(struct in_addr) <= _nm_alignof(NMIPAddr)); -G_STATIC_ASSERT(_nm_alignof(struct in6_addr) <= _nm_alignof(NMIPAddr)); -G_STATIC_ASSERT(_nm_alignof(NMEtherAddr) <= _nm_alignof(NMIPAddr)); - -int -nm_ip_addr_cmp_for_sort(gconstpointer a, gconstpointer b, gpointer user_data) -{ - /* This is a compare function that can be used for sorting IP addresses. - * Essentially, it calls memcmp(). @user_data must be GINT_TO_POINTER(addr_family). - * @a and @b must be either pointers to in_addr_t, struct in6_addr or NMIPAddr. */ - return nm_ip_addr_cmp(GPOINTER_TO_INT(user_data), a, b); -} - -/* this initializes a struct in_addr/in6_addr and allows for untrusted - * arguments (like unsuitable @addr_family or @src_len). It's almost safe - * in the sense that it verifies input arguments strictly. Also, it - * uses memcpy() to access @src, so alignment is not an issue. - * - * Only potential pitfalls: - * - * - it allows for @addr_family to be AF_UNSPEC. If that is the case (and the - * caller allows for that), the caller MUST provide @out_addr_family. - * - when setting @dst to an IPv4 address, the trailing bytes are not touched. - * Meaning, if @dst is an NMIPAddr union, only the first bytes will be set. - * If that matter to you, clear @dst before. */ -gboolean -nm_ip_addr_set_from_untrusted(int addr_family, - gpointer dst, - gconstpointer src, - gsize src_len, - int *out_addr_family) -{ - nm_assert(dst); - - switch (addr_family) { - case AF_UNSPEC: - if (!out_addr_family) { - /* when the callers allow undefined @addr_family, they must provide - * an @out_addr_family argument. */ - nm_assert_not_reached(); - return FALSE; - } - switch (src_len) { - case sizeof(struct in_addr): - addr_family = AF_INET; - break; - case sizeof(struct in6_addr): - addr_family = AF_INET6; - break; - default: - return FALSE; - } - break; - case AF_INET: - if (src_len != sizeof(struct in_addr)) - return FALSE; - break; - case AF_INET6: - if (src_len != sizeof(struct in6_addr)) - return FALSE; - break; - default: - /* when the callers allow undefined @addr_family, they must provide - * an @out_addr_family argument. */ - nm_assert(out_addr_family); - return FALSE; - } - - nm_assert(src); - - memcpy(dst, src, src_len); - NM_SET_OUT(out_addr_family, addr_family); - return TRUE; -} - -gboolean -nm_ip_addr_set_from_variant(int addr_family, gpointer dst, GVariant *variant, int *out_addr_family) -{ - gconstpointer bytes; - gsize len; - - g_return_val_if_fail(dst, FALSE); - g_return_val_if_fail(variant, FALSE); - - /* This function always expects IP addressea a byte arrays ("ay"). Note that - * several NetworkManager API uses "u" (32 bit unsigned intergers) for IPv4 addresses. - * So this function won't work in those cases. - * - * Btw, using "u" for IPv4 address messes badly with the endianness (host - * vs network byte order). Don't do that. - */ - g_return_val_if_fail(g_variant_is_of_type(variant, G_VARIANT_TYPE("ay")), FALSE); - - bytes = g_variant_get_fixed_array(variant, &len, sizeof(guint8)); - - return nm_ip_addr_set_from_untrusted(addr_family, dst, bytes, len, out_addr_family); -} - -/*****************************************************************************/ - G_STATIC_ASSERT(ETH_ALEN == sizeof(struct ether_addr)); G_STATIC_ASSERT(ETH_ALEN == 6); G_STATIC_ASSERT(ETH_ALEN == sizeof(NMEtherAddr)); @@ -244,7 +139,7 @@ nm_utils_ipv6_interface_identifier_get_from_token(NMUtilsIPv6IfaceId *iid, const /** * nm_utils_inet6_interface_identifier_to_token: * @iid: %NMUtilsIPv6IfaceId interface identifier - * @buf: the destination buffer of at least %NM_UTILS_INET_ADDRSTRLEN + * @buf: the destination buffer of at least %NM_INET_ADDRSTRLEN * bytes. * * Converts the interface identifier to a string token. @@ -261,7 +156,7 @@ nm_utils_inet6_interface_identifier_to_token(const NMUtilsIPv6IfaceId *iid, nm_assert(buf); nm_utils_ipv6_addr_set_interface_identifier(&i6_token, iid); - return _nm_utils_inet6_ntop(&i6_token, buf); + return nm_inet6_ntop(&i6_token, buf); } /*****************************************************************************/ @@ -981,293 +876,6 @@ nm_utils_flags2str(const NMUtilsFlags2StrDesc *descs, /*****************************************************************************/ -guint32 -_nm_utils_ip4_get_default_prefix0(in_addr_t ip) -{ - /* The function is originally from ipcalc.c of Red Hat's initscripts. */ - switch (ntohl(ip) >> 24) { - case 0 ... 127: - return 8; /* Class A */ - case 128 ... 191: - return 16; /* Class B */ - case 192 ... 223: - return 24; /* Class C */ - } - return 0; -} - -guint32 -_nm_utils_ip4_get_default_prefix(in_addr_t ip) -{ - return _nm_utils_ip4_get_default_prefix0(ip) ?: 24; -} - -gboolean -nm_utils_ip_is_site_local(int addr_family, const void *address) -{ - in_addr_t addr4; - - switch (addr_family) { - case AF_INET: - /* RFC1918 private addresses - * 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 */ - addr4 = ntohl(*((const in_addr_t *) address)); - return (addr4 & 0xff000000) == 0x0a000000 || (addr4 & 0xfff00000) == 0xac100000 - || (addr4 & 0xffff0000) == 0xc0a80000; - case AF_INET6: - /* IN6_IS_ADDR_SITELOCAL() is for deprecated fec0::/10 addresses (see rfc3879, 4.). - * Note that for unique local IPv6 addresses (ULA, fc00::/7) this returns false, - * which may or may not be a bug. */ - return IN6_IS_ADDR_SITELOCAL(address); - default: - g_return_val_if_reached(FALSE); - } -} - -gboolean -nm_utils_ip6_is_ula(const struct in6_addr *address) -{ - /* Unique local IPv6 address (ULA) fc00::/7 */ - return (address->s6_addr32[0] & htonl(0xfe000000u)) == htonl(0xfc000000u); -} - -/*****************************************************************************/ - -static gboolean -_parse_legacy_addr4(const char *text, in_addr_t *out_addr, GError **error) -{ - gs_free char *s_free = NULL; - struct in_addr a1; - guint8 bin[sizeof(a1)]; - char *s; - int i; - - if (inet_aton(text, &a1) != 1) { - g_set_error_literal(error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_INVALID_ARGUMENT, - "address invalid according to inet_aton()"); - return FALSE; - } - - /* OK, inet_aton() accepted the format. That's good, because we want - * to accept IPv4 addresses in octal format, like 255.255.000.000. - * That's what "legacy" means here. inet_pton() doesn't accept those. - * - * But inet_aton() also ignores trailing garbage and formats with fewer than - * 4 digits. That is just too crazy and we don't do that. Perform additional checks - * and reject some forms that inet_aton() accepted. - * - * Note that we still should (of course) accept everything that inet_pton() - * accepts. However this code never gets called if inet_pton() succeeds - * (see below, aside the assertion code). */ - - if (NM_STRCHAR_ANY(text, ch, (!(ch >= '0' && ch <= '9') && !NM_IN_SET(ch, '.', 'x')))) { - /* We only accepts '.', digits, and 'x' for "0x". */ - g_set_error_literal(error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_INVALID_ARGUMENT, - "contains an invalid character"); - return FALSE; - } - - s = nm_memdup_maybe_a(300, text, strlen(text) + 1, &s_free); - - for (i = 0; i < G_N_ELEMENTS(bin); i++) { - char *current_token = s; - gint32 v; - - s = strchr(s, '.'); - if (s) { - s[0] = '\0'; - s++; - } - - if ((i == G_N_ELEMENTS(bin) - 1) != (s == NULL)) { - /* Exactly for the last digit, we expect to have no more following token. - * But this isn't the case. Abort. */ - g_set_error(error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_INVALID_ARGUMENT, - "wrong number of tokens (index %d, token '%s')", - i, - s); - return FALSE; - } - - v = _nm_utils_ascii_str_to_int64(current_token, 0, 0, 0xFF, -1); - if (v == -1) { - int errsv = errno; - - /* we do accept octal and hex (even with leading "0x"). But something - * about this token is wrong. */ - g_set_error(error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_INVALID_ARGUMENT, - "invalid token '%s': %s (%d)", - current_token, - nm_strerror_native(errsv), - errsv); - return FALSE; - } - - bin[i] = v; - } - - if (memcmp(bin, &a1, sizeof(bin)) != 0) { - /* our parsing did not agree with what inet_aton() gave. Something - * is wrong. Abort. */ - g_set_error( - error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_INVALID_ARGUMENT, - "inet_aton() result 0x%08x differs from computed value 0x%02hhx%02hhx%02hhx%02hhx", - a1.s_addr, - bin[0], - bin[1], - bin[2], - bin[3]); - return FALSE; - } - - *out_addr = a1.s_addr; - return TRUE; -} - -gboolean -nm_utils_parse_inaddr_bin_full(int addr_family, - gboolean accept_legacy, - const char *text, - int *out_addr_family, - gpointer out_addr) -{ - NMIPAddr addrbin; - - g_return_val_if_fail(text, FALSE); - - if (addr_family == AF_UNSPEC) { - g_return_val_if_fail(!out_addr || out_addr_family, FALSE); - addr_family = strchr(text, ':') ? AF_INET6 : AF_INET; - } else - g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), FALSE); - - if (inet_pton(addr_family, text, &addrbin) != 1) { - if (accept_legacy && addr_family == AF_INET - && _parse_legacy_addr4(text, &addrbin.addr4, NULL)) { - /* The address is in some legacy format which inet_aton() accepts, but not inet_pton(). - * Most likely octal digits (leading zeros). We accept the address. */ - } else - return FALSE; - } - -#if NM_MORE_ASSERTS > 10 - if (addr_family == AF_INET) { - NM_PRAGMA_WARNING_DISABLE_DANGLING_POINTER - gs_free_error GError *error = NULL; - in_addr_t a; - - /* The legacy parser should accept everything that inet_pton() accepts too. Meaning, - * it should strictly parse *more* formats. And of course, parse it the same way. */ - if (!_parse_legacy_addr4(text, &a, &error)) { - char buf[INET_ADDRSTRLEN]; - - g_error("unexpected assertion failure: could parse \"%s\" as %s, but not accepted by " - "legacy parser: %s", - text, - _nm_utils_inet4_ntop(addrbin.addr4, buf), - error->message); - } - nm_assert(addrbin.addr4 == a); - NM_PRAGMA_WARNING_REENABLE - } -#endif - - NM_SET_OUT(out_addr_family, addr_family); - if (out_addr) - nm_ip_addr_set(addr_family, out_addr, &addrbin); - return TRUE; -} - -gboolean -nm_utils_parse_inaddr(int addr_family, const char *text, char **out_addr) -{ - NMIPAddr addrbin; - char addrstr_buf[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)]; - - g_return_val_if_fail(text, FALSE); - - if (addr_family == AF_UNSPEC) - addr_family = strchr(text, ':') ? AF_INET6 : AF_INET; - else - g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), FALSE); - - if (inet_pton(addr_family, text, &addrbin) != 1) - return FALSE; - - NM_SET_OUT(out_addr, - g_strdup(inet_ntop(addr_family, &addrbin, addrstr_buf, sizeof(addrstr_buf)))); - return TRUE; -} - -gboolean -nm_utils_parse_inaddr_prefix_bin(int addr_family, - const char *text, - int *out_addr_family, - gpointer out_addr, - int *out_prefix) -{ - gs_free char *addrstr_free = NULL; - int prefix = -1; - const char *slash; - const char *addrstr; - NMIPAddr addrbin; - - g_return_val_if_fail(text, FALSE); - - if (addr_family == AF_UNSPEC) { - g_return_val_if_fail(!out_addr || out_addr_family, FALSE); - addr_family = strchr(text, ':') ? AF_INET6 : AF_INET; - } else - g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), FALSE); - - slash = strchr(text, '/'); - if (slash) - addrstr = nm_strndup_a(300, text, slash - text, &addrstr_free); - else - addrstr = text; - - if (inet_pton(addr_family, addrstr, &addrbin) != 1) - return FALSE; - - if (slash) { - /* For IPv4, `ip addr add` supports the prefix-length as a netmask. We don't - * do that. */ - prefix = - _nm_utils_ascii_str_to_int64(&slash[1], 10, 0, addr_family == AF_INET ? 32 : 128, -1); - if (prefix == -1) - return FALSE; - } - - NM_SET_OUT(out_addr_family, addr_family); - if (out_addr) - nm_ip_addr_set(addr_family, out_addr, &addrbin); - NM_SET_OUT(out_prefix, prefix); - return TRUE; -} - -gboolean -nm_utils_parse_inaddr_prefix(int addr_family, const char *text, char **out_addr, int *out_prefix) -{ - NMIPAddr addrbin; - char addrstr_buf[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)]; - - if (!nm_utils_parse_inaddr_prefix_bin(addr_family, text, &addr_family, &addrbin, out_prefix)) - return FALSE; - NM_SET_OUT(out_addr, - g_strdup(inet_ntop(addr_family, &addrbin, addrstr_buf, sizeof(addrstr_buf)))); - return TRUE; -} - gboolean nm_utils_parse_next_line(const char **inout_ptr, gsize *inout_len, @@ -1323,43 +931,6 @@ done: /*****************************************************************************/ -gboolean -nm_utils_ipaddr_is_valid(int addr_family, const char *str_addr) -{ - nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6)); - - return str_addr && nm_utils_parse_inaddr_bin(addr_family, str_addr, NULL, NULL); -} - -gboolean -nm_utils_ipaddr_is_normalized(int addr_family, const char *str_addr) -{ - NMIPAddr addr; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6)); - - if (!str_addr) - return FALSE; - - if (!nm_utils_parse_inaddr_bin(addr_family, str_addr, &addr_family, &addr)) - return FALSE; - - nm_utils_inet_ntop(addr_family, &addr, sbuf); - return nm_streq(sbuf, str_addr); -} - -/*****************************************************************************/ - -NM_UTILS_ENUM2STR_DEFINE(nm_icmpv6_router_pref_to_string, - NMIcmpv6RouterPref, - NM_UTILS_ENUM2STR(NM_ICMPV6_ROUTER_PREF_LOW, "low"), - NM_UTILS_ENUM2STR(NM_ICMPV6_ROUTER_PREF_MEDIUM, "medium"), - NM_UTILS_ENUM2STR(NM_ICMPV6_ROUTER_PREF_HIGH, "high"), - NM_UTILS_ENUM2STR(NM_ICMPV6_ROUTER_PREF_INVALID, "invalid"), ); - -/*****************************************************************************/ - /** * nm_g_ascii_strtoll() * @nptr: the string to parse @@ -6359,98 +5930,6 @@ _nm_utils_ssid_to_string_gbytes(GBytes *ssid) /*****************************************************************************/ -gconstpointer -nm_utils_ipx_address_clear_host_address(int family, gpointer dst, gconstpointer src, guint32 plen) -{ - g_return_val_if_fail(dst, NULL); - - switch (family) { - case AF_INET: - g_return_val_if_fail(plen <= 32, NULL); - - if (!src) { - /* allow "self-assignment", by specifying %NULL as source. */ - src = dst; - } - - *((guint32 *) dst) = nm_utils_ip4_address_clear_host_address(*((guint32 *) src), plen); - break; - case AF_INET6: - nm_utils_ip6_address_clear_host_address(dst, src, plen); - break; - default: - g_return_val_if_reached(NULL); - } - return dst; -} - -/* nm_utils_ip6_address_clear_host_address: - * @dst: destination output buffer, will contain the network part of the @src address - * @src: source ip6 address. If NULL, this does an in-place update of @dst. - * Also, @src and @dst are allowed to be the same pointers. - * @plen: prefix length of network - * - * Note: this function is self assignment safe, to update @src inplace, set both - * @dst and @src to the same destination or set @src NULL. - */ -const struct in6_addr * -nm_utils_ip6_address_clear_host_address(struct in6_addr *dst, - const struct in6_addr *src, - guint32 plen) -{ - g_return_val_if_fail(plen <= 128, NULL); - g_return_val_if_fail(dst, NULL); - - if (!src) - src = dst; - - if (plen < 128) { - guint nbytes = plen / 8; - guint nbits = plen % 8; - - if (nbytes && dst != src) - memcpy(dst, src, nbytes); - if (nbits) { - dst->s6_addr[nbytes] = (src->s6_addr[nbytes] & (0xFF << (8 - nbits))); - nbytes++; - } - if (nbytes <= 15) - memset(&dst->s6_addr[nbytes], 0, 16 - nbytes); - } else if (src != dst) - *dst = *src; - - return dst; -} - -int -nm_utils_ip6_address_same_prefix_cmp(const struct in6_addr *addr_a, - const struct in6_addr *addr_b, - guint32 plen) -{ - int nbytes; - guint8 va, vb, m; - - if (plen >= 128) { - nm_assert(plen == 128); - NM_CMP_DIRECT_MEMCMP(addr_a, addr_b, sizeof(struct in6_addr)); - } else { - nbytes = plen / 8; - if (nbytes) - NM_CMP_DIRECT_MEMCMP(addr_a, addr_b, nbytes); - - plen = plen % 8; - if (plen != 0) { - m = ~((1 << (8 - plen)) - 1); - va = ((((const guint8 *) addr_a))[nbytes]) & m; - vb = ((((const guint8 *) addr_b))[nbytes]) & m; - NM_CMP_DIRECT(va, vb); - } - } - return 0; -} - -/*****************************************************************************/ - #define IPV6_PROPERTY_DIR "/proc/sys/net/ipv6/conf/" #define IPV4_PROPERTY_DIR "/proc/sys/net/ipv4/conf/" diff --git a/src/libnm-glib-aux/nm-shared-utils.h b/src/libnm-glib-aux/nm-shared-utils.h index 3d8eaced07..892d0d3012 100644 --- a/src/libnm-glib-aux/nm-shared-utils.h +++ b/src/libnm-glib-aux/nm-shared-utils.h @@ -214,128 +214,6 @@ nm_ether_addr_equal(const NMEtherAddr *a, const NMEtherAddr *b) /*****************************************************************************/ -typedef struct { - union { - guint8 addr_ptr[sizeof(struct in6_addr)]; - in_addr_t addr4; - struct in_addr addr4_struct; - struct in6_addr addr6; - - /* NMIPAddr is really a union for IP addresses. - * However, as ethernet addresses fit in here nicely, use - * it also for an ethernet MAC address. */ - guint8 ether_addr_octet[6 /*ETH_ALEN*/]; - NMEtherAddr ether_addr; - - guint8 array[sizeof(struct in6_addr)]; - }; -} NMIPAddr; - -#define NM_IP_ADDR_INIT \ - { \ - .array = { 0 } \ - } - -extern const NMIPAddr nm_ip_addr_zero; - -#define nm_ether_addr_zero (nm_ip_addr_zero.ether_addr) - -static inline int -nm_ip_addr_cmp(int addr_family, gconstpointer a, gconstpointer b) -{ - /* Note that @a and @b are not required to be full NMIPAddr unions. - * Depending on @addr_family, they can also be only in_addr_t or - * struct in6_addr. */ - NM_CMP_SELF(a, b); - NM_CMP_DIRECT_MEMCMP(a, b, nm_utils_addr_family_to_size(addr_family)); - return 0; -} - -int nm_ip_addr_cmp_for_sort(gconstpointer a, gconstpointer b, gpointer user_data); - -static inline gboolean -nm_ip_addr_equal(int addr_family, gconstpointer a, gconstpointer b) -{ - return nm_ip_addr_cmp(addr_family, a, b) == 0; -} - -static inline gboolean -nm_ip_addr_is_null(int addr_family, gconstpointer addr) -{ - nm_assert(addr); - - if (NM_IS_IPv4(addr_family)) { - in_addr_t t; - - /* also for in_addr_t type (AF_INET), we accept that the pointer might - * be unaligned. */ - memcpy(&t, addr, sizeof(t)); - return t == 0; - } - - return IN6_IS_ADDR_UNSPECIFIED((const struct in6_addr *) addr); -} - -static inline void -nm_ip_addr_set(int addr_family, gpointer dst, gconstpointer src) -{ - nm_assert(dst); - nm_assert(src); - - /* this MUST use memcpy() to support unaligned src/dst pointers. */ - memcpy(dst, src, nm_utils_addr_family_to_size(addr_family)); - - /* Note that @dst is not necessarily a NMIPAddr, it could also be just - * an in_addr_t/struct in6_addr. We thus can only set the bytes that - * we know are present based on the address family. - * - * Using this function to initialize an NMIPAddr union (for IPv4) leaves - * uninitalized bytes. Avoid that by using nm_ip_addr_init() instead. */ -} - -static inline NMIPAddr -nm_ip_addr_init(int addr_family, gconstpointer src) -{ - NMIPAddr a; - - nm_assert_addr_family(addr_family); - nm_assert(src); - - G_STATIC_ASSERT_EXPR(sizeof(NMIPAddr) == sizeof(struct in6_addr)); - - /* this MUST use memcpy() to support unaligned src/dst pointers. */ - - if (NM_IS_IPv4(addr_family)) { - memcpy(&a, src, sizeof(in_addr_t)); - - /* ensure all bytes of the union are initialized. If only to make - * valgrind happy. */ - memset(&a.array[sizeof(in_addr_t)], 0, sizeof(a) - sizeof(in_addr_t)); - } else - memcpy(&a, src, sizeof(struct in6_addr)); - - return a; -} - -gboolean nm_ip_addr_set_from_untrusted(int addr_family, - gpointer dst, - gconstpointer src, - gsize src_len, - int *out_addr_family); - -gboolean -nm_ip_addr_set_from_variant(int addr_family, gpointer dst, GVariant *variant, int *out_addr_family); - -static inline gconstpointer -nm_ip_addr_from_packed_array(int addr_family, gconstpointer ipaddr_arr, gsize idx) -{ - return NM_IS_IPv4(addr_family) - ? ((gconstpointer) & (((const struct in_addr *) ipaddr_arr)[idx])) - : ((gconstpointer) & (((const struct in6_addr *) ipaddr_arr)[idx])); -} - -/*****************************************************************************/ - struct ether_addr; static inline int @@ -397,219 +275,6 @@ gboolean nm_utils_get_ipv6_interface_identifier(NMLinkType link_type, /*****************************************************************************/ -static inline guint32 -_nm_utils_ip4_netmask_to_prefix(in_addr_t subnetmask) -{ - G_STATIC_ASSERT_EXPR(__SIZEOF_INT__ == 4); - G_STATIC_ASSERT_EXPR(sizeof(int) == 4); - G_STATIC_ASSERT_EXPR(sizeof(guint) == 4); - G_STATIC_ASSERT_EXPR(sizeof(subnetmask) == 4); - - return ((subnetmask != 0u) ? (guint32) (32 - __builtin_ctz(ntohl(subnetmask))) : 0u); -} - -/** - * _nm_utils_ip4_prefix_to_netmask: - * @prefix: a CIDR prefix - * - * Returns: the netmask represented by the prefix, in network byte order - **/ -static inline in_addr_t -_nm_utils_ip4_prefix_to_netmask(guint32 prefix) -{ - nm_assert(prefix <= 32); - return prefix < 32 ? ~htonl(0xFFFFFFFFu >> prefix) : 0xFFFFFFFFu; -} - -guint32 _nm_utils_ip4_get_default_prefix0(in_addr_t ip); -guint32 _nm_utils_ip4_get_default_prefix(in_addr_t ip); - -gconstpointer -nm_utils_ipx_address_clear_host_address(int family, gpointer dst, gconstpointer src, guint32 plen); - -/* nm_utils_ip4_address_clear_host_address: - * @addr: source ip6 address - * @plen: prefix length of network - * - * returns: the input address, with the host address set to 0. - */ -static inline in_addr_t -nm_utils_ip4_address_clear_host_address(in_addr_t addr, guint32 plen) -{ - return addr & _nm_utils_ip4_prefix_to_netmask(plen); -} - -const struct in6_addr *nm_utils_ip6_address_clear_host_address(struct in6_addr *dst, - const struct in6_addr *src, - guint32 plen); - -static inline int -nm_utils_ip4_address_same_prefix_cmp(in_addr_t addr_a, in_addr_t addr_b, guint32 plen) -{ - NM_CMP_DIRECT(htonl(nm_utils_ip4_address_clear_host_address(addr_a, plen)), - htonl(nm_utils_ip4_address_clear_host_address(addr_b, plen))); - return 0; -} - -int nm_utils_ip6_address_same_prefix_cmp(const struct in6_addr *addr_a, - const struct in6_addr *addr_b, - guint32 plen); - -static inline gboolean -nm_utils_ip4_address_same_prefix(in_addr_t addr_a, in_addr_t addr_b, guint32 plen) -{ - return nm_utils_ip4_address_same_prefix_cmp(addr_a, addr_b, plen) == 0; -} - -static inline gboolean -nm_utils_ip6_address_same_prefix(const struct in6_addr *addr_a, - const struct in6_addr *addr_b, - guint8 plen) -{ - return nm_utils_ip6_address_same_prefix_cmp(addr_a, addr_b, plen) == 0; -} - -static inline int -nm_utils_ip_address_same_prefix_cmp(int addr_family, - gconstpointer addr_a, - gconstpointer addr_b, - guint8 plen) -{ - NM_CMP_SELF(addr_a, addr_b); - - if (NM_IS_IPv4(addr_family)) { - return nm_utils_ip4_address_same_prefix_cmp(*((const in_addr_t *) addr_a), - *((const in_addr_t *) addr_b), - plen); - } - - return nm_utils_ip6_address_same_prefix_cmp(addr_a, addr_b, plen); -} - -static inline gboolean -nm_utils_ip_address_same_prefix(int addr_family, - gconstpointer addr_a, - gconstpointer addr_b, - guint8 plen) -{ - return nm_utils_ip_address_same_prefix_cmp(addr_family, addr_a, addr_b, plen) == 0; -} - -#define NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX(a, b, plen) \ - NM_CMP_RETURN(nm_utils_ip4_address_same_prefix_cmp((a), (b), (plen))) - -#define NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX(a, b, plen) \ - NM_CMP_RETURN(nm_utils_ip6_address_same_prefix_cmp((a), (b), (plen))) - -/*****************************************************************************/ - -gboolean nm_utils_ip_is_site_local(int addr_family, const void *address); -gboolean nm_utils_ip6_is_ula(const struct in6_addr *address); - -/*****************************************************************************/ - -#define NM_IPV4LL_NETWORK ((in_addr_t) htonl(0xA9FE0000lu)) -#define NM_IPV4LL_NETMASK ((in_addr_t) htonl(0xFFFF0000lu)) - -static inline gboolean -nm_utils_ip4_address_is_loopback(in_addr_t addr) -{ - /* There is also IN_LOOPBACK() in <linux/in.h>, but there the - * argument is in host order not `in_addr_t`. */ - return (addr & htonl(0xFF000000u)) == htonl(0x7F000000u); -} - -static inline gboolean -nm_utils_ip4_address_is_link_local(in_addr_t addr) -{ - return (addr & NM_IPV4LL_NETMASK) == NM_IPV4LL_NETWORK; -} - -static inline gboolean -nm_utils_ip4_address_is_zeronet(in_addr_t network) -{ - /* Same as ipv4_is_zeronet() from kernel's include/linux/in.h. */ - return (network & htonl(0xFF000000u)) == htonl(0x00000000u); -} - -/*****************************************************************************/ - -#define NM_UTILS_INET_ADDRSTRLEN INET6_ADDRSTRLEN - -/* Forward declare function so we don't have to drag in <arpa/inet.h>. */ -const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); - -static inline const char * -nm_utils_inet_ntop(int addr_family, gconstpointer addr, char *dst) -{ - const char *s; - - nm_assert_addr_family(addr_family); - nm_assert(addr); - nm_assert(dst); - - s = inet_ntop(addr_family, - addr, - dst, - addr_family == AF_INET6 ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN); - nm_assert(s); - return s; -} - -static inline const char * -_nm_utils_inet4_ntop(in_addr_t addr, char dst[static INET_ADDRSTRLEN]) -{ - return nm_utils_inet_ntop(AF_INET, &addr, dst); -} - -static inline const char * -_nm_utils_inet6_ntop(const struct in6_addr *addr, char dst[static INET6_ADDRSTRLEN]) -{ - return nm_utils_inet_ntop(AF_INET6, addr, dst); -} - -static inline char * -nm_utils_inet_ntop_dup(int addr_family, gconstpointer addr) -{ - char buf[NM_UTILS_INET_ADDRSTRLEN]; - - return g_strdup(nm_utils_inet_ntop(addr_family, addr, buf)); -} - -static inline char * -nm_utils_inet4_ntop_dup(in_addr_t addr) -{ - return nm_utils_inet_ntop_dup(AF_INET, &addr); -} - -static inline char * -nm_utils_inet6_ntop_dup(const struct in6_addr *addr) -{ - return nm_utils_inet_ntop_dup(AF_INET6, addr); -} - -/*****************************************************************************/ - -gboolean nm_utils_ipaddr_is_valid(int addr_family, const char *str_addr); - -gboolean nm_utils_ipaddr_is_normalized(int addr_family, const char *str_addr); - -/*****************************************************************************/ - -/* this enum is compatible with ICMPV6_ROUTER_PREF_* (from <linux/icmpv6.h>, - * the values for netlink attribute RTA_PREF) and "enum ndp_route_preference" - * from <ndp.h>. */ -typedef enum _nm_packed { - NM_ICMPV6_ROUTER_PREF_MEDIUM = 0x0, /* ICMPV6_ROUTER_PREF_MEDIUM */ - NM_ICMPV6_ROUTER_PREF_LOW = 0x3, /* ICMPV6_ROUTER_PREF_LOW */ - NM_ICMPV6_ROUTER_PREF_HIGH = 0x1, /* ICMPV6_ROUTER_PREF_HIGH */ - NM_ICMPV6_ROUTER_PREF_INVALID = 0x2, /* ICMPV6_ROUTER_PREF_INVALID */ -} NMIcmpv6RouterPref; - -const char *nm_icmpv6_router_pref_to_string(NMIcmpv6RouterPref pref, char *buf, gsize len); - -/*****************************************************************************/ - gboolean nm_utils_memeqzero(gconstpointer data, gsize length); /*****************************************************************************/ @@ -1042,31 +707,6 @@ nm_utils_escaped_tokens_options_escape_val(const char *val, char **out_to_free) /*****************************************************************************/ -gboolean nm_utils_parse_inaddr_bin_full(int addr_family, - gboolean accept_legacy, - const char *text, - int *out_addr_family, - gpointer out_addr); -static inline gboolean -nm_utils_parse_inaddr_bin(int addr_family, - const char *text, - int *out_addr_family, - gpointer out_addr) -{ - return nm_utils_parse_inaddr_bin_full(addr_family, FALSE, text, out_addr_family, out_addr); -} - -gboolean nm_utils_parse_inaddr(int addr_family, const char *text, char **out_addr); - -gboolean nm_utils_parse_inaddr_prefix_bin(int addr_family, - const char *text, - int *out_addr_family, - gpointer out_addr, - int *out_prefix); - -gboolean -nm_utils_parse_inaddr_prefix(int addr_family, const char *text, char **out_addr, int *out_prefix); - gboolean nm_utils_parse_next_line(const char **inout_ptr, gsize *inout_len, const char **out_line, @@ -1658,6 +1298,10 @@ nm_g_variant_new_au(const guint32 *data, gsize len) return g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, data, len, sizeof(guint32)); } +struct _NMIPAddr; + +extern const struct _NMIPAddr nm_ip_addr_zero; + static inline GVariant * nm_g_variant_new_ay_inaddr(int addr_family, gconstpointer addr) { diff --git a/src/libnm-glib-aux/nm-test-utils.h b/src/libnm-glib-aux/nm-test-utils.h index 83702070b8..fd2ddf86fb 100644 --- a/src/libnm-glib-aux/nm-test-utils.h +++ b/src/libnm-glib-aux/nm-test-utils.h @@ -1944,9 +1944,9 @@ nmtst_setting_ip_config_add_address(NMSettingIPConfig *s_ip, const char *address g_assert(s_ip); - if (nm_utils_ipaddr_is_valid(AF_INET, address)) + if (nm_inet_is_valid(AF_INET, address)) family = AF_INET; - else if (nm_utils_ipaddr_is_valid(AF_INET6, address)) + else if (nm_inet_is_valid(AF_INET6, address)) family = AF_INET6; else g_assert_not_reached(); @@ -1969,9 +1969,9 @@ nmtst_setting_ip_config_add_route(NMSettingIPConfig *s_ip, g_assert(s_ip); - if (nm_utils_ipaddr_is_valid(AF_INET, dest)) + if (nm_inet_is_valid(AF_INET, dest)) family = AF_INET; - else if (nm_utils_ipaddr_is_valid(AF_INET6, dest)) + else if (nm_inet_is_valid(AF_INET6, dest)) family = AF_INET6; else g_assert_not_reached(); @@ -2913,7 +2913,7 @@ nmtst_ip_address_new(int addr_family, const char *str) GError *error = NULL; NMIPAddress *a; - if (!nm_utils_parse_inaddr_prefix_bin(addr_family, str, &addr_family, &addr, &plen)) + if (!nm_inet_parse_with_prefix_bin(addr_family, str, &addr_family, &addr, &plen)) g_assert_not_reached(); if (plen == -1) diff --git a/src/libnm-glib-aux/tests/test-shared-general.c b/src/libnm-glib-aux/tests/test-shared-general.c index 7d36d64a8c..e6e57c5218 100644 --- a/src/libnm-glib-aux/tests/test-shared-general.c +++ b/src/libnm-glib-aux/tests/test-shared-general.c @@ -251,37 +251,37 @@ test_nm_strndup_a(void) /*****************************************************************************/ static void -test_nm_utils_ip4_address_is_loopback(void) +test_nm_ip4_addr_is_loopback(void) { - g_assert(nm_utils_ip4_address_is_loopback(nmtst_inet4_from_string("127.0.0.0"))); - g_assert(nm_utils_ip4_address_is_loopback(nmtst_inet4_from_string("127.0.0.1"))); - g_assert(nm_utils_ip4_address_is_loopback(nmtst_inet4_from_string("127.5.0.1"))); - g_assert(!nm_utils_ip4_address_is_loopback(nmtst_inet4_from_string("126.5.0.1"))); - g_assert(!nm_utils_ip4_address_is_loopback(nmtst_inet4_from_string("128.5.0.1"))); - g_assert(!nm_utils_ip4_address_is_loopback(nmtst_inet4_from_string("129.5.0.1"))); + g_assert(nm_ip4_addr_is_loopback(nmtst_inet4_from_string("127.0.0.0"))); + g_assert(nm_ip4_addr_is_loopback(nmtst_inet4_from_string("127.0.0.1"))); + g_assert(nm_ip4_addr_is_loopback(nmtst_inet4_from_string("127.5.0.1"))); + g_assert(!nm_ip4_addr_is_loopback(nmtst_inet4_from_string("126.5.0.1"))); + g_assert(!nm_ip4_addr_is_loopback(nmtst_inet4_from_string("128.5.0.1"))); + g_assert(!nm_ip4_addr_is_loopback(nmtst_inet4_from_string("129.5.0.1"))); } /*****************************************************************************/ static void -test_nm_utils_ip4_prefix_to_netmask(void) +test_nm_ip4_addr_netmask_from_prefix(void) { - g_assert_cmpint(_nm_utils_ip4_prefix_to_netmask(0), ==, nmtst_inet4_from_string("0.0.0.0")); - g_assert_cmpint(_nm_utils_ip4_prefix_to_netmask(1), ==, nmtst_inet4_from_string("128.0.0.0")); - g_assert_cmpint(_nm_utils_ip4_prefix_to_netmask(2), ==, nmtst_inet4_from_string("192.0.0.0")); - g_assert_cmpint(_nm_utils_ip4_prefix_to_netmask(16), + g_assert_cmpint(nm_ip4_addr_netmask_from_prefix(0), ==, nmtst_inet4_from_string("0.0.0.0")); + g_assert_cmpint(nm_ip4_addr_netmask_from_prefix(1), ==, nmtst_inet4_from_string("128.0.0.0")); + g_assert_cmpint(nm_ip4_addr_netmask_from_prefix(2), ==, nmtst_inet4_from_string("192.0.0.0")); + g_assert_cmpint(nm_ip4_addr_netmask_from_prefix(16), ==, nmtst_inet4_from_string("255.255.0.0")); - g_assert_cmpint(_nm_utils_ip4_prefix_to_netmask(24), + g_assert_cmpint(nm_ip4_addr_netmask_from_prefix(24), ==, nmtst_inet4_from_string("255.255.255.0")); - g_assert_cmpint(_nm_utils_ip4_prefix_to_netmask(30), + g_assert_cmpint(nm_ip4_addr_netmask_from_prefix(30), ==, nmtst_inet4_from_string("255.255.255.252")); - g_assert_cmpint(_nm_utils_ip4_prefix_to_netmask(31), + g_assert_cmpint(nm_ip4_addr_netmask_from_prefix(31), ==, nmtst_inet4_from_string("255.255.255.254")); - g_assert_cmpint(_nm_utils_ip4_prefix_to_netmask(32), + g_assert_cmpint(nm_ip4_addr_netmask_from_prefix(32), ==, nmtst_inet4_from_string("255.255.255.255")); } @@ -2201,6 +2201,19 @@ test_hostname_is_valid(void) /*****************************************************************************/ +static void +test_inet_utils(void) +{ + g_assert(nm_ip_addr_is_site_local(AF_INET, nmtst_inet_from_string(AF_INET, "172.16.0.1"))); + g_assert(nm_ip_addr_is_site_local(AF_INET, nmtst_inet_from_string(AF_INET, "172.17.0.1"))); + g_assert(nm_ip_addr_is_site_local(AF_INET, nmtst_inet_from_string(AF_INET, "192.168.7.5"))); + g_assert(!nm_ip_addr_is_site_local(AF_INET, nmtst_inet_from_string(AF_INET, "192.0.7.5"))); + g_assert(nm_ip_addr_is_site_local(AF_INET6, nmtst_inet_from_string(AF_INET6, "fec0::"))); + g_assert(!nm_ip_addr_is_site_local(AF_INET6, nmtst_inet_from_string(AF_INET6, "fc00::"))); +} + +/*****************************************************************************/ + NMTST_DEFINE(); int @@ -2215,10 +2228,9 @@ main(int argc, char **argv) g_test_add_func("/general/test_nm_make_strv", test_make_strv); g_test_add_func("/general/test_nm_strdup_int", test_nm_strdup_int); g_test_add_func("/general/test_nm_strndup_a", test_nm_strndup_a); - g_test_add_func("/general/test_nm_utils_ip4_address_is_loopback", - test_nm_utils_ip4_address_is_loopback); - g_test_add_func("/general/test_nm_utils_ip4_prefix_to_netmask", - test_nm_utils_ip4_prefix_to_netmask); + g_test_add_func("/general/test_nm_ip4_addr_is_loopback", test_nm_ip4_addr_is_loopback); + g_test_add_func("/general/test_nm_ip4_addr_netmask_from_prefix", + test_nm_ip4_addr_netmask_from_prefix); g_test_add_func("/general/test_unaligned", test_unaligned); g_test_add_func("/general/test_strv_cmp", test_strv_cmp); g_test_add_func("/general/test_strstrip_avoid_copy", test_strstrip_avoid_copy); @@ -2246,6 +2258,7 @@ main(int argc, char **argv) g_test_add_func("/general/test_path_startswith", test_path_startswith); g_test_add_func("/general/test_path_simplify", test_path_simplify); g_test_add_func("/general/test_hostname_is_valid", test_hostname_is_valid); + g_test_add_func("/general/test_inet_utils", test_inet_utils); return g_test_run(); } |