Tobias Heider([email protected]) on 2021.09.04 12:39:26 +0200:
> Here's an updated diff including the man page bits.

I don't want to bikeshed the manpage. The code is ok benno@ :)

> 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.

This is because the both parsers define "lists" as "duplicate the rules for
all combinations".

The parsers of other programs (like bgpd, ospfd or relayd) have more
elaborate language constructs where simple expansion by duplicating the
line/rule is not sensible. This also applies to iked.

So i think one should look at those daemons and document the fact
that a specific keyword takes a { ... } list as argument, like this:

diff --git sbin/iked/iked.conf.5 sbin/iked/iked.conf.5
index df1a0f09442..6d8cb47cdbe 100644
--- sbin/iked/iked.conf.5
+++ sbin/iked/iked.conf.5
@@ -354,7 +354,13 @@ Note that this only matters for IKEv2 endpoints and does 
not
 restrict the traffic selectors to negotiate flows with different
 address families, e.g. IPv6 flows negotiated by IPv4 endpoints.
 .Pp
-.It Ic proto Ar protocol
+.It Xo
+.Ic proto Ar protocol
+.Xc
+.It Xo
+.Ic proto
+.Ic { Ar protocol ... Ic }
+.Xc
 The optional
 .Ic proto
 parameter restricts the flow to a specific IP protocol.
@@ -368,6 +374,14 @@ For a list of all the protocol name to number mappings 
used by
 see the file
 .Pa /etc/protocols .
 .Pp
+Multiple
+.Ar protocol
+entries can be specified, separated by commas or whitespace,
+if enclosed in curly brackets:
+.Bd -literal -offset indent
+proto { tcp, udp }
+.Ed
+.Pp
 .It Ic rdomain Ar number
 Specify a different routing domain for unencrypted traffic.
 The resulting IPsec SAs will match outgoing packets in the specified

Search for "Multiple" in bgpd.conf for more examples.

I CC jmc@, maybe he wants to help with the manpage.

> 
> 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