Esempio n. 1
0
NMIP6Config *
nm_ip6_config_new_for_interface (int ifindex)
{
	NMIP6Config *ip6;
	GArray *addrs_array, *routes_array;
	NMPlatformIP6Address *addrs;
	NMPlatformIP6Route *routes;
	NMIP6Address *addr;
	NMIP6Route *route;
	int i;

	addrs_array = nm_platform_ip6_address_get_all (ifindex);
	if (addrs_array->len == 0) {
		g_array_unref (addrs_array);
		return NULL;
	}

	ip6 = nm_ip6_config_new ();

	addrs = (NMPlatformIP6Address *)addrs_array->data;
	for (i = 0; i < addrs_array->len; i++) {
		addr = nm_ip6_address_new ();
		nm_ip6_address_set_address (addr, &addrs[i].address);
		nm_ip6_address_set_prefix (addr, addrs[i].plen);
		nm_ip6_config_take_address (ip6, addr);
	}
	g_array_unref (addrs_array);

	routes_array = nm_platform_ip6_route_get_all (ifindex);
	routes = (NMPlatformIP6Route *)routes_array->data;
	for (i = 0; i < routes_array->len; i++) {
		/* Default route ignored; it's handled internally by NM and not
		* tracked in the device's IP config.
		*/
		if (routes[i].plen == 0)
			continue;

		route = nm_ip6_route_new ();
		nm_ip6_route_set_dest (route, &routes[i].network);
		nm_ip6_route_set_prefix (route, routes[i].plen);
		nm_ip6_route_set_next_hop (route, &routes[i].gateway);
		nm_ip6_route_set_metric (route, routes[i].metric);
		nm_ip6_config_take_route (ip6, route);
	}
	g_array_unref (routes_array);

	return ip6;
}
Esempio n. 2
0
static gboolean
demarshal_ip6_config (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field)
{
	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (object);
	const char *path;
	NMIP6Config *config = NULL;
	DBusGConnection *connection;

	if (!G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH))
		return FALSE;

	priv->null_ip6_config = FALSE;

	path = g_value_get_boxed (value);
	if (path) {
		if (!strcmp (path, "/"))
			priv->null_ip6_config = TRUE;
		else {
			config = NM_IP6_CONFIG (_nm_object_cache_get (path));
			if (config)
				config = g_object_ref (config);
			else {
				connection = nm_object_get_connection (object);
				config = NM_IP6_CONFIG (nm_ip6_config_new (connection, path));
			}
		}
	}

	if (priv->ip6_config) {
		g_object_unref (priv->ip6_config);
		priv->ip6_config = NULL;
	}

	if (config)
		priv->ip6_config = config;

	_nm_object_queue_notify (object, NM_DEVICE_IP6_CONFIG);
	return TRUE;
}
Esempio n. 3
0
static void
impl_ppp_manager_set_ip6_config (NMPPPManager *manager,
                                 GDBusMethodInvocation *context,
                                 GVariant *config_dict)
{
	NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager);
	NMIP6Config *config;
	NMPlatformIP6Address addr;
	struct in6_addr a;
	NMUtilsIPv6IfaceId iid = NM_UTILS_IPV6_IFACE_ID_INIT;

	_LOGI ("(IPv6 Config Get) reply received.");

	remove_timeout_handler (manager);

	config = nm_ip6_config_new (nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface));

	memset (&addr, 0, sizeof (addr));
	addr.plen = 64;

	if (iid_value_to_ll6_addr (config_dict, NM_PPP_IP6_CONFIG_PEER_IID, &a, NULL)) {
		nm_ip6_config_set_gateway (config, &a);
		addr.peer_address = a;
	}

	if (iid_value_to_ll6_addr (config_dict, NM_PPP_IP6_CONFIG_OUR_IID, &addr.address, &iid)) {
		nm_ip6_config_add_address (config, &addr);

		if (set_ip_config_common (manager, config_dict, NM_PPP_IP6_CONFIG_INTERFACE, NULL)) {
			/* Push the IPv6 config and interface identifier up to the device */
			g_signal_emit (manager, signals[IP6_CONFIG], 0, priv->ip_iface, &iid, config);
		}
	} else
		_LOGE ("invalid IPv6 address received!");

	g_object_unref (config);
	g_dbus_method_invocation_return_value (context, NULL);
}
Esempio n. 4
0
NMIP6Config *
nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex)
{
	NMIP6ManagerPrivate *priv;
	NMIP6Device *device;
	NMIP6Config *config;
	struct rtnl_addr *rtnladdr;
	struct nl_addr *nladdr;
	struct in6_addr *addr;
	NMIP6Address *ip6addr;
	struct rtnl_route *rtnlroute;
	struct nl_addr *nldest, *nlgateway;
	struct in6_addr *dest, *gateway;
	gboolean defgw_set = FALSE;
	struct in6_addr defgw;
	uint32_t metric;
	NMIP6Route *ip6route;
	int i;

	g_return_val_if_fail (NM_IS_IP6_MANAGER (manager), NULL);
	g_return_val_if_fail (ifindex > 0, NULL);

	priv = NM_IP6_MANAGER_GET_PRIVATE (manager);

	device = (NMIP6Device *) g_hash_table_lookup (priv->devices,
	                                              GINT_TO_POINTER (ifindex));
	if (!device) {
		nm_log_warn (LOGD_IP6, "(%d): addrconf not started.", ifindex);
		return NULL;
	}

	config = nm_ip6_config_new ();
	if (!config) {
		nm_log_err (LOGD_IP6, "(%s): out of memory creating IP6 config object.",
		            device->iface);
		return NULL;
	}

	/* Make sure we refill the route and address caches, otherwise we won't get
	 * up-to-date information here since the netlink route/addr change messages
	 * may be lagging a bit.
	 */
	nl_cache_refill (priv->nlh, priv->route_cache);
	nl_cache_refill (priv->nlh, priv->addr_cache);

	/* Add routes */
	for (rtnlroute = FIRST_ROUTE (priv->route_cache); rtnlroute; rtnlroute = NEXT_ROUTE (rtnlroute)) {
		/* Make sure it's an IPv6 route for this device */
		if (rtnl_route_get_oif (rtnlroute) != device->ifindex)
			continue;
		if (rtnl_route_get_family (rtnlroute) != AF_INET6)
			continue;

		nldest = rtnl_route_get_dst (rtnlroute);
		if (!nldest || nl_addr_get_family (nldest) != AF_INET6)
			continue;
		dest = nl_addr_get_binary_addr (nldest);

		nlgateway = rtnl_route_get_gateway (rtnlroute);
		if (!nlgateway || nl_addr_get_family (nlgateway) != AF_INET6)
			continue;
		gateway = nl_addr_get_binary_addr (nlgateway);

		if (rtnl_route_get_dst_len (rtnlroute) == 0) {
			/* Default gateway route; don't add to normal routes but to each address */
			if (!defgw_set) {
				memcpy (&defgw, gateway, sizeof (defgw));
				defgw_set = TRUE;
			}
			continue;
		}

		/* Also ignore link-local routes where the destination and gateway are
		 * the same, which apparently get added by the kernel but return -EINVAL
		 * when we try to add them via netlink.
		 */
		if (gateway && IN6_ARE_ADDR_EQUAL (dest, gateway))
			continue;

		ip6route = nm_ip6_route_new ();
		nm_ip6_route_set_dest (ip6route, dest);
		nm_ip6_route_set_prefix (ip6route, rtnl_route_get_dst_len (rtnlroute));
		nm_ip6_route_set_next_hop (ip6route, gateway);
		rtnl_route_get_metric(rtnlroute, 1, &metric);
		if (metric != UINT_MAX)
			nm_ip6_route_set_metric (ip6route, metric);
		nm_ip6_config_take_route (config, ip6route);
	}

	/* Add addresses */
	for (rtnladdr = FIRST_ADDR (priv->addr_cache); rtnladdr; rtnladdr = NEXT_ADDR (rtnladdr)) {
		if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex)
			continue;

		nladdr = rtnl_addr_get_local (rtnladdr);
		if (!nladdr || nl_addr_get_family (nladdr) != AF_INET6)
			continue;

		addr = nl_addr_get_binary_addr (nladdr);
		ip6addr = nm_ip6_address_new ();
		nm_ip6_address_set_prefix (ip6addr, rtnl_addr_get_prefixlen (rtnladdr));
		nm_ip6_address_set_address (ip6addr, addr);
		nm_ip6_config_take_address (config, ip6addr);
		if (defgw_set)
			nm_ip6_address_set_gateway (ip6addr, &defgw);
	}

	/* Add DNS servers */
	if (device->rdnss_servers) {
		NMIP6RDNSS *rdnss = (NMIP6RDNSS *)(device->rdnss_servers->data);

		for (i = 0; i < device->rdnss_servers->len; i++)
			nm_ip6_config_add_nameserver (config, &rdnss[i].addr);
	}

	/* Add DNS domains */
	if (device->dnssl_domains) {
		NMIP6DNSSL *dnssl = (NMIP6DNSSL *)(device->dnssl_domains->data);

		for (i = 0; i < device->dnssl_domains->len; i++)
			nm_ip6_config_add_domain (config, dnssl[i].domain);
	}

	return config;
}
static void
rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, gpointer user_data)
{
    static NMIP6Config *rdisc_config = NULL;
    NMIP6Config *existing;
    static int system_support = -1;
    guint32 ifa_flags = 0x00;
    int i;

    if (system_support == -1) {
        /*
         * Check, whether kernel is recent enough, to help user space handling RA.
         * If it's not supported, we have no ipv6-privacy and must add autoconf
         * addresses as /128.
         * The reason for the /128 is to prevent the kernel
         * from adding a prefix route for this address.
         **/
        system_support = nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET);
    }

    if (system_support)
        ifa_flags = IFA_F_NOPREFIXROUTE;
    if (global_opt.tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR
            || global_opt.tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR)
    {
        /* without system_support, this flag will be ignored. Still set it, doesn't seem to do any harm. */
        ifa_flags |= IFA_F_MANAGETEMPADDR;
    }

    existing = nm_ip6_config_capture (ifindex, FALSE, global_opt.tempaddr);
    if (rdisc_config)
        nm_ip6_config_subtract (existing, rdisc_config);
    else
        rdisc_config = nm_ip6_config_new (ifindex);

    if (changed & NM_RDISC_CONFIG_GATEWAYS) {
        /* Use the first gateway as ordered in router discovery cache. */
        if (rdisc->gateways->len) {
            NMRDiscGateway *gateway = &g_array_index (rdisc->gateways, NMRDiscGateway, 0);

            nm_ip6_config_set_gateway (rdisc_config, &gateway->address);
        } else
            nm_ip6_config_set_gateway (rdisc_config, NULL);
    }

    if (changed & NM_RDISC_CONFIG_ADDRESSES) {
        /* Rebuild address list from router discovery cache. */
        nm_ip6_config_reset_addresses (rdisc_config);

        /* rdisc->addresses contains at most max_addresses entries.
         * This is different from what the kernel does, which
         * also counts static and temporary addresses when checking
         * max_addresses.
         **/
        for (i = 0; i < rdisc->addresses->len; i++) {
            NMRDiscAddress *discovered_address = &g_array_index (rdisc->addresses, NMRDiscAddress, i);
            NMPlatformIP6Address address;

            memset (&address, 0, sizeof (address));
            address.address = discovered_address->address;
            address.plen = system_support ? 64 : 128;
            address.timestamp = discovered_address->timestamp;
            address.lifetime = discovered_address->lifetime;
            address.preferred = discovered_address->preferred;
            if (address.preferred > address.lifetime)
                address.preferred = address.lifetime;
            address.source = NM_IP_CONFIG_SOURCE_RDISC;
            address.n_ifa_flags = ifa_flags;

            nm_ip6_config_add_address (rdisc_config, &address);
        }
    }

    if (changed & NM_RDISC_CONFIG_ROUTES) {
        /* Rebuild route list from router discovery cache. */
        nm_ip6_config_reset_routes (rdisc_config);

        for (i = 0; i < rdisc->routes->len; i++) {
            NMRDiscRoute *discovered_route = &g_array_index (rdisc->routes, NMRDiscRoute, i);
            NMPlatformIP6Route route;

            /* Only accept non-default routes.  The router has no idea what the
             * local configuration or user preferences are, so sending routes
             * with a prefix length of 0 is quite rude and thus ignored.
             */
            if (   discovered_route->plen > 0
                    && discovered_route->plen <= 128) {
                memset (&route, 0, sizeof (route));
                route.network = discovered_route->network;
                route.plen = discovered_route->plen;
                route.gateway = discovered_route->gateway;
                route.source = NM_IP_CONFIG_SOURCE_RDISC;
                route.metric = global_opt.priority_v6;

                nm_ip6_config_add_route (rdisc_config, &route);
            }
        }
    }

    if (changed & NM_RDISC_CONFIG_DHCP_LEVEL) {
        /* Unsupported until systemd DHCPv6 is ready */
    }

    if (changed & NM_RDISC_CONFIG_HOP_LIMIT)
        nm_platform_sysctl_set_ip6_hop_limit_safe (NM_PLATFORM_GET, global_opt.ifname, rdisc->hop_limit);

    if (changed & NM_RDISC_CONFIG_MTU) {
        char val[16];

        g_snprintf (val, sizeof (val), "%d", rdisc->mtu);
        nm_platform_sysctl_set (NM_PLATFORM_GET, nm_utils_ip6_property_path (global_opt.ifname, "mtu"), val);
    }

    nm_ip6_config_merge (existing, rdisc_config, NM_IP_CONFIG_MERGE_DEFAULT);
    if (!nm_ip6_config_commit (existing, ifindex, TRUE))
        nm_log_warn (LOGD_IP6, "(%s): failed to apply IPv6 config", global_opt.ifname);
}
static NMIP6Config *
lease_to_ip6_config (const char *iface,
                     int ifindex,
                     sd_dhcp6_lease *lease,
                     GHashTable *options,
                     gboolean log_lease,
                     gboolean info_only,
                     GError **error)
{
	struct in6_addr tmp_addr, *dns;
	uint32_t lft_pref, lft_valid;
	NMIP6Config *ip6_config;
	const char *addr_str;
	char **domains;
	GString *str;
	int num, i;
	gint32 ts;

	g_return_val_if_fail (lease, NULL);
	ip6_config = nm_ip6_config_new (ifindex);
	ts = nm_utils_get_monotonic_timestamp_s ();
	str = g_string_sized_new (30);

	/* Addresses */
	sd_dhcp6_lease_reset_address_iter (lease);
	while (sd_dhcp6_lease_get_address (lease, &tmp_addr, &lft_pref, &lft_valid) >= 0) {
		NMPlatformIP6Address address = {
			.plen = 128,
			.address = tmp_addr,
			.timestamp = ts,
			.lifetime = lft_valid,
			.preferred = lft_pref,
			.addr_source = NM_IP_CONFIG_SOURCE_DHCP,
		};

		nm_ip6_config_add_address (ip6_config, &address);

		addr_str = nm_utils_inet6_ntop (&tmp_addr, NULL);
		g_string_append_printf (str, "%s%s", str->len ? " " : "", addr_str);

		LOG_LEASE (LOGD_DHCP6,
		           "  address %s",
		           nm_platform_ip6_address_to_string (&address, NULL, 0));
	};

	if (str->len) {
		add_option (options, dhcp6_requests, DHCP6_OPTION_IP_ADDRESS, str->str);
		g_string_set_size (str , 0);
	}

	if (!info_only && nm_ip6_config_get_num_addresses (ip6_config) == 0) {
		g_string_free (str, TRUE);
		g_object_unref (ip6_config);
		g_set_error_literal (error,
		                     NM_MANAGER_ERROR,
		                     NM_MANAGER_ERROR_FAILED,
		                     "no address received in managed mode");
		return NULL;
	}

	/* DNS servers */
	num = sd_dhcp6_lease_get_dns (lease, &dns);
	if (num > 0) {
		for (i = 0; i < num; i++) {
			nm_ip6_config_add_nameserver (ip6_config, &dns[i]);
			addr_str = nm_utils_inet6_ntop (&dns[i], NULL);
			g_string_append_printf (str, "%s%s", str->len ? " " : "", addr_str);
			LOG_LEASE (LOGD_DHCP6, "  nameserver %s", addr_str);
		}
		add_option (options, dhcp6_requests, SD_DHCP6_OPTION_DNS_SERVERS, str->str);
		g_string_set_size (str, 0);
	}

	/* Search domains */
	num = sd_dhcp6_lease_get_domains (lease, &domains);
	if (num > 0) {
		for (i = 0; i < num; i++) {
			nm_ip6_config_add_search (ip6_config, domains[i]);
			g_string_append_printf (str, "%s%s", str->len ? " " : "", domains[i]);
			LOG_LEASE (LOGD_DHCP6, "  domain name '%s'", domains[i]);
		}
		add_option (options, dhcp6_requests, SD_DHCP6_OPTION_DOMAIN_LIST, str->str);
		g_string_set_size (str, 0);
	}

	g_string_free (str, TRUE);

	return ip6_config;
}

