Subject: RFC3484 problem: scoping with site-locals/ULAs

From: Pekka Savola <[email-masked]>
Date: Tue, 9 May 2006 17:27:16 +0300 (EEST)

Hi,

I was alerted to a practical deployment problem. As a result Linux 
glibc has started prefering IPv4 by default... so, I believe we need 
to find a better solution.

1) v6 site-local address selection problems

A site has deployed IPv6 site-local addresses (alongside with NATed 
v4).  They do not have global IPv6 reachability yet, but want to test 
IPv6 alongside IPv4 internally.

As a result, RFC 3484 address selection breaks: when trying to connect 
to a hostname with a public IPv4 and IPv6 address, the host will first 
try v6 fails (incurring about 3 min TCP timeout if ICMP error is not 
sent), and after that connects to the v4 address.

I.e., 'prefer matching scope' has v6 globals and site-locals, while v4 
has globals and private v4 addresses, and v6 wins, with bad results.

An easy fix could be that v4 is preferable to v6 if both have 
mismatching scope as v4 is likely to be NATed while v6 isn't.

Has anyone else run into this problem?  Is there something I'm 
missing?  What has been the implementation (or deployment) approach 
here?

(I don't believe using RFC 4191 to advertise only the site-local 
prefix instead of a default route is a feasible solution here. 
Likewise, requiring that routers will always send back an ICMP error 
and the host gets it and honors it seems unfeasible in general.)

2) v6 ULA address selection problems

Deploying ULAs doesn't help here, it just makes the problem worse as 
you couldn't even use the 'matching scope' tweak.

Do we need to specify that v6 ULAs should be treated as "site scope" 
for the purposes of default address selection, or something else?

Note that I do not believe it's sufficient to require that each site 
(and each host within the site) deploys non-default RFC3484 policies.

-- 
Pekka Savola                 "You each name yourselves king, yet the
Netcore Oy                    kingdom bleeds."
Systems. Networks. Security. -- George R.R. Martin: A Clash of Kings

---

From: Rémi Denis-Courmont <[email-masked]>
Date: Tue, 9 May 2006 18:32:15 +0300

> 1) v6 site-local address selection problems

I assume you refer to the deprecated but Linux kernel-supported 
site-local fec0::/12 address space (not sure if it is /12 - but 
anyway).

> As a result, RFC 3484 address selection breaks: when trying to
> connect to a hostname with a public IPv4 and IPv6 address, the host
> will first try v6 fails (incurring about 3 min TCP timeout if ICMP
> error is not sent), and after that connects to the v4 address.

I am pretty sure it used to work “properly”... when trying to connect() 
to some public IPv6 address while the host only had link-local and 
site-local addresses, the stack would immediatly (non-blocking) address 
unreachable. Then software using the getaddrinfo() paradigm would 
fallback to IPv4 without the user noticing any delay. But then indeed, 
it seems to be now broken.

> you couldn't even use the 'matching scope' tweak.

Yes, I definitely have had these issues. Since ULA have global scope, 
there is no way to detect the issue there.

Another (Linux-specific) issue is that source address selection is 
completely broken, so if you have both public addresses and ULAs on the 
host, the stack might be an ULA (non-routable!) address as source when 
sending packets toward a public address. But that, I guess, it because 
Linux does not implement source address selection properly.

That said I don't think defaulting to IPv4 in libc is wise, and it will 
actually break in other case. Linux users should probably rather 
refrain from using ULAs until their OS supports them properly.
I'm actually pretty sure some apps rely on getaddrinfo() returning 
AF_INET6 entries before AF_INET. Inverting the ordering might cause 
serious troubles there.
This is ***definitely*** going to break listening TCP socket 
applications that relied on IPv6-mapped IPv4 addresses to catch both IP 
protocol versions with a single socket. This includes noteworthy Apache 
httpd 2 and OpenSSH, and probably a bunch of other server apps. This 
could, to a lesser extent also affect the UDP and “outgoing” TCP 
cases... in fact, whenever one uses IPv6-mapped IPv4 addresses.

-- 
Rémi Denis-Courmont
http://www.simphalempin.com/home/

---

From: Fred Baker <[email-masked]>
Date: Wed, 10 May 2006 08:30:41 -0700

So I have a dumb question.

Why not:
	- use a DNS lookup that asks for all records (including A, MX, and  
AAAA)
	- open both a v4 and a v6 connection simultaneously
	- accept the first to successfully open and shut down all others

Down sides: It gets all of the DNS data, which may be more than it  
wanted to know, and it issues a second SYN-or-whatever, and in the  
worst case one to each address. But it deterministically finds a  
solution that works and gives the system the service it is looking for.

I the big picture, the problem with that behavior is what?

On May 9, 2006, at 7:27 AM, Pekka Savola wrote:

> glibc has started prefering IPv4 by default... so, I believe we  
> need to find a better solution.
>
> v4).  They do not have global IPv6 reachability yet, but want to  
> test IPv6 alongside IPv4 internally.
>
> I.e., 'prefer matching scope' has v6 globals and site-locals, while  
> v4 has globals and private v4 addresses, and v6 wins, with bad  
> results.
>
> Likewise, requiring that routers will always send back an ICMP  
> error and the host gets it and honors it seems unfeasible in general.)
>
> Deploying ULAs doesn't help here, it just makes the problem worse  
> as you couldn't even use the 'matching scope' tweak.
>
> Do we need to specify that v6 ULAs should be treated as "site  
> scope" for the purposes of default address selection, or something  
> else?
>
> Note that I do not believe it's sufficient to require that each  
> site (and each host within the site) deploys non-default RFC3484  
> policies.
>
> --

---

From: Havard Eidnes <[email-masked]>
Date: Thu, 11 May 2006 10:17:42 +0200 (CEST)

> 	- use a DNS lookup that asks for all records (including A, MX, and  

Because you can't do this with a single DNS query.  The "ANY" query
type will return all the records/record types cached for a given name,
but there is no guarantee that the cache has been filled with all the
information available on the authoritative name servers for the given
name.  Individual RRsets (name+type) can have different TTLs, so even
if the cache was filled with all the information initially, a caching
name server can't guarantee that will always be the case at a later
time.

That's a minor detail, though -- one or two DNS queries doesn't make
much of a difference.

> 	- accept the first to successfully open and shut down all others

I think that the TCP connect operations are typically synchronous at
the user/kernel interface.  Doing several connection attempts in
parallel is therefore at best problematical.  Using pthreads could
possibly be a workaround, but mandating use of pthreads for all
applications for using the C library is, I think, not acceptable.

Regards,

- Håvard

---

From: Erik Nordmark <[email-masked]>
Date: Fri, 12 May 2006 13:50:50 -0700

Fred Baker wrote:
> wanted to know, and it issues a second SYN-or-whatever, and in the worst 
> case one to each address. But it deterministically finds a solution that 
> works and gives the system the service it is looking for.
> 

In the big picture, I think that's the direction we need to move.
But I don't think we want to have every application have that logic, 
since the logic might need to evolve over time (and needs to take into 
account Alain's example of umpteen different IP addresses - might want 
to stagger the attempts when there are lots of IP addresses to try.)

So instead I think we want to raise the abstraction layer for the 
applications by introducing a connect-by-name socket API so that the 
application just hands in the FQDN and the port number to which it wants 
to connect.

It isn't hard to come up with an initial cut of a connect-by-name 
implementation entirely as a library routine (using non-blocking sockets 
for the connect() system calls so that multiple can be outstanding and 
the same time.)

    Erik