IPv6 Patch

Tomash Brechko tomash.brechko at gmail.com
Fri Feb 1 09:03:19 UTC 2008


On Thu, Jan 31, 2008 at 14:03:56 -0800, dormando wrote:
> getaddrinfo() returns a list.
> If you're setting the AI_ADDRCONFIG flag it'll at least only return 
> addresses which are available on the interface (ipv6 only, etc).


> But if a hostname returns multiple addresses (getaddrinfo(NULL, ...)) 
> and the host might be a dedicated server with a private net, it'll bind 
> to both the public address and private address?

More than one address may be returned even if you specify
getaddrinfo(host_name, ...).  Yes, it will bind to all addresses
regardless of their scope.

> I'm not entirely clear on the conditions where getaddrinfo would suggest 
> you bind to both a public and a private address, unless you're binding 
> to INADDR_ANY, which I _believe_ is the present default for memcached, 
> and will certainly bind to any public IP if it exists.

Yep, current memcached behaviour is either INADDR_ANY, or a single IP
address specified with -l.  If we would bind to all addresses returned
by getaddrinfo(), we will get this very behaviour (when the user gives
IP address, not host name, to -l).  POSIX says:

  If  the  AI_PASSIVE flag is specified, the returned address information
  shall be suitable for use in binding a socket  for  accepting  incoming
  connections  for  the  specified service. In this case, if the nodename
  argument is null, then the IP address portion  of  the  socket  address
  structure   shall   be  set  to  INADDR_ANY  for  an  IPv4  address  or
  IN6ADDR_ANY_INIT for an IPv6 address.

As a bonus, when the user would give a host name to -l, it will
resolve to one or several addresses, and memcached will bind to them
all.  This is natural, several addresses were connected to one host
name in DNS exactly with the purpose that they all will be used for
this name.

> Could someone perhaps clear it up a bit? Is this identical or different 
> to the present IPv4 default behavior, and if this is going to be 
> different, we might need a new option to accomodate.

On server side, this is identical.  On client side (without
AI_PASSIVE) there's a subtle difference (that again will leave no
choice but to use all addresses returned), but this is irrelevant to

> IE; if someone wants to bind to a private-network in IPv4 land, they
> presently use -l, but if you're binding by hostname in IPv6, it
> makes sense (to me) to continue to allow someone to select a private
> address.

There's no way for memcached to automatically distinct between private
and public address.  You may relay on the address class, but the truth
is the whole public/private stuff for IPv4 is controlled by your NAT

The user will still have a full control if he gives IP address (v4 or
v6) to -l.  It would make sense to allow several -l for flexibility
then.  Right now I would have to create a DNS record for a set of
addresses I want to use, and then use -l set_name to bind to them all
(that is, if we process all results of getaddrinfo()).

Let me stress this again: first returned address is in no way special.
Or rather, it is special as it "has the best chances to succeed", but
this is more relevant to the client side.  Actually the return order
may be configured for a site, and the first returned may be any of
loopback, site-local, or globally scoped address.  More to that, since
getaddrinfo() can't know how you would use the address, for AI_PASSIVE
the address with "the best chances to succeed" is likely a global
externally visible address ;) (if you use host name, that is,
otherwise it will be INADDR_ANY or IN6ADDR_ANY_INIT).  More to that,
there's the line in Drepper's:

  But it is possible to accept an IPv4 connection with an IPv6
  socket. The address returned by the accept() call is an V4-mapped
  IPv6 address. What this means is that if a server is meant to accept
  IPv4 and IPv6 connections the server has to bind an IPv6 socket. For
  the benefits of systems which allow/require binding an IPv4 and IPv6
  socket the server code still iterates over all addresses returned by

(note "require").  It seems there are systems that require to bind
both IPv6 and IPv4 sockets if you are going to accept connections with
both protocols.  http://en.wikipedia.org/wiki/IPv4_mapped_address

  Some common IPv6 stacks do not support this mechanism, either
  because the IPv6 and IPv4 are separate (Microsoft Windows prior to
  Vista/Longhorn: e.g. XP/2003), or because of security concerns
  (OpenBSD). On these operating systems, it is necessary to open a
  separate socket for each IP protocol that is to be supported. On
  some systems (e.g., NetBSD, FreeBSD) this feature is controlled by
  the option IPV6_V6ONLY per socket as specified in RFC 3493.

Even if the system can accept IPv4 connection on IPv6 socket, as Linux
does, you have to bind IPv6 socket to an IPv4-mapped address
(otherwise you won't be able to connect with IPv4 address).  As you
guess, there's no guarantee that the first returned address is such.

BTW, that "bug" of OS X 10.5 that was mentioned earlier may not be a
bug at all: if you iterate over all returned addresses, skipping those
you can't bind to, you'll eventually succeed (at least because there's
an IPv4 address down the list).  So disabling IPv6 for UDP is an
incorrect workaround.  This would also solve the problem with "older
glibc returns garbage".

Brian, if you have any pointers to papers describing the technique you
propose (use only the first address), sharing them would be very
appreciated.  However, if that's your own invention, then I suggest
for memcached to stay with the mainstream and be as much secure as the
rest of the world, at least until this technique will be widely
recognized and adopted.  Forever I guess... ;)

   Tomash Brechko

More information about the memcached mailing list