Discussion:
OpenBSD ignoring RFC-compliant IPv6 neighbor solicitation?
Martin Schmitt
2013-02-11 10:09:00 UTC
Permalink
All,

I got my first non-tunneled IPv6 uplink a while ago, and now I have
issues with NDP.

Over the same shared LAN, the ISP apparently serves several (more than
one, but as far as I can see not neccessarily more than two) customer
routers, with a logical /125 transfer network for each customer. What I
currently see, is this:

1) 2001:db8:1234:5678::08/125 <- Someone else's transfer network
2) 2001:db8:1234:5678::10/125 <- "My" transfer network

What happens now is that the ISP router sometimes sends neigbor
solicitation requests for my OpenBSD router using a source IP from its
proper physical interface, but a different logical network. In this
case: 2001:db8:1234:5678::9

When the NDP solicitations from 2001:db8:1234:5678::9 come in, OpenBSD
does not respond to them, apparently because their source IP doesn't
match the OpenBSD router's own prefix. The ISP router receives no
neighbor advertisement from my OpenBSD router, and deems it unreachable.
IPv6 is now down until a while later, when the solicitations happen to
come from 2001:db8:1234:5678::11 again.

RFC4861 says about the source IP for neighbor solicitations, that it has
to be "an address assigned to the interface from which this message is
sent". The ISP router firmware interprets this to mean "any address from
the interface", thus using an IP from a different logical subnet.
OpenBSD, in turn, does not seem to be willing to respond to requests
from a different subnet.

This was reproduced with OpenBSD 5.2-release, with pf turned off. It
also happens on the production router, which happens to still run
OpenBSD 4.6.

To try to better understand the issue, I also set up a Linux system
(Debian 6), which does in fact send advertisements in response to those
wrong-prefix solicitations.

What I understand is that either OpenBSD or the ISP router interpret the
RFC in a way that leads to unintended results.

Is this a bug in OpenBSD? Is there a workaround, e.g. in the form of a
sysctl or a pf.conf hack that will make OpenBSD's NDP more liberal?

Thanks for all input,

-martin
Stefan Sperling
2013-02-11 11:12:14 UTC
Permalink
Post by Martin Schmitt
All,
I got my first non-tunneled IPv6 uplink a while ago, and now I have
issues with NDP.
Over the same shared LAN, the ISP apparently serves several (more than
one, but as far as I can see not neccessarily more than two) customer
routers, with a logical /125 transfer network for each customer. What I
1) 2001:db8:1234:5678::08/125 <- Someone else's transfer network
2) 2001:db8:1234:5678::10/125 <- "My" transfer network
What happens now is that the ISP router sometimes sends neigbor
solicitation requests for my OpenBSD router using a source IP from its
proper physical interface, but a different logical network. In this
case: 2001:db8:1234:5678::9
When the NDP solicitations from 2001:db8:1234:5678::9 come in, OpenBSD
does not respond to them, apparently because their source IP doesn't
match the OpenBSD router's own prefix. The ISP router receives no
neighbor advertisement from my OpenBSD router, and deems it unreachable.
IPv6 is now down until a while later, when the solicitations happen to
come from 2001:db8:1234:5678::11 again.
RFC4861 says about the source IP for neighbor solicitations, that it has
to be "an address assigned to the interface from which this message is
sent". The ISP router firmware interprets this to mean "any address from
the interface", thus using an IP from a different logical subnet.
OpenBSD, in turn, does not seem to be willing to respond to requests
from a different subnet.
This was reproduced with OpenBSD 5.2-release, with pf turned off. It
also happens on the production router, which happens to still run
OpenBSD 4.6.
To try to better understand the issue, I also set up a Linux system
(Debian 6), which does in fact send advertisements in response to those
wrong-prefix solicitations.
What I understand is that either OpenBSD or the ISP router interpret the
RFC in a way that leads to unintended results.
Interesting problem. I'm not sure who's at fault here.

I'm surprised your ISP doesn't use link-local addresses for transfer
networks (mine does).

I believe the code path you're hitting is this one in netinet6/nd6_nbr.c,
in nd6_ns_input():

} else {
/*
* Make sure the source address is from a neighbor's address.
*/
if (!in6_ifpprefix(ifp, &saddr6)) {
nd6log((LOG_INFO, "nd6_ns_input: "
"NS packet from non-neighbor\n"));
goto bad;
}
}
Post by Martin Schmitt
Is this a bug in OpenBSD? Is there a workaround, e.g. in the form of a
sysctl or a pf.conf hack that will make OpenBSD's NDP more liberal?
Have you tried using a /64 netmask at your end of the transfer link,
instead of the /125?
Martin Schmitt
2013-02-11 11:51:54 UTC
Permalink
Post by Stefan Sperling
I believe the code path you're hitting is this one in netinet6/nd6_nbr.c,
} else {
/*
* Make sure the source address is from a neighbor's address.
*/
if (!in6_ifpprefix(ifp, &saddr6)) {
nd6log((LOG_INFO, "nd6_ns_input: "
"NS packet from non-neighbor\n"));
goto bad;
}
}
Thanks for your quick response!

