GNOME Bugzilla – Bug 544730
XDMCP broadcast discovery not working on BSD w/ ipv6 enabled
Last modified: 2010-06-16 21:19:04 UTC
Please describe the problem:
On FreeBSD and NetBSD, IPv6 support in GDM is usually enabled by default. In that case, XDMCP discovery of remote hosts through broadcast by gdmchooser will not work: GDM uses a mapped IPv4 address, e.g. ::ffff:172.18.1.255 that will not work on *BSD without disabling the IPV6_V6ONLY socket option first on the socket GDM uses for the broadcasts.
Steps to reproduce:
1. Select Remote XDMCP session -> gdmchooser can't find any hosts, tcpdump shows no packets on the wire on FreeBSD (and apparently NetBSD)
Chooser stays empty, no UDP broadcast packets to xdmcp port on the wire
Chooser discovers willing hosts, tcpdump showing packets
Does this happen every time?
In gui/gdmchooser.c, apply the following patch which is already in NetBSD's 'pkgsrc' and also works on FreeBSD (cut'n'paste, whitespacing may be broken):
@@ -1123,6 +1123,12 @@
have_ipv6 = FALSE;
have_ipv6 = TRUE;
+ /* Net- & FreeBSD default to V6ONLY */
+ int no = 0;
+ setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no));
I'm a little wary about applying a patch that looks like it hardcodes things to use IPv6. Has this been also tested in a variety of environments? It should probably be tested in the following situtions:
+ an IPv4 machine connecting to an IPv6 machine
+ an IPv4 machine connecting to an IPv4 machine
+ an IPv6 machine connecting to an IPv6 machine
+ an IPv6 machine connecting to an IPv4 machine
Does it work in all 4 common situations? I'd imagine this patch might need a little work to support all situations.
The patch addresses IPv4 to IPv4 with IPv6 enabled (but maybe not configured apart from link-local addressing). Note that GDM on BSD had enabled IPv6 before this patch already, but ONLY IPv6 without also supporting IPv4 on the same socket -- remember the we are switching OFF IPv6 ONLY through this instruction. Installations without IPv6 support are not affected at all through the patch (#ifdef'd).
The only other tests I can run are IPv6 using link-local fe80-addresses against our Sun Fire as server:
1) unpatched GDM: browser stays empty (cause for initial bug report)
2) I can manually add the fe80-address, but then after choosing the host through its IPv6 address doesn't work...the FreeBSD-side sees the IPv6 UDP packets coming in, but is stuck on the moiree X for a few seconds.
3) patched GDM: browser sees IPv4 hosts again (bug fix through patch)
4) manually adding the IPv6 address: same effect as 2)
So, to summarise you could say that IPv6 (at least in the link-local case) WAS and STAYS BROKEN on FreeBSD anyway, but the patch at least gets IPv4 going again. NetBSD pkgsrc has another patch along the same lines for daemon/gdm-xdmcp-manager.c, but this doesn't change anything on FreeBSD.
I will contact the NetBSD folks that came up with the patches, maybe they can help.
(I'm the person who came up with the NetBSD patches.)
The IPV6_V6ONLY patch above should not harm anything. It does only allow
the AF_INET6 socket to use v6 mapped IPv4 addresses. The gdm code assumes
this all over the place, and other systems allow this per default.
(It is considered a security risk by some people because one could
bypass firewall rules etc which were written for IPv4, that's why the BSDs
discourage v6 mapped v4 addresses.)
In the long term, I'd suggest to use seperate sockets for AF_INET and
AF_INET6. Seeing all that code which does only convert addresses forth
and back - this would be much simpler.
For me (on NetBSD), XDMCP works if I enter a _global_ IPv6 address.
I suspect problems with missing scope IDs cause that link-local
addresses fail. There are some uses of inet_ntop() and inet_pton()
which don't deal with scoped addresses correctly (here getaddrinfo()
and getnameinfo() should be used). There is likely more in X11 code.
To get ipv6 multicasts working, the chooser/Multicast configuration flag
needs to be set to "true". There is a bug in the chooser code which
makes it crash immediately if I try - wrong memory allocation. Changing
- tmp = "BROADCAST";
+ tmp = g_strdup("BROADCAST");
and likewise for MULTICAST helps.
As said, I still don't get a working session, but at least it
doesn't crash anymore. (This somehow indicates that IPv6 hasn't been
tested for a while, so I don't know whether bugs are BSD platform specific
issues or more general.)
The change you suggest to gui/gdmchooser.c to use g_strdup looks right to me. I went ahead and committed this fix to the 2.20 branch. I noticed a similar line later in the code where we set tmp = "MULTICAST" and I also use g_strup there since I think there would be the same issue there, but you are likely not running into it since it is in the IPv6 code.
I would like some further comment, and testing before accepting the IPV6_V6ONLY change upstream. It might be better if this were configurable, rather than the code just assuming to do this. Not sure. Anybody else have any thoughts?
You say the code assumes allowing the AF_INET6 socket to use v6 mapped IPv4 addresses "all over the place". Could you explain in more detail, and perhaps show me some examples? I would be more agreeable if you could show that this change really doesn't significantly mnodify the way the code works.
Note that the XDMCP code was pretty much rewritten by Jon McCann in the 2.19/2.20 release cycle, so the code is pretty new. We have had to fix a lot of regressions in this code to get it working again, so it doesn't surprise me to find another issue. If you have further XDMCP related fixes, please let me know. I'm happy to get any fixes upstream.
Just a HEADS UP, the impacts are coming closer: this may also become an issue on Linux soon, grep http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=560238 for GDM.
(In reply to comment #4)
> You say the code assumes allowing the AF_INET6 socket to use v6 mapped IPv4
> addresses "all over the place". Could you explain in more detail, and perhaps
> show me some examples? I would be more agreeable if you could show that this
> change really doesn't significantly mnodify the way the code works.
A few places with this assumption:
- the xdmcp display factory has only 1 socket fd, and open_port only calls do_bind(AF_INET) if the AF_INET6 one failed. When the v6only option is enabled, this socket will only listen for ipv6 packets. To change this without disabling the v6only option, it needs to be able to create a socket for every sockaddr returned by getaddrinfo, instead of just the first.
- likewise, GdmHostChooserWidgetPrivate only has one socket_fd. with v6only enabled, this would prevent talking to ipv4 hosts.
Disabling the IPV6_V6ONLY option explicitly is the easiest way to fix this, but if you prefer the other way (using multiple sockets) I suppose that can be done too.
Patches against current master are at
http://lists.debian.org/debian-devel/2010/04/msg00439.html and http://lists.debian.org/debian-devel/2010/04/msg00440.html
The patches look reasonable to me. Ray, what do you think?
Looks good. Pushed to 2-30 and master.