Hi,
I would like to test IPsec with NAT-T. For that it would be useful
to set the udpencap flag and port of a SA. I added that to
ipseectl(8).
ok?
bluhm
Index: sbin/ipsecctl/ipsec.conf.5
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sbin/ipsecctl/ipsec.conf.5,v
retrieving revision 1.156
diff -u -p -r1.156 ipsec.conf.5
--- sbin/ipsecctl/ipsec.conf.5 10 Nov 2019 20:51:52 -0000 1.156
+++ sbin/ipsecctl/ipsec.conf.5 6 Feb 2020 00:00:06 -0000
@@ -890,6 +890,10 @@ and
The SPI identifies a specific SA.
.Ar number
is a 32-bit value and needs to be unique.
+.It Ic udpencap Op Ic port Ar dport
+For NAT-Traversal encapsulate the IPsec traffic in UDP.
+The port number of the peer can be set to
+.Ar dport .
.It Ic auth Ar algorithm
For ESP and AH
an authentication algorithm can be specified.
Index: sbin/ipsecctl/ipsecctl.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sbin/ipsecctl/ipsecctl.h,v
retrieving revision 1.73
diff -u -p -r1.73 ipsecctl.h
--- sbin/ipsecctl/ipsecctl.h 20 Nov 2017 10:51:24 -0000 1.73
+++ sbin/ipsecctl/ipsecctl.h 5 Feb 2020 20:42:45 -0000
@@ -208,6 +208,8 @@ struct ipsec_rule {
u_int8_t ikemode;
u_int8_t p1ie;
u_int8_t p2ie;
+ u_int8_t udpencap;
+ u_int16_t udpdport;
u_int16_t sport;
u_int16_t dport;
u_int32_t spi;
Index: sbin/ipsecctl/parse.y
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sbin/ipsecctl/parse.y,v
retrieving revision 1.177
diff -u -p -r1.177 parse.y
--- sbin/ipsecctl/parse.y 26 Aug 2019 18:53:58 -0000 1.177
+++ sbin/ipsecctl/parse.y 5 Feb 2020 20:46:00 -0000
@@ -205,7 +205,8 @@ int validate_sa(u_int32_t, u_int8_t,
struct ipsec_transforms *, struct ipsec_key *,
struct ipsec_key *, u_int8_t);
struct ipsec_rule *create_sa(u_int8_t, u_int8_t, struct ipsec_hosts *,
- u_int32_t, struct ipsec_transforms *,
+ u_int32_t, u_int8_t, u_int16_t,
+ struct ipsec_transforms *,
struct ipsec_key *, struct ipsec_key *);
struct ipsec_rule *reverse_sa(struct ipsec_rule *, u_int32_t,
struct ipsec_key *, struct ipsec_key *);
@@ -257,6 +258,10 @@ typedef struct {
u_int32_t spiin;
} spis;
struct {
+ u_int8_t encap;
+ u_int16_t port;
+ } udpencap;
+ struct {
struct ipsec_key *keyout;
struct ipsec_key *keyin;
} authkeys;
@@ -281,7 +286,7 @@ typedef struct {
%token AUTHKEY ENCKEY FILENAME AUTHXF ENCXF ERROR IKE MAIN QUICK AGGRESSIVE
%token PASSIVE ACTIVE ANY IPIP IPCOMP COMPXF TUNNEL TRANSPORT DYNAMIC LIFETIME
%token TYPE DENY BYPASS LOCAL PROTO USE ACQUIRE REQUIRE DONTACQ GROUP PORT TAG
-%token INCLUDE BUNDLE
+%token INCLUDE BUNDLE UDPENCAP
%token <v.string> STRING
%token <v.number> NUMBER
%type <v.string> string
@@ -300,6 +305,7 @@ typedef struct {
%type <v.ids> ids
%type <v.id> id
%type <v.spis> spispec
+%type <v.udpencap> udpencap
%type <v.authkeys> authkeyspec
%type <v.enckeys> enckeyspec
%type <v.string> bundlestring
@@ -347,7 +353,7 @@ tcpmd5rule : TCPMD5 hosts spispec authke
struct ipsec_rule *r;
r = create_sa(IPSEC_TCPMD5, IPSEC_TRANSPORT, &$2,
- $3.spiout, NULL, $4.keyout, NULL);
+ $3.spiout, 0, 0, NULL, $4.keyout, NULL);
if (r == NULL)
YYERROR;
@@ -357,17 +363,17 @@ tcpmd5rule : TCPMD5 hosts spispec authke
}
;
-sarule : satype tmode hosts spispec transforms authkeyspec
+sarule : satype tmode hosts spispec udpencap transforms authkeyspec
enckeyspec bundlestring {
struct ipsec_rule *r;
- r = create_sa($1, $2, &$3, $4.spiout, $5, $6.keyout,
- $7.keyout);
+ r = create_sa($1, $2, &$3, $4.spiout, $5.encap, $5.port,
+ $6, $7.keyout, $8.keyout);
if (r == NULL)
YYERROR;
- if (expand_rule(r, NULL, 0, $4.spiin, $6.keyin,
- $7.keyin, $8))
+ if (expand_rule(r, NULL, 0, $4.spiin, $7.keyin,
+ $8.keyin, $9))
errx(1, "sarule: expand_rule");
}
;
@@ -668,6 +674,19 @@ spispec : SPI STRING {
}
;
+udpencap : /* empty */ {
+ $$.encap = 0;
+ }
+ | UDPENCAP {
+ $$.encap = 1;
+ $$.port = 0;
+ }
+ | UDPENCAP PORT NUMBER {
+ $$.encap = 1;
+ $$.port = $3;
+ }
+ ;
+
transforms : {
if ((ipsec_transforms = calloc(1,
sizeof(struct ipsec_transforms))) == NULL)
@@ -1014,6 +1033,7 @@ lookup(char *s)
{ "transport", TRANSPORT },
{ "tunnel", TUNNEL },
{ "type", TYPE },
+ { "udpencap", UDPENCAP },
{ "use", USE }
};
const struct keywords *p;
@@ -2209,6 +2229,8 @@ copyrule(struct ipsec_rule *rule)
r->dport = rule->dport;
r->ikemode = rule->ikemode;
r->spi = rule->spi;
+ r->udpencap = rule->udpencap;
+ r->udpdport = rule->udpdport;
r->nr = rule->nr;
return (r);
@@ -2398,8 +2420,8 @@ add_sabundle(struct ipsec_rule *r, char
struct ipsec_rule *
create_sa(u_int8_t satype, u_int8_t tmode, struct ipsec_hosts *hosts,
- u_int32_t spi, struct ipsec_transforms *xfs, struct ipsec_key *authkey,
- struct ipsec_key *enckey)
+ u_int32_t spi, u_int8_t udpencap, u_int16_t udpdport,
+ struct ipsec_transforms *xfs, struct ipsec_key *authkey, struct ipsec_key
*enckey)
{
struct ipsec_rule *r;
@@ -2416,6 +2438,8 @@ create_sa(u_int8_t satype, u_int8_t tmod
r->src = hosts->src;
r->dst = hosts->dst;
r->spi = spi;
+ r->udpencap = udpencap;
+ r->udpdport = udpdport;
r->xfs = xfs;
r->authkey = authkey;
r->enckey = enckey;
@@ -2443,6 +2467,8 @@ reverse_sa(struct ipsec_rule *rule, u_in
reverse->src = copyhost(rule->dst);
reverse->dst = copyhost(rule->src);
reverse->spi = spi;
+ reverse->udpencap = rule->udpencap;
+ reverse->udpdport = rule->udpdport;
reverse->xfs = copytransforms(rule->xfs);
reverse->authkey = authkey;
reverse->enckey = enckey;
Index: sbin/ipsecctl/pfkey.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sbin/ipsecctl/pfkey.c,v
retrieving revision 1.61
diff -u -p -r1.61 pfkey.c
--- sbin/ipsecctl/pfkey.c 28 Jun 2019 13:32:44 -0000 1.61
+++ sbin/ipsecctl/pfkey.c 5 Feb 2020 23:47:18 -0000
@@ -49,6 +49,7 @@ static int pfkey_flow(int, u_int8_t, u_i
struct ipsec_auth *, u_int8_t);
static int pfkey_sa(int, u_int8_t, u_int8_t, u_int32_t,
struct ipsec_addr_wrap *, struct ipsec_addr_wrap *,
+ u_int8_t, u_int16_t,
struct ipsec_transforms *, struct ipsec_key *,
struct ipsec_key *, u_int8_t);
static int pfkey_sabundle(int, u_int8_t, u_int8_t, u_int8_t,
@@ -388,6 +389,7 @@ pfkey_flow(int sd, u_int8_t satype, u_in
static int
pfkey_sa(int sd, u_int8_t satype, u_int8_t action, u_int32_t spi,
struct ipsec_addr_wrap *src, struct ipsec_addr_wrap *dst,
+ u_int8_t encap, u_int16_t dport,
struct ipsec_transforms *xfs, struct ipsec_key *authkey,
struct ipsec_key *enckey, u_int8_t tmode)
{
@@ -395,6 +397,7 @@ pfkey_sa(int sd, u_int8_t satype, u_int8
struct sadb_sa sa;
struct sadb_address sa_src, sa_dst;
struct sadb_key sa_authkey, sa_enckey;
+ struct sadb_x_udpencap udpencap;
struct sockaddr_storage ssrc, sdst;
struct iovec iov[IOV_CNT];
ssize_t n;
@@ -541,6 +544,12 @@ pfkey_sa(int sd, u_int8_t satype, u_int8
sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8;
sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST;
+ if (encap) {
+ sa.sadb_sa_flags |= SADB_X_SAFLAGS_UDPENCAP;
+ udpencap.sadb_x_udpencap_exttype = SADB_X_EXT_UDPENCAP;
+ udpencap.sadb_x_udpencap_len = sizeof(udpencap) / 8;
+ udpencap.sadb_x_udpencap_port = htons(dport);
+ }
if (action == SADB_ADD && !authkey && !enckey && satype !=
SADB_X_SATYPE_IPCOMP && satype != SADB_X_SATYPE_IPIP) { /* XXX
ENCNULL */
warnx("no key specified");
@@ -592,6 +601,12 @@ pfkey_sa(int sd, u_int8_t satype, u_int8
smsg.sadb_msg_len += sa_dst.sadb_address_len;
iov_cnt++;
+ if (encap) {
+ iov[iov_cnt].iov_base = &udpencap;
+ iov[iov_cnt].iov_len = sizeof(udpencap);
+ smsg.sadb_msg_len += udpencap.sadb_x_udpencap_len;
+ iov_cnt++;
+ }
if (authkey) {
/* authentication key */
iov[iov_cnt].iov_base = &sa_authkey;
@@ -1170,12 +1185,12 @@ pfkey_ipsec_establish(int action, struct
switch (action) {
case ACTION_ADD:
ret = pfkey_sa(fd, satype, SADB_ADD, r->spi,
- r->src, r->dst, r->xfs, r->authkey, r->enckey,
- r->tmode);
+ r->src, r->dst, r->udpencap, r->udpdport,
+ r->xfs, r->authkey, r->enckey, r->tmode);
break;
case ACTION_DELETE:
ret = pfkey_sa(fd, satype, SADB_DELETE, r->spi,
- r->src, r->dst, r->xfs, NULL, NULL, r->tmode);
+ r->src, r->dst, 0, 0, r->xfs, NULL, NULL, r->tmode);
break;
default:
return -1;