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; }
/* 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; }
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 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; }