The ISP has now worked around the issue by adding a fixed NDP entry for
my router's address so I can't really test with it, but I have added
another address on the interface, which gives me this, after sysctl
net.inet6.icmp6.nd6_debug=1:

nd6_ns_input: src=2001:0db8:1234:5678::0009
nd6_ns_input: dst=ff02:0001::0001:ff00:0015
nd6_ns_input: tgt=2001:0db8:1234:5678::0015
nd6_ns_input: NS packet from non-neighbor
Post by Stefan Sperling
Have you tried using a /64 netmask at your end of the transfer link,
instead of the /125?
I had already tried /123, which made it work. Such a workaround comes
across a bit desperate, because with further expansion of the ISP's IPv6
customer base, further widening of the prefix will be required. I'm not
sure whether this is how the uplink is intended to work and if it has
the potential to do any damage.

How is your understanding of NDP? Do you think OpenBSD is at fault for
ignoring these solicitations, or do you think the ISP router's OS
selects the wrong source IP? The wording in the RFC is really very terse
and leaves room for interpretation.

-martin

[demime 1.01d removed an attachment of type application/pgp-signature which had a name of signature.asc]
Stuart Henderson
2013-02-12 11:53:58 UTC
Permalink
Post by Martin Schmitt
Post by Stefan Sperling
I believe the code path you're hitting is this one in netinet6/nd6_nbr.c,
} else {
/*
* Make sure the source address is from a neighbor's address.
*/
if (!in6_ifpprefix(ifp, &saddr6)) {
nd6log((LOG_INFO, "nd6_ns_input: "
"NS packet from non-neighbor\n"));
goto bad;
}
}
Thanks for your quick response!
The ISP has now worked around the issue by adding a fixed NDP entry for
my router's address so I can't really test with it, but I have added
another address on the interface, which gives me this, after sysctl
nd6_ns_input: src=2001:0db8:1234:5678::0009
nd6_ns_input: dst=ff02:0001::0001:ff00:0015
nd6_ns_input: tgt=2001:0db8:1234:5678::0015
nd6_ns_input: NS packet from non-neighbor
Post by Stefan Sperling
Have you tried using a /64 netmask at your end of the transfer link,
instead of the /125?
I had already tried /123, which made it work. Such a workaround comes
across a bit desperate, because with further expansion of the ISP's IPv6
customer base, further widening of the prefix will be required. I'm not
sure whether this is how the uplink is intended to work and if it has
the potential to do any damage.
How is your understanding of NDP? Do you think OpenBSD is at fault for
ignoring these solicitations, or do you think the ISP router's OS
selects the wrong source IP? The wording in the RFC is really very terse
and leaves room for interpretation.
RFC 4861 says

If the source address of the packet prompting the solicitation is the
same as one of the addresses assigned to the outgoing interface, that
address SHOULD be placed in the IP Source Address of the outgoing
solicitation. Otherwise, any one of the addresses assigned to the
interface should be used.

so it would seem permissible for another address to appear here.
RFC 5942 updates RFC 4861 and to my reading it doesn't change this.

NetBSD will have the same problem btw, the check in nd6_nbr.c came
from there. The check goes beyond the validation specified by RFC
4861 7.1.1 (by itself this is not necessarily a problem, in some
cases it is eminently sensible to be stricter than RFC, but it
looks like we may possibly need to relax this here..).
Janne Johansson
2013-05-06 14:59:20 UTC
Permalink
I have now run into this problem also. (which sadly affects
anoncvs.eu.openbsd.org).
The router has another ip on a loopback interface somewhere which it thinks
is it's own "main" v6 ip, and then it sends it as the source ip of the
solictation.
This in turn means that my obsd wont respond to the NDP which makes the
router ignore my box and v6 anoncvs users don't get v6 access. 8-/

14:21:43.113824 2001:6b0:5:1::151 > ff02::1:ffa9:f5ba: icmp6: neighbor sol:
who
has 2001:6b0:5:1825:1c2f:5c1b:dfa9:f5ba

