NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
kern/51280: if_srt fails to correctly route IPv6 packets (+ potential fix)
>Number: 51280
>Category: kern
>Synopsis: if_srt fails to correctly route IPv6 packets (+ potential fix)
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Mon Jun 27 01:20:01 +0000 2016
>Originator: Robert Elz
>Release: NetBSD 7.99.32 (and everything since srt(4) was added)
>Organization:
>Environment:
This is the system sending the PR ... Not useful info...
System: NetBSD andromeda.noi.kre.to 7.99.26 NetBSD 7.99.26 (VBOX64-1.1-20160128) #43: Thu Jan 28 16:09:08 ICT 2016 kre%onyx.coe.psu.ac.th@localhost:/usr/obj/current/kernels/amd64/VBOX64 amd64
Architecture: x86_64
Machine: amd64
>Description:
if_srt (srt(4)) enables routing based upon the source address
of the packets - when packets are routed to it (via normal routing
mechanisms, usually a default route aimed at the srt interface)
it matches the source addr against a configured list of (addr,prefixlen)
pairs and if a match is found, sends the packet a configured dest
addr via another interface.
For ipv4 sending a packet is done by calling the interface
ip_output routine, and that is what if_srt does. But for
ipv6 packet output is done by sending the packet via nd6_output()
which then calls the ip_output routine after naighbour discovery
is performed. if_srt doesn't do that.
Once that is fixed, there is another issue ... ipv6 routes are
generally via link local addresses (for many reasons not relevant
here). In my case, on a system with 2 interfaces (not a router,
just a multi-homed host) the router on one of the links has no
global addr available to use, only link local. The issue
here is that in the KAME IPv6 stack, inside the kernel, link
local addresses have the interface-id embedded in them (a truly
ugly hack) and Neighbour Discovery expects link local addresses
it sees to contain that embedded scope-id (interface id), and
fails if it is not present. Since the interface id is not
really exposed to userland, it would be difficult to have the
srt config tool (srtconfig(8)) embed that ID in link local
addresses it configures - and in any case, this is an in-kernel
hack, and should be confined there.
Hence we also need a fix to detect when a srt destination address
is link local, and embed the scope-id in the address when it is.
>How-To-Repeat:
Attempt to use srt to source route IPv6 packets (required in the
setup I have, as without it, packets addressed to the node via
one of its addresses, coming from random internet sources, all
get replies sent via the default interface (the interface to
which the default route is attached). In general this works,
it produces (slightly) asymmetric routing, but that's not all
that unusual. Unfortunately, there are firewalls (outside my
contro) on the links, and they do not at all like seeing just
half of a TCP connection - and cause such things to fail.
Watch it fail...
>Fix:
The patch below is intended for review by those more knowledgeable
of the IPv6 stack (and NetBSD networking in general) than I am.
There are 3 segments to the patch.
The first just adds the necessary include files to make the
rest of it compile...
The second runs nd6_output() instead if ifp->if_output (via the
new locking interface) for IPv6 packets (the locking stuff then
gets done in nd6_output). This piece I am reasonably confident
is correct (the XXX comment that just precedes the change applies
to both output calls now.)
The third does the link local address embedding stuff. I know
it is only half done (in the sense, that the embedded scope remains
visible when the config tool requests the current config and displays
it - that doesn't stop anything working, and it makes it easier to
debug the rest of this, though it is not really correct, and is ugly)
and also is probably not really the right way to do this - rather than
just using the if_index as the scope id (or zone id, this thing seems
unsure what it really should be called) it should probably really
use the data explicitly added to each interface to contain such things,
but for link locals, the zone id and interface index are always the
same, and link locals (or multicast link locals, but a multicast
dest addr makes no sense) are the only address forms that
in6_setzoneid() modifies, so the shortcut seems reasonable to me.
Index: if_srt.c
===================================================================
RCS file: /cvsroot/src/sys/net/if_srt.c,v
retrieving revision 1.22
diff -u -r1.22 if_srt.c
--- if_srt.c 20 Jun 2016 06:46:37 -0000 1.22
+++ if_srt.c 27 Jun 2016 00:29:36 -0000
@@ -33,6 +33,9 @@
#include <sys/ioctl.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
+#include <netinet6/scope6_var.h>
#include <net/if_types.h>
#include "if_srt.h"
@@ -232,6 +235,8 @@
return 0; /* XXX ENETDOWN? */
}
/* XXX is 0 the right last arg here? */
+ if (to->sa_family == AF_INET6)
+ return nd6_output(r->u.dstifp, r->u.dstifp, m, &r->dst.sin6, 0);
return if_output_lock(r->u.dstifp, r->u.dstifp, m, &r->dst.sa, 0);
}
@@ -432,6 +437,8 @@
scr->srcmask = dr->srcmask;
scr->u.dstifp = ifp;
memcpy(&scr->dst,&dr->dst,dr->dst.sa.sa_len);
+ if (dr->af == AF_INET6)
+ in6_setzoneid(&scr->dst.sin6.sin6_addr, ifp->if_index);
update_mtu(sc);
return 0;
case SRT_DELRT:
Home |
Main Index |
Thread Index |
Old Index