kern/142937: IPSec doesn't work with link-local addresses on FreeBSD 6

Matthijs Kooijman matthijs at
Mon Jan 18 15:30:09 UTC 2010

>Number:         142937
>Category:       kern
>Synopsis:       IPSec doesn't work with link-local addresses on FreeBSD 6
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Jan 18 15:30:03 UTC 2010
>Originator:     Matthijs Kooijman
>Release:        FreeBSD 6.4
I.C.T.S.V. Inter-Actief
(Please assign this bug to Bjoern A. Zeeb <bz at> at his request)

I've been trying to get ipsec working on a FreeBSD 6.4 box, and found a bug. This bug is specific to FreeBSD 6, since it is in the original IPSEC implementation (that got removed in FreeBSD 7 and replaced with FAST_IPSEC).

However, since the bug might still be worth fixing for people running FreeBSD 6, I'll describe it anyway.

The bug occurs when using link-local addresses for ipsec. The kernel is then unable to find the right SA for an incoming packet. The cause of this lies in the scope identifier of the address. These scope identifiers are initially embedded in the full address (in the 3rd and 4th byte IIRC).

When addresses are stored in the sadb, these scope id's are left embedded (even though the addresses are stored in a sockaddr_in6 struct with the scope id field left to 0). However, when looking for a matching SA in key_allocsa, the zone id is recovered from the address and put into the zone id field before comparison. This means the address will never match.

A simple fix (as attached) is not to recover the zone id and just always leave it embedded. I think it would be better to always recover the zone id instead, but I don't know the code well enough to produce a patch for that.

The patch attached is currently in use on a production system and has showed up no problems so far. However, I've discussed this with Bjoern through email and he thinks it needs a better look first. Hence this PR.



Patch attached with submission follows:

Leave the ipv6 link-local scope embedded in the address when looking for a
security association. This makes incoming ipv6 packets on a link-local address
work again.

It is probably more elegant to do the reverse: Recover the scope from the
address when storing the SA (in or around KEY_SETSECASIDX), so that is always
recovered instead of never. However, this patch is simpler and seems to work as

This patch applies to the IPSEC implementation (not FAST_IPSEC) that was
removed in 7.0. It is made against the 6.4 sources.
--- sys/netkey/key.c
+++ sys/netkey/key.c
@@ -1040,9 +1040,9 @@
 #ifdef INET6
 		case AF_INET6:
 			bcopy(dst, &sin6.sin6_addr, sizeof(sin6.sin6_addr));
+			/* Leave the ipv6 link-local scope embedded in the
+			 * address, since the SA also has it embedded. */
 			sin6.sin6_scope_id = 0;
-			if (sa6_recoverscope(&sin6))
-				continue;
 			if (key_sockaddrcmp((struct sockaddr *)&sin6,
 			    (struct sockaddr *)&sav->sah->saidx.dst, 0) != 0)


More information about the freebsd-bugs mailing list