static void
real_ip4_config_pre_commit (NMDevice *self, NMIP4Config *config)
{
	NMConnection *connection;
	NMSettingInfiniband *s_infiniband;
	guint32 mtu;

	connection = nm_device_get_connection (self);
	g_assert (connection);
	s_infiniband = nm_connection_get_setting_infiniband (connection);
	g_assert (s_infiniband);

	/* MTU override */
	mtu = nm_setting_infiniband_get_mtu (s_infiniband);
	if (mtu)
		nm_ip4_config_set_mtu (config, mtu);
}
Example #2
0
static void
ip4_config_pre_commit (NMDevice *device, NMIP4Config *config)
{
	NMConnection *connection;
	NMSettingWired *s_wired;
	guint32 mtu;

	connection = nm_device_get_applied_connection (device);
	g_assert (connection);

	s_wired = nm_connection_get_setting_wired (connection);
	if (s_wired) {
		mtu = nm_setting_wired_get_mtu (s_wired);
		if (mtu)
			nm_ip4_config_set_mtu (config, mtu, NM_IP_CONFIG_SOURCE_USER);
	}
}
static void
ip4_config_pre_commit (NMDevice *device, NMIP4Config *config)
{
	NMConnection *connection;
	NMSettingIPTunnel *s_ip_tunnel;
	guint32 mtu;

	connection = nm_device_get_applied_connection (device);
	g_assert (connection);
	s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection);
	g_assert (s_ip_tunnel);

	/* MTU override */
	mtu = nm_setting_ip_tunnel_get_mtu (s_ip_tunnel);
	if (mtu)
		nm_ip4_config_set_mtu (config, mtu, NM_IP_CONFIG_SOURCE_USER);
}
static NMIP4Config *
lease_to_ip4_config (const char *iface,
                     int ifindex,
                     sd_dhcp_lease *lease,
                     GHashTable *options,
                     guint32 default_priority,
                     gboolean log_lease,
                     GError **error)
{
	NMIP4Config *ip4_config = NULL;
	struct in_addr tmp_addr;
	const struct in_addr *addr_list;
	char buf[INET_ADDRSTRLEN];
	const char *str;
	guint32 lifetime = 0, i;
	NMPlatformIP4Address address;
	GString *l;
	gs_free sd_dhcp_route **routes = NULL;
	guint16 mtu;
	int r, num;
	guint64 end_time;
	const void *data;
	gsize data_len;
	gboolean metered = FALSE;
	gboolean static_default_gateway = FALSE;

	g_return_val_if_fail (lease != NULL, NULL);

	ip4_config = nm_ip4_config_new (ifindex);

	/* Address */
	sd_dhcp_lease_get_address (lease, &tmp_addr);
	memset (&address, 0, sizeof (address));
	address.address = tmp_addr.s_addr;
	address.peer_address = tmp_addr.s_addr;
	str = nm_utils_inet4_ntop (tmp_addr.s_addr, NULL);
	LOG_LEASE (LOGD_DHCP4, "  address %s", str);
	add_option (options, dhcp4_requests, DHCP_OPTION_IP_ADDRESS, str);

	/* Prefix/netmask */
	sd_dhcp_lease_get_netmask (lease, &tmp_addr);
	address.plen = nm_utils_ip4_netmask_to_prefix (tmp_addr.s_addr);
	LOG_LEASE (LOGD_DHCP4, "  plen %d", address.plen);
	add_option (options,
	            dhcp4_requests,
	            SD_DHCP_OPTION_SUBNET_MASK,
	            nm_utils_inet4_ntop (tmp_addr.s_addr, NULL));

	/* Lease time */
	sd_dhcp_lease_get_lifetime (lease, &lifetime);
	address.timestamp = nm_utils_get_monotonic_timestamp_s ();
	address.lifetime = address.preferred = lifetime;
	end_time = (guint64) time (NULL) + lifetime;
	LOG_LEASE (LOGD_DHCP4, "  expires in %" G_GUINT32_FORMAT " seconds", lifetime);
	add_option_u64 (options,
	                dhcp4_requests,
	                SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME,
	                end_time);

	address.addr_source = NM_IP_CONFIG_SOURCE_DHCP;
	nm_ip4_config_add_address (ip4_config, &address);

	/* DNS Servers */
	num = sd_dhcp_lease_get_dns (lease, &addr_list);
	if (num > 0) {
		l = g_string_sized_new (30);
		for (i = 0; i < num; i++) {
			if (addr_list[i].s_addr) {
				nm_ip4_config_add_nameserver (ip4_config, addr_list[i].s_addr);
				str = nm_utils_inet4_ntop (addr_list[i].s_addr, NULL);
				LOG_LEASE (LOGD_DHCP4, "  nameserver '%s'", str);
				g_string_append_printf (l, "%s%s", l->len ? " " : "", str);
			}
		}
		if (l->len)
			add_option (options, dhcp4_requests, SD_DHCP_OPTION_DOMAIN_NAME_SERVER, l->str);
		g_string_free (l, TRUE);
	}

	/* Domain Name */
	r = sd_dhcp_lease_get_domainname (lease, &str);
	if (r == 0) {
		/* Multiple domains sometimes stuffed into option 15 "Domain Name".
		 * As systemd escapes such characters, split them at \\032. */
		char **domains = g_strsplit (str, "\\032", 0);
		char **s;

		for (s = domains; *s; s++) {
			LOG_LEASE (LOGD_DHCP4, "  domain name '%s'", *s);
			nm_ip4_config_add_domain (ip4_config, *s);
		}
		g_strfreev (domains);
		add_option (options, dhcp4_requests, SD_DHCP_OPTION_DOMAIN_NAME, str);
	}

	/* Hostname */
	r = sd_dhcp_lease_get_hostname (lease, &str);
	if (r == 0) {
		LOG_LEASE (LOGD_DHCP4, "  hostname '%s'", str);
		add_option (options, dhcp4_requests, SD_DHCP_OPTION_HOST_NAME, str);
	}

	/* Routes */
	num = sd_dhcp_lease_get_routes (lease, &routes);
	if (num > 0) {
		l = g_string_sized_new (30);
		for (i = 0; i < num; i++) {
			NMPlatformIP4Route route = { 0 };
			const char *gw_str;
			guint8 plen;
			struct in_addr a;

			if (sd_dhcp_route_get_destination (routes[i], &a) < 0)
				continue;
			route.network = a.s_addr;

			if (   sd_dhcp_route_get_destination_prefix_length (routes[i], &plen) < 0
			    || plen > 32)
				continue;
			route.plen = plen;

			if (sd_dhcp_route_get_gateway (routes[i], &a) < 0)
				continue;
			route.gateway = a.s_addr;

			if (route.plen) {
				route.rt_source = NM_IP_CONFIG_SOURCE_DHCP;
				route.metric = default_priority;
				nm_ip4_config_add_route (ip4_config, &route);

				str = nm_utils_inet4_ntop (route.network, buf);
				gw_str = nm_utils_inet4_ntop (route.gateway, NULL);
				LOG_LEASE (LOGD_DHCP4, "  static route %s/%d gw %s", str, route.plen, gw_str);

				g_string_append_printf (l, "%s%s/%d %s", l->len ? " " : "", str, route.plen, gw_str);
			} else {
				if (!static_default_gateway) {
					static_default_gateway = TRUE;
					nm_ip4_config_set_gateway (ip4_config, route.gateway);

					str = nm_utils_inet4_ntop (route.gateway, NULL);
					LOG_LEASE (LOGD_DHCP4, "  gateway %s", str);
					add_option (options, dhcp4_requests, SD_DHCP_OPTION_ROUTER, str);
				}
			}
		}
		if (l->len)
			add_option (options, dhcp4_requests, SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE, l->str);
		g_string_free (l, TRUE);
	}

	/* If the DHCP server returns both a Classless Static Routes option and a
	 * Router option, the DHCP client MUST ignore the Router option [RFC 3442].
	 * Be more lenient and ignore the Router option only if Classless Static
	 * Routes contain a default gateway (as other DHCP backends do).
	 */
	/* Gateway */
	if (!static_default_gateway) {
		r = sd_dhcp_lease_get_router (lease, &tmp_addr);
		if (r == 0) {
			nm_ip4_config_set_gateway (ip4_config, tmp_addr.s_addr);
			str = nm_utils_inet4_ntop (tmp_addr.s_addr, NULL);
			LOG_LEASE (LOGD_DHCP4, "  gateway %s", str);
			add_option (options, dhcp4_requests, SD_DHCP_OPTION_ROUTER, str);
		}
	}

	/* MTU */
	r = sd_dhcp_lease_get_mtu (lease, &mtu);
	if (r == 0 && mtu) {
		nm_ip4_config_set_mtu (ip4_config, mtu, NM_IP_CONFIG_SOURCE_DHCP);
		add_option_u32 (options, dhcp4_requests, SD_DHCP_OPTION_INTERFACE_MTU, mtu);
		LOG_LEASE (LOGD_DHCP4, "  mtu %u", mtu);
	}

	/* NTP servers */
	num = sd_dhcp_lease_get_ntp (lease, &addr_list);
	if (num > 0) {
		l = g_string_sized_new (30);
		for (i = 0; i < num; i++) {
			str = nm_utils_inet4_ntop (addr_list[i].s_addr, buf);
			LOG_LEASE (LOGD_DHCP4, "  ntp server '%s'", str);
			g_string_append_printf (l, "%s%s", l->len ? " " : "", str);
		}
		add_option (options, dhcp4_requests, SD_DHCP_OPTION_NTP_SERVER, l->str);
		g_string_free (l, TRUE);
	}

	r = sd_dhcp_lease_get_vendor_specific (lease, &data, &data_len);
	if (r >= 0)
		metered = !!memmem (data, data_len, "ANDROID_METERED", NM_STRLEN ("ANDROID_METERED"));
	nm_ip4_config_set_metered (ip4_config, metered);

	return ip4_config;
}
NMIP4Config *
nm_dhcp_utils_ip4_config_from_options (int ifindex,
                                       const char *iface,
                                       GHashTable *options,
                                       guint32 priority)
{
	NMIP4Config *ip4_config = NULL;
	guint32 tmp_addr;
	in_addr_t addr;
	NMPlatformIP4Address address;
	char *str = NULL;
	guint32 gwaddr = 0;
	guint8 plen = 0;

	g_return_val_if_fail (options != NULL, NULL);

	ip4_config = nm_ip4_config_new (ifindex);
	memset (&address, 0, sizeof (address));
	address.timestamp = nm_utils_get_monotonic_timestamp_s ();

	str = g_hash_table_lookup (options, "ip_address");
	if (str && (inet_pton (AF_INET, str, &addr) > 0))
		nm_log_info (LOGD_DHCP4, "  address %s", str);
	else
		goto error;

	str = g_hash_table_lookup (options, "subnet_mask");
	if (str && (inet_pton (AF_INET, str, &tmp_addr) > 0)) {
		plen = nm_utils_ip4_netmask_to_prefix (tmp_addr);
		nm_log_info (LOGD_DHCP4, "  plen %d (%s)", plen, str);
	} else {
		/* Get default netmask for the IP according to appropriate class. */
		plen = nm_utils_ip4_get_default_prefix (addr);
		nm_log_info (LOGD_DHCP4, "  plen %d (default)", plen);
	}
	nm_platform_ip4_address_set_addr (&address, addr, plen);

	/* Routes: if the server returns classless static routes, we MUST ignore
	 * the 'static_routes' option.
	 */
	if (!ip4_process_classless_routes (options, priority, ip4_config, &gwaddr))
		process_classful_routes (options, priority, ip4_config);

	if (gwaddr) {
		nm_log_info (LOGD_DHCP4, "  gateway %s", nm_utils_inet4_ntop (gwaddr, NULL));
		nm_ip4_config_set_gateway (ip4_config, gwaddr);
	} else {
		/* If the gateway wasn't provided as a classless static route with a
		 * subnet length of 0, try to find it using the old-style 'routers' option.
		 */
		str = g_hash_table_lookup (options, "routers");
		if (str) {
			char **routers = g_strsplit (str, " ", 0);
			char **s;

			for (s = routers; *s; s++) {
				/* FIXME: how to handle multiple routers? */
				if (inet_pton (AF_INET, *s, &gwaddr) > 0) {
					nm_ip4_config_set_gateway (ip4_config, gwaddr);
					nm_log_info (LOGD_DHCP4, "  gateway %s", *s);
					break;
				} else
					nm_log_warn (LOGD_DHCP4, "ignoring invalid gateway '%s'", *s);
			}
			g_strfreev (routers);
		}
	}

	/*
	 * RFC 2132, section 9.7
	 *   DHCP clients use the contents of the 'server identifier' field
	 *   as the destination address for any DHCP messages unicast to
	 *   the DHCP server.
	 *
	 * Some ISP's provide leases from central servers that are on
	 * different subnets that the address offered.  If the host
	 * does not configure the interface as the default route, the
	 * dhcp server may not be reachable via unicast, and a host
	 * specific route is needed.
	 **/
	str = g_hash_table_lookup (options, "dhcp_server_identifier");
	if (str) {
		if (inet_pton (AF_INET, str, &tmp_addr) > 0) {

			nm_log_info (LOGD_DHCP4, "  server identifier %s", str);
			if (   nm_utils_ip4_address_clear_host_address(tmp_addr, address.plen) != nm_utils_ip4_address_clear_host_address(address.address, address.plen)
			    && !nm_ip4_config_get_direct_route_for_host (ip4_config, tmp_addr)) {
				/* DHCP server not on assigned subnet and the no direct route was returned. Add route */
				NMPlatformIP4Route route = { 0 };

				route.network = tmp_addr;
				route.plen = 32;
				/* this will be a device route if gwaddr is 0 */
				route.gateway = gwaddr;
				route.source = NM_IP_CONFIG_SOURCE_DHCP;
				route.metric = priority;
				nm_ip4_config_add_route (ip4_config, &route);
				nm_log_dbg (LOGD_IP, "adding route for server identifier: %s",
				                      nm_platform_ip4_route_to_string (&route, NULL, 0));
			}
		}
		else
			nm_log_warn (LOGD_DHCP4, "ignoring invalid server identifier '%s'", str);
	}

	str = g_hash_table_lookup (options, "dhcp_lease_time");
	if (str) {
		address.lifetime = address.preferred = strtoul (str, NULL, 10);
		nm_log_info (LOGD_DHCP4, "  lease time %u", address.lifetime);
	}

	address.source = NM_IP_CONFIG_SOURCE_DHCP;
	nm_ip4_config_add_address (ip4_config, &address);

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

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

		for (s = dns; *s; s++) {
			if (inet_pton (AF_INET, *s, &tmp_addr) > 0) {
				if (tmp_addr) {
					nm_ip4_config_add_nameserver (ip4_config, tmp_addr);
					nm_log_info (LOGD_DHCP4, "  nameserver '%s'", *s);
				}
			} else
				nm_log_warn (LOGD_DHCP4, "ignoring invalid nameserver '%s'", *s);
		}
		g_strfreev (dns);
	}

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

		for (s = domains; *s; s++) {
			nm_log_info (LOGD_DHCP4, "  domain name '%s'", *s);
			nm_ip4_config_add_domain (ip4_config, *s);
		}
		g_strfreev (domains);
	}

	str = g_hash_table_lookup (options, "domain_search");
	if (str)
		process_domain_search (str, ip4_add_domain_search, ip4_config);

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

		for (s = nbns; *s; s++) {
			if (inet_pton (AF_INET, *s, &tmp_addr) > 0) {
				if (tmp_addr) {
					nm_ip4_config_add_wins (ip4_config, tmp_addr);
					nm_log_info (LOGD_DHCP4, "  wins '%s'", *s);
				}
			} else
				nm_log_warn (LOGD_DHCP4, "ignoring invalid WINS server '%s'", *s);
		}
		g_strfreev (nbns);
	}

	str = g_hash_table_lookup (options, "interface_mtu");
	if (str) {
		int int_mtu;

		errno = 0;
		int_mtu = strtol (str, NULL, 10);
		if ((errno == EINVAL) || (errno == ERANGE))
			goto error;

		if (int_mtu > 576)
			nm_ip4_config_set_mtu (ip4_config, int_mtu, NM_IP_CONFIG_SOURCE_DHCP);
	}

	str = g_hash_table_lookup (options, "nis_domain");
	if (str) {
		nm_log_info (LOGD_DHCP4, "  NIS domain '%s'", str);
		nm_ip4_config_set_nis_domain (ip4_config, str);
	}

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

		for (s = nis; *s; s++) {
			if (inet_pton (AF_INET, *s, &tmp_addr) > 0) {
				if (tmp_addr) {
					nm_ip4_config_add_nis_server (ip4_config, tmp_addr);
					nm_log_info (LOGD_DHCP4, "  nis '%s'", *s);
				}
			} else
				nm_log_warn (LOGD_DHCP4, "ignoring invalid NIS server '%s'", *s);
		}
		g_strfreev (nis);
	}

	str = g_hash_table_lookup (options, "vendor_encapsulated_options");
	nm_ip4_config_set_metered (ip4_config, str && strstr (str, "ANDROID_METERED"));

	return ip4_config;

