static char * ip6_addr_to_string (const struct in6_addr *addr, const char *iface) { char *buf; if (IN6_IS_ADDR_V4MAPPED (addr)) { /* inet_ntop is probably supposed to do this for us, but it doesn't */ buf = g_malloc (INET_ADDRSTRLEN); nm_utils_inet4_ntop (addr->s6_addr32[3], buf); } else if (!iface || !iface[0] || !IN6_IS_ADDR_LINKLOCAL (addr)) { buf = g_malloc (INET6_ADDRSTRLEN); nm_utils_inet6_ntop (addr, buf); } else { /* If we got a scope identifier, we need use '%' instead of * '@', since dnsmasq supports '%' in server= addresses * only since version 2.58 and up */ buf = g_strconcat (nm_utils_inet6_ntop (addr, NULL), "@", iface, NULL); } return buf; }
static char * ip6_addr_to_string (const struct in6_addr *addr, const char *iface) { char *buf; if (IN6_IS_ADDR_V4MAPPED (addr)) { buf = g_malloc (INET_ADDRSTRLEN); nm_utils_inet4_ntop (addr->s6_addr32[3], buf); } else if (!iface || !iface[0] || !IN6_IS_ADDR_LINKLOCAL (addr)) { buf = g_malloc (INET6_ADDRSTRLEN); nm_utils_inet6_ntop (addr, buf); } else { /* Need to scope the address with %<zone-id>. Before dnsmasq 2.58, * only '@' was supported as delimiter. Since 2.58, '@' and '%' * are supported. Due to a bug, since 2.73 only '%' works properly * as "server" address. */ buf = g_strconcat (nm_utils_inet6_ntop (addr, NULL), "%", iface, NULL); } return buf; }
static char * ip6_addr_to_string (const struct in6_addr *addr, const char *iface) { char buf[NM_UTILS_INET_ADDRSTRLEN]; if (IN6_IS_ADDR_V4MAPPED (addr)) nm_utils_inet4_ntop (addr->s6_addr32[3], buf); else nm_utils_inet6_ntop (addr, buf); /* Need to scope link-local addresses with %<zone-id>. Before dnsmasq 2.58, * only '@' was supported as delimiter. Since 2.58, '@' and '%' are * supported. Due to a bug, since 2.73 only '%' works properly as "server" * address. */ return g_strdup_printf ("%s%c%s", buf, IN6_IS_ADDR_LINKLOCAL (addr) ? '%' : '@', iface); }
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); } }
static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE (object); NMDevice *parent; switch (prop_id) { case PROP_PARENT: parent = nm_manager_get_device_by_ifindex (nm_manager_get (), priv->props.parent_ifindex); nm_utils_g_value_set_object_path (value, parent); break; case PROP_ID: g_value_set_uint (value, priv->props.id); break; case PROP_GROUP: if (priv->props.group) g_value_set_string (value, nm_utils_inet4_ntop (priv->props.group, NULL)); else if (!IN6_IS_ADDR_UNSPECIFIED (&priv->props.group6)) g_value_set_string (value, nm_utils_inet6_ntop (&priv->props.group6, NULL)); break; case PROP_LOCAL: if (priv->props.local) g_value_set_string (value, nm_utils_inet4_ntop (priv->props.local, NULL)); else if (!IN6_IS_ADDR_UNSPECIFIED (&priv->props.local6)) g_value_set_string (value, nm_utils_inet6_ntop (&priv->props.local6, NULL)); break; case PROP_TOS: g_value_set_uchar (value, priv->props.tos); break; case PROP_TTL: g_value_set_uchar (value, priv->props.ttl); break; case PROP_LEARNING: g_value_set_boolean (value, priv->props.learning); break; case PROP_AGEING: g_value_set_uint (value, priv->props.ageing); break; case PROP_LIMIT: g_value_set_uint (value, priv->props.limit); break; case PROP_DST_PORT: g_value_set_uint (value, priv->props.dst_port); break; case PROP_SRC_PORT_MIN: g_value_set_uint (value, priv->props.src_port_min); break; case PROP_SRC_PORT_MAX: g_value_set_uint (value, priv->props.src_port_max); break; case PROP_PROXY: g_value_set_boolean (value, priv->props.proxy); break; case PROP_RSC: g_value_set_boolean (value, priv->props.rsc); break; case PROP_L2MISS: g_value_set_boolean (value, priv->props.l2miss); break; case PROP_L3MISS: g_value_set_boolean (value, priv->props.l3miss); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void update_properties_from_ifindex (NMDevice *device, int ifindex) { NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL (device); NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (self); GObject *object = G_OBJECT (device); NMDevice *parent; int parent_ifindex; in_addr_t local4, remote4; struct in6_addr local6, remote6; guint8 ttl = 0, tos = 0, encap_limit = 0; gboolean pmtud = FALSE; guint32 flow_label = 0; char *key; if (ifindex <= 0) { clear: if (priv->parent || priv->parent_ifindex) { g_clear_object (&priv->parent); priv->parent_ifindex = 0; g_object_notify (object, NM_DEVICE_IP_TUNNEL_PARENT); } if (priv->local) { g_clear_pointer (&priv->local, g_free); g_object_notify (object, NM_DEVICE_IP_TUNNEL_LOCAL); } if (priv->remote) { g_clear_pointer (&priv->remote, g_free); g_object_notify (object, NM_DEVICE_IP_TUNNEL_REMOTE); } if (priv->input_key) { g_clear_pointer (&priv->input_key, g_free); g_object_notify (object, NM_DEVICE_IP_TUNNEL_INPUT_KEY); } if (priv->output_key) { g_clear_pointer (&priv->output_key, g_free); g_object_notify (object, NM_DEVICE_IP_TUNNEL_OUTPUT_KEY); } goto out; } if (priv->mode == NM_IP_TUNNEL_MODE_GRE) { const NMPlatformLnkGre *lnk; lnk = nm_platform_link_get_lnk_gre (NM_PLATFORM_GET, ifindex, NULL); if (!lnk) { _LOGW (LOGD_HW, "could not read %s properties", "gre"); goto clear; } parent_ifindex = lnk->parent_ifindex; local4 = lnk->local; remote4 = lnk->remote; ttl = lnk->ttl; tos = lnk->tos; pmtud = lnk->path_mtu_discovery; if (NM_FLAGS_HAS (lnk->input_flags, NM_GRE_KEY)) { key = g_strdup_printf ("%u", lnk->input_key); if (g_strcmp0 (priv->input_key, key)) { g_free (priv->input_key); priv->input_key = key; g_object_notify (object, NM_DEVICE_IP_TUNNEL_INPUT_KEY); } else g_free (key); } else { if (priv->input_key) { g_clear_pointer (&priv->input_key, g_free); g_object_notify (object, NM_DEVICE_IP_TUNNEL_INPUT_KEY); } } if (NM_FLAGS_HAS (lnk->output_flags, NM_GRE_KEY)) { key = g_strdup_printf ("%u", lnk->output_key); if (g_strcmp0 (priv->output_key, key)) { g_free (priv->output_key); priv->output_key = key; g_object_notify (object, NM_DEVICE_IP_TUNNEL_OUTPUT_KEY); } else g_free (key); } else { if (priv->output_key) { g_clear_pointer (&priv->output_key, g_free); g_object_notify (object, NM_DEVICE_IP_TUNNEL_OUTPUT_KEY); } } } else if (priv->mode == NM_IP_TUNNEL_MODE_SIT) { const NMPlatformLnkSit *lnk; lnk = nm_platform_link_get_lnk_sit (NM_PLATFORM_GET, ifindex, NULL); if (!lnk) { _LOGW (LOGD_HW, "could not read %s properties", "sit"); goto clear; } parent_ifindex = lnk->parent_ifindex; local4 = lnk->local; remote4 = lnk->remote; ttl = lnk->ttl; tos = lnk->tos; pmtud = lnk->path_mtu_discovery; } else if (priv->mode == NM_IP_TUNNEL_MODE_IPIP) { const NMPlatformLnkIpIp *lnk; lnk = nm_platform_link_get_lnk_ipip (NM_PLATFORM_GET, ifindex, NULL); if (!lnk) { _LOGW (LOGD_HW, "could not read %s properties", "ipip"); goto clear; } parent_ifindex = lnk->parent_ifindex; local4 = lnk->local; remote4 = lnk->remote; ttl = lnk->ttl; tos = lnk->tos; pmtud = lnk->path_mtu_discovery; } else if ( priv->mode == NM_IP_TUNNEL_MODE_IPIP6 || priv->mode == NM_IP_TUNNEL_MODE_IP6IP6) { const NMPlatformLnkIp6Tnl *lnk; lnk = nm_platform_link_get_lnk_ip6tnl (NM_PLATFORM_GET, ifindex, NULL); if (!lnk) { _LOGW (LOGD_HW, "could not read %s properties", "ip6tnl"); goto clear; } parent_ifindex = lnk->parent_ifindex; local6 = lnk->local; remote6 = lnk->remote; ttl = lnk->ttl; tos = lnk->tclass; encap_limit = lnk->encap_limit; flow_label = lnk->flow_label; } else g_return_if_reached (); if (priv->parent_ifindex != parent_ifindex) { g_clear_object (&priv->parent); priv->parent_ifindex = parent_ifindex; parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex); if (parent) priv->parent = g_object_ref (parent); g_object_notify (object, NM_DEVICE_IP_TUNNEL_PARENT); } if (priv->addr_family == AF_INET) { if (!address_equal_pn (AF_INET, priv->local, &local4)) { g_clear_pointer (&priv->local, g_free); if (local4) priv->local = g_strdup (nm_utils_inet4_ntop (local4, NULL)); g_object_notify (object, NM_DEVICE_IP_TUNNEL_LOCAL); } if (!address_equal_pn (AF_INET, priv->remote, &remote4)) { g_clear_pointer (&priv->remote, g_free); if (remote4) priv->remote = g_strdup (nm_utils_inet4_ntop (remote4, NULL)); g_object_notify (object, NM_DEVICE_IP_TUNNEL_REMOTE); } } else { if (!address_equal_pn (AF_INET6, priv->local, &local6)) { g_clear_pointer (&priv->local, g_free); if (memcmp (&local6, &in6addr_any, sizeof (in6addr_any))) priv->local = g_strdup (nm_utils_inet6_ntop (&local6, NULL)); g_object_notify (object, NM_DEVICE_IP_TUNNEL_LOCAL); } if (!address_equal_pn (AF_INET6, priv->remote, &remote6)) { g_clear_pointer (&priv->remote, g_free); if (memcmp (&remote6, &in6addr_any, sizeof (in6addr_any))) priv->remote = g_strdup (nm_utils_inet6_ntop (&remote6, NULL)); g_object_notify (object, NM_DEVICE_IP_TUNNEL_REMOTE); } } out: if (priv->ttl != ttl) { priv->ttl = ttl; g_object_notify (object, NM_DEVICE_IP_TUNNEL_TTL); } if (priv->tos != tos) { priv->tos = tos; g_object_notify (object, NM_DEVICE_IP_TUNNEL_TOS); } if (priv->path_mtu_discovery != pmtud) { priv->path_mtu_discovery = pmtud; g_object_notify (object, NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY); } if (priv->encap_limit != encap_limit) { priv->encap_limit = encap_limit; g_object_notify (object, NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT); } if (priv->flow_label != flow_label) { priv->flow_label = flow_label; g_object_notify (object, NM_DEVICE_IP_TUNNEL_FLOW_LABEL); } }
static void update_connection (NMDevice *device, NMConnection *connection) { NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE (device); NMSettingVxlan *s_vxlan = nm_connection_get_setting_vxlan (connection); NMDevice *parent = NULL; const char *setting_parent, *new_parent; if (!s_vxlan) { s_vxlan = (NMSettingVxlan *) nm_setting_vxlan_new (); nm_connection_add_setting (connection, (NMSetting *) s_vxlan); } if (priv->props.id != nm_setting_vxlan_get_id (s_vxlan)) g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_ID, priv->props.id, NULL); if (priv->props.parent_ifindex != NM_PLATFORM_LINK_OTHER_NETNS) parent = nm_manager_get_device_by_ifindex (nm_manager_get (), priv->props.parent_ifindex); /* Update parent in the connection; default to parent's interface name */ if (parent) { new_parent = nm_device_get_iface (parent); setting_parent = nm_setting_vxlan_get_parent (s_vxlan); if (setting_parent && nm_utils_is_uuid (setting_parent)) { NMConnection *parent_connection; /* Don't change a parent specified by UUID if it's still valid */ parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (nm_device_get_settings (device), setting_parent); if (parent_connection && nm_device_check_connection_compatible (parent, parent_connection)) new_parent = NULL; } if (new_parent) g_object_set (s_vxlan, NM_SETTING_VXLAN_PARENT, new_parent, NULL); } else g_object_set (s_vxlan, NM_SETTING_VXLAN_PARENT, NULL, NULL); if (!address_matches (nm_setting_vxlan_get_remote (s_vxlan), priv->props.group, &priv->props.group6)) { if (priv->props.group) { g_object_set (s_vxlan, NM_SETTING_VXLAN_REMOTE, nm_utils_inet4_ntop (priv->props.group, NULL), NULL); } else { g_object_set (s_vxlan, NM_SETTING_VXLAN_REMOTE, nm_utils_inet6_ntop (&priv->props.group6, NULL), NULL); } } if (!address_matches (nm_setting_vxlan_get_local (s_vxlan), priv->props.local, &priv->props.local6)) { if (priv->props.local) { g_object_set (s_vxlan, NM_SETTING_VXLAN_LOCAL, nm_utils_inet4_ntop (priv->props.local, NULL), NULL); } else if (memcmp (&priv->props.local6, &in6addr_any, sizeof (in6addr_any))) { g_object_set (s_vxlan, NM_SETTING_VXLAN_LOCAL, nm_utils_inet6_ntop (&priv->props.local6, NULL), NULL); } } if (priv->props.src_port_min != nm_setting_vxlan_get_source_port_min (s_vxlan)) { g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_SOURCE_PORT_MIN, priv->props.src_port_min, NULL); } if (priv->props.src_port_max != nm_setting_vxlan_get_source_port_max (s_vxlan)) { g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_SOURCE_PORT_MAX, priv->props.src_port_max, NULL); } if (priv->props.dst_port != nm_setting_vxlan_get_destination_port (s_vxlan)) { g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_DESTINATION_PORT, priv->props.dst_port, NULL); } if (priv->props.tos != nm_setting_vxlan_get_tos (s_vxlan)) { g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_TOS, priv->props.tos, NULL); } if (priv->props.ttl != nm_setting_vxlan_get_ttl (s_vxlan)) { g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_TTL, priv->props.ttl, NULL); } if (priv->props.learning != nm_setting_vxlan_get_learning (s_vxlan)) { g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_LEARNING, priv->props.learning, NULL); } if (priv->props.ageing != nm_setting_vxlan_get_ageing (s_vxlan)) { g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_AGEING, priv->props.ageing, NULL); } if (priv->props.proxy != nm_setting_vxlan_get_proxy (s_vxlan)) { g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_PROXY, priv->props.proxy, NULL); } if (priv->props.rsc != nm_setting_vxlan_get_rsc (s_vxlan)) { g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_RSC, priv->props.rsc, NULL); } if (priv->props.l2miss != nm_setting_vxlan_get_l2_miss (s_vxlan)) { g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_L2_MISS, priv->props.l2miss, NULL); } if (priv->props.l3miss != nm_setting_vxlan_get_l3_miss (s_vxlan)) { g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_L3_MISS, priv->props.l3miss, NULL); } }