static void
bound6_handle (NMDhcpSystemd *self)
{
	NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self);
	const char *iface = nm_dhcp_client_get_iface (NM_DHCP_CLIENT (self));
	gs_unref_object NMIP6Config *ip6_config = NULL;
	gs_unref_hashtable GHashTable *options = NULL;
	gs_free_error GError *error = NULL;
	sd_dhcp6_lease *lease;
	int r;

	r = sd_dhcp6_client_get_lease (priv->client6, &lease);
	if (r < 0 || !lease) {
		_LOGW (" no lease!");
		nm_dhcp_client_set_state (NM_DHCP_CLIENT (self), NM_DHCP_STATE_FAIL, NULL, NULL);
		return;
	}

	_LOGD ("lease available");

	options = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
	ip6_config = lease_to_ip6_config (iface,
	                                  nm_dhcp_client_get_ifindex (NM_DHCP_CLIENT (self)),
	                                  lease,
	                                  options,
	                                  TRUE,
	                                  priv->info_only,
	                                  &error);

	if (ip6_config) {
		nm_dhcp_client_set_state (NM_DHCP_CLIENT (self),
		                          NM_DHCP_STATE_BOUND,
		                          G_OBJECT (ip6_config),
		                          options);
	} else {
		_LOGW ("%s", error->message);
		nm_dhcp_client_set_state (NM_DHCP_CLIENT (self), NM_DHCP_STATE_FAIL, NULL, NULL);
	}
}
Esempio n. 7
0
NMIP6Config *
nm_dhcp_utils_ip6_config_from_options (int ifindex,
                                       const char *iface,
                                       GHashTable *options,
                                       guint32 priority,
                                       gboolean info_only)
{
	NMIP6Config *ip6_config = NULL;
	struct in6_addr tmp_addr;
	NMPlatformIP6Address address;
	char *str = NULL;
	GHashTableIter iter;
	gpointer key, value;

	g_return_val_if_fail (options != NULL, NULL);

	memset (&address, 0, sizeof (address));
	address.plen = 128;
	address.timestamp = nm_utils_get_monotonic_timestamp_s ();

	g_hash_table_iter_init (&iter, options);
	while (g_hash_table_iter_next (&iter, &key, &value)) {
		nm_log_dbg (LOGD_DHCP6, "(%s): option '%s'=>'%s'",
		            iface, (const char *) key, (const char *) value);
	}

	ip6_config = nm_ip6_config_new (ifindex);

	str = g_hash_table_lookup (options, "max_life");
	if (str) {
		address.lifetime = strtoul (str, NULL, 10);
		nm_log_info (LOGD_DHCP6, "  valid_lft %u", address.lifetime);
	}

	str = g_hash_table_lookup (options, "preferred_life");
	if (str) {
		address.preferred = strtoul (str, NULL, 10);
		nm_log_info (LOGD_DHCP6, "  preferred_lft %u", address.preferred);
	}

	str = g_hash_table_lookup (options, "ip6_address");
	if (str) {
		if (!inet_pton (AF_INET6, str, &tmp_addr)) {
			nm_log_warn (LOGD_DHCP6, "(%s): DHCP returned invalid address '%s'",
			             iface, str);
			goto error;
		}

		address.address = tmp_addr;
		address.source = NM_IP_CONFIG_SOURCE_DHCP;
		nm_ip6_config_add_address (ip6_config, &address);
		nm_log_info (LOGD_DHCP6, "  address %s", str);
	} else if (info_only == FALSE) {
		/* No address in Managed mode is a hard error */
		goto error;
	}

	str = g_hash_table_lookup (options, "host_name");
	if (str)
		nm_log_info (LOGD_DHCP6, "  hostname '%s'", str);

	str = g_hash_table_lookup (options, "dhcp6_name_servers");
	if (str) {
		char **dns = g_strsplit (str, " ", 0);
		char **s;

		for (s = dns; *s; s++) {
			if (inet_pton (AF_INET6, *s, &tmp_addr) > 0) {
				if (!IN6_IS_ADDR_UNSPECIFIED (&tmp_addr)) {
					nm_ip6_config_add_nameserver (ip6_config, &tmp_addr);
					nm_log_info (LOGD_DHCP6, "  nameserver '%s'", *s);
				}
			} else
				nm_log_warn (LOGD_DHCP6, "ignoring invalid nameserver '%s'", *s);
		}
		g_strfreev (dns);
	}

	str = g_hash_table_lookup (options, "dhcp6_domain_search");
	if (str)
		process_domain_search (str, ip6_add_domain_search, ip6_config);

	return ip6_config;

error:
	g_object_unref (ip6_config);
	return NULL;
}
/* Given a table of DHCP options from the client, convert into an IP6Config */
static NMIP6Config *
ip6_options_to_config (NMDHCPClient *self)
{
	NMDHCPClientPrivate *priv;
	NMIP6Config *ip6_config = NULL;
	struct in6_addr tmp_addr;
	NMIP6Address *addr = NULL;
	char *str = NULL;
	GHashTableIter iter;
	gpointer key, value;

	g_return_val_if_fail (self != NULL, NULL);
	g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL);

	priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
	g_return_val_if_fail (priv->options != NULL, NULL);

	g_hash_table_iter_init (&iter, priv->options);
	while (g_hash_table_iter_next (&iter, &key, &value)) {
		nm_log_dbg (LOGD_DHCP6, "(%s): option '%s'=>'%s'",
		            priv->iface, (const char *) key, (const char *) value);
	}

	ip6_config = nm_ip6_config_new ();
	if (!ip6_config) {
		nm_log_warn (LOGD_DHCP6, "(%s): couldn't allocate memory for an IP6Config!", priv->iface);
		return NULL;
	}

	str = g_hash_table_lookup (priv->options, "new_ip6_address");
	if (str) {
		if (!inet_pton (AF_INET6, str, &tmp_addr)) {
			nm_log_warn (LOGD_DHCP6, "(%s): DHCP returned invalid address '%s'",
			             priv->iface, str);
			goto error;
		}

		addr = nm_ip6_address_new ();
		g_assert (addr);
		nm_ip6_address_set_address (addr, &tmp_addr);
		/* DHCPv6 IA_NA assignments are single address only */
		nm_ip6_address_set_prefix (addr, 128);
		nm_log_info (LOGD_DHCP6, "  address %s/128", str);

		nm_ip6_config_take_address (ip6_config, addr);
	} else if (priv->info_only == FALSE) {
		/* No address in Managed mode is a hard error */
		goto error;
	}

	str = g_hash_table_lookup (priv->options, "new_host_name");
	if (str)
		nm_log_info (LOGD_DHCP6, "  hostname '%s'", str);

	str = g_hash_table_lookup (priv->options, "new_dhcp6_name_servers");
	if (str) {
		char **searches = g_strsplit (str, " ", 0);
		char **s;

		for (s = searches; *s; s++) {
			if (inet_pton (AF_INET6, *s, &tmp_addr) > 0) {
				nm_ip6_config_add_nameserver (ip6_config, &tmp_addr);
				nm_log_info (LOGD_DHCP6, "  nameserver '%s'", *s);
			} else
				nm_log_warn (LOGD_DHCP6, "ignoring invalid nameserver '%s'", *s);
		}
		g_strfreev (searches);
	}

	str = g_hash_table_lookup (priv->options, "new_dhcp6_domain_search");
	if (str)
		process_domain_search (str, ip6_add_domain_search, ip6_config);

	return ip6_config;

