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;

Reply via email to