static void connect_ip6_page (CEPageIP6 *page) { GtkWidget *content; const gchar *str_method; gboolean disabled; GtkListStore *store; GtkTreeIter iter; guint method; add_address_section (page); add_dns_section (page); add_routes_section (page); page->enabled = GTK_SWITCH (gtk_builder_get_object (CE_PAGE (page)->builder, "switch_enable")); g_signal_connect (page->enabled, "notify::active", G_CALLBACK (switch_toggled), page); str_method = nm_setting_ip6_config_get_method (page->setting); disabled = g_strcmp0 (str_method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0; gtk_switch_set_active (page->enabled, !disabled); g_signal_connect_swapped (page->enabled, "notify::active", G_CALLBACK (ce_page_changed), page); content = GTK_WIDGET (gtk_builder_get_object (CE_PAGE (page)->builder, "page_content")); g_object_bind_property (page->enabled, "active", content, "sensitive", G_BINDING_SYNC_CREATE); page->method = GTK_COMBO_BOX (gtk_builder_get_object (CE_PAGE (page)->builder, "combo_addresses")); store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_UINT); gtk_list_store_insert_with_values (store, &iter, -1, METHOD_COL_NAME, _("Automatic"), METHOD_COL_METHOD, IP6_METHOD_AUTO, -1); gtk_list_store_insert_with_values (store, &iter, -1, METHOD_COL_NAME, _("Automatic, DHCP only"), METHOD_COL_METHOD, IP6_METHOD_DHCP, -1); gtk_list_store_insert_with_values (store, &iter, -1, METHOD_COL_NAME, _("Manual"), METHOD_COL_METHOD, IP6_METHOD_MANUAL, -1); gtk_list_store_insert_with_values (store, &iter, -1, METHOD_COL_NAME, _("Link-Local Only"), METHOD_COL_METHOD, IP6_METHOD_LINK_LOCAL, -1); gtk_combo_box_set_model (page->method, GTK_TREE_MODEL (store)); method = IP6_METHOD_AUTO; if (g_strcmp0 (str_method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) == 0) { method = IP6_METHOD_DHCP; } else if (g_strcmp0 (str_method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0) { method = IP6_METHOD_LINK_LOCAL; } else if (g_strcmp0 (str_method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL) == 0) { method = IP6_METHOD_MANUAL; } else if (g_strcmp0 (str_method, NM_SETTING_IP6_CONFIG_METHOD_SHARED) == 0) { method = IP6_METHOD_SHARED; } else if (g_strcmp0 (str_method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0) { method = IP6_METHOD_IGNORE; } page->never_default = GTK_WIDGET (gtk_builder_get_object (CE_PAGE (page)->builder, "never_default_check")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (page->never_default), nm_setting_ip6_config_get_never_default (page->setting)); g_signal_connect (page->method, "changed", G_CALLBACK (method_changed), page); if (method != IP6_METHOD_SHARED && method != IP6_METHOD_IGNORE) gtk_combo_box_set_active (page->method, method); }
static void update_ip6_routing_and_dns (NMPolicy *policy, gboolean force_update) { NMDnsIPConfigType dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE; NMDevice *best = NULL; NMActRequest *best_req = NULL; NMDnsManager *dns_mgr; GSList *devices = NULL, *iter; #if NOT_YET GSList *vpns; #endif NMIP6Config *ip6_config = NULL; NMIP6Address *addr; const char *ip_iface = NULL; NMConnection *connection = NULL; NMSettingConnection *s_con = NULL; const char *connection_id; best = get_best_ip6_device (policy->manager, &best_req); if (!best) goto out; if (!force_update && (best == policy->default_device6)) goto out; #if NOT_YET /* If a VPN connection is active, it is preferred */ vpns = nm_vpn_manager_get_active_connections (policy->vpn_manager); for (iter = vpns; iter; iter = g_slist_next (iter)) { NMVPNConnection *candidate = NM_VPN_CONNECTION (iter->data); NMConnection *vpn_connection; NMSettingIP6Config *s_ip6; gboolean can_default = TRUE; NMVPNConnectionState vpn_state; /* If it's marked 'never-default', don't make it default */ vpn_connection = nm_vpn_connection_get_connection (candidate); g_assert (vpn_connection); s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (vpn_connection, NM_TYPE_SETTING_IP6_CONFIG); if (s_ip6 && nm_setting_ip6_config_get_never_default (s_ip6)) can_default = FALSE; vpn_state = nm_vpn_connection_get_vpn_state (candidate); if (can_default && (vpn_state == NM_VPN_CONNECTION_STATE_ACTIVATED)) { NMIP6Config *parent_ip6; NMDevice *parent; ip_iface = nm_vpn_connection_get_ip_iface (candidate); connection = nm_vpn_connection_get_connection (candidate); ip6_config = nm_vpn_connection_get_ip6_config (candidate); addr = nm_ip6_config_get_address (ip6_config, 0); parent = nm_vpn_connection_get_parent_device (candidate); parent_ip6 = nm_device_get_ip6_config (parent); nm_system_replace_default_ip6_route_vpn (ip_iface, nm_ip6_address_get_gateway (addr), nm_vpn_connection_get_ip4_internal_gateway (candidate), nm_ip6_config_get_mss (ip4_config), nm_device_get_ip_iface (parent), nm_ip6_config_get_mss (parent_ip4)); dns_type = NM_DNS_IP_CONFIG_TYPE_VPN; } g_object_unref (candidate); } g_slist_free (vpns); #endif /* The best device gets the default route if a VPN connection didn't */ if (!ip_iface || !ip6_config) { connection = nm_act_request_get_connection (best_req); ip_iface = nm_device_get_ip_iface (best); ip6_config = nm_device_get_ip6_config (best); g_assert (ip6_config); addr = nm_ip6_config_get_address (ip6_config, 0); nm_system_replace_default_ip6_route (ip_iface, nm_ip6_address_get_gateway (addr)); dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE; } if (!ip_iface || !ip6_config) { nm_log_warn (LOGD_CORE, "couldn't determine IP interface (%p) or IPv6 config (%p)!", ip_iface, ip6_config); goto out; } /* Update the default active connection. Only mark the new default * active connection after setting default = FALSE on all other connections * first. The order is important, we don't want two connections marked * default at the same time ever. */ devices = nm_manager_get_devices (policy->manager); for (iter = devices; iter; iter = g_slist_next (iter)) { NMDevice *dev = NM_DEVICE (iter->data); NMActRequest *req; req = nm_device_get_act_request (dev); if (req && (req != best_req)) nm_act_request_set_default6 (req, FALSE); } dns_mgr = nm_dns_manager_get (NULL); nm_dns_manager_add_ip6_config (dns_mgr, ip_iface, ip6_config, dns_type); g_object_unref (dns_mgr); /* Now set new default active connection _after_ updating DNS info, so that * if the connection is shared dnsmasq picks up the right stuff. */ if (best_req) nm_act_request_set_default6 (best_req, TRUE); if (connection) s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); connection_id = s_con ? nm_setting_connection_get_id (s_con) : NULL; if (connection_id) { nm_log_info (LOGD_CORE, "Policy set '%s' (%s) as default for IPv6 routing and DNS.", connection_id, ip_iface); } else { nm_log_info (LOGD_CORE, "Policy set (%s) as default for IPv6 routing and DNS.", ip_iface); } out: policy->default_device6 = best; }
/* This is exactly identical to nm_utils_merge_ip4_config, with s/4/6/, * except that we can't compare addresses with ==. */ void nm_utils_merge_ip6_config (NMIP6Config *ip6_config, NMSettingIP6Config *setting) { int i, j; if (!setting) return; /* Defaults are just fine */ if (nm_setting_ip6_config_get_ignore_auto_dns (setting)) { nm_ip6_config_reset_nameservers (ip6_config); nm_ip6_config_reset_domains (ip6_config); nm_ip6_config_reset_searches (ip6_config); } if (nm_setting_ip6_config_get_ignore_auto_routes (setting)) nm_ip6_config_reset_routes (ip6_config); for (i = 0; i < nm_setting_ip6_config_get_num_dns (setting); i++) { const struct in6_addr *ns; gboolean found = FALSE; /* Avoid dupes */ ns = nm_setting_ip6_config_get_dns (setting, i); for (j = 0; j < nm_ip6_config_get_num_nameservers (ip6_config); j++) { if (ip6_addresses_equal (nm_ip6_config_get_nameserver (ip6_config, j), ns)) { found = TRUE; break; } } if (!found) nm_ip6_config_add_nameserver (ip6_config, ns); } /* DNS search domains */ for (i = 0; i < nm_setting_ip6_config_get_num_dns_searches (setting); i++) { const char *search = nm_setting_ip6_config_get_dns_search (setting, i); gboolean found = FALSE; /* Avoid dupes */ for (j = 0; j < nm_ip6_config_get_num_searches (ip6_config); j++) { if (!strcmp (search, nm_ip6_config_get_search (ip6_config, j))) { found = TRUE; break; } } if (!found) nm_ip6_config_add_search (ip6_config, search); } /* IPv6 addresses */ for (i = 0; i < nm_setting_ip6_config_get_num_addresses (setting); i++) { NMIP6Address *setting_addr = nm_setting_ip6_config_get_address (setting, i); guint32 num; num = nm_ip6_config_get_num_addresses (ip6_config); for (j = 0; j < num; j++) { NMIP6Address *cfg_addr = nm_ip6_config_get_address (ip6_config, j); /* Dupe, override with user-specified address */ if (ip6_addresses_equal (nm_ip6_address_get_address (cfg_addr), nm_ip6_address_get_address (setting_addr))) { nm_ip6_config_replace_address (ip6_config, j, setting_addr); break; } } if (j == num) nm_ip6_config_add_address (ip6_config, setting_addr); } /* IPv6 routes */ for (i = 0; i < nm_setting_ip6_config_get_num_routes (setting); i++) { NMIP6Route *setting_route = nm_setting_ip6_config_get_route (setting, i); guint32 num; num = nm_ip6_config_get_num_routes (ip6_config); for (j = 0; j < num; j++) { NMIP6Route *cfg_route = nm_ip6_config_get_route (ip6_config, j); /* Dupe, override with user-specified route */ if ( ip6_addresses_equal (nm_ip6_route_get_dest (cfg_route), nm_ip6_route_get_dest (setting_route)) && (nm_ip6_route_get_prefix (cfg_route) == nm_ip6_route_get_prefix (setting_route)) && ip6_addresses_equal (nm_ip6_route_get_next_hop (cfg_route), nm_ip6_route_get_next_hop (setting_route))) { nm_ip6_config_replace_route (ip6_config, j, setting_route); break; } } if (j == num) nm_ip6_config_add_route (ip6_config, setting_route); } if (nm_setting_ip6_config_get_never_default (setting)) nm_ip6_config_set_never_default (ip6_config, TRUE); }
static NMDevice * get_best_ip6_device (NMManager *manager, NMActRequest **out_req) { GSList *devices, *iter; NMDevice *best = NULL; int best_prio = G_MAXINT; g_return_val_if_fail (manager != NULL, NULL); g_return_val_if_fail (NM_IS_MANAGER (manager), NULL); g_return_val_if_fail (out_req != NULL, NULL); g_return_val_if_fail (*out_req == NULL, NULL); devices = nm_manager_get_devices (manager); for (iter = devices; iter; iter = g_slist_next (iter)) { NMDevice *dev = NM_DEVICE (iter->data); NMActRequest *req; NMConnection *connection; NMIP6Config *ip6_config; NMSettingIP6Config *s_ip6; int prio; guint i; gboolean can_default = FALSE; const char *method = NULL; if (nm_device_get_state (dev) != NM_DEVICE_STATE_ACTIVATED) continue; ip6_config = nm_device_get_ip6_config (dev); if (!ip6_config) continue; req = nm_device_get_act_request (dev); g_assert (req); connection = nm_act_request_get_connection (req); g_assert (connection); /* Never set the default route through an IPv4LL-addressed device */ s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); if (s_ip6) method = nm_setting_ip6_config_get_method (s_ip6); if (method && !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) continue; /* Make sure at least one of this device's IP addresses has a gateway */ for (i = 0; i < nm_ip6_config_get_num_addresses (ip6_config); i++) { NMIP6Address *addr; addr = nm_ip6_config_get_address (ip6_config, i); if (nm_ip6_address_get_gateway (addr)) { can_default = TRUE; break; } } if (!can_default && !NM_IS_DEVICE_MODEM (dev)) continue; /* 'never-default' devices can't ever be the default */ if (s_ip6 && nm_setting_ip6_config_get_never_default (s_ip6)) continue; prio = nm_device_get_priority (dev); if (prio > 0 && prio < best_prio) { best = dev; best_prio = prio; *out_req = req; } } return best; }
GtkWidget * ip6_routes_dialog_new (NMSettingIP6Config *s_ip6, gboolean automatic) { GtkBuilder *builder; GtkWidget *dialog, *widget, *ok_button; GtkListStore *store; GtkTreeIter model_iter; GtkTreeSelection *selection; gint offset; GtkTreeViewColumn *column; GtkCellRenderer *renderer; int i; GSList *renderers = NULL; GError* error = NULL; /* Initialize temporary storage vars */ g_free (last_edited); last_edited = NULL; last_path = NULL; g_free (last_path); last_column = -1; builder = gtk_builder_new (); if (!gtk_builder_add_from_file (builder, UIDIR "/ce-ip6-routes.ui", &error)) { g_warning ("Couldn't load builder file: %s", error->message); g_error_free (error); return NULL; } dialog = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_routes_dialog")); if (!dialog) { g_warning ("%s: Couldn't load ip6 routes dialog from .ui file.", __func__); g_object_unref (builder); return NULL; } gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); g_object_set_data_full (G_OBJECT (dialog), "builder", builder, (GDestroyNotify) g_object_unref); ok_button = GTK_WIDGET (gtk_builder_get_object (builder, "ok_button")); store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); /* Add existing routes */ for (i = 0; i < nm_setting_ip6_config_get_num_routes (s_ip6); i++) { NMIP6Route *route = nm_setting_ip6_config_get_route (s_ip6, i); const struct in6_addr *tmp_addr; char ip_string[INET6_ADDRSTRLEN]; char *tmp; if (!route) { g_warning ("%s: empty IP6 route structure!", __func__); continue; } gtk_list_store_append (store, &model_iter); tmp_addr = nm_ip6_route_get_dest (route); if (inet_ntop (AF_INET6, tmp_addr, ip_string, sizeof (ip_string))) gtk_list_store_set (store, &model_iter, COL_ADDRESS, ip_string, -1); tmp = g_strdup_printf ("%u", nm_ip6_route_get_prefix (route)); gtk_list_store_set (store, &model_iter, COL_PREFIX, tmp, -1); g_free (tmp); tmp_addr = nm_ip6_route_get_next_hop (route); if (tmp_addr && !IN6_IS_ADDR_UNSPECIFIED (tmp_addr) && inet_ntop (AF_INET6, tmp_addr, ip_string, sizeof (ip_string))) gtk_list_store_set (store, &model_iter, COL_NEXT_HOP, ip_string, -1); if (nm_ip6_route_get_metric (route)) { tmp = g_strdup_printf ("%u", nm_ip6_route_get_metric (route)); gtk_list_store_set (store, &model_iter, COL_METRIC, tmp, -1); g_free (tmp); } } widget = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_routes")); gtk_tree_view_set_model (GTK_TREE_VIEW (widget), GTK_TREE_MODEL (store)); g_object_unref (store); /* IP Address column */ renderer = gtk_cell_renderer_text_new (); g_object_set (renderer, "editable", TRUE, NULL); g_signal_connect (renderer, "edited", G_CALLBACK (cell_edited), builder); g_object_set_data (G_OBJECT (renderer), "column", GUINT_TO_POINTER (COL_ADDRESS)); g_signal_connect (renderer, "editing-started", G_CALLBACK (ip6_cell_editing_started), ok_button); g_signal_connect (renderer, "editing-canceled", G_CALLBACK (cell_editing_canceled), builder); renderers = g_slist_append (renderers, renderer); offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (widget), -1, _("Address"), renderer, "text", COL_ADDRESS, NULL); column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), offset - 1); gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE); gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); /* Prefix column */ renderer = gtk_cell_renderer_text_new (); g_object_set (renderer, "editable", TRUE, NULL); g_signal_connect (renderer, "edited", G_CALLBACK (cell_edited), builder); g_object_set_data (G_OBJECT (renderer), "column", GUINT_TO_POINTER (COL_PREFIX)); g_signal_connect (renderer, "editing-started", G_CALLBACK (uint_cell_editing_started), ok_button); g_signal_connect (renderer, "editing-canceled", G_CALLBACK (cell_editing_canceled), builder); renderers = g_slist_append (renderers, renderer); offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (widget), -1, _("Prefix"), renderer, "text", COL_PREFIX, NULL); column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), offset - 1); gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE); gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); /* Gateway column */ renderer = gtk_cell_renderer_text_new (); g_object_set (renderer, "editable", TRUE, NULL); g_signal_connect (renderer, "edited", G_CALLBACK (cell_edited), builder); g_object_set_data (G_OBJECT (renderer), "column", GUINT_TO_POINTER (COL_NEXT_HOP)); g_signal_connect (renderer, "editing-started", G_CALLBACK (ip6_cell_editing_started), ok_button); g_signal_connect (renderer, "editing-canceled", G_CALLBACK (cell_editing_canceled), builder); renderers = g_slist_append (renderers, renderer); offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (widget), -1, _("Gateway"), renderer, "text", COL_NEXT_HOP, NULL); column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), offset - 1); gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE); gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); /* Metric column */ renderer = gtk_cell_renderer_text_new (); g_object_set (renderer, "editable", TRUE, NULL); g_signal_connect (renderer, "edited", G_CALLBACK (cell_edited), builder); g_object_set_data (G_OBJECT (renderer), "column", GUINT_TO_POINTER (COL_METRIC)); g_signal_connect (renderer, "editing-started", G_CALLBACK (uint_cell_editing_started), ok_button); g_signal_connect (renderer, "editing-canceled", G_CALLBACK (cell_editing_canceled), builder); renderers = g_slist_append (renderers, renderer); offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (widget), -1, _("Metric"), renderer, "text", COL_METRIC, NULL); column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), offset - 1); gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE); gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); g_object_set_data_full (G_OBJECT (dialog), "renderers", renderers, (GDestroyNotify) g_slist_free); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); g_signal_connect (selection, "changed", G_CALLBACK (list_selection_changed), GTK_WIDGET (gtk_builder_get_object (builder, "ip6_route_delete_button"))); g_signal_connect (widget, "button-press-event", G_CALLBACK (tree_view_button_pressed_cb), builder); widget = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_route_add_button")); gtk_widget_set_sensitive (widget, TRUE); g_signal_connect (widget, "clicked", G_CALLBACK (route_add_clicked), builder); widget = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_route_delete_button")); gtk_widget_set_sensitive (widget, FALSE); g_signal_connect (widget, "clicked", G_CALLBACK (route_delete_clicked), builder); widget = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_ignore_auto_routes")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), nm_setting_ip6_config_get_ignore_auto_routes (s_ip6)); gtk_widget_set_sensitive (widget, automatic); widget = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_never_default")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), nm_setting_ip6_config_get_never_default (s_ip6)); /* Update initial validity */ validate (dialog); return dialog; }