error:
	g_object_unref (ip4_config);
	return NULL;
}
static void
impl_ppp_manager_set_ip4_config (NMPPPManager *manager,
                                 GDBusMethodInvocation *context,
                                 GVariant *config_dict)
{
	NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager);
	NMIP4Config *config;
	NMPlatformIP4Address address;
	guint32 u32;
	GVariantIter *iter;

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

	remove_timeout_handler (manager);

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

	memset (&address, 0, sizeof (address));
	address.plen = 32;

	if (g_variant_lookup (config_dict, NM_PPP_IP4_CONFIG_ADDRESS, "u", &u32))
		address.address = u32;

	if (g_variant_lookup (config_dict, NM_PPP_IP4_CONFIG_GATEWAY, "u", &u32)) {
		nm_ip4_config_set_gateway (config, u32);
		address.peer_address = u32;
	} else
		address.peer_address = address.address;

	if (g_variant_lookup (config_dict, NM_PPP_IP4_CONFIG_PREFIX, "u", &u32))
		address.plen = u32;

	if (address.address && address.plen) {
		address.source = NM_IP_CONFIG_SOURCE_PPP;
		nm_ip4_config_add_address (config, &address);
	} else {
		_LOGE ("invalid IPv4 address received!");
		goto out;
	}

	if (g_variant_lookup (config_dict, NM_PPP_IP4_CONFIG_DNS, "au", &iter)) {
		while (g_variant_iter_next (iter, "u", &u32))
			nm_ip4_config_add_nameserver (config, u32);
		g_variant_iter_free (iter);
	}

	if (g_variant_lookup (config_dict, NM_PPP_IP4_CONFIG_WINS, "au", &iter)) {
		while (g_variant_iter_next (iter, "u", &u32))
			nm_ip4_config_add_wins (config, u32);
		g_variant_iter_free (iter);
	}

	if (!set_ip_config_common (manager, config_dict, NM_PPP_IP4_CONFIG_INTERFACE, &u32))
		goto out;

	if (u32)
		nm_ip4_config_set_mtu (config, u32, NM_IP_CONFIG_SOURCE_PPP);

	/* Push the IP4 config up to the device */
	g_signal_emit (manager, signals[IP4_CONFIG], 0, priv->ip_iface, config);

