glib-aux: fix various nm_ip_addr_*() functions for unaligned addresses

Most of our nm_ip_addr_*() functions take an opaque pointer, that
can be either in_addr_t, struct in6_addr or NMIPAddr.

They also tend to support that their argument pointer is not aligned.
The reason is not very strong, except that usually it's simple to
support and it allows the caller to use those low-level functions for
pointers of unknown alignment (e.g. from a package on the network).

Fix a few cases for that.
This commit is contained in:
Thomas Haller 2022-08-19 13:26:14 +02:00
parent 232df1c08d
commit b02aeaf2f3
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
2 changed files with 46 additions and 37 deletions

View file

@ -138,20 +138,22 @@ nm_ip4_addr_get_default_prefix(in_addr_t ip)
gboolean
nm_ip_addr_is_site_local(int addr_family, const void *address)
{
in_addr_t addr4;
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 */
addr4 = ntohl(*((const in_addr_t *) address));
return (addr4 & 0xff000000) == 0x0a000000 || (addr4 & 0xfff00000) == 0xac100000
|| (addr4 & 0xffff0000) == 0xc0a80000;
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,
* which may or may not be a bug. */
return IN6_IS_ADDR_SITELOCAL(address);
* 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);
}
@ -169,25 +171,33 @@ nm_ip6_addr_is_ula(const struct in6_addr *address)
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);
if (!src) {
/* allow "self-assignment", by specifying %NULL as source. */
src = dst;
}
*((guint32 *) dst) = nm_ip4_addr_clear_host_address(*((guint32 *) src), plen);
a2.addr4 = nm_ip4_addr_clear_host_address(a.addr4, plen);
break;
case AF_INET6:
nm_ip6_addr_clear_host_address(dst, src, plen);
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;
}

View file

@ -50,23 +50,6 @@ 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)
{
@ -84,6 +67,19 @@ nm_ip_addr_set(int addr_family, gpointer dst, gconstpointer src)
* 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)
{
@ -201,15 +197,18 @@ nm_ip6_addr_same_prefix(const struct in6_addr *addr_a, const struct in6_addr *ad
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);
if (NM_IS_IPv4(addr_family)) {
return nm_ip4_addr_same_prefix_cmp(*((const in_addr_t *) addr_a),
*((const in_addr_t *) addr_b),
plen);
}
nm_ip_addr_set(addr_family, &a, addr_a);
nm_ip_addr_set(addr_family, &b, addr_b);
return nm_ip6_addr_same_prefix_cmp(addr_a, addr_b, plen);
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