I have made a FreeBSD port of the portable version of OpenBSD's IKEv2
daemon, Openiked. It's submitted as
security/openiked
.
Please note that this is the straight version and not my NAT-T development version (see below). Also, since there hasn't been any official releases of Openiked yet the port uses a Git version from 2013-03-12.
You can follow its progress here:
http://www.freebsd.org/cgi/query-pr.cgi?pr=177651
It's also available here as a compressed share archive: openiked-20130404.shar.bz2.
This shar archive can be unpacked as openiked
under
/usr/ports/security
.
You will also have to add this to /usr/ports/UIDs
and
/usr/ports/GIDs
accordingly:
--- UIDs~ 2013-04-04 13:35:18.000000000 +0200
+++ UIDs 2013-04-04 13:35:18.000000000 +0200
@@ -258,4 +258,5 @@
ossecm:*:967:966::0:0:OSSEC mail user:/usr/local/ossec-hids:/usr/sbin/nologin
ossecr:*:968:966::0:0:OSSEC rem user:/usr/local/ossec-hids:/usr/sbin/nologin
kippo:*:969:969::0:0:kippo user:/nonexistent:/usr/sbin/nologin
+_iked:*:970:970::0:0:iked privsep user:/nonexistent:/usr/sbin/nologin
nobody:*:65534:65534::0:0:Unprivileged user:/nonexistent:/usr/sbin/nologin
--- GIDs~ 2013-04-04 13:35:31.000000000 +0200
+++ GIDs 2013-04-04 13:35:31.000000000 +0200
@@ -250,5 +250,6 @@
elasticsearch:*:965:
ossec:*:966:
kippo:*:969:
+_iked:*:970:
nogroup:*:65533:
nobody:*:65534:
I also tried to add NAT-traversal support on FreeBSD. No development has happened since May, 2013.
My NAT-T branch is called "natt" and lives here:
http://github.com/mchackorg/openiked/
It seems to work, but only one way. The receiving node doesn't seem to unpack the ESP from UDP.
The IKE dialogue succesfully negotiates security associations and both ends agree to use ESP-UDP. When I try to ping a node on the other end my ICMP packets are succesfully encapsulated as ESP-UDP and can be seen as such on the other end. However, it seems the ESP-UDP packets are thrown away.
In May 2013 I declared that I'm stuck. Does anyone have any idea what's happening here and what I can do about it?
Here I've collected some information to recreate my test setup so someone, perhaps myself, can be brought up to speed to finish the work. Consider this a sort of braindump.
Here's an old fashioned patch: patch-20130515.txt
The code is quite simple. For every Security Association established, usually one in each direction, we tell the IPsec stack to use UDP encapsulation
SADB_X_EXT_NAT_T_TYPE UDP_ENCAP_ESPINUDP
and set the ports we're going to use, source port:
SADB_X_EXT_NAT_T_SPORT 4500
and destination port
SADB_X_EXT_NAT_T_DPORT 4500
When run this looks like this in a setkey -x
dump:
sadb_ext{ len=1 type=20 }
sadb_x_nat_t_type{ type=2 }
sadb_ext{ len=1 type=21 }
sadb_x_nat_t_port{ port=4500 }
sadb_ext{ len=1 type=22 }
sadb_x_nat_t_port{ port=4500 }
That should do it, I thought. And it does, partially. Packets going out are encapsulated in UDP.
The situation is the same for FreeBSD and Linux.
The test network consists of two virtual machines running Linux on a FreeBSD hosts that also acts as router:
active router/nat passive
10.0.0.8 - 10.0.0.5 em0 em1 10.0.2.1 - 10.0.2.2
After a succesful IKEv2 dialogue we have situation described below.
This is under Linux. Note that if you're using FreeBSD on the test
nodes you need setkey
from the security/ipsec-tools
port. The one
included in base doesn't know anything about ESP-UDP.
On the active host:
# setkey -D
10.0.2.2[4500] 10.0.0.8[4500]
esp-udp mode=tunnel spi=2161504314(0x80d5f03a) reqid=0(0x00000000)
E: aes-cbc bb188555 0231925f 0169e61c d78cac7b 517cd4bb f32e9f9a 12fafda4 effa71c0
A: hmac-sha1 3b2d6aa8 dfd99e30 fd7fcbd5 a164cfb4 e8cc8860
seq=0x00000000 replay=64 flags=0x00000000 state=mature
created: May 6 15:35:13 2013 current: May 6 15:35:25 2013
diff: 12(s) hard: 10800(s) soft: 9568(s)
last: hard: 0(s) soft: 0(s)
current: 0(bytes) hard: 536870912(bytes) soft: 475667628(bytes)
allocated: 0 hard: 0 soft: 0
sadb_seq=1 pid=727 refcnt=0
10.0.0.8[4500] 10.0.2.2[4500]
esp-udp mode=tunnel spi=2189894628(0x828723e4) reqid=0(0x00000000)
E: aes-cbc 0c2d9d3f d41169c8 24974e89 94cccd4a 504136e3 54e95e96 77b44011 0f599363
A: hmac-sha1 8ec0eafb 8d56565a 815a66c7 3f9d2c00 f9c1e4e3
seq=0x00000000 replay=64 flags=0x00000000 state=mature
created: May 6 15:35:13 2013 current: May 6 15:35:25 2013
diff: 12(s) hard: 10800(s) soft: 9968(s)
last: hard: 0(s) soft: 0(s)
current: 0(bytes) hard: 536870912(bytes) soft: 495531851(bytes)
allocated: 0 hard: 0 soft: 0
sadb_seq=0 pid=727 refcnt=0
# setkey -DP
10.0.2.2[any] 10.0.0.8[any] reserved
in ipsec
esp/tunnel/10.0.2.2-10.0.0.8/use
created: May 6 15:35:13 2013 lastused:
lifetime: 0(s) validtime: 0(s)
spid=312 seq=1 pid=728
refcnt=1
10.0.0.8[any] 10.0.2.2[any] reserved
out ipsec
esp/tunnel/10.0.0.8-10.0.2.2/require
created: May 6 15:35:13 2013 lastused:
lifetime: 0(s) validtime: 0(s)
spid=305 seq=2 pid=728
refcnt=1
On the passive host:
# setkey -D
10.0.2.2[4500] 10.0.2.1[4500]
esp-udp mode=tunnel spi=2161504314(0x80d5f03a) reqid=0(0x00000000)
E: aes-cbc bb188555 0231925f 0169e61c d78cac7b 517cd4bb f32e9f9a 12fafda4 effa71c0
A: hmac-sha1 3b2d6aa8 dfd99e30 fd7fcbd5 a164cfb4 e8cc8860
seq=0x00000000 replay=64 flags=0x00000000 state=mature
created: May 6 15:35:13 2013 current: May 6 15:36:15 2013
diff: 62(s) hard: 10800(s) soft: 9741(s)
last: hard: 0(s) soft: 0(s)
current: 0(bytes) hard: 536870912(bytes) soft: 484257562(bytes)
allocated: 0 hard: 0 soft: 0
sadb_seq=1 pid=722 refcnt=0
10.0.2.1[4500] 10.0.2.2[4500]
esp-udp mode=tunnel spi=2189894628(0x828723e4) reqid=0(0x00000000)
E: aes-cbc 0c2d9d3f d41169c8 24974e89 94cccd4a 504136e3 54e95e96 77b44011 0f599363
A: hmac-sha1 8ec0eafb 8d56565a 815a66c7 3f9d2c00 f9c1e4e3
seq=0x00000000 replay=64 flags=0x00000000 state=mature
created: May 6 15:35:13 2013 current: May 6 15:36:15 2013
diff: 62(s) hard: 10800(s) soft: 9763(s)
last: hard: 0(s) soft: 0(s)
current: 0(bytes) hard: 536870912(bytes) soft: 485331304(bytes)
allocated: 0 hard: 0 soft: 0
sadb_seq=0 pid=722 refcnt=0
# setkey -DP
10.0.0.8[any] 10.0.2.2[any] reserved
in ipsec
esp/tunnel/10.0.2.1-10.0.2.2/use
created: May 6 15:35:13 2013 lastused:
lifetime: 0(s) validtime: 0(s)
spid=312 seq=1 pid=723
refcnt=1
10.0.2.2[any] 10.0.0.8[any] reserved
out ipsec
esp/tunnel/10.0.2.2-10.0.2.1/require
created: May 6 15:35:13 2013 lastused:
lifetime: 0(s) validtime: 0(s)
spid=305 seq=2 pid=723
refcnt=1
Pinging from active to passive we see this on the passive side:
# tcpdump -i eth0 -n udp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
16:58:13.658616 IP 10.0.2.1.4500 > 10.0.2.2.4500: UDP-encap: ESP(spi=0x133a7a52,seq=0x1), length 132
16:58:14.658114 IP 10.0.2.1.4500 > 10.0.2.2.4500: UDP-encap: ESP(spi=0x133a7a52,seq=0x2), length 132
16:58:15.658020 IP 10.0.2.1.4500 > 10.0.2.2.4500: UDP-encap: ESP(spi=0x133a7a52,seq=0x3), length 132
16:58:16.657999 IP 10.0.2.1.4500 > 10.0.2.2.4500: UDP-encap: ESP(spi=0x133a7a52,seq=0x4), length 132
so traffic is coming through. Note that the source 10.0.0.8 is translated to 10.0.2.1. If I ping the other way (10.0.2.2->10.0.0.8) traffic comes through in the other direction as well:
# tcpdump -i eth0 -n udp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
17:00:02.226220 IP 10.0.2.2.4500 > 10.0.0.8.4500: UDP-encap: ESP(spi=0xe759e15b,seq=0x1), length 132
17:00:03.223184 IP 10.0.2.2.4500 > 10.0.0.8.4500: UDP-encap: ESP(spi=0xe759e15b,seq=0x2), length 132
17:00:04.223011 IP 10.0.2.2.4500 > 10.0.0.8.4500: UDP-encap: ESP(spi=0xe759e15b,seq=0x3), length 132
but nothing is unpacked from UDP.
This was under Linux. The situation is the same in FreeBSD.
I looked through the FreeBSD kernel to find the way packets are unpacked. The packets seem to go this path:
sys/netinet/udp_usrreq.c: udp_input() -> udp_append() -> udp4_espdecap()
In udp_append()
there's some code dealing with UDP encapsulated ESP,
so I added a small debug printout:
--- udp_usrreq.c-orig 2013-02-12 14:28:30.000000000 +0100
+++ udp_usrreq.c 2013-02-12 14:28:08.000000000 +0100
@@ -284,6 +284,7 @@ udp_append(struct inpcb *inp, struct ip
#ifdef IPSEC_NAT_T
up = intoudpcb(inp);
KASSERT(up != NULL, ("%s: udpcb NULL", __func__));
+ log(LOG_DEBUG, "udp_append in NAT_T. up->u_flags: %d\n", up->u_flags);
if (up->u_flags & UF_ESPINUDP_ALL) { /* IPSec UDP encaps. */
n = udp4_espdecap(inp, n, off);
if (n == NULL) /* Consumed. */
When I see ESP-UDP traffic coming in I see this in the log for every packet received:
udp_append in NAT_T. up->u_flags: 0
I was expecting this flag variable to be set. Where should it be set?
I tried to use Strongswan under Linux in the same test network to see if it works with NAT-traversal. It does. Configuration below.
Active ipsec.conf:
conn rw
left=10.0.0.8
leftcert=brain-cert.pem
type=tunnel
right=10.0.2.2
rightcert=ipsec3-cert.pem
keyexchange=ikev2
auto=start
Passive ipsec.conf:
conn rw
left=10.0.2.2
leftcert=ipsec3-cert.pem
leftid=@ipsec3.hack.org
type=tunnel
right=%any
rightcert=brain-cert.pem
rightsubnet=10.0.0.8/32
keyexchange=ikev2
auto=add
I dumped all the configuration Strongswan's charon
does to the IPsec
stack with setkey -x
:
strongswan-client.dump.bz2.
Compare it to what Openiked does: openiked-client.dump.bz2.
enc0 under FreeBSD gives nothing when I use tcpdump on it when I'm running Openiked on FreeBSD. I don't know why.
I may have stumbled on a possible bug in FreeBSD's version of pf(4)
.
With this simple rule as the sole rule in pf.conf
:
nat on em1 inet from ! (em1) to any -> (em1)
NAT works fine until IKE has concluded and ESP traffic starts flowing. Then address translation stops working.
This is under FreeBSD 9.0. I have not yet tested 9.1 or current.
If I use ipfw(8)
instead of pf
, everything works fine.
My test network is made up of two virtual machines running on a host which acts as the router and NAT between them. The network looks like this:
active router/nat passive
10.0.0.8 - 10.0.0.5 em0 em1 10.0.2.1 - 10.0.2.2
If you want to use IPsec on FreeBSD you need to build a custom kernel with
options IPSEC
options IPSEC_NAT_T
device crypto
and, if you want an enc(4)
device:
device enc
# ipfw nat 123 config if em1
# ipfw add 50 nat 123 ip from any to any via em1
ikev2 active esp from 10.0.0.8 to 10.0.2.2 srcid totoro.hack.org
ikev2 passive esp from 10.0.2.2/32 to 10.0.0.8/32 local 10.0.2.2 peer any srcid totoro.hack.org
Create a CA:
% ikectl ca vpn create
Generate a host key pair and certificate:
% ikectl ca vpn certificate totoro.hack.org create
Or use these: totoro.hack.org.tgz.
Last updated: <2013-12-06 16:12:08 CET>