about summary refs log tree commit diff
path: root/shared/nm-glib-aux/nm-hash-utils.c
diff options
context:
space:
mode:
authorSebastien Bacher <seb128@ubuntu.com>2019-05-10 15:07:08 +0200
committerSebastien Bacher <seb128@ubuntu.com>2019-05-22 13:41:30 +0200
commitd57a1dd26f8e9859252b0983c2d2ec3b95eb5714 (patch)
tree46f1146e87af8cc7b58b751f7e575bd0abb2f59d /shared/nm-glib-aux/nm-hash-utils.c
parentad9ed8bfb963266b4eea524131845f406cfc55d7 (diff)
parent85563b7fc7ec2cd21e38debb9b28db342e2e8e7c (diff)
Import Debian changes 1.18.0-1ubuntu1
network-manager (1.18.0-1ubuntu1) eoan; urgency=medium

  * Update to 1.18, merge on Debian, new version includes nwe support for
    policy routing rules and for VLAN filtering for Linux bridge.
  * Remaining Ubuntu changes
    - Use systemd-resolved instead of dnsmasq
    - debian/control:
      + Depend on isc-dhcp-client instead of recommends
      + Recommend network-manager-pptp
      + Suggest avahi-autoipd for IPv4LL support
    - debian/rules, debian/network-manager.postinst:
      + Don't restart NetworkManager on upgrade but recommend restarting
        the computer
    - debian/rules, debian/network-manager.postinst:
      + Don't install sysvinit scripts or migrate from sysvinit
    - debian/network-manager.postinst:
      + Don't add the netdev group.
      + drop in an empty override file for NetworkManager to manage all
        devices for upgrade from any version, as long as there is no
        netplan configuration yet.
    - debian/default-wifi-powersave-on.conf, debian/rules:
      + Install a config file to enable WiFi powersave
    - Enable build tests
    - Add autopkgtests
    - debian/source_network-manager.py, debian/network-manager.install,
      debian/network-manager.links: Add apport hook
    - Add network-manager-config-connectivity-ubuntu package
    - NetworkManager.conf: disable MAC randomization feature. There is no
      easy way for desktop users to disable this feature yet. And there are
      reports that it doesn't work well with some systems.
    - Update Vcs links to point to Ubuntu branch
    - Add patches. See patch descriptions for more details:
      + Provide-access-to-some-of-NM-s-interfaces-to-whoopsie.patch
      + Update-dnsmasq-parameters.patch
      + Disable-general-with-expect.patch
      + libnm-Check-self-still-NMManager-or-not.patch
      + dns-manager-don-t-merge-split-DNS-search-domains.patch (but disabled)
      + Read-system-connections-from-run.patch
    - debian/tests/urfkill-integration - don't stop/start network manager
    - Revert "Add Conflicts to network-manager-dev against deprecated libraries"
      This reverts commit b4acc5e03e2b821e1cccc69529bb70826c741942.  We're still
      building libnm-glib for now, so these packages have a use in Ubuntu.
  * Removed delta, not needed anymore
    - debian/network-manager.maintscript
      + Remove /etc/dbus-1/system.d/nm-ofono.conf
