Here's an updated diff including the man page bits.  Looking at pf.conf(5)
and ipsec.conf(5), there does not really seem to be a standard way to document
which parameters accept lists.

Index: iked.conf.5
===================================================================
RCS file: /cvs/src/sbin/iked/iked.conf.5,v
retrieving revision 1.86
diff -u -p -r1.86 iked.conf.5
--- iked.conf.5 3 Aug 2021 12:46:30 -0000       1.86
+++ iked.conf.5 4 Sep 2021 09:54:55 -0000
@@ -93,6 +93,16 @@ keyword, for example:
 .Bd -literal -offset indent
 include "/etc/macros.conf"
 .Ed
+.Pp
+Certain parameters can be expressed as lists, in which case
+.Xr iked 8
+generates all the necessary flow combinations.
+For example:
+.Bd -literal -offset indent
+ikev2 esp proto { tcp, udp } \e
+       from 192.168.1.1 to 10.0.0.18 \e
+       peer 192.168.10.1
+.Ed
 .Sh MACROS
 Macros can be defined that will later be expanded in context.
 Macro names must start with a letter, digit, or underscore,
Index: iked.h
===================================================================
RCS file: /cvs/src/sbin/iked/iked.h,v
retrieving revision 1.193
diff -u -p -r1.193 iked.h
--- iked.h      1 Sep 2021 15:30:06 -0000       1.193
+++ iked.h      4 Sep 2021 09:54:55 -0000
@@ -242,10 +242,9 @@ struct iked_policy {
 
 #define IKED_SKIP_FLAGS                         0
 #define IKED_SKIP_AF                    1
-#define IKED_SKIP_PROTO                         2
-#define IKED_SKIP_SRC_ADDR              3
-#define IKED_SKIP_DST_ADDR              4
-#define IKED_SKIP_COUNT                         5
+#define IKED_SKIP_SRC_ADDR              2
+#define IKED_SKIP_DST_ADDR              3
+#define IKED_SKIP_COUNT                         4
        struct iked_policy              *pol_skip[IKED_SKIP_COUNT];
 
        uint8_t                          pol_flags;
@@ -265,7 +264,8 @@ struct iked_policy {
        int                              pol_af;
        int                              pol_rdomain;
        uint8_t                          pol_saproto;
-       unsigned int                     pol_ipproto;
+       unsigned int                     pol_ipproto[IKED_IPPROTO_MAX];
+       unsigned int                     pol_nipproto;
 
        struct iked_addr                 pol_peer;
        struct iked_static_id            pol_peerid;
Index: parse.y
===================================================================
RCS file: /cvs/src/sbin/iked/parse.y,v
retrieving revision 1.131
diff -u -p -r1.131 parse.y
--- parse.y     28 May 2021 18:01:39 -0000      1.131
+++ parse.y     4 Sep 2021 09:54:55 -0000
@@ -374,7 +374,7 @@ void                         copy_transforms(unsigned int,
                            const struct ipsec_xf **, unsigned int,
                            struct iked_transform **, unsigned int *,
                            struct iked_transform *, size_t);
-int                     create_ike(char *, int, uint8_t,
+int                     create_ike(char *, int, struct ipsec_addr_wrap *,
                            int, struct ipsec_hosts *,
                            struct ipsec_hosts *, struct ipsec_mode *,
                            struct ipsec_mode *, uint8_t,
@@ -388,9 +388,9 @@ uint8_t                      x2i(unsigned char *);
 int                     parsekey(unsigned char *, size_t, struct iked_auth *);
 int                     parsekeyfile(char *, struct iked_auth *);
 void                    iaw_free(struct ipsec_addr_wrap *);
-static int              create_flow(struct iked_policy *pol, struct 
ipsec_addr_wrap *ipa,
+static int              create_flow(struct iked_policy *pol, int, struct 
ipsec_addr_wrap *ipa,
                            struct ipsec_addr_wrap *ipb);
-static int              expand_flows(struct iked_policy *, struct 
ipsec_addr_wrap *,
+static int              expand_flows(struct iked_policy *, int, struct 
ipsec_addr_wrap *,
                            struct ipsec_addr_wrap *);
 static struct ipsec_addr_wrap *
                         expand_keyword(struct ipsec_addr_wrap *);
@@ -407,7 +407,6 @@ typedef struct {
                uint8_t                  ikemode;
                uint8_t                  dir;
                uint8_t                  satype;
-               uint8_t                  proto;
                char                    *string;
                uint16_t                 port;
                struct ipsec_hosts      *hosts;
@@ -415,6 +414,7 @@ typedef struct {
                struct ipsec_addr_wrap  *anyhost;
                struct ipsec_addr_wrap  *host;
                struct ipsec_addr_wrap  *cfg;
+               struct ipsec_addr_wrap  *proto;
                struct {
                        char            *srcid;
                        char            *dstid;
@@ -449,8 +449,7 @@ typedef struct {
 %token <v.number>              NUMBER
 %type  <v.string>              string
 %type  <v.satype>              satype
-%type  <v.proto>               proto
-%type  <v.number>              protoval
+%type  <v.proto>               proto proto_list protoval
 %type  <v.hosts>               hosts hosts_list
 %type  <v.port>                port
 %type  <v.number>              portval af rdomain
@@ -630,10 +629,23 @@ af                : /* empty */                   { $$ = 
AF_UNSPEC; }
                | INET6                         { $$ = AF_INET6; }
                ;
 
-proto          : /* empty */                   { $$ = 0; }
+proto          : /* empty */                   { $$ = NULL; }
                | PROTO protoval                { $$ = $2; }
-               | PROTO ESP                     { $$ = IPPROTO_ESP; }
-               | PROTO AH                      { $$ = IPPROTO_AH; }
+               | PROTO '{' proto_list '}'      { $$ = $3; }
+               ;
+
+proto_list     : protoval                      { $$ = $1; }
+               | proto_list comma protoval     {
+                       if ($3 == NULL)
+                               $$ = $1;
+                       else if ($1 == NULL)
+                               $$ = $3;
+                       else {
+                               $1->tail->next = $3;
+                               $1->tail = $3->tail;
+                               $$ = $1;
+                       }
+               }
                ;
 
 protoval       : STRING                        {
@@ -644,7 +656,12 @@ protoval   : STRING                        {
                                yyerror("unknown protocol: %s", $1);
                                YYERROR;
                        }
-                       $$ = p->p_proto;
+
+                       if (($$ = calloc(1, sizeof(*$$))) == NULL)
+                               err(1, "protoval: calloc");
+
+                       $$->type = p->p_proto;
+                       $$->tail = $$;
                        free($1);
                }
                | NUMBER                        {
@@ -652,6 +669,11 @@ protoval   : STRING                        {
                                yyerror("protocol outside range");
                                YYERROR;
                        }
+                       if (($$ = calloc(1, sizeof(*$$))) == NULL)
+                               err(1, "protoval: calloc");
+
+                       $$->type = $1;
+                       $$->tail = $$;
                }
                ;
 
@@ -2444,7 +2466,7 @@ copy_transforms(unsigned int type,
 }
 
 int
-create_ike(char *name, int af, uint8_t ipproto,
+create_ike(char *name, int af, struct ipsec_addr_wrap *ipproto,
     int rdomain, struct ipsec_hosts *hosts,
     struct ipsec_hosts *peers, struct ipsec_mode *ike_sa,
     struct ipsec_mode *ipsec_sa, uint8_t saproto,
@@ -2454,7 +2476,7 @@ create_ike(char *name, int af, uint8_t i
     struct ipsec_addr_wrap *ikecfg, char *iface)
 {
        char                     idstr[IKED_ID_SIZE];
-       struct ipsec_addr_wrap  *ipa, *ipb;
+       struct ipsec_addr_wrap  *ipa, *ipb, *ipp;
        struct iked_auth        *ikeauth;
        struct iked_policy       pol;
        struct iked_proposal    *p, *ptmp;
@@ -2473,7 +2495,15 @@ create_ike(char *name, int af, uint8_t i
        pol.pol_certreqtype = env->sc_certreqtype;
        pol.pol_af = af;
        pol.pol_saproto = saproto;
-       pol.pol_ipproto = ipproto;
+       for (i = 0, ipp = ipproto; ipp; ipp = ipp->next, i++) {
+               if (i > IKED_IPPROTO_MAX) {
+                       yyerror("too many protocols");
+                       return (-1);
+               }
+               pol.pol_ipproto[i] = ipp->type;
+               pol.pol_nipproto++;
+       }
+       
        pol.pol_flags = flags;
        pol.pol_rdomain = rdomain;
        memcpy(&pol.pol_auth, authtype, sizeof(struct iked_auth));
@@ -2823,13 +2853,15 @@ create_ike(char *name, int af, uint8_t i
                }
        }
 
-       if (hosts == NULL || hosts->src == NULL || hosts->dst == NULL)
-               fatalx("create_ike: no traffic selectors/flows");
-
        for (ipa = hosts->src, ipb = hosts->dst; ipa && ipb;
-           ipa = ipa->next, ipb = ipb->next)
-               if (expand_flows(&pol, ipa, ipb))
-                       fatalx("create_ike: invalid flow");
+           ipa = ipa->next, ipb = ipb->next) {
+               for (j = 0; j < pol.pol_nipproto; j++)
+                       if (expand_flows(&pol, pol.pol_ipproto[j], ipa, ipb))
+                               fatalx("create_ike: invalid flow");
+               if (pol.pol_nipproto == 0)
+                       if (expand_flows(&pol, 0, ipa, ipb))
+                               fatalx("create_ike: invalid flow");
+       }
 
        for (j = 0, ipa = ikecfg; ipa; ipa = ipa->next, j++) {
                if (j >= IKED_CFG_MAX)
@@ -2918,6 +2950,7 @@ done:
                free(hosts);
        }
        iaw_free(ikecfg);
+       iaw_free(ipproto);
        RB_FOREACH_SAFE(flow, iked_flows, &pol.pol_flows, ftmp) {
                RB_REMOVE(iked_flows, &pol.pol_flows, flow);
                free(flow);
@@ -2929,7 +2962,7 @@ done:
 }
 
 static int
-create_flow(struct iked_policy *pol, struct ipsec_addr_wrap *ipa,
+create_flow(struct iked_policy *pol, int proto, struct ipsec_addr_wrap *ipa,
     struct ipsec_addr_wrap *ipb)
 {
        struct iked_flow        *flow;
@@ -2969,8 +3002,8 @@ create_flow(struct iked_policy *pol, str
        }
 
        flow->flow_dir = IPSP_DIRECTION_OUT;
+       flow->flow_ipproto = proto;
        flow->flow_saproto = pol->pol_saproto;
-       flow->flow_ipproto = pol->pol_ipproto;
        flow->flow_rdomain = pol->pol_rdomain;
 
        if (RB_INSERT(iked_flows, &pol->pol_flows, flow) == NULL)
@@ -2984,11 +3017,15 @@ create_flow(struct iked_policy *pol, str
 }
 
 static int
-expand_flows(struct iked_policy *pol, struct ipsec_addr_wrap *src,
+expand_flows(struct iked_policy *pol, int proto, struct ipsec_addr_wrap *src,
     struct ipsec_addr_wrap *dst)
 {
        struct ipsec_addr_wrap  *ipa = NULL, *ipb = NULL;
        int                      ret = -1;
+       int                      srcaf, dstaf;
+
+       srcaf = src->af;
+       dstaf = dst->af;
 
        if (src->af == AF_UNSPEC &&
            dst->af == AF_UNSPEC) {
@@ -2998,7 +3035,7 @@ expand_flows(struct iked_policy *pol, st
                ipb = expand_keyword(dst);
                if (!ipa || !ipb)
                        goto done;
-               if (create_flow(pol, ipa, ipb))
+               if (create_flow(pol, proto, ipa, ipb))
                        goto done;
 
                iaw_free(ipa);
@@ -3008,26 +3045,28 @@ expand_flows(struct iked_policy *pol, st
                ipb = expand_keyword(dst);
                if (!ipa || !ipb)
                        goto done;
-               if (create_flow(pol, ipa, ipb))
+               if (create_flow(pol, proto, ipa, ipb))
                        goto done;
        } else if (src->af == AF_UNSPEC) {
                src->af = dst->af;
                ipa = expand_keyword(src);
                if (!ipa)
                        goto done;
-               if (create_flow(pol, ipa, dst))
+               if (create_flow(pol, proto, ipa, dst))
                        goto done;
        } else if (dst->af == AF_UNSPEC) {
                dst->af = src->af;
                ipa = expand_keyword(dst);
                if (!ipa)
                        goto done;
-               if (create_flow(pol, src, ipa))
+               if (create_flow(pol, proto, src, ipa))
                        goto done;
-       } else if (create_flow(pol, src, dst))
+       } else if (create_flow(pol, proto, src, dst))
                goto done;
        ret = 0;
  done:
+       src->af = srcaf;
+       dst->af = dstaf;
        iaw_free(ipa);
        iaw_free(ipb);
        return (ret);
Index: policy.c
===================================================================
RCS file: /cvs/src/sbin/iked/policy.c,v
retrieving revision 1.83
diff -u -p -r1.83 policy.c
--- policy.c    1 Sep 2021 15:30:06 -0000       1.83
+++ policy.c    4 Sep 2021 09:54:55 -0000
@@ -223,9 +223,6 @@ policy_test(struct iked *env, struct ike
                else if (key->pol_af && p->pol_af &&
                    key->pol_af != p->pol_af)
                        p = p->pol_skip[IKED_SKIP_AF];
-               else if (key->pol_ipproto && p->pol_ipproto &&
-                   key->pol_ipproto != p->pol_ipproto)
-                       p = p->pol_skip[IKED_SKIP_PROTO];
                else if (sockaddr_cmp((struct sockaddr *)&key->pol_peer.addr,
                    (struct sockaddr *)&p->pol_peer.addr,
                    p->pol_peer.addr_mask) != 0)
@@ -334,9 +331,6 @@ policy_calc_skip_steps(struct iked_polic
                    prev->pol_af != AF_UNSPEC &&
                    cur->pol_af != prev->pol_af)
                        IKED_SET_SKIP_STEPS(IKED_SKIP_AF);
-               if (cur->pol_ipproto && prev->pol_ipproto &&
-                   cur->pol_ipproto != prev->pol_ipproto)
-                       IKED_SET_SKIP_STEPS(IKED_SKIP_PROTO);
                if (IKED_ADDR_NEQ(&cur->pol_peer, &prev->pol_peer))
                        IKED_SET_SKIP_STEPS(IKED_SKIP_DST_ADDR);
                if (IKED_ADDR_NEQ(&cur->pol_local, &prev->pol_local))
Index: print.c
===================================================================
RCS file: /cvs/src/sbin/iked/print.c,v
retrieving revision 1.2
diff -u -p -r1.2 print.c
--- print.c     21 Mar 2021 22:18:00 -0000      1.2
+++ print.c     4 Sep 2021 09:54:55 -0000
@@ -90,8 +90,16 @@ print_policy(struct iked_policy *pol)
 
        print_verbose(" %s", print_xf(pol->pol_saproto, 0, saxfs));
 
-       if (pol->pol_ipproto)
-               print_verbose(" proto %s", print_proto(pol->pol_ipproto));
+       if (pol->pol_nipproto > 0) {
+               print_verbose(" proto {");
+               for (i = 0; i < pol->pol_nipproto; i++) {
+                       if (i == 0)
+                               print_verbose(" %s", 
print_proto(pol->pol_ipproto[i]));
+                       else
+                               print_verbose(", %s", 
print_proto(pol->pol_ipproto[i]));
+               }
+               print_verbose(" }");
+       }
 
        if (pol->pol_af) {
                if (pol->pol_af == AF_INET)
Index: types.h
===================================================================
RCS file: /cvs/src/sbin/iked/types.h,v
retrieving revision 1.45
diff -u -p -r1.45 types.h
--- types.h     1 Sep 2021 15:30:06 -0000       1.45
+++ types.h     4 Sep 2021 09:54:55 -0000
@@ -63,6 +63,7 @@
 #define IKED_PSK_SIZE          1024    /* XXX should be dynamic */
 #define IKED_MSGBUF_MAX                8192
 #define IKED_CFG_MAX           16      /* maximum CP attributes */
+#define IKED_IPPROTO_MAX       16
 #define IKED_TAG_SIZE          64
 #define IKED_CYCLE_BUFFERS     8       /* # of static buffers for mapping */
 #define IKED_PASSWORD_SIZE     256     /* limited by most EAP types */

Reply via email to