Bug 512032 - Lack of support for ipv6 source address selection in openssh client.
Lack of support for ipv6 source address selection in openssh client.
Product: Fedora
Classification: Fedora
Component: openssh (Show other bugs)
All Linux
low Severity low
: ---
: ---
Assigned To: Jan F. Chadima
Fedora Extras Quality Assurance
Depends On:
  Show dependency treegraph
Reported: 2009-07-15 20:25 EDT by Maciej Żenczykowski
Modified: 2017-03-23 16:19 EDT (History)
7 users (show)

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Last Closed: 2011-08-15 02:41:30 EDT
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---

Attachments (Terms of Use)
first attempt at a patch: spec file (792 bytes, patch)
2009-10-06 00:01 EDT, Maciej Żenczykowski
no flags Details | Diff
first attempt at a patch: patch proper (7.16 KB, patch)
2009-10-06 00:02 EDT, Maciej Żenczykowski
no flags Details | Diff

  None (edit)
Description Maciej Żenczykowski 2009-07-15 20:25:30 EDT
The ssh client should include an option to choose IPv6 socket options for outgoing connection source address selection.  Indeed the default should probably be to select the public address (instead of letting the kernel autoselect) - otherwise, if you have ipv6 privacy extensions configured outgoing ssh connections eventually break as the source address expires (by default a new one is generated daily and old ones expire after 7 days).