out:
	g_object_unref (config);
	g_dbus_method_invocation_return_value (context, NULL);
}
static NMIP4Config *
lease_to_ip4_config (const char *iface,
                     int ifindex,
                     sd_dhcp_lease *lease,
                     GHashTable *options,
                     guint32 default_priority,
                     gboolean log_lease,
                     GError **error)
{
	NMIP4Config *ip4_config = NULL;
	struct in_addr tmp_addr;
	const struct in_addr *addr_list;
	char buf[INET_ADDRSTRLEN];
	const char *str;
	guint32 lifetime = 0, i;
	NMPlatformIP4Address address;
	GString *l;
	struct sd_dhcp_route *routes;
	guint16 mtu;
	int r, num;
	guint64 end_time;
	const void *data;
	gsize data_len;
	gboolean metered = FALSE;

	g_return_val_if_fail (lease != NULL, NULL);

	ip4_config = nm_ip4_config_new (ifindex);

	/* Address */
	sd_dhcp_lease_get_address (lease, &tmp_addr);
	memset (&address, 0, sizeof (address));
	address.address = tmp_addr.s_addr;
	address.peer_address = tmp_addr.s_addr;
	str = nm_utils_inet4_ntop (tmp_addr.s_addr, NULL);
	LOG_LEASE (LOGD_DHCP4, "  address %s", str);
	add_option (options, dhcp4_requests, DHCP_OPTION_IP_ADDRESS, str);

	/* Prefix/netmask */
	sd_dhcp_lease_get_netmask (lease, &tmp_addr);
	address.plen = nm_utils_ip4_netmask_to_prefix (tmp_addr.s_addr);
	LOG_LEASE (LOGD_DHCP4, "  plen %d", address.plen);
	add_option (options,
	            dhcp4_requests,
	            DHCP_OPTION_SUBNET_MASK,
	            nm_utils_inet4_ntop (tmp_addr.s_addr, NULL));

	/* Lease time */
	sd_dhcp_lease_get_lifetime (lease, &lifetime);
	address.timestamp = nm_utils_get_monotonic_timestamp_s ();
	address.lifetime = address.preferred = lifetime;
	end_time = (guint64) time (NULL) + lifetime;
	LOG_LEASE (LOGD_DHCP4, "  expires in %" G_GUINT32_FORMAT " seconds", lifetime);
	add_option_u64 (options,
	                dhcp4_requests,
	                DHCP_OPTION_IP_ADDRESS_LEASE_TIME,
	                end_time);

	address.source = NM_IP_CONFIG_SOURCE_DHCP;
	nm_ip4_config_add_address (ip4_config, &address);

	/* Gateway */
	r = sd_dhcp_lease_get_router (lease, &tmp_addr);
	if (r == 0) {
		nm_ip4_config_set_gateway (ip4_config, tmp_addr.s_addr);
		str = nm_utils_inet4_ntop (tmp_addr.s_addr, NULL);
		LOG_LEASE (LOGD_DHCP4, "  gateway %s", str);
		add_option (options, dhcp4_requests, DHCP_OPTION_ROUTER, str);
	}

	/* DNS Servers */
	num = sd_dhcp_lease_get_dns (lease, &addr_list);
	if (num > 0) {
		l = g_string_sized_new (30);
		for (i = 0; i < num; i++) {
			if (addr_list[i].s_addr) {
				nm_ip4_config_add_nameserver (ip4_config, addr_list[i].s_addr);
				str = nm_utils_inet4_ntop (addr_list[i].s_addr, NULL);
				LOG_LEASE (LOGD_DHCP4, "  nameserver '%s'", str);
				g_string_append_printf (l, "%s%s", l->len ? " " : "", str);
			}
		}
		if (l->len)
			add_option (options, dhcp4_requests, DHCP_OPTION_DOMAIN_NAME_SERVER, l->str);
		g_string_free (l, TRUE);
	}

	/* Domain Name */
	r = sd_dhcp_lease_get_domainname (lease, &str);
	if (r == 0) {
		/* Multiple domains sometimes stuffed into the option */
		char **domains = g_strsplit (str, " ", 0);
		char **s;

		for (s = domains; *s; s++) {
			LOG_LEASE (LOGD_DHCP4, "  domain name '%s'", *s);
			nm_ip4_config_add_domain (ip4_config, *s);
		}
		g_strfreev (domains);
		add_option (options, dhcp4_requests, DHCP_OPTION_DOMAIN_NAME, str);
	}

	/* Hostname */
	r = sd_dhcp_lease_get_hostname (lease, &str);
	if (r == 0) {
		LOG_LEASE (LOGD_DHCP4, "  hostname '%s'", str);
		add_option (options, dhcp4_requests, DHCP_OPTION_HOST_NAME, str);
	}

	/* Routes */
	num = sd_dhcp_lease_get_routes (lease, &routes);
	if (num > 0) {
		l = g_string_sized_new (30);
		for (i = 0; i < num; i++) {
			NMPlatformIP4Route route;
			const char *gw_str;

			memset (&route, 0, sizeof (route));
			route.network = routes[i].dst_addr.s_addr;
			route.plen = routes[i].dst_prefixlen;
			route.gateway = routes[i].gw_addr.s_addr;
			route.source = NM_IP_CONFIG_SOURCE_DHCP;
			route.metric = default_priority;
			nm_ip4_config_add_route (ip4_config, &route);

			str = nm_utils_inet4_ntop (route.network, buf);
			gw_str = nm_utils_inet4_ntop (route.gateway, NULL);
			LOG_LEASE (LOGD_DHCP4, "  static route %s/%d gw %s", str, route.plen, gw_str);

			g_string_append_printf (l, "%s%s/%d %s", l->len ? " " : "", str, route.plen, gw_str);
		}
		add_option (options, dhcp4_requests, DHCP_OPTION_RFC3442_ROUTES, l->str);
		g_string_free (l, TRUE);
	}

	/* MTU */
	r = sd_dhcp_lease_get_mtu (lease, &mtu);
	if (r == 0 && mtu) {
		nm_ip4_config_set_mtu (ip4_config, mtu, NM_IP_CONFIG_SOURCE_DHCP);
		add_option_u32 (options, dhcp4_requests, DHCP_OPTION_INTERFACE_MTU, mtu);
		LOG_LEASE (LOGD_DHCP4, "  mtu %u", mtu);
	}

	/* NTP servers */
	num = sd_dhcp_lease_get_ntp (lease, &addr_list);
	if (num > 0) {
		l = g_string_sized_new (30);
		for (i = 0; i < num; i++) {
			str = nm_utils_inet4_ntop (addr_list[i].s_addr, buf);
			LOG_LEASE (LOGD_DHCP4, "  ntp server '%s'", str);
			g_string_append_printf (l, "%s%s", l->len ? " " : "", str);
		}
		add_option (options, dhcp4_requests, DHCP_OPTION_NTP_SERVER, l->str);
		g_string_free (l, TRUE);
	}

	r = sd_dhcp_lease_get_vendor_specific (lease, &data, &data_len);
	if (r >= 0)
		metered = !!memmem (data, data_len, "ANDROID_METERED", STRLEN ("ANDROID_METERED"));
	nm_ip4_config_set_metered (ip4_config, metered);

	return ip4_config;
}
/* Given a table of DHCP options from the client, convert into an IP4Config */
static NMIP4Config *
ip4_options_to_config (NMDHCPClient *self)
{
	NMDHCPClientPrivate *priv;
	NMIP4Config *ip4_config = NULL;
	struct in_addr tmp_addr;
	NMIP4Address *addr = NULL;
	char *str = NULL;
	guint32 gwaddr = 0, prefix = 0;

	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);

	ip4_config = nm_ip4_config_new ();
	if (!ip4_config) {
		nm_log_warn (LOGD_DHCP4, "(%s): couldn't allocate memory for an IP4Config!", priv->iface);
		return NULL;
	}

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

	str = g_hash_table_lookup (priv->options, "new_ip_address");
	if (str && (inet_pton (AF_INET, str, &tmp_addr) > 0)) {
		nm_ip4_address_set_address (addr, tmp_addr.s_addr);
		nm_log_info (LOGD_DHCP4, "  address %s", str);
	} else
		goto error;

	str = g_hash_table_lookup (priv->options, "new_subnet_mask");
	if (str && (inet_pton (AF_INET, str, &tmp_addr) > 0)) {
		prefix = nm_utils_ip4_netmask_to_prefix (tmp_addr.s_addr);
		nm_log_info (LOGD_DHCP4, "  prefix %d (%s)", prefix, str);
	} else {
		/* Get default netmask for the IP according to appropriate class. */
		prefix = nm_utils_ip4_get_default_prefix (nm_ip4_address_get_address (addr));
		nm_log_info (LOGD_DHCP4, "  prefix %d (default)", prefix);
	}
	nm_ip4_address_set_prefix (addr, prefix);

	/* Routes: if the server returns classless static routes, we MUST ignore
	 * the 'static_routes' option.
	 */
	if (!ip4_process_classless_routes (priv->options, ip4_config, &gwaddr))
		process_classful_routes (priv->options, ip4_config);

	if (gwaddr) {
		char buf[INET_ADDRSTRLEN + 1];

		inet_ntop (AF_INET, &gwaddr, buf, sizeof (buf));
		nm_log_info (LOGD_DHCP4, "  gateway %s", buf);
		nm_ip4_address_set_gateway (addr, gwaddr);
	} else {
		/* If the gateway wasn't provided as a classless static route with a
		 * subnet length of 0, try to find it using the old-style 'routers' option.
		 */
		str = g_hash_table_lookup (priv->options, "new_routers");
		if (str) {
			char **routers = g_strsplit (str, " ", 0);
			char **s;

			for (s = routers; *s; s++) {
				/* FIXME: how to handle multiple routers? */
				if (inet_pton (AF_INET, *s, &tmp_addr) > 0) {
					nm_ip4_address_set_gateway (addr, tmp_addr.s_addr);
					nm_log_info (LOGD_DHCP4, "  gateway %s", *s);
					break;
				} else
					nm_log_warn (LOGD_DHCP4, "ignoring invalid gateway '%s'", *s);
			}
			g_strfreev (routers);
		}
	}

	nm_ip4_config_take_address (ip4_config, addr);
	addr = NULL;

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

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

		for (s = searches; *s; s++) {
			if (inet_pton (AF_INET, *s, &tmp_addr) > 0) {
				nm_ip4_config_add_nameserver (ip4_config, tmp_addr.s_addr);
				nm_log_info (LOGD_DHCP4, "  nameserver '%s'", *s);
			} else
				nm_log_warn (LOGD_DHCP4, "ignoring invalid nameserver '%s'", *s);
		}
		g_strfreev (searches);
	}

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

		for (s = domains; *s; s++) {
			nm_log_info (LOGD_DHCP4, "  domain name '%s'", *s);
			nm_ip4_config_add_domain (ip4_config, *s);
		}
		g_strfreev (domains);
	}

	str = g_hash_table_lookup (priv->options, "new_domain_search");
	if (str)
		process_domain_search (str, ip4_add_domain_search, ip4_config);

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

		for (s = searches; *s; s++) {
			if (inet_pton (AF_INET, *s, &tmp_addr) > 0) {
				nm_ip4_config_add_wins (ip4_config, tmp_addr.s_addr);
				nm_log_info (LOGD_DHCP4, "  wins '%s'", *s);
			} else
				nm_log_warn (LOGD_DHCP4, "ignoring invalid WINS server '%s'", *s);
		}
		g_strfreev (searches);
	}

	str = g_hash_table_lookup (priv->options, "new_interface_mtu");
	if (str) {
		int int_mtu;

		errno = 0;
		int_mtu = strtol (str, NULL, 10);
		if ((errno == EINVAL) || (errno == ERANGE))
			goto error;

		if (int_mtu > 576)
			nm_ip4_config_set_mtu (ip4_config, int_mtu);
	}

	str = g_hash_table_lookup (priv->options, "new_nis_domain");
	if (str) {
		nm_log_info (LOGD_DHCP4, "  NIS domain '%s'", str);
		nm_ip4_config_set_nis_domain (ip4_config, str);
	}

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

		for (s = searches; *s; s++) {
			if (inet_pton (AF_INET, *s, &tmp_addr) > 0) {
				nm_ip4_config_add_nis_server (ip4_config, tmp_addr.s_addr);
				nm_log_info (LOGD_DHCP4, "  nis '%s'", *s);
			} else
				nm_log_warn (LOGD_DHCP4, "ignoring invalid NIS server '%s'", *s);
		}
		g_strfreev (searches);
	}

	return ip4_config;

