summary refs log tree commit diff
path: root/system-settings/plugins/ifnet/net_utils.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2010-11-29 19:00:22 +0100
committerMichael Biebl <biebl@debian.org>2010-11-29 19:00:22 +0100
commita6b89d35fabd9f5934b84d7cde22e9268f92c3d3 (patch)
tree9e44755880d5933fcc90c6008d4585a76298a1bd /system-settings/plugins/ifnet/net_utils.c
parent9fae01fa351805b2903e535736e06971bc0b925e (diff)
Imported Upstream version 0.8.2 upstream/0.8.2
Diffstat (limited to 'system-settings/plugins/ifnet/net_utils.c')
-rw-r--r--system-settings/plugins/ifnet/net_utils.c932
1 files changed, 932 insertions, 0 deletions
diff --git a/system-settings/plugins/ifnet/net_utils.c b/system-settings/plugins/ifnet/net_utils.c
new file mode 100644
index 00000000..8a541979
--- /dev/null
+++ b/system-settings/plugins/ifnet/net_utils.c
@@ -0,0 +1,932 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Mu Qiao <qiaomuf@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 1999-2010 Gentoo Foundation, Inc.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <nm-utils.h>
+#include <nm-system-config-interface.h>
+#include "net_utils.h"
+#include "wpa_parser.h"
+#include "net_parser.h"
+
+/* emit heading and tailing blank space, tab, character t */
+gchar *
+strip_string (gchar * str, gchar t)
+{
+	gchar *ret = str;
+	gint length = 0;
+	guint i = 0;
+
+	while (ret[i] != '\0'
+	       && (ret[i] == '\t' || ret[i] == ' ' || ret[i] == t)) {
+		length++;
+		i++;
+	}
+	i = 0;
+	while (ret[i + length] != '\0') {
+		ret[i] = ret[i + length];
+		i++;
+	}
+	ret[i] = '\0';
+	length = strlen (ret);
+	while ((length - 1) >= 0
+	       && (ret[length - 1] == ' ' || ret[length - 1] == '\n'
+		   || ret[length - 1] == '\t' || ret[length - 1] == t))
+		length--;
+	ret[length] = '\0';
+	return ret;
+}
+
+gboolean
+is_hex (gchar * value)
+{
+	gchar *p;
+
+	if (!value)
+		return FALSE;
+	p = value;
+	while (*p) {
+		if (!isxdigit (*p)) {
+			return FALSE;
+		}
+		p++;
+	}
+	return TRUE;
+}
+
+gboolean
+is_ascii (gchar * value)
+{
+	gchar *p;
+
+	p = value;
+	while (*p) {
+		if (!isascii (*p)) {
+			return FALSE;
+		}
+		p++;
+	}
+	return TRUE;
+
+}
+
+gboolean
+is_true (char *str)
+{
+	if (!g_ascii_strcasecmp (str, "yes")
+	    || !g_ascii_strcasecmp (str, "true"))
+		return TRUE;
+	return FALSE;
+}
+
+static int
+hex2num (char c)
+{
+	if (c >= '0' && c <= '9')
+		return c - '0';
+	if (c >= 'a' && c <= 'f')
+		return c - 'a' + 10;
+	if (c >= 'A' && c <= 'F')
+		return c - 'A' + 10;
+	return -1;
+}
+
+static int
+hex2byte (const char *hex)
+{
+	int a, b;
+
+	a = hex2num (*hex++);
+	if (a < 0)
+		return -1;
+	b = hex2num (*hex++);
+	if (b < 0)
+		return -1;
+	return (a << 4) | b;
+}
+
+/* free return value by caller */
+gchar *
+utils_hexstr2bin (const gchar * hex, size_t len)
+{
+	size_t i;
+	int a;
+	const gchar *ipos = hex;
+	gchar *buf = NULL;
+	gchar *opos;
+
+	/* Length must be a multiple of 2 */
+	if ((len % 2) != 0)
+		return NULL;
+
+	opos = buf = g_malloc0 ((len / 2) + 1);
+	for (i = 0; i < len; i += 2) {
+		a = hex2byte (ipos);
+		if (a < 0) {
+			g_free (buf);
+			return NULL;
+		}
+		*opos++ = a;
+		ipos += 2;
+	}
+	return buf;
+}
+
+/* free return value by caller */
+gchar *
+utils_bin2hexstr (const gchar * bytes, int len, int final_len)
+{
+	static gchar hex_digits[] = "0123456789abcdef";
+	gchar *result;
+	int i;
+	gsize buflen = (len * 2) + 1;
+
+	g_return_val_if_fail (bytes != NULL, NULL);
+	g_return_val_if_fail (len > 0, NULL);
+	g_return_val_if_fail (len < 4096, NULL);	/* Arbitrary limit */
+	if (final_len > -1)
+		g_return_val_if_fail (final_len < buflen, NULL);
+
+	result = g_malloc0 (buflen);
+	for (i = 0; i < len; i++) {
+		result[2 * i] = hex_digits[(bytes[i] >> 4) & 0xf];
+		result[2 * i + 1] = hex_digits[bytes[i] & 0xf];
+	}
+	/* Cut converted key off at the correct length for this cipher type */
+	if (final_len > -1)
+		result[final_len] = '\0';
+	else
+		result[buflen - 1] = '\0';
+
+	return result;
+}
+
+GQuark
+ifnet_plugin_error_quark (void)
+{
+	static GQuark error_quark = 0;
+
+	if (G_UNLIKELY (error_quark == 0))
+		error_quark =
+		    g_quark_from_static_string ("ifnet-plugin-error-quark");
+	return error_quark;
+}
+
+gboolean
+reload_parsers ()
+{
+	ifnet_destroy ();
+	wpa_parser_destroy ();
+	if (!ifnet_init (CONF_NET_FILE))
+		return FALSE;
+	wpa_parser_init (WPA_SUPPLICANT_CONF);
+	return TRUE;
+}
+
+gchar *
+read_hostname (gchar * path)
+{
+	gchar *contents = NULL, *result = NULL, *tmp;
+	gchar **all_lines = NULL;
+	guint line_num, i;
+
+	if (!g_file_get_contents (path, &contents, NULL, NULL))
+		return NULL;
+	all_lines = g_strsplit (contents, "\n", 0);
+	line_num = g_strv_length (all_lines);
+	for (i = 0; i < line_num; i++) {
+		g_strstrip (all_lines[i]);
+		if (all_lines[i][0] == '#' || all_lines[i][0] == '\0')
+			continue;
+		if (g_str_has_prefix (all_lines[i], "hostname")) {
+			tmp = strstr (all_lines[i], "=");
+			tmp++;
+			tmp = strip_string (tmp, '"');
+			result = g_strdup (tmp);
+			break;
+		}
+
+	}
+	g_strfreev (all_lines);
+	g_free (contents);
+	return result;
+}
+
+gboolean
+write_hostname (const gchar * hostname, gchar * path)
+{
+	gchar *contents = g_strdup_printf ("#Generated by NetworkManager\n"
+					   "hostname=\"%s\"\n", hostname);
+	gboolean result = g_file_set_contents (path, contents, -1, NULL);
+
+	g_free (contents);
+	return result;
+}
+
+gboolean
+is_static_ip4 (gchar * conn_name)
+{
+	gchar *data = ifnet_get_data (conn_name, "config");
+	gchar *dhcp6;
+
+	if (!data)
+		return FALSE;
+	dhcp6 = strstr (data, "dhcp6");
+	if (dhcp6) {
+		gchar *dhcp4;
+
+		if (strstr (data, "dhcp "))
+			return FALSE;
+		dhcp4 = strstr (data, "dhcp");
+		if (!dhcp4)
+			return TRUE;
+		if (dhcp4[4] == '\0')
+			return FALSE;
+		return TRUE;
+	}
+	return strstr (data, "dhcp") == NULL ? TRUE : FALSE;
+}
+
+gboolean
+is_static_ip6 (gchar * conn_name)
+{
+	gchar *data = ifnet_get_data (conn_name, "config");
+
+	if (!data)
+		return TRUE;
+	return strstr (data, "dhcp6") == NULL ? TRUE : FALSE;
+}
+
+gboolean
+is_ip4_address (gchar * in_address)
+{
+	gchar *pattern =
+	    "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.((\\{\\d{1,3}\\.\\.\\d{1,3}\\})|\\d{1,3})$";
+	gchar *address = g_strdup (in_address);
+	gboolean result = FALSE;
+	gchar *tmp;
+	GRegex *regex = g_regex_new (pattern, 0, 0, NULL);
+	GMatchInfo *match_info;
+
+	if (!address)
+		goto done;
+	g_strstrip (address);
+	if ((tmp = strstr (address, "/")) != NULL)
+		*tmp = '\0';
+	if ((tmp = strstr (address, " ")) != NULL)
+		*tmp = '\0';
+	g_regex_match (regex, address, 0, &match_info);
+	result = g_match_info_matches (match_info);
+      done:
+	if (match_info)
+		g_match_info_free (match_info);
+	g_regex_unref (regex);
+	g_free (address);
+	return result;
+}
+
+gboolean
+is_ip6_address (gchar * in_address)
+{
+	struct in6_addr tmp_ip6_addr;
+	gchar *tmp;
+	gchar *address = g_strdup (in_address);
+	gboolean result = FALSE;
+
+	if (!address) {
+		g_free (address);
+		return FALSE;
+	}
+	g_strstrip (address);
+	if ((tmp = strchr (address, '/')) != NULL)
+		*tmp = '\0';
+	if (inet_pton (AF_INET6, address, &tmp_ip6_addr))
+		result = TRUE;
+	g_free (address);
+	return result;
+
+}
+
+gboolean
+has_ip6_address (gchar * conn_name)
+{
+	gchar **ipset;
+	guint length;
+	guint i;
+
+	g_return_val_if_fail (conn_name != NULL, FALSE);
+	ipset = g_strsplit (ifnet_get_data (conn_name, "config"), "\" \"", 0);
+	length = g_strv_length (ipset);
+	for (i = 0; i < length; i++) {
+		if (!is_ip6_address (ipset[i]))
+			continue;
+		else {
+			g_strfreev (ipset);
+			return TRUE;
+		}
+
+	}
+	g_strfreev (ipset);
+	return FALSE;
+}
+
+gboolean
+has_default_route (gchar * conn_name, gboolean (*check_fn) (gchar *))
+{
+	gchar *routes = NULL, *tmp, *end;
+
+	g_return_val_if_fail (conn_name != NULL, FALSE);
+	tmp = ifnet_get_data (conn_name, "routes");
+	if (!tmp)
+		return FALSE;
+	routes = g_strdup (tmp);
+	tmp = strstr (routes, "default via ");
+	if (!tmp) {
+		goto error;
+	}
+	tmp += strlen ("default via ");
+	g_strstrip (tmp);
+	if ((end = strstr (tmp, "\"")) != NULL)
+		*end = '\0';
+	if (check_fn (tmp)) {
+		g_free (routes);
+		return TRUE;
+	}
+      error:
+	g_free (routes);
+	return FALSE;
+}
+
+static ip_block *
+create_ip4_block (gchar * ip)
+{
+	ip_block *iblock = g_slice_new0 (ip_block);
+	struct in_addr tmp_ip4_addr;
+	int i;
+	guint length;
+	gchar **ip_mask;
+
+	/* prefix format */
+	if (strstr (ip, "/")) {
+		gchar *prefix;
+
+		ip_mask = g_strsplit (ip, "/", 0);
+		length = g_strv_length (ip_mask);
+		if (!inet_pton (AF_INET, ip_mask[0], &tmp_ip4_addr))
+			goto error;
+		iblock->ip = tmp_ip4_addr.s_addr;
+		prefix = ip_mask[1];
+		i = 0;
+		while (i < length && isdigit (prefix[i]))
+			i++;
+		prefix[i] = '\0';
+		iblock->netmask = nm_utils_ip4_prefix_to_netmask ((guint32)
+								  atoi (ip_mask
+									[1]));
+	} else if (strstr (ip, "netmask")) {
+		ip_mask = g_strsplit (ip, " ", 0);
+		length = g_strv_length (ip_mask);
+		if (!inet_pton (AF_INET, ip_mask[0], &tmp_ip4_addr))
+			goto error;
+		iblock->ip = tmp_ip4_addr.s_addr;
+		i = 0;
+		while (i < length && !strstr (ip_mask[++i], "netmask")) ;
+		while (i < length && ip_mask[++i][0] == '\0') ;
+		if (i >= length)
+			goto error;
+		if (!inet_pton (AF_INET, ip_mask[i], &tmp_ip4_addr))
+			goto error;
+		iblock->netmask = tmp_ip4_addr.s_addr;
+	} else {
+		g_slice_free (ip_block, iblock);
+		if (!is_ip6_address (ip) && !strstr (ip, "dhcp"))
+			PLUGIN_WARN (IFNET_PLUGIN_NAME,
+				     "Can't handle ipv4 address: %s, missing netmask or prefix",
+				     ip);
+		return NULL;
+	}
+	g_strfreev (ip_mask);
+	return iblock;
+      error:
+	if (!is_ip6_address (ip))
+		PLUGIN_WARN (IFNET_PLUGIN_NAME, "Can't handle IPv4 address: %s",
+			     ip);
+	g_strfreev (ip_mask);
+	g_slice_free (ip_block, iblock);
+	return NULL;
+}
+
+static ip6_block *
+create_ip6_block (gchar * ip)
+{
+	ip6_block *iblock = g_slice_new0 (ip6_block);
+	gchar *dup_ip = g_strdup (ip);
+	struct in6_addr *tmp_ip6_addr = g_slice_new0 (struct in6_addr);
+	gchar *prefix = NULL;
+
+	if ((prefix = strstr (dup_ip, "/")) != NULL) {
+		*prefix = '\0';
+		prefix++;
+	}
+	if (!inet_pton (AF_INET6, dup_ip, tmp_ip6_addr)) {
+		goto error;
+	}
+	iblock->ip = tmp_ip6_addr;
+	if (prefix) {
+		errno = 0;
+		iblock->prefix = strtol (prefix, NULL, 10);
+		if (errno || iblock->prefix <= 0 || iblock->prefix > 128) {
+			goto error;
+		}
+	} else
+		iblock->prefix = 64;
+	g_free (dup_ip);
+	return iblock;
+      error:
+	if (!is_ip4_address (ip))
+		PLUGIN_WARN (IFNET_PLUGIN_NAME, "Can't handle IPv6 address: %s",
+			     ip);
+	g_slice_free (ip6_block, iblock);
+	g_slice_free (struct in6_addr, tmp_ip6_addr);
+
+	g_free (dup_ip);
+	return NULL;
+}
+
+static guint32
+get_ip4_gateway (gchar * gateway)
+{
+	gchar *tmp, *split;
+	struct in_addr tmp_ip4_addr;
+
+	if (!gateway)
+		return 0;
+	tmp = strstr (gateway, "via ");
+	tmp = g_strdup (tmp + strlen ("via "));
+	strip_string (tmp, ' ');
+	strip_string (tmp, '"');
+	if ((split = strstr (tmp, "\"")) != NULL)
+		*split = '\0';
+	if (!inet_pton (AF_INET, tmp, &tmp_ip4_addr))
+		goto error;
+	g_free (tmp);
+	return tmp_ip4_addr.s_addr;
+      error:
+	if (!is_ip6_address (tmp))
+		PLUGIN_WARN (IFNET_PLUGIN_NAME, "Can't handle IPv4 gateway: %s",
+			     tmp);
+	g_free (tmp);
+	return 0;
+}
+
+static struct in6_addr *
+get_ip6_next_hop (gchar * next_hop)
+{
+	gchar *tmp;
+	struct in6_addr *tmp_ip6_addr = g_slice_new0 (struct in6_addr);
+
+	if (!next_hop)
+		return 0;
+	tmp = strstr (next_hop, "via ");
+	tmp = g_strdup (tmp + strlen ("via "));
+	strip_string (tmp, ' ');
+	strip_string (tmp, '"');
+	g_strstrip (tmp);
+	if (!inet_pton (AF_INET6, tmp, tmp_ip6_addr))
+		goto error;
+	g_free (tmp);
+	return tmp_ip6_addr;
+      error:
+	if (!is_ip4_address (tmp))
+		PLUGIN_WARN (IFNET_PLUGIN_NAME,
+			     "Can't handle IPv6 next_hop: %s", tmp);
+	g_free (tmp);
+	g_slice_free (struct in6_addr, tmp_ip6_addr);
+
+	return NULL;
+}
+
+ip_block *
+convert_ip4_config_block (gchar * conn_name)
+{
+	gchar **ipset;
+	guint length;
+	guint i;
+	gchar *ip;
+	guint32 def_gateway;
+	gchar *routes;
+	gchar *pos;
+	ip_block *start = NULL, *current = NULL, *iblock = NULL;
+	gchar *pattern =
+	    "((\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.)\\{(\\d{1,3})\\.\\.(\\d{1,3})\\}(/\\d{1,2}))";
+	GRegex *regex = g_regex_new (pattern, 0, 0, NULL);
+
+	g_return_val_if_fail (conn_name != NULL, NULL);
+	ipset = g_strsplit (ifnet_get_data (conn_name, "config"), "\" \"", 0);
+	length = g_strv_length (ipset);
+	routes = ifnet_get_data (conn_name, "routes");
+	if (routes)
+		def_gateway = get_ip4_gateway (strstr (routes, "default"));
+	else
+		def_gateway = 0;
+	for (i = 0; i < length; i++) {
+		ip = ipset[i];
+		ip = strip_string (ip, '"');
+		//Handle ip like 192.168.4.{1..3}
+		if ((pos = strchr (ip, '{')) != NULL) {
+			gchar *ip_start, *ip_prefix;
+			gchar *begin_str, *end_str;
+			int begin, end, j;
+			GMatchInfo *match_info;
+
+			g_regex_match (regex, ip, 0, &match_info);
+			if (!g_match_info_matches (match_info)) {
+				g_match_info_free (match_info);
+				continue;
+			}
+			begin_str = g_match_info_fetch (match_info, 3);
+			end_str = g_match_info_fetch (match_info, 4);
+			begin = atoi (begin_str);
+			end = atoi (end_str);
+			ip_start = g_match_info_fetch (match_info, 2);
+			ip_prefix = g_match_info_fetch (match_info, 5);
+			if (end < begin || begin < 1 || end > 254) {
+				g_match_info_free (match_info);
+				continue;
+			}
+
+			for (j = begin; j <= end; j++) {
+				char suf[4];
+				gchar *newip;
+
+				sprintf (suf, "%d", j);
+				newip =
+				    g_strconcat (ip_start, suf, ip_prefix,
+						 NULL);
+				iblock = create_ip4_block (newip);
+				if (iblock == NULL) {
+					g_free (newip);
+					continue;
+				}
+				if (!iblock->gateway && def_gateway != 0)
+					iblock->gateway = def_gateway;
+				if (start == NULL)
+					start = current = iblock;
+				else {
+					current->next = iblock;
+					current = iblock;
+				}
+				g_free (newip);
+			}
+			g_free (begin_str);
+			g_free (end_str);
+			g_free (ip_start);
+			g_free (ip_prefix);
+			g_match_info_free (match_info);
+		} else {
+			iblock = create_ip4_block (ip);
+			if (iblock == NULL)
+				continue;
+			if (!iblock->gateway && def_gateway != 0)
+				iblock->gateway = def_gateway;
+			if (start == NULL)
+				start = current = iblock;
+			else {
+				current->next = iblock;
+				current = iblock;
+			}
+		}
+	}
+	g_strfreev (ipset);
+	g_regex_unref (regex);
+	return start;
+}
+
+ip6_block *
+convert_ip6_config_block (gchar * conn_name)
+{
+	gchar **ipset;
+	guint length;
+	guint i;
+	gchar *ip;
+	ip6_block *start = NULL, *current = NULL, *iblock = NULL;
+
+	g_return_val_if_fail (conn_name != NULL, NULL);
+	ipset = g_strsplit (ifnet_get_data (conn_name, "config"), "\" \"", 0);
+	length = g_strv_length (ipset);
+	for (i = 0; i < length; i++) {
+		ip = ipset[i];
+		ip = strip_string (ip, '"');
+		iblock = create_ip6_block (ip);
+		if (iblock == NULL)
+			continue;
+		if (start == NULL)
+			start = current = iblock;
+		else {
+			current->next = iblock;
+			current = iblock;
+		}
+	}
+	g_strfreev (ipset);
+	return start;
+}
+
+ip_block *
+convert_ip4_routes_block (gchar * conn_name)
+{
+	gchar **ipset;
+	guint length;
+	guint i;
+	gchar *ip;
+	gchar *routes;
+	ip_block *start = NULL, *current = NULL, *iblock = NULL;
+
+	g_return_val_if_fail (conn_name != NULL, NULL);
+	routes = ifnet_get_data (conn_name, "routes");
+	if (!routes)
+		return NULL;
+	ipset = g_strsplit (routes, "\" \"", 0);
+	length = g_strv_length (ipset);
+	for (i = 0; i < length; i++) {
+		ip = ipset[i];
+		if (strstr (ip, "default via ") || strstr (ip, "::")
+		    || !strstr (ip, "via"))
+			continue;
+		ip = strip_string (ip, '"');
+		iblock = create_ip4_block (ip);
+		if (iblock == NULL)
+			continue;
+		iblock->gateway = get_ip4_gateway (ip);
+		if (start == NULL)
+			start = current = iblock;
+		else {
+			current->next = iblock;
+			current = iblock;
+		}
+	}
+	g_strfreev (ipset);
+	return start;
+}
+
+ip6_block *
+convert_ip6_routes_block (gchar * conn_name)
+{
+	gchar **ipset;
+	guint length;
+	guint i;
+	gchar *ip, *tmp_addr;
+	gchar *routes;
+	ip6_block *start = NULL, *current = NULL, *iblock = NULL;
+	struct in6_addr *tmp_ip6_addr;
+
+	g_return_val_if_fail (conn_name != NULL, NULL);
+	routes = ifnet_get_data (conn_name, "routes");
+	if (!routes)
+		return NULL;
+	ipset = g_strsplit (routes, "\" \"", 0);
+	length = g_strv_length (ipset);
+	for (i = 0; i < length; i++) {
+		ip = ipset[i];
+		ip = strip_string (ip, '"');
+		if (ip[0] == '\0')
+			continue;
+		printf ("ip:%s\n", ip);
+		if ((tmp_addr = strstr (ip, "default via ")) != NULL) {
+			tmp_addr += strlen ("default via ");
+			if (!is_ip6_address (tmp_addr))
+				continue;
+			else {
+				tmp_ip6_addr = g_slice_new0 (struct in6_addr);
+
+				if (inet_pton (AF_INET6, "::", tmp_ip6_addr)) {
+					iblock = g_slice_new0 (ip6_block);
+					iblock->ip = tmp_ip6_addr;
+					iblock->prefix = 128;
+				} else {
+					g_slice_free (struct in6_addr,
+						      tmp_ip6_addr);
+					continue;
+				}
+			}
+		} else
+			iblock = create_ip6_block (ip);
+		if (iblock == NULL)
+			continue;
+		iblock->next_hop = get_ip6_next_hop (ip);
+		if (iblock->next_hop == NULL) {
+			destroy_ip6_block (iblock);
+			continue;
+		}
+		if (start == NULL)
+			start = current = iblock;
+		else {
+			current->next = iblock;
+			current = iblock;
+		}
+	}
+	g_strfreev (ipset);
+	return start;
+}
+
+void
+destroy_ip_block (ip_block * iblock)
+{
+	g_slice_free (ip_block, iblock);
+}
+
+void
+destroy_ip6_block (ip6_block * iblock)
+{
+	g_slice_free (struct in6_addr, iblock->ip);
+	g_slice_free (struct in6_addr, iblock->next_hop);
+
+	g_slice_free (ip6_block, iblock);
+}
+
+void
+set_ip4_dns_servers (NMSettingIP4Config * s_ip4, gchar * conn_name)
+{
+	gchar *dns_servers = ifnet_get_data (conn_name, "dns_servers");
+	gchar **server_list;
+	guint length, i;
+	struct in_addr tmp_ip4_addr;
+	guint32 new_dns;
+
+	if (!dns_servers)
+		return;
+	strip_string (dns_servers, '"');
+	server_list = g_strsplit (dns_servers, " ", 0);
+	length = g_strv_length (server_list);
+	if (length)
+		g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS,
+			      TRUE, NULL);
+	for (i = 0; i < length; i++) {
+		g_strstrip (server_list[i]);
+		if (server_list[i][0] == '\0')
+			continue;
+		if (!inet_pton (AF_INET, server_list[i], &tmp_ip4_addr)) {
+			if (!is_ip6_address (server_list[i]))
+				PLUGIN_WARN (IFNET_PLUGIN_NAME,
+					     "ignored dns: %s\n",
+					     server_list[i]);
+			continue;
+		}
+		new_dns = tmp_ip4_addr.s_addr;
+		if (new_dns && !nm_setting_ip4_config_add_dns (s_ip4, new_dns))
+			PLUGIN_WARN (IFNET_PLUGIN_NAME,
+				     "warning: duplicate DNS server %s",
+				     server_list[i]);
+	}
+	g_strfreev (server_list);
+}
+
+void
+set_ip6_dns_servers (NMSettingIP6Config * s_ip6, gchar * conn_name)
+{
+	gchar *dns_servers = ifnet_get_data (conn_name, "dns_servers");
+	gchar **server_list;
+	guint length, i;
+	struct in6_addr tmp_ip6_addr;
+
+	if (!dns_servers)
+		return;
+	strip_string (dns_servers, '"');
+	server_list = g_strsplit (dns_servers, " ", 0);
+	length = g_strv_length (server_list);
+	if (length)
+		g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS,
+			      TRUE, NULL);
+	for (i = 0; i < length; i++) {
+		g_strstrip (server_list[i]);
+		if (server_list[i][0] == '\0')
+			continue;
+		if (!inet_pton (AF_INET6, server_list[i], &tmp_ip6_addr)) {
+			if (is_ip6_address (server_list[i]))
+				PLUGIN_WARN (IFNET_PLUGIN_NAME,
+					     "ignored dns: %s\n",
+					     server_list[i]);
+			continue;
+		}
+		if (!IN6_IS_ADDR_UNSPECIFIED (&tmp_ip6_addr)
+		    && !nm_setting_ip6_config_add_dns (s_ip6, &tmp_ip6_addr))
+			PLUGIN_WARN (IFNET_PLUGIN_NAME,
+				     "warning: duplicate DNS server %s",
+				     server_list[i]);
+	}
+	g_strfreev (server_list);
+}
+
+gboolean
+is_managed (gchar * conn_name)
+{
+	gchar *config;
+
+	g_return_val_if_fail (conn_name != NULL, FALSE);
+	config = (gchar *) ifnet_get_data (conn_name, "managed");
+	if (!config)
+		return TRUE;
+	if (strcmp (config, "false") == 0)
+		return FALSE;
+	return TRUE;
+}
+
+void
+get_dhcp_hostname_and_client_id (char **hostname, char **client_id)
+{
+	gchar *dhcp_client = ifnet_get_global_setting ("main", "dhcp");
+	const gchar *dhcpcd_conf = "/etc/dhcpcd.conf";
+	const gchar *dhclient_conf = "/etc/dhcp/dhclient.conf";
+	gchar *line = NULL, *tmp = NULL, *contents = NULL;
+	gchar **all_lines;
+	guint line_num, i;
+
+	*hostname = NULL;
+	*client_id = NULL;
+	if (dhcp_client) {
+		if (!strcmp (dhcp_client, "dhclient"))
+			g_file_get_contents (dhclient_conf, &contents, NULL,
+					     NULL);
+		else if (!strcmp (dhcp_client, "dhcpcd"))
+			g_file_get_contents (dhcpcd_conf, &contents, NULL,
+					     NULL);
+	} else {
+		if (g_file_test (dhclient_conf, G_FILE_TEST_IS_REGULAR))
+			g_file_get_contents (dhclient_conf, &contents, NULL,
+					     NULL);
+		else if (g_file_test (dhcpcd_conf, G_FILE_TEST_IS_REGULAR))
+			g_file_get_contents (dhcpcd_conf, &contents, NULL,
+					     NULL);
+	}
+	if (!contents)
+		return;
+	all_lines = g_strsplit (contents, "\n", 0);
+	line_num = g_strv_length (all_lines);
+	for (i = 0; i < line_num; i++) {
+		line = all_lines[i];
+		// dhcpcd.conf
+		g_strstrip (line);
+		if (g_str_has_prefix (line, "hostname")) {
+			tmp = line + strlen ("hostname");
+			g_strstrip (tmp);
+			if (tmp[0] != '\0')
+				*hostname = g_strdup (tmp);
+			else
+				PLUGIN_PRINT (IFNET_PLUGIN_NAME,
+					      "dhcpcd hostname not defined, ignoring");
+		} else if (g_str_has_prefix (line, "clientid")) {
+			tmp = line + strlen ("clientid");
+			g_strstrip (tmp);
+			if (tmp[0] != '\0')
+				*client_id = g_strdup (tmp);
+			else
+				PLUGIN_PRINT (IFNET_PLUGIN_NAME,
+					      "dhcpcd clientid not defined, ignoring");
+		}
+		// dhclient.conf
+		else if ((tmp = strstr (line, "send host-name")) != NULL) {
+			tmp += strlen ("send host-name");
+			g_strstrip (tmp);
+			strip_string (tmp, '"');
+			strip_string (tmp, ';');
+			if (tmp[0] != '\0')
+				*hostname = g_strdup (tmp);
+			else
+				PLUGIN_PRINT (IFNET_PLUGIN_NAME,
+					      "dhclient hostname not defined, ignoring");
+		} else if ((tmp = strstr (line, "send dhcp-client-identifier"))
+			   != NULL) {
+			tmp += strlen ("send dhcp-client-identifier");
+			g_strstrip (tmp);
+			strip_string (tmp, ';');
+			if (tmp[0] != '\0')
+				*client_id = g_strdup (tmp);
+			else
+				PLUGIN_PRINT (IFNET_PLUGIN_NAME,
+					      "dhclient clientid not defined, ignoring");
+		}
+	}
+	g_strfreev (all_lines);
+	g_free (contents);
+}