mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-04-22 10:30:43 +02:00
Reformat with: clang-format version 19.1.0 (Fedora 19.1.0-1.fc41) https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2046
416 lines
14 KiB
C
416 lines
14 KiB
C
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
|
|
#ifndef __NM_INET_UTILS_H__
|
|
#define __NM_INET_UTILS_H__
|
|
|
|
#include "libnm-std-aux/unaligned-fundamental.h"
|
|
|
|
typedef union _NMIPAddr {
|
|
guint8 addr_ptr[sizeof(struct in6_addr)];
|
|
in_addr_t addr4;
|
|
struct in_addr addr4_struct;
|
|
struct in6_addr addr6;
|
|
|
|
/* This union field only exists, so that it's guaranteed that NMIPAddr has
|
|
* a suitable alignment. We use that with nm_ether_addr_zero macro, that
|
|
* aliases nm_ip_addr_zero. */
|
|
NMEtherAddr _ether_addr;
|
|
} NMIPAddr;
|
|
|
|
typedef struct _NMIPAddrTyped {
|
|
NMIPAddr addr;
|
|
gint8 addr_family;
|
|
} NMIPAddrTyped;
|
|
|
|
#define NM_IP_ADDR_INIT {.addr_ptr = {0}}
|
|
|
|
#define _NM_IN6ADDR_INIT(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af) \
|
|
{ \
|
|
.s6_addr = { \
|
|
(a0), \
|
|
(a1), \
|
|
(a2), \
|
|
(a3), \
|
|
(a4), \
|
|
(a5), \
|
|
(a6), \
|
|
(a7), \
|
|
(a8), \
|
|
(a9), \
|
|
(aa), \
|
|
(ab), \
|
|
(ac), \
|
|
(ad), \
|
|
(ae), \
|
|
(af), \
|
|
} \
|
|
}
|
|
|
|
#define NM_IN6ADDR_INIT(...) ((struct in6_addr) _NM_IN6ADDR_INIT(__VA_ARGS__))
|
|
|
|
extern const NMIPAddr nm_ip_addr_zero;
|
|
|
|
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)
|
|
{
|
|
struct in6_addr a6;
|
|
|
|
nm_assert(addr);
|
|
|
|
if (NM_IS_IPv4(addr_family))
|
|
return unaligned_read_ne32(addr) == 0;
|
|
|
|
memcpy(&a6, addr, sizeof(struct in6_addr));
|
|
return IN6_IS_ADDR_UNSPECIFIED(&a6);
|
|
}
|
|
|
|
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.addr_ptr[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 int
|
|
nm_ip_addr_typed_cmp(const NMIPAddrTyped *a, const NMIPAddrTyped *b)
|
|
{
|
|
NM_CMP_SELF(a, b);
|
|
NM_CMP_FIELD(a, b, addr_family);
|
|
NM_CMP_DIRECT_MEMCMP(&a->addr, &b->addr, nm_utils_addr_family_to_size(a->addr_family));
|
|
return 0;
|
|
}
|
|
|
|
static inline gboolean
|
|
nm_ip_addr_typed_equal(const NMIPAddrTyped *a, const NMIPAddrTyped *b)
|
|
{
|
|
return nm_ip_addr_typed_cmp(a, b) == 0;
|
|
}
|
|
|
|
static inline void
|
|
nm_ip_addr_typed_hash_update(NMHashState *h, const NMIPAddrTyped *addr)
|
|
{
|
|
nm_hash_update_vals(h, addr->addr_family);
|
|
nm_hash_update_mem(h, &addr->addr, nm_utils_addr_family_to_size(addr->addr_family));
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
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);
|
|
|
|
static inline in_addr_t
|
|
nm_ip4_addr_get_broadcast_address(in_addr_t address, guint8 plen)
|
|
{
|
|
return address | ~nm_ip4_addr_netmask_from_prefix(plen);
|
|
}
|
|
|
|
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)) /* 169.254.0.0 */
|
|
#define NM_IPV4LL_NETMASK ((in_addr_t) htonl(0xFFFF0000lu)) /* 255.255.0.0 */
|
|
#define NM_IPV4LL_PREFIXLEN 16
|
|
#define NM_IPV4LO_NETWORK ((in_addr_t) htonl(0x7F000000lu)) /* 127.0.0.0 */
|
|
#define NM_IPV4LO_NETMASK ((in_addr_t) htonl(0xFF000000lu)) /* 255.0.0.0 */
|
|
#define NM_IPV4LO_PREFIXLEN 8
|
|
#define NM_IPV4LO_ADDR1 ((in_addr_t) htonl(0x7F000001lu)) /* 127.0.0.1 */
|
|
|
|
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 & NM_IPV4LO_NETMASK) == NM_IPV4LO_NETWORK;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
int nmtst_inet_aton(const char *text, in_addr_t *out_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__ */
|