So the network segment is really 2001:6b0:5:1825/64 but the NDP'ing router
sends from 2001:6b0:5:1::151 instead which isn't inside the prefix of
course.

Grrr.
Post by Stefan Sperling
Post by Martin Schmitt
Post by Stefan Sperling
I believe the code path you're hitting is this one in
netinet6/nd6_nbr.c,
Post by Martin Schmitt
Post by Stefan Sperling
} else {
/*
* Make sure the source address is from a neighbor's
address.
Post by Martin Schmitt
Post by Stefan Sperling
*/
if (!in6_ifpprefix(ifp, &saddr6)) {
nd6log((LOG_INFO, "nd6_ns_input: "
"NS packet from non-neighbor\n"));
goto bad;
}
}
Thanks for your quick response!
The ISP has now worked around the issue by adding a fixed NDP entry for
my router's address so I can't really test with it, but I have added
another address on the interface, which gives me this, after sysctl
nd6_ns_input: src=2001:0db8:1234:5678::0009
nd6_ns_input: dst=ff02:0001::0001:ff00:0015
nd6_ns_input: tgt=2001:0db8:1234:5678::0015
nd6_ns_input: NS packet from non-neighbor
Post by Stefan Sperling
Have you tried using a /64 netmask at your end of the transfer link,
instead of the /125?
I had already tried /123, which made it work. Such a workaround comes
across a bit desperate, because with further expansion of the ISP's IPv6
customer base, further widening of the prefix will be required. I'm not
sure whether this is how the uplink is intended to work and if it has
the potential to do any damage.
How is your understanding of NDP? Do you think OpenBSD is at fault for
ignoring these solicitations, or do you think the ISP router's OS
selects the wrong source IP? The wording in the RFC is really very terse
and leaves room for interpretation.
RFC 4861 says
If the source address of the packet prompting the solicitation is the
same as one of the addresses assigned to the outgoing interface, that
address SHOULD be placed in the IP Source Address of the outgoing
solicitation. Otherwise, any one of the addresses assigned to the
interface should be used.
so it would seem permissible for another address to appear here.
RFC 5942 updates RFC 4861 and to my reading it doesn't change this.
NetBSD will have the same problem btw, the check in nd6_nbr.c came
from there. The check goes beyond the validation specified by RFC
4861 7.1.1 (by itself this is not necessarily a problem, in some
cases it is eminently sensible to be stricter than RFC, but it
looks like we may possibly need to relax this here..).
--
May the most significant bit of your life be positive.
Janne Johansson
2013-05-07 14:48:41 UTC
Permalink
this patch (stupidly) fixes my problem. I don't like my broken setup,
but this works.


Index: nd6_nbr.c
===================================================================
RCS file: /cvs/src/sys/netinet6/nd6_nbr.c,v
retrieving revision 1.66
diff -u -p -r1.66 nd6_nbr.c
--- nd6_nbr.c 7 Mar 2013 09:03:16 -0000 1.66
+++ nd6_nbr.c 7 May 2013 11:44:56 -0000
@@ -132,17 +132,7 @@ nd6_ns_input(struct mbuf *m, int off, in
"(wrong ip6 dst)\n"));
goto bad;
}
- } else {
- /*
- * Make sure the source address is from a neighbor's address.
- */
- if (!in6_ifpprefix(ifp, &saddr6)) {
- nd6log((LOG_INFO, "nd6_ns_input: "
- "NS packet from non-neighbor\n"));
- goto bad;
- }
}
-

