GNOME Bugzilla – Bug 403183
IPv6: support platforms which don't allow accepting IPv4 mapped IPv6 connections
Last modified: 2008-12-12 20:01:42 UTC
On Linux, you cannot bind both an IPv6 and IPv4 socket to the same port ... you must use an IPv6 socket to accept both IPv4 and IPv6 connections. However, on *BSD it seems that IPv4 mapped IPv6 connections aren't supported and you must create *both* IPv4 and IPv4 sockets. So, vino should first attempt to create an IPv6 socket and bind it to the port. Whether or not that succeeds, it should also try and create an IPv4 socket and bind it to the port. If it already has an IPv6 socket bound, it should ignore the EADDRINUSE it will get on Linux when attempting to bind the IPv4 socket. See here for some background info: http://httpd.apache.org/docs/trunk/bind.html
Created attachment 110389 [details] [review] IPv6 listening any interface. this patch change the option "local_only" to "network_interface", receive a string with iface, ex: eth1
Okay, so there are several things in this patch: 1) Add a "network_interface" preference - i.e. what interface to listen on 2) Remove the "local_only" preference - presumably the idea is that setting "network_interface" to "lo" is sufficient 3) An attempt to fix this bug I'd much prefer the patches to be split up and filed separately. The patch to fix this particular bug should be fairly small and should be tested on e.g. both Linux and *BSD Other thoughts: - If we add "network_interface", it's inevitable that people will want multiple interfaces supported, so we should add that too - Don't support network_interface == "all" - if the key is unset, that should mean "all" - Pass an address to ListenOnTcpPort() and do the SIOCGIFADDR stuff outside of that function - I wouldn't sanity check port numbers in libvncserver - either sanity check in vino-prefs, or just treat the bind failure like any other system error - I'm not sure the code to fix this bug is correct - e.g. from my research above, I'd concluded that you needed to create an IPv6 socket first and then *always* try and create an IPv4 socket
Created attachment 111125 [details] [review] this patchs reference of capplet (glade + preferences) This patchs reference of suggestions by mark, that add option for set a network interface and remove local_only in vino-preferences.{c,glade}
Comment on attachment 111125 [details] [review] this patchs reference of capplet (glade + preferences) >Index: capplet/vino-preferences.glade >=================================================================== >--- capplet/vino-preferences.glade (revision 840) >+++ capplet/vino-preferences.glade (working copy) >@@ -1,6 +1,6 @@ >-<?xml version="1.0" encoding="UTF-8" standalone="no"?> >-<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd"> >-<!--*- mode: xml -*--> >+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> >+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd"> >+ > <glade-interface> > <widget class="GtkDialog" id="vino_dialog"> > <property name="border_width">5</property> >@@ -358,8 +358,8 @@ > <property name="label" translatable="yes">General</property> > </widget> > <packing> >+ <property name="tab_fill">False</property> > <property name="type">tab</property> >- <property name="tab_fill">False</property> > </packing> > </child> > <child> >@@ -393,7 +393,6 @@ > <widget class="GtkImage" id="network_icon"> > <property name="visible">True</property> > <property name="yalign">0</property> >- <property name="stock">gtk-missing-image</property> > <property name="icon_size">6</property> > <property name="icon_name">gnome-fs-network</property> > </widget> >@@ -407,15 +406,35 @@ > <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK</property> > <property name="spacing">6</property> > <child> >- <widget class="GtkCheckButton" id="local_only_toggle"> >+ <widget class="GtkHBox" id="hbox2"> > <property name="visible">True</property> >- <property name="can_focus">True</property> >- <property name="has_tooltip">True</property> >- <property name="tooltip" translatable="yes">If checked, the server will only accept connections from localhost</property> >- <property name="label" translatable="yes">_Only allow local connections</property> >- <property name="use_underline">True</property> >- <property name="response_id">0</property> >- <property name="draw_indicator">True</property> >+ <child> >+ <widget class="GtkLabel" id="label4"> >+ <property name="visible">True</property> >+ <property name="tooltip" translatable="yes">listener in network interface selected, otherwise it will listen to all network interfaces.</property> >+ <property name="xalign">0</property> >+ <property name="xpad">20</property> >+ <property name="label" translatable="yes">Nework Interface:</property> >+ </widget> >+ <packing> >+ <property name="expand">False</property> >+ <property name="fill">False</property> >+ <property name="position">1</property> >+ </packing> >+ </child> >+ <child> >+ <widget class="GtkComboBox" id="network_interface_combox"> >+ <property name="visible">True</property> >+ <property name="tearoff_title">Click here to change the network interface!</property> >+ <property name="items" translatable="yes"></property> >+ </widget> >+ <packing> >+ <property name="expand">False</property> >+ <property name="fill">False</property> >+ <property name="pack_type">GTK_PACK_END</property> >+ <property name="position">1</property> >+ </packing> >+ </child> > </widget> > <packing> > <property name="expand">False</property> >@@ -501,7 +520,6 @@ > <widget class="GtkImage" id="network_icon2"> > <property name="visible">True</property> > <property name="yalign">0</property> >- <property name="stock">gtk-missing-image</property> > <property name="icon_size">6</property> > <property name="icon_name">system-lock-screen</property> > </widget> >@@ -571,7 +589,7 @@ > <property name="visible">True</property> > <property name="spacing">6</property> > <child> >- <widget class="GtkLabel" id="label1"> >+ <widget class="GtkLabel" id="label2"> > <property name="visible">True</property> > <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> > <property name="xalign">0</property> >@@ -588,7 +606,6 @@ > <widget class="GtkImage" id="notification_icon"> > <property name="visible">True</property> > <property name="yalign">0</property> >- <property name="stock">gtk-missing-image</property> > <property name="icon_size">6</property> > <property name="icon_name">gnome-panel-notification-area</property> > </widget> >@@ -668,15 +685,15 @@ > </packing> > </child> > <child> >- <widget class="GtkLabel" id="label2"> >+ <widget class="GtkLabel" id="label3"> > <property name="visible">True</property> > <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> > <property name="label" translatable="yes">Advanced</property> > </widget> > <packing> >- <property name="type">tab</property> > <property name="position">1</property> > <property name="tab_fill">False</property> >+ <property name="type">tab</property> > </packing> > </child> > </widget> >Index: capplet/vino-preferences.c >=================================================================== >--- capplet/vino-preferences.c (revision 840) >+++ capplet/vino-preferences.c (working copy) >@@ -30,6 +30,8 @@ > #include <libintl.h> > #include <unistd.h> > #include <netdb.h> >+#include <net/if.h> >+#include <ifaddrs.h> > #include <gtk/gtk.h> > #include <glade/glade.h> > #include <gconf/gconf-client.h> >@@ -49,7 +51,7 @@ > #define VINO_PREFS_VNC_PASSWORD VINO_PREFS_DIR "/vnc_password" > #define VINO_PREFS_MAILTO VINO_PREFS_DIR "/mailto" > #define VINO_PREFS_ICON_VISIBILITY VINO_PREFS_DIR "/icon_visibility" >-#define VINO_PREFS_LOCAL_ONLY VINO_PREFS_DIR "/local_only" >+#define VINO_PREFS_NETWORK_INTERFACE VINO_PREFS_DIR "/network_interface" > #define VINO_PREFS_ENCRYPTION VINO_PREFS_DIR "/require_encryption" > #define VINO_PREFS_USE_ALTERNATIVE_PORT VINO_PREFS_DIR "/use_alternative_port" > #define VINO_PREFS_ALTERNATIVE_PORT VINO_PREFS_DIR "/alternative_port" >@@ -78,7 +80,7 @@ > GtkWidget *icon_always_radio; > GtkWidget *icon_client_radio; > GtkWidget *icon_never_radio; >- GtkWidget *local_only_toggle; >+ GtkWidget *network_interface_combox; > GtkWidget *encryption_toggle; > GtkWidget *use_alternative_port_toggle; > GtkWidget *alternative_port_entry; >@@ -162,16 +164,16 @@ > vino_preferences_dialog_update_for_allowed (VinoPreferencesDialog *dialog, > gboolean allowed) > { >- gtk_widget_set_sensitive (dialog->prompt_enabled_toggle, allowed); >- gtk_widget_set_sensitive (dialog->view_only_toggle, allowed); >- gtk_widget_set_sensitive (dialog->url_labels_box, allowed); >- gtk_widget_set_sensitive (dialog->password_toggle, allowed); >- gtk_widget_set_sensitive (dialog->password_box, allowed ? dialog->use_password : FALSE); >- gtk_widget_set_sensitive (dialog->icon_always_radio, allowed); >- gtk_widget_set_sensitive (dialog->icon_client_radio, allowed); >- gtk_widget_set_sensitive (dialog->icon_never_radio, allowed); >- gtk_widget_set_sensitive (dialog->local_only_toggle, allowed); >- gtk_widget_set_sensitive (dialog->encryption_toggle, allowed); >+ gtk_widget_set_sensitive (dialog->prompt_enabled_toggle, allowed); >+ gtk_widget_set_sensitive (dialog->view_only_toggle, allowed); >+ gtk_widget_set_sensitive (dialog->url_labels_box, allowed); >+ gtk_widget_set_sensitive (dialog->password_toggle, allowed); >+ gtk_widget_set_sensitive (dialog->password_box, allowed ? dialog->use_password : FALSE); >+ gtk_widget_set_sensitive (dialog->icon_always_radio, allowed); >+ gtk_widget_set_sensitive (dialog->icon_client_radio, allowed); >+ gtk_widget_set_sensitive (dialog->icon_never_radio, allowed); >+ gtk_widget_set_sensitive (dialog->network_interface_combox, allowed); >+ gtk_widget_set_sensitive (dialog->encryption_toggle, allowed); > gtk_widget_set_sensitive (dialog->use_alternative_port_toggle, allowed); > gtk_widget_set_sensitive (dialog->alternative_port_entry, allowed && > gconf_client_get_bool (dialog->client, VINO_PREFS_USE_ALTERNATIVE_PORT, NULL)); >@@ -179,64 +181,146 @@ > } > > static void >-vino_preferences_dialog_local_only_toggled (GtkToggleButton *toggle, >- VinoPreferencesDialog *dialog) >+vino_preferences_load_network_interfaces (GList **list, >+ gint *pos) > { >- gboolean local_only; >+ struct ifaddrs *myaddrs, *ifa; > >- local_only = gtk_toggle_button_get_active (toggle); >+ g_assert (getifaddrs (&myaddrs) == 0); > >- gconf_client_set_bool (dialog->client, VINO_PREFS_LOCAL_ONLY, local_only, NULL); >+ for (ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next) >+ { >+ if (ifa->ifa_addr == NULL) >+ continue; >+ >+ if ((ifa->ifa_flags & IFF_UP) == 0) >+ continue; >+ >+ if ((ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6) && >+ ifa->ifa_name != NULL) >+ { >+ if(g_list_find_custom (*list, ifa->ifa_name, (GCompareFunc)g_strcasecmp) == NULL) >+ { >+ *list = g_list_append (*list, g_strdup (ifa->ifa_name)); >+ *pos += 1; >+ } >+ } >+ } >+ >+ *pos += 1; >+ *list = g_list_append (*list, g_strdup ("all")); >+ >+ freeifaddrs(myaddrs); > } > > static void >-vino_preferences_dialog_local_only_notify (GConfClient *client, >- guint cnx_id, >- GConfEntry *entry, >- VinoPreferencesDialog *dialog) >+vino_preferences_dialog_network_interface_update_combox (VinoPreferencesDialog *dialog, >+ const gchar *iface_default, >+ gboolean first_time) > { >- gboolean local_only; >+ GList *list = NULL; >+ gint pos = 0, here = 0; >+ const gchar *iface_check = iface_default; > >- if (!entry->value || entry->value->type != GCONF_VALUE_BOOL) >+ vino_preferences_load_network_interfaces (&list, &pos); >+ >+ g_return_if_fail (GTK_IS_COMBO_BOX (dialog->network_interface_combox)); >+ >+ if(iface_default == NULL) >+ { >+ iface_check = gconf_client_get_string (dialog->client, VINO_PREFS_NETWORK_INTERFACE, NULL); >+ } >+ >+ for(; list != NULL; list = g_list_next (list)) >+ { >+ const gchar *iface = list->data; >+ >+ if (iface != NULL) >+ { >+ pos -= 1; >+ >+ if (first_time) >+ { >+ gtk_combo_box_prepend_text (GTK_COMBO_BOX(dialog->network_interface_combox), iface); >+ } >+ >+ if (iface_check != NULL && !g_strcasecmp (iface, iface_check)) >+ { >+ here = pos; >+ iface_check = NULL; >+ } >+ } >+ } >+ >+ gtk_combo_box_set_active (GTK_COMBO_BOX(dialog->network_interface_combox), here); >+ >+ g_list_free (list); >+ list = NULL; >+} >+ >+static void >+vino_preferences_dialog_network_interface_notify (GConfClient *client, >+ guint cnx_id, >+ GConfEntry *entry, >+ VinoPreferencesDialog *dialog) >+{ >+ const gchar *network_interfaceOld = NULL; >+ const gchar *network_interfaceNew = NULL; >+ >+ if (!entry->value || entry->value->type != GCONF_VALUE_STRING) > return; > >- local_only = gconf_value_get_bool (entry->value) != FALSE; >+ network_interfaceNew = gconf_value_get_string (entry->value); >+ network_interfaceOld = gtk_combo_box_get_active_text (GTK_COMBO_BOX(dialog->network_interface_combox)); > >- if (local_only != gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->local_only_toggle))) >- { >- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->local_only_toggle), local_only); >- } >+ if (network_interfaceOld != NULL && network_interfaceNew != NULL && >+ g_strcasecmp (network_interfaceNew, network_interfaceOld) != 0) >+ { >+ vino_preferences_dialog_network_interface_update_combox (dialog, network_interfaceNew, FALSE); >+ } > } > >-static gboolean >-vino_preferences_dialog_setup_local_only_toggle (VinoPreferencesDialog *dialog) >+static void >+vino_preferences_dialog_network_interface_changed (gpointer unused, >+ VinoPreferencesDialog *dialog) > { >- gboolean local_only; >+ gchar *network_interface; > >- dialog->local_only_toggle = glade_xml_get_widget (dialog->xml, "local_only_toggle"); >- g_assert (dialog->local_only_toggle != NULL); >+ network_interface = gtk_combo_box_get_active_text(GTK_COMBO_BOX(dialog->network_interface_combox)); > >- local_only = gconf_client_get_bool (dialog->client, VINO_PREFS_LOCAL_ONLY, NULL); >+ if(network_interface != NULL) >+ { >+ if (!g_strcasecmp (network_interface, "all")) >+ gconf_client_set_string (dialog->client, VINO_PREFS_NETWORK_INTERFACE, "", NULL); >+ else >+ gconf_client_set_string (dialog->client, VINO_PREFS_NETWORK_INTERFACE, network_interface, NULL); >+ } >+} > >- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->local_only_toggle), local_only); >+static void >+vino_preferences_dialog_setup_network_interface_combox (VinoPreferencesDialog *dialog) >+{ >+ dialog->network_interface_combox = glade_xml_get_widget (dialog->xml, "network_interface_combox"); >+ g_assert (dialog->network_interface_combox != NULL); >+ >+ vino_preferences_dialog_network_interface_update_combox(dialog, NULL, TRUE); > >- g_signal_connect (dialog->local_only_toggle, "toggled", >- G_CALLBACK (vino_preferences_dialog_local_only_toggled), dialog); >+ g_signal_connect (dialog->network_interface_combox, "changed", >+ G_CALLBACK (vino_preferences_dialog_network_interface_changed), dialog); > >- if (!gconf_client_key_is_writable (dialog->client, VINO_PREFS_LOCAL_ONLY, NULL)) >+ if (!gconf_client_key_is_writable (dialog->client, VINO_PREFS_NETWORK_INTERFACE, NULL)) > { >- gtk_widget_set_sensitive (dialog->local_only_toggle, FALSE); >+ gtk_widget_set_sensitive (dialog->network_interface_combox, FALSE); > gtk_widget_show (dialog->writability_warning); > } > >- dialog->listeners [dialog->n_listeners] = >- gconf_client_notify_add (dialog->client, >- VINO_PREFS_LOCAL_ONLY, >- (GConfClientNotifyFunc) vino_preferences_dialog_local_only_notify, >- dialog, NULL, NULL); >+ dialog->listeners [dialog->n_listeners] = >+ gconf_client_notify_add (dialog->client, >+ VINO_PREFS_NETWORK_INTERFACE, >+ (GConfClientNotifyFunc) vino_preferences_dialog_network_interface_notify, >+ dialog, NULL, NULL); > dialog->n_listeners++; >- >- return local_only; > } > > static void >@@ -1041,6 +1125,7 @@ > G_CALLBACK (vino_preferences_server_updated), dialog, NULL); > } > >+#ifndef VINO_ENABLE_HTTP_SERVER > static int > vino_preferences_get_server_port (VinoPreferencesDialog *dialog) > { >@@ -1100,6 +1185,7 @@ > #undef VINO_MIN_PORT > #undef VINO_MAX_PORT > } >+#endif > > #ifdef VINO_ENABLE_HTTP_SERVER > static int >@@ -1426,13 +1512,13 @@ > > allowed = vino_preferences_dialog_setup_allowed_toggle (dialog); > >- vino_preferences_dialog_setup_prompt_enabled_toggle (dialog); >- vino_preferences_dialog_setup_view_only_toggle (dialog); >- vino_preferences_dialog_setup_password_toggle (dialog); >- vino_preferences_dialog_setup_password_entry (dialog); >- vino_preferences_dialog_setup_icon_visibility (dialog); >- vino_preferences_dialog_setup_local_only_toggle (dialog); >- vino_preferences_dialog_setup_encryption_toggle (dialog); >+ vino_preferences_dialog_setup_prompt_enabled_toggle (dialog); >+ vino_preferences_dialog_setup_view_only_toggle (dialog); >+ vino_preferences_dialog_setup_password_toggle (dialog); >+ vino_preferences_dialog_setup_password_entry (dialog); >+ vino_preferences_dialog_setup_icon_visibility (dialog); >+ vino_preferences_dialog_setup_network_interface_combox (dialog); >+ vino_preferences_dialog_setup_encryption_toggle (dialog); > vino_preferences_dialog_setup_alternative_port_entry (dialog); > vino_preferences_dialog_setup_use_alternative_port_toggle (dialog); > vino_preferences_dialog_setup_lock_screen_toggle (dialog); >@@ -1511,3 +1597,4 @@ > > return 0; > } >+
Created attachment 121387 [details] [review] new patch Hi! * I Remove the feature localOnly, added correct support for IPv4 mapped IPv6, and added a new feature to able to set network interface for accept connection. * I used the same base thath sshd to support a specific network interface and support ipv4 mapped ipv6. * This patch affect the tickets #403183,#403192,#384833,#488354
Created attachment 121487 [details] [review] fixed the correct support for IPv6, and listen in any network interface Hi! * I Remove the feature localOnly, added correct support for IPv4 mapped IPv6, and added a new feature to able to set network interface for accept connection. * I used the same base thath sshd to support a specific network interface and support ipv4 mapped ipv6. * This patch affect the tickets #403183,#403192,#384833,#488354
Created attachment 121586 [details] [review] fixed the correct support for IPv6, and listen in any network interface Hi! * I Remove the feature localOnly, added correct support for IPv4 mapped IPv6, and added a new feature to able to set network interface for accept connection. * I used the same base thath sshd to support a specific network interface and support ipv4 mapped ipv6. * This patch affect the tickets #403183,#403192,#384833,#488354
Created attachment 121709 [details] [review] final patch Hi! * I Remove the feature localOnly, added correct support for IPv4 mapped IPv6, and added a new feature to able to set network interface for accept connection. * I used the same base thath sshd to support a specific network interface and support ipv4 mapped ipv6. * This patch affect the tickets #403183,#403192,#384833,#488354 * final patch!
Okay, I'm sorry that I don't have time to review in much detail, but some more comments: - if the patch was broken down into smaller pieces (using e.g. quilt or git) we could review and commit the smaller pieces first. I'd split it up into e.g.: 1) Fix the subject of this bug by trying IPv6 first and falling back to IPv4 2) Add the network_interfaces property to GConf and hook it up in the server 3) Add the UI for the network interfaces property (I'm not sure we should do this at all, might be okay to leave it as GConf only) really, the smaller chunks the patch is broken into, the easier it is to get it in. - we should keep the local_only feature for now, IMHO - can we implement it so that if local_only is set, we ignore the network_interface configuration? - the network_interfaces property should be a list of strings, not a single string with interfaces separated by ','
Created attachment 123393 [details] [review] fixed the correct support for IPv6, and listen in any network interface done! ;)
Hey, Jorge! Thank you very much for your work on this. Just committed your patch. Stay tuned!