Diffstat (limited to 'shared/nm-glib-aux/nm-hash-utils.c')
-rw-r--r--shared/nm-glib-aux/nm-hash-utils.c196
1 files changed, 196 insertions, 0 deletions
diff --git a/shared/nm-glib-aux/nm-hash-utils.c b/shared/nm-glib-aux/nm-hash-utils.c
new file mode 100644
index 00000000..6e728e6b
--- /dev/null
+++ b/shared/nm-glib-aux/nm-hash-utils.c
@@ -0,0 +1,196 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2017 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "nm-hash-utils.h"
+
+#include <stdint.h>
+
+#include "nm-shared-utils.h"
+#include "nm-random-utils.h"
+
+/*****************************************************************************/
+
+#define HASH_KEY_SIZE 16u
+#define HASH_KEY_SIZE_GUINT ((HASH_KEY_SIZE + sizeof (guint) - 1) / sizeof (guint))
+
+G_STATIC_ASSERT (sizeof (guint) * HASH_KEY_SIZE_GUINT >= HASH_KEY_SIZE);
+
+static const guint8 *volatile global_seed = NULL;
+
+static const guint8 *
+_get_hash_key_init (void)
+{
+	static gsize g_lock;
+	/* the returned hash is aligned to guin64, hence, it is safe
+	 * to use it as guint* or guint64* pointer. */
+	static union {
+		guint8 v8[HASH_KEY_SIZE];
+	} g_arr _nm_alignas (guint64);
+	const guint8 *g;
+	union {
+		guint8 v8[HASH_KEY_SIZE];
+		guint vuint;
+	} t_arr;
+
+again:
+	g = g_atomic_pointer_get (&global_seed);
+	if (G_LIKELY (g != NULL)) {
+		nm_assert (g == g_arr.v8);
+		return g;
+	}
+
+	{
+		CSipHash siph_state;
+		uint64_t h;
+
+		/* initialize a random key in t_arr. */
+
+		nm_utils_random_bytes (&t_arr, sizeof (t_arr));
+
+		/* use siphash() of the key-size, to mangle the first guint. Otherwise,
+		 * the first guint has only the entropy that nm_utils_random_bytes()
+		 * generated for the first 4 bytes and relies on a good random generator.
+		 *
+		 * The first int is especially interesting for nm_hash_static() below, and we
+		 * want to have it all the entropy of t_arr. */
+		c_siphash_init (&siph_state, t_arr.v8);
+		c_siphash_append (&siph_state, (const guint8 *) &t_arr, sizeof (t_arr));
+		h = c_siphash_finalize (&siph_state);
+		if (sizeof (guint) < sizeof (h))
+			t_arr.vuint = t_arr.vuint ^ ((guint) (h & 0xFFFFFFFFu)) ^ ((guint) (h >> 32));
+		else
+			t_arr.vuint = t_arr.vuint ^ ((guint) (h & 0xFFFFFFFFu));
+	}
+
+	if (!g_once_init_enter (&g_lock)) {
+		/* lost a race. The random key is already initialized. */
+		goto again;
+	}
+
+	memcpy (g_arr.v8, t_arr.v8, HASH_KEY_SIZE);
+	g = g_arr.v8;
+	g_atomic_pointer_set (&global_seed, g);
+	g_once_init_leave (&g_lock, 1);
+	return g;
+}
+
+#define _get_hash_key() \
+	({ \
+		const guint8 *_g; \
+		\
+		_g = g_atomic_pointer_get (&global_seed); \
+		if (G_UNLIKELY (!_g)) \
+			_g = _get_hash_key_init (); \
+		_g; \
+	})
+
+guint
+nm_hash_static (guint static_seed)
+{
+	/* note that we only xor the static_seed with the key.
+	 * We don't use siphash, which would mix the bits better.
+	 * Note that this doesn't matter, because static_seed is not
+	 * supposed to be a value that you are hashing (for that, use
+	 * full siphash).
+	 * Instead, different callers may set a different static_seed
+	 * so that nm_hash_str(NULL) != nm_hash_ptr(NULL).
+	 *
+	 * Also, ensure that we don't return zero.
+	 */
+	return ((*((const guint *) _get_hash_key ())) ^ static_seed)
+	       ?: static_seed ?: 3679500967u;
+}
+
+void
+nm_hash_siphash42_init (CSipHash *h, guint static_seed)
+{
+	const guint8 *g;
+	guint seed[HASH_KEY_SIZE_GUINT];
+
+	nm_assert (h);
+
+	g = _get_hash_key ();
+	memcpy (seed, g, HASH_KEY_SIZE);
+	seed[0] ^= static_seed;
+	c_siphash_init (h, (const guint8 *) seed);
+}
+
+guint
+nm_hash_str (const char *str)
+{
+	NMHashState h;
+
+	if (!str)
+		return nm_hash_static (1867854211u);
+	nm_hash_init (&h, 1867854211u);
+	nm_hash_update_str (&h, str);
+	return nm_hash_complete (&h);
+}
+
+guint
+nm_str_hash (gconstpointer str)
+{
+	return nm_hash_str (str);
+}
+
+guint
+nm_hash_ptr (gconstpointer ptr)
+{
+	NMHashState h;
+
+	if (!ptr)
+		return nm_hash_static (2907677551u);
+	nm_hash_init (&h, 2907677551u);
+	nm_hash_update (&h, &ptr, sizeof (ptr));
+	return nm_hash_complete (&h);
+}
+
+guint
+nm_direct_hash (gconstpointer ptr)
+{
+	return nm_hash_ptr (ptr);
+}
+
+/*****************************************************************************/
+
+guint
+nm_pstr_hash (gconstpointer p)
+{
+	const char *const*s = p;
+
+	if (!s)
+		return nm_hash_static (101061439u);
+	return nm_hash_str (*s);
+}
+
+gboolean
+nm_pstr_equal (gconstpointer a, gconstpointer b)
+{
+	const char *const*s1 = a;
+	const char *const*s2 = b;
+
+	return    (s1 == s2)
+	       || (   s1
+	           && s2
+	           && nm_streq0 (*s1, *s2));
+}