You are affected if use_tempaddr on the outgoing interface is set to 2 (please note this setting can only be meaningfully changed on a down'ed interface).

For example:
/proc/sys/net/ipv6/conf/${INTERFACE}/use_tempaddr: 2
/proc/sys/net/ipv6/conf/${INTERFACE}/temp_prefered_lft: 86400
/proc/sys/net/ipv6/conf/${INTERFACE}/temp_valid_lft: 604800

To quote linux+v2.6.29.6/include/linux/in6.h:

/* RFC5014: Source address selection */

#define IPV6_PREFER_SRC_TMP             0x0001
#define IPV6_PREFER_SRC_PUBLIC          0x0002
#define IPV6_PREFER_SRC_COA             0x0004
#define IPV6_PREFER_SRC_HOME            0x0400
#define IPV6_PREFER_SRC_CGA             0x0008
#define IPV6_PREFER_SRC_NONCGA          0x0800

so you need to call
setsockopt(socket, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES, &value, sizeof(value)).

Supported should probably be values of 'default', 'tmp', 'public' and an explicit integer value.
Comment 1 Maciej Żenczykowski 2009-10-06 00:01:51 EDT
Created attachment 363770 [details]
first attempt at a patch: spec file
Comment 2 Maciej Żenczykowski 2009-10-06 00:02:43 EDT
Created attachment 363771 [details]
first attempt at a patch: patch proper
Comment 3 Maciej Żenczykowski 2009-10-06 00:05:12 EDT
First attempt at a patch which adds this support.
As yet, untested (although it does build).

The main problem seems to be that the constants aren't defined outside of <linux/in6.h> (or <linux/ipv6.h>) which includes them.

AFAICT openssh appears not to use linux specific include files...
Not sure how to procede...
Comment 4 Maciej Żenczykowski 2009-10-06 00:17:18 EDT
Patch appears to function.

- v4 works normally

$ ssh -4 root@fate 'lsof -i -n' | egrep '^ssh.*ESTABLISHED'
sshd      4201     root    3r  IPv4 919505      0t0  TCP> (ESTABLISHED)

- v6 defaults to asking for public ip

$ ssh -6 root@fate 'lsof -i -n' | egrep '^ssh.*ESTABLISHED'
sshd      4204     root    3r  IPv6 919579      0t0  TCP [A:B:C:D::2]:ssh->[D:E:A:D:21f:5bff:fee8:xxxx]:37626 (ESTABLISHED)

- if you ask for none, we skip the setsockopt and get the kernel default of tmp ip (use_tempaddr == 2)

$ ssh -6 -o IPv6AddressPreference=none root@fate 'lsof -i -n' | egrep '^ssh.*ESTABLISHED'
sshd      4207     root    3r  IPv6 919653      0t0  TCP [A:B:C:D::2]:ssh->[D:E:A:D:e811:55f:6eda:yyyy]:55648 (ESTABLISHED)

- if you ask for tmp, you get it

$ ssh -6 -o IPv6AddressPreference=tmp root@fate 'lsof -i -n' | egrep '^ssh.*ESTABLISHED'
sshd      4210     root    3r  IPv6 919745      0t0  TCP [A:B:C:D::2]:ssh->[D:E:A:D:e811:55f:6eda:yyyy]:55650 (ESTABLISHED)

- if you ask for public, you get it

$ ssh -6 -o IPv6AddressPreference=public root@fate 'lsof -i -n' | egrep '^ssh.*ESTABLISHED'
sshd      4213     root    3r  IPv6 919841      0t0  TCP [A:B:C:D::2]:ssh->[D:E:A:D:21f:5bff:fee8:xxxx]:53395 (ESTABLISHED)

How do we proceed from here?
Comment 5 Maciej Żenczykowski 2009-10-06 00:21:44 EDT
Oh, one last thing.

- if you pass in '1' (tmp): it works

- if you pass in '2' (public): it works

- if you pass in a numeric value that the kernel doesn't like
$ ssh -6 -o IPv6AddressPreference=3 root@fate 'lsof -i -n' | egrep '^ssh.*ESTABLISHED'
setsockopt(..., IPV6_ADDR_PREFERENCES, [3]): Invalid argument
sshd      4219     root    3r  IPv6 919958      0t0  TCP [A:B:C:D::2]:ssh->[2620:0:1000:1301:e811:55f:6eda:yyyy]:37349 (ESTABLISHED)

You get an error message (error message appears to be on stdout), but the connection still succeeds.
Comment 6 Jan F. Chadima 2009-10-06 05:52:17 EDT
Have you sent the patch upstream?
Comment 7 Maciej Żenczykowski 2009-10-06 06:17:47 EDT
No, I haven't, yet.

I'm wondering where to pull the constants from, and how linux specific this is...
I also still have to clean the patch up.
Comment 8 Maciej Żenczykowski 2009-10-06 06:52:17 EDT
From the kernel source (and the RFC), it looks like you can set one of:

#define IPV6_PREFER_SRC_TMP             0x0001
#define IPV6_PREFER_SRC_PUBLIC          0x0002

(the last being effectively 0)

and one of:

#define IPV6_PREFER_SRC_COA             0x0004
#define IPV6_PREFER_SRC_HOME            0x0400

(the last being effectively 0)

and one of:

#define IPV6_PREFER_SRC_CGA             0x0008
#define IPV6_PREFER_SRC_NONCGA          0x0800

(the last being effectively 0, and the first being currently unimplemented in linux)

The flags which I mention are effectively zero, allow you to clear a previously set flag from that group, but don't actually get retained in the kernel socket state.

To me this suggests the default value should actually be IPV6_PREFER_SRC_PUBLIC | IPV6_PREFER_SRC_HOME | IPV6_PREFER_SRC_NONCGA.
The meaning is: prefer a public IP (temp ones could expire), prefer a home ip (instead of a care-of-address, this is for mobility on the client/roadwarrior), prefer a non care-give-address ip (again for mobility on the server/gateway).

Current linux default behaviour is PUBTMP_DEFAULT | HOME | NONCGA.  Where whether PUBTMP_DEFAULT means PUBLIC or TMP depends on a configuration setting of the output interface.

Since ssh connections have a tendency to be looong, and are usually to servers which we trust at least a little bit, using the longest duration source IP seems appropriate.  This implies PUBLIC, not TMP or PUBTMP_DEFAULT.  This also implies HOME - not COA, and to a lesser degree NONCGA - not CGA.

I'll make the changes.

This also clearly needs a better way to be specified in the config file.

Maybe I should split this into 3 separate options?

The RFC specifies the flag names, but not their values, they're supposed to be a result of #include <netinet/in.h>.
As such encoding the values directly into the patch would be linux specific.  

The values also apparently haven't yet made it into netinet/in.h (at least in F11).  I see them only in linux/in6.h and indirectly in linux/ipv6.h.

Further reading the RFC, it looks like the patch has to be further modified to add the flag values to the initial getaddrinfo call.  Since dst address selection (may) depend on src address selection, and as such the getaddrinfo call needs to have something along the lines of:

preferences = IPV6_PREFER_SRC_TMP;

hints.ai_flags |= AI_EXTFLAGS;
hints.ai_eflags = preferences;
/* Fill in other hints fields */

getaddrinfo(....,&hints,. &ai0..);

I'll take another stab at this.
Comment 9 Maciej Żenczykowski 2009-10-06 07:12:10 EDT
CGA = cryptographically generated addresses, and not care-giver-address, doesn't change the fact we want NONCGA as default IMHO.

The RFC seems to make no reference of which header file should define IPV6_ADDR_PREFERENCES.

It also appears that IPV6_PREFER_SRC_PUBTMP_DEFAULT is Linux specific.  The RFC specifies the default to be IPV6_PREFER_SRC_PUBLIC and makes no mention of PUBTMP_DEFAULT.
Comment 10 Bug Zapper 2010-04-27 11:42:48 EDT
This message is a reminder that Fedora 11 is nearing its end of life.
Approximately 30 (thirty) days from now Fedora will stop maintaining
and issuing updates for Fedora 11.  It is Fedora's policy to close all
bug reports from releases that are no longer maintained.  At that time
this bug will be closed as WONTFIX if it remains open with a Fedora 
'version' of '11'.

Package Maintainer: If you wish for this bug to remain open because you
plan to fix it in a currently maintained version, simply change the 'version' 
to a later Fedora version prior to Fedora 11's end of life.

Bug Reporter: Thank you for reporting this issue and we are sorry that 
we may not be able to fix it before Fedora 11 is end of life.  If you 
would still like to see this bug fixed and are able to reproduce it 
against a later version of Fedora please change the 'version' of this 
bug to the applicable version.  If you are unable to change the version, 
please add a comment here and someone will do it for you.

Although we aim to fix as many bugs as possible during every release's 
lifetime, sometimes those efforts are overtaken by events.  Often a 
more recent Fedora release includes newer upstream software that fixes 
bugs or makes them obsolete.

The process we are following is described here: 
Comment 11 Maciej Żenczykowski 2010-04-27 23:40:57 EDT
Still present in F12, I should really get back around to fixing this...
Comment 12 Jan F. Chadima 2010-04-28 03:12:09 EDT
If the values of the constants are RFC-based, make own header in openssh sources, or maybe the compat sources, using linux headers if exists (configure.ac is your friend) and send it upstream please. Without it I can NOT accept it.
Comment 13 Jan F. Chadima 2010-06-07 04:53:21 EDT
Do you plan to provide the patch and send it upstream?
Comment 14 Jan F. Chadima 2010-09-14 09:45:07 EDT
Reporter, can you please respond? Without it I'll have to close this request
Comment 15 Maciej Żenczykowski 2010-09-17 03:17:06 EDT
I do very much plan to get this done, unfortunately I just haven't had the time to work on it lately.  However, this has sat around for way too long, I'll try and take another stab at the patch soon.
Comment 16 Jan F. Chadima 2010-09-17 03:44:57 EDT
Maciej thans you.
Comment 17 Sebastian Goll 2010-11-11 07:53:24 EST
Any chance of seeing this patch go upstream to be included in the official OpenSSH release soon? I am using Debian GNU/Linux and would very much like to take advantage of the functionality described in this report, which, apparently, is still missing from OpenSSH as of November 2010.

The problem seems to be to make this patch more portable but unfortunately the general API described in RFC 5014 is still not available in <netinet/in.h> and <netdb.h> as suggested by the RFC, at least not on my system. On Linux, it is available through <linux/in6.h> but including that directly results in a redefinition of 'struct in6_addr', amongst others.

I am lacking the skills required for cleaning up and submitting this patch, but maybe Maciej or somebody else can look into it. Another idea would be to just send the patch as-is to the OpenSSH dev mailing list and see if someone over there can finish the work.

It would be a terrible shame if this patch was lost in this bug report.
Comment 18 Jan F. Chadima 2010-11-20 07:25:25 EST
Maciej do you plan to finish this patch soon?
Comment 19 Jan F. Chadima 2011-05-24 11:54:59 EDT
Comment 20 Jan F. Chadima 2011-08-15 02:41:30 EDT
Closed for lack of data. You can re-open anytime you want.

Note You need to log in before you can comment on or make changes to this bug.