if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
nd6log((LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n"));
Post by Janne Johansson
I have now run into this problem also. (which sadly affects
anoncvs.eu.openbsd.org).
The router has another ip on a loopback interface somewhere which it
thinks is it's own "main" v6 ip, and then it sends it as the source ip of
the solictation.
This in turn means that my obsd wont respond to the NDP which makes the
router ignore my box and v6 anoncvs users don't get v6 access. 8-/
14:21:43.113824 2001:6b0:5:1::151 > ff02::1:ffa9:f5ba: icmp6: neighbor
sol: who
has 2001:6b0:5:1825:1c2f:5c1b:dfa9:f5ba
So the network segment is really 2001:6b0:5:1825/64 but the NDP'ing router
sends from 2001:6b0:5:1::151 instead which isn't inside the prefix of
course.
Grrr.
Post by Stefan Sperling
Post by Martin Schmitt
Post by Stefan Sperling
I believe the code path you're hitting is this one in
netinet6/nd6_nbr.c,
Post by Martin Schmitt
Post by Stefan Sperling
} else {
/*
* Make sure the source address is from a neighbor's
address.
Post by Martin Schmitt
Post by Stefan Sperling
*/
if (!in6_ifpprefix(ifp, &saddr6)) {
nd6log((LOG_INFO, "nd6_ns_input: "
"NS packet from non-neighbor\n"));
goto bad;
}
}
Thanks for your quick response!
The ISP has now worked around the issue by adding a fixed NDP entry for
my router's address so I can't really test with it, but I have added
another address on the interface, which gives me this, after sysctl
nd6_ns_input: src=2001:0db8:1234:5678::0009
nd6_ns_input: dst=ff02:0001::0001:ff00:0015
nd6_ns_input: tgt=2001:0db8:1234:5678::0015
nd6_ns_input: NS packet from non-neighbor
Post by Stefan Sperling
Have you tried using a /64 netmask at your end of the transfer link,
instead of the /125?
I had already tried /123, which made it work. Such a workaround comes
across a bit desperate, because with further expansion of the ISP's IPv6
customer base, further widening of the prefix will be required. I'm not
sure whether this is how the uplink is intended to work and if it has
the potential to do any damage.
How is your understanding of NDP? Do you think OpenBSD is at fault for
ignoring these solicitations, or do you think the ISP router's OS
selects the wrong source IP? The wording in the RFC is really very terse
and leaves room for interpretation.
RFC 4861 says
If the source address of the packet prompting the solicitation is the
same as one of the addresses assigned to the outgoing interface, that
address SHOULD be placed in the IP Source Address of the outgoing
solicitation. Otherwise, any one of the addresses assigned to the
interface should be used.
so it would seem permissible for another address to appear here.
RFC 5942 updates RFC 4861 and to my reading it doesn't change this.
NetBSD will have the same problem btw, the check in nd6_nbr.c came
from there. The check goes beyond the validation specified by RFC
4861 7.1.1 (by itself this is not necessarily a problem, in some
cases it is eminently sensible to be stricter than RFC, but it
looks like we may possibly need to relax this here..).
--
May the most significant bit of your life be positive.
--
May the most significant bit of your life be positive.
Stefan Sperling
2013-05-07 16:26:21 UTC
Permalink
Post by Janne Johansson
this patch (stupidly) fixes my problem. I don't like my broken setup,
but this works.
We've determined the RFC doesn't require source addresses in
neighbour solicitations to be sent from a matching prefix.

I don't see any reason why responding to such solicitations is bad.
I agree with removing this check.
Post by Janne Johansson
Index: nd6_nbr.c
===================================================================
RCS file: /cvs/src/sys/netinet6/nd6_nbr.c,v
retrieving revision 1.66
diff -u -p -r1.66 nd6_nbr.c
--- nd6_nbr.c 7 Mar 2013 09:03:16 -0000 1.66
+++ nd6_nbr.c 7 May 2013 11:44:56 -0000
@@ -132,17 +132,7 @@ nd6_ns_input(struct mbuf *m, int off, in
"(wrong ip6 dst)\n"));
goto bad;
}
- } else {
- /*
- * Make sure the source address is from a neighbor's address.
- */
- if (!in6_ifpprefix(ifp, &saddr6)) {
- nd6log((LOG_INFO, "nd6_ns_input: "
- "NS packet from non-neighbor\n"));
- goto bad;
- }
}
-
if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
nd6log((LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n"));
Stefan Bagdohn
2013-05-07 19:16:25 UTC
Permalink
Wasn't this check introduced as mitigation of CVE-2008-2476 five years ago? E.g. http://ftp.openbsd.org/pub/OpenBSD/patches/4.4/common/001_ndp.patch
Post by Stefan Sperling
Post by Janne Johansson
this patch (stupidly) fixes my problem. I don't like my broken setup,
but this works.
We've determined the RFC doesn't require source addresses in
neighbour solicitations to be sent from a matching prefix.
I don't see any reason why responding to such solicitations is bad.
I agree with removing this check.
Post by Janne Johansson
Index: nd6_nbr.c
===================================================================
RCS file: /cvs/src/sys/netinet6/nd6_nbr.c,v
retrieving revision 1.66
diff -u -p -r1.66 nd6_nbr.c
--- nd6_nbr.c 7 Mar 2013 09:03:16 -0000 1.66
+++ nd6_nbr.c 7 May 2013 11:44:56 -0000
@@ -132,17 +132,7 @@ nd6_ns_input(struct mbuf *m, int off, in
"(wrong ip6 dst)\n"));
goto bad;
}
- } else {
- /*
- * Make sure the source address is from a neighbor's address.
- */
- if (!in6_ifpprefix(ifp, &saddr6)) {
- nd6log((LOG_INFO, "nd6_ns_input: "
- "NS packet from non-neighbor\n"));
- goto bad;
- }
}
-
if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
nd6log((LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n"));
Patrik Lundin
2013-05-07 21:02:25 UTC
Permalink
Post by Stefan Bagdohn
Wasn't this check introduced as mitigation of CVE-2008-2476 five years ago?
E.g. http://ftp.openbsd.org/pub/OpenBSD/patches/4.4/common/001_ndp.patch
Maby something along the lines of the 'nd6_onlink_ns_rfc4861' sysctl
flag mentioned at
http://www.freebsd.org/security/advisories/FreeBSD-SA-08:10.nd6.asc
could be used for the odd cases where it's needed?

Regards,
Patrik Lundin
Todd T. Fries
2013-05-07 21:49:25 UTC
Permalink
Penned by Patrik Lundin on 20130507 16:02.25, we have:
| On Tue, May 07, 2013 at 09:16:25PM +0200, Stefan Bagdohn wrote:
| > Wasn't this check introduced as mitigation of CVE-2008-2476 five years ago?
| > E.g. http://ftp.openbsd.org/pub/OpenBSD/patches/4.4/common/001_ndp.patch
| >
|
| Maby something along the lines of the 'nd6_onlink_ns_rfc4861' sysctl
| flag mentioned at
| http://www.freebsd.org/security/advisories/FreeBSD-SA-08:10.nd6.asc
| could be used for the odd cases where it's needed?
|
| Regards,
| Patrik Lundin

This makes the most sense to me. Otherwise, someone should fix their
broken router.
--
Todd Fries .. ***@fries.net

____________________________________________
| \ 1.636.410.0632 (voice)
| Free Daemon Consulting, LLC \ 1.405.227.9094 (voice)
| http://FreeDaemonConsulting.com \ 1.866.792.3418 (FAX)
| PO Box 16169, Oklahoma City, OK 73113 \ sip:***@ekiga.net
| "..in support of free software solutions." \ sip:***@ekiga.net
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

37E7 D3EB 74D0 8D66 A68D B866 0326 204E 3F42 004A
http://todd.fries.net/pgp.txt
Stefan Bagdohn
2013-05-08 05:31:33 UTC
Permalink
Post by Patrik Lundin
Maby something along the lines of the 'nd6_onlink_ns_rfc4861' sysctl
flag mentioned at
http://www.freebsd.org/security/advisories/FreeBSD-SA-08:10.nd6.asc
could be used for the odd cases where it's needed?
This is an all-or-nothing approach. What about the option to provide the "known-good" address of the router (via sysctl or by other means)?
If an address is given, treat this exception as a neighbor. If left empty, just behave as-is.
Janne Johansson
2013-05-08 06:14:58 UTC
Permalink
Not that I have a better suggestion than yours, but I don't like
"whitelisting" at the ip level. If I have multiple trusted routers this
ends up as a long shell-script that tries to feed ips until it works.
I can see a point (for both v4 and v6) to sometimes lock the arp/ndp for
your def-gw so that noone else can trivially spoof the gw ip, but adding
the gws own idea of some other ip it has to a whitelist of acceptable
senders of ndp feels like a layering violation to me.
Post by Stefan Bagdohn
Post by Patrik Lundin
Maby something along the lines of the 'nd6_onlink_ns_rfc4861' sysctl
flag mentioned at
http://www.freebsd.org/security/advisories/FreeBSD-SA-08:10.nd6.asc
could be used for the odd cases where it's needed?
This is an all-or-nothing approach. What about the option to provide the
"known-good" address of the router (via sysctl or by other means)?
If an address is given, treat this exception as a neighbor. If left empty,
just behave as-is.
--
May the most significant bit of your life be positive.
Stefan Bagdohn
2013-05-08 09:09:36 UTC
Permalink
Right. This is not a clean solution, but the only one that came to my mind, as it does not disable the check completely.
If desired, an option for disabling the check completely could be an addition.
Not that I have a better suggestion than yours, but I don't like "whitelisting" at the ip level.
Stefan Sperling
2013-05-07 22:01:22 UTC
Permalink
Post by Stefan Bagdohn
Wasn't this check introduced as mitigation of CVE-2008-2476 five years ago? E.g. http://ftp.openbsd.org/pub/OpenBSD/patches/4.4/common/001_ndp.patch
Right, thanks for pointing that out.
Claudio added this check in 2008. RFC 4861 is older than that.
I should have used cvs blame first. This issue definitely needs
more thought.
Loading...