summaryrefslogtreecommitdiff
path: root/src/libnm-glib-aux/nm-inet-utils.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnm-glib-aux/nm-inet-utils.h')
-rw-r--r--src/libnm-glib-aux/nm-inet-utils.h359
1 files changed, 359 insertions, 0 deletions
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__ */