error:
	if (addr)
		nm_ip4_address_unref (addr);
	g_object_unref (ip4_config);
	return NULL;
}
Example #9
0
static gboolean
impl_ppp_manager_set_ip4_config (NMPPPManager *manager,
						   GHashTable *config_hash,
						   GError **err)
{
	NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager);
	NMConnection *connection;
	NMSettingPPP *s_ppp;
	NMIP4Config *config;
	NMIP4Address *addr;
	GValue *val;
	int i;

	nm_log_info (LOGD_PPP, "PPP manager(IP Config Get) reply received.");

	remove_timeout_handler (manager);

	config = nm_ip4_config_new ();
	addr = nm_ip4_address_new ();
	nm_ip4_address_set_prefix (addr, 32);

	val = (GValue *) g_hash_table_lookup (config_hash, NM_PPP_IP4_CONFIG_GATEWAY);
	if (val) {
		nm_ip4_address_set_gateway (addr, g_value_get_uint (val));
		nm_ip4_config_set_ptp_address (config, g_value_get_uint (val));
	}

	val = (GValue *) g_hash_table_lookup (config_hash, NM_PPP_IP4_CONFIG_ADDRESS);
	if (val)
		nm_ip4_address_set_address (addr, g_value_get_uint (val));

	val = (GValue *) g_hash_table_lookup (config_hash, NM_PPP_IP4_CONFIG_PREFIX);
	if (val)
		nm_ip4_address_set_prefix (addr, g_value_get_uint (val));

	if (nm_ip4_address_get_address (addr) && nm_ip4_address_get_prefix (addr)) {
		nm_ip4_config_take_address (config, addr);
	} else {
		nm_log_err (LOGD_PPP, "invalid IPv4 address received!");
		nm_ip4_address_unref (addr);
		goto out;
	}

	val = (GValue *) g_hash_table_lookup (config_hash, NM_PPP_IP4_CONFIG_DNS);
	if (val) {
		GArray *dns = (GArray *) g_value_get_boxed (val);

		for (i = 0; i < dns->len; i++)
			nm_ip4_config_add_nameserver (config, g_array_index (dns, guint, i));
	}

	val = (GValue *) g_hash_table_lookup (config_hash, NM_PPP_IP4_CONFIG_WINS);
	if (val) {
		GArray *wins = (GArray *) g_value_get_boxed (val);

		for (i = 0; i < wins->len; i++)
			nm_ip4_config_add_wins (config, g_array_index (wins, guint, i));
	}

	val = (GValue *) g_hash_table_lookup (config_hash, NM_PPP_IP4_CONFIG_INTERFACE);
	if (!val || !G_VALUE_HOLDS_STRING (val)) {
		nm_log_err (LOGD_PPP, "no interface received!");
		goto out;
	}
	priv->ip_iface = g_value_dup_string (val);

	/* Got successful IP4 config; obviously the secrets worked */
	connection = nm_act_request_get_connection (priv->act_req);
	g_assert (connection);
	g_object_set_data (G_OBJECT (connection), PPP_MANAGER_SECRET_TRIES, NULL);

	/* Merge in custom MTU */
	s_ppp = (NMSettingPPP *) nm_connection_get_setting (connection, NM_TYPE_SETTING_PPP);
	if (s_ppp) {
		guint32 mtu = nm_setting_ppp_get_mtu (s_ppp);

		if (mtu)
			nm_ip4_config_set_mtu (config, mtu);
	}

	/* Push the IP4 config up to the device */
	g_signal_emit (manager, signals[IP4_CONFIG], 0, priv->ip_iface, config);

	monitor_stats (manager);

 out:
	g_object_unref (config);

	return TRUE;
}