error:
	g_object_unref (ip6_config);
	return NULL;
}
Esempio n. 9
0
/* Given a table of DHCP options from the client, convert into an IP6Config */
static NMIP6Config *
ip6_options_to_config (NMDHCPClient *self)
{
	NMDHCPClientPrivate *priv;
	NMIP6Config *ip6_config = NULL;
	struct in6_addr tmp_addr;
	NMIP6Address *addr = NULL;
	char *str = NULL;
	GHashTableIter iter;
	gpointer key, value;

	g_return_val_if_fail (self != NULL, NULL);
	g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL);

	priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
	g_return_val_if_fail (priv->options != NULL, NULL);

	g_hash_table_iter_init (&iter, priv->options);
	while (g_hash_table_iter_next (&iter, &key, &value)) {
		nm_log_dbg (LOGD_DHCP6, "(%s): option '%s'=>'%s'",
		            priv->iface, (const char *) key, (const char *) value);
	}

	ip6_config = nm_ip6_config_new ();
	if (!ip6_config) {
		nm_log_warn (LOGD_DHCP6, "(%s): couldn't allocate memory for an IP6Config!", priv->iface);
		return NULL;
	}

	addr = nm_ip6_address_new ();
	if (!addr) {
		nm_log_warn (LOGD_DHCP6, "(%s): couldn't allocate memory for an IP6 Address!", priv->iface);
		goto error;
	}

	str = g_hash_table_lookup (priv->options, "new_ip6_address");
	if (str) {
		if (!inet_pton (AF_INET6, str, &tmp_addr)) {
			nm_log_warn (LOGD_DHCP6, "(%s): DHCP returned invalid address '%s'",
			             priv->iface);
			goto error;
		}

		nm_ip6_address_set_address (addr, &tmp_addr);
		nm_log_info (LOGD_DHCP6, "  address %s", str);
	} else {
		/* No address in managed mode is a hard error */
		if (priv->info_only == FALSE)
			goto error;

		/* But "info-only" setups don't necessarily need an address */
		nm_ip6_address_unref (addr);
		addr = NULL;
	}

	/* Only care about prefix if we got an address */
	if (addr) {
		str = g_hash_table_lookup (priv->options, "new_ip6_prefixlen");
		if (str) {
			long unsigned int prefix;

			errno = 0;
			prefix = strtoul (str, NULL, 10);
			if (errno != 0 || prefix > 128)
				goto error;

			nm_ip6_address_set_prefix (addr, (guint32) prefix);
			nm_log_info (LOGD_DHCP6, "  prefix %lu", prefix);
		}

		nm_ip6_config_take_address (ip6_config, addr);
		addr = NULL;
	}

	str = g_hash_table_lookup (priv->options, "new_host_name");
	if (str)
		nm_log_info (LOGD_DHCP6, "  hostname '%s'", str);

	str = g_hash_table_lookup (priv->options, "new_dhcp6_name_servers");
	if (str) {
		char **searches = g_strsplit (str, " ", 0);
		char **s;

		for (s = searches; *s; s++) {
			if (inet_pton (AF_INET6, *s, &tmp_addr) > 0) {
				nm_ip6_config_add_nameserver (ip6_config, &tmp_addr);
				nm_log_info (LOGD_DHCP6, "  nameserver '%s'", *s);
			} else
				nm_log_warn (LOGD_DHCP6, "ignoring invalid nameserver '%s'", *s);
		}
		g_strfreev (searches);
	}

	str = g_hash_table_lookup (priv->options, "new_dhcp6_domain_search");
	if (str)
		process_domain_search (str, ip6_add_domain_search, ip6_config);

	return ip6_config;

error:
	if (addr)
		nm_ip6_address_unref (addr);
	g_object_unref (ip6_config);
	return NULL;
}