hi,

On Thu, May 19, 2011 at 11:06:44PM +0400, Vadim Zhukov wrote:
> This patch allows ipsecctl-like flow grouping along with current
> behavior. It allows to write many-to-many policies in a more
> compact way, see an example:
> 
>   ikev2 esp \
>     from { 1.2.3.4, 5.6.7.8 } to { 3.4.5.6, 4.5.6.7} \
>     from 7.8.9.0 to { 0.1.2.3, 2.3.4.5 } \
>     ...
> 
> will create six flows:
> 
>   1.2.3.4 -> 3.4.5.6
>   1.2.3.4 -> 4.5.6.7
>   5.6.7.8 -> 3.4.5.6
>   5.6.7.8 -> 4.5.6.7
>   7.8.9.0 -> 0.1.2.3
>   7.8.9.0 -> 2.3.4.5
> 
> Please note that you're still limited by MAX_IMSGSIZE, which is
> about 7 flows, depending on arch. This will be addressed in
> another patch.
> 

The difference between ipsec.conf and iked.conf and IKEv1 and IKEv2 is
that an IKEv2 SA can have multiple flows, a.k.a. traffic selectors, in
a single exchange while IKEv1 can only have one.

So in ipsec.conf the code would expand it into multiple independent
ike policies that would lead to multiple independent IKEv1 exchanges
and SAs.

With IKEv2 this would expand into a single IKEv2 SA with many traffic
selectors that would have to fit into a single IKEv2 UDP packet
(IKE_AUTH) which can lead to IP fragmentation and all kinds of
problems.  The current code does not prevent multiple traffic
selectors as it is totally legal in IKEv2, but I would be careful with
using macros to generate _many_ traffic selectors, or flows, in a
policy.  Maybe this is just a documentation issue or you need some
additional length checking here to avoid/warn about excessive
fragmentation (considering the 64k IPv4 limit as well).

Reyk

> -- 
>   Best wishes,
>     Vadim Zhukov
> 
> A: Because it messes up the order in which people normally read text.
> Q: Why is top-posting such a bad thing?
> A: Top-posting.
> Q: What is the most annoying thing in e-mail?
> 
> 
> Index: iked.conf.5
> ===================================================================
> RCS file: /cvs/src/sbin/iked/iked.conf.5,v
> retrieving revision 1.13
> diff -u -p -r1.13 iked.conf.5
> --- iked.conf.5       21 Jan 2011 12:34:11 -0000      1.13
> +++ iked.conf.5       19 May 2011 17:18:54 -0000
> @@ -318,6 +318,29 @@ For a list of all port name to number ma
>  .Xr ipsecctl 8 ,
>  see the file
>  .Pa /etc/services .
> +.Pp
> +Traffic selector can contain more than one address for both
> +.Ic from
> +and
> +.Ic to
> +clauses, for example:
> +.Bd -literal -offset indent
> +ikev2 esp \e
> +     from { 172.16.0.0/24, 172.16.4.0/24, 172.16.9.0/24 } \e
> +     to   { 192.168.0.0/20, 10.0.0.0/8 } \e
> +     peer 1.2.3.4 local 5.6.7.8
> +.Ed
> +.Pp
> +In this case, six actual selectors will be created, from each
> +address in
> +.Ic from
> +part to each address in
> +.Ic to
> +part.
> +Commas between addresses are optional.
> +.Pp
> +You can combine multiple addresses and multiple traffic selectors
> +features in one statement.
>  .It Ic local Ar localip Ic peer Ar remote
>  The
>  .Ic local
> @@ -821,9 +844,13 @@ and any other connection will be matched
>  .Sq catch all
>  policy.
>  .Bd -literal -offset indent
> -ikev2 quick esp from 10.10.10.0/24 to 10.20.20.0/24 \e
> +ikev2 quick esp \e
> +     from { 10.10.10.0/24, 10.11.10.0/24 } \e
> +     to 10.20.20.0/24 \e
>       peer 192.168.1.34
> -ikev2 "catch all" esp from 10.0.1.0/24 to 10.0.2.0/24 \e
> +ikev2 "catch all" esp \e
> +     from 10.0.1.0/24 to 10.0.2.0/24 \e
> +     from 10.0.31.0/24 to 10.0.35.0/24 \e
>       peer any
>  ikev2 "subnet" esp from 10.0.3.0/24 to 10.0.4.0/24 \e
>       peer 192.168.1.0/24
> Index: parse.y
> ===================================================================
> RCS file: /cvs/src/sbin/iked/parse.y,v
> retrieving revision 1.21
> diff -u -p -r1.21 parse.y
> --- parse.y   18 Apr 2011 08:45:43 -0000      1.21
> +++ parse.y   19 May 2011 17:18:54 -0000
> @@ -258,6 +258,8 @@ struct ipsec_hosts {
>       struct ipsec_addr_wrap  *dst;
>       u_int16_t                sport;
>       u_int16_t                dport;
> +     struct ipsec_hosts      *next;
> +     struct ipsec_hosts      *tail;
>  };
>  
>  struct ipsec_filters {
> @@ -293,6 +295,8 @@ int                        get_id_type(char *);
>  u_int8_t              x2i(unsigned char *);
>  int                   parsekey(unsigned char *, size_t, struct iked_auth *);
>  int                   parsekeyfile(char *, struct iked_auth *);
> +struct ipsec_hosts   *expand_hosts(struct ipsec_addr_wrap *, u_int16_t,
> +                          struct ipsec_addr_wrap *, u_int16_t);
>  
>  struct ipsec_transforms *ipsec_transforms;
>  struct ipsec_filters *ipsec_filters;
> @@ -345,7 +349,7 @@ typedef struct {
>  %type        <v.number>              portval af
>  %type        <v.peers>               peers
>  %type        <v.anyhost>             anyhost
> -%type        <v.host>                host host_spec
> +%type        <v.host>                host host_list host_spec
>  %type        <v.ids>                 ids
>  %type        <v.id>                  id
>  %type        <v.transforms>          transforms
> @@ -490,51 +494,20 @@ hosts_list      : hosts                         { $$ = 
> $1; }
>                       else if ($1 == NULL)
>                               $$ = $3;
>                       else {
> -                             $1->src->tail->next = $3->src;
> -                             $1->src->tail = $3->src->tail;
> -                             $1->dst->tail->next = $3->dst;
> -                             $1->dst->tail = $3->dst->tail;
>                               $$ = $1;
> +                             $$->tail->next = $3;
> +                             $$->tail = $3;
>                       }
>               }
>               ;
>  
>  hosts                : FROM host port TO host port           {
> -                     struct ipsec_addr_wrap *ipa;
> -                     for (ipa = $5; ipa; ipa = ipa->next) {
> -                             if (ipa->srcnat) {
> -                                     yyerror("no flow NAT support for"
> -                                         " destination network: %s",
> -                                         ipa->name);
> -                                     YYERROR;
> -                             }
> -                     }
> -
> -                     if (($$ = calloc(1, sizeof(*$$))) == NULL)
> -                             err(1, "hosts: calloc");
> -
> -                     $$->src = $2;
> -                     $$->sport = $3;
> -                     $$->dst = $5;
> -                     $$->dport = $6;
> +                     if(($$ = expand_hosts($2, $3, $5, $6)) == NULL)
> +                             YYERROR;
>               }
>               | TO host port FROM host port           {
> -                     struct ipsec_addr_wrap *ipa;
> -                     for (ipa = $2; ipa; ipa = ipa->next) {
> -                             if (ipa->srcnat) {
> -                                     yyerror("no flow NAT support for"
> -                                         " destination network: %s",
> -                                         ipa->name);
> -                                     YYERROR;
> -                             }
> -                     }
> -                     if (($$ = calloc(1, sizeof(*$$))) == NULL)
> -                             err(1, "hosts: calloc");
> -
> -                     $$->src = $5;
> -                     $$->sport = $6;
> -                     $$->dst = $2;
> -                     $$->dport = $3;
> +                     if (($$ = expand_hosts($5, $6, $2, $3)) == NULL)
> +                             YYERROR;
>               }
>               ;
>  
> @@ -589,6 +562,20 @@ anyhost          : host_spec                     { $$ = 
> $1; }
>                       $$ = host_any();
>               }
>  
> +host_list    : host                          { $$ = $1; }
> +             | host_list comma host          {
> +                     if ($3 == NULL)
> +                             $$ = $1;
> +                     else if ($1 == NULL)
> +                             $$ = $3;
> +                     else {
> +                             $1->tail->next = $3;
> +                             $1->tail = $3->tail;
> +                             $$ = $1;
> +                     }
> +             }
> +             ;
> +
>  host_spec    : STRING                        {
>                       if (($$ = host($1)) == NULL) {
>                               free($1);
> @@ -622,6 +609,7 @@ host              : host_spec                     { $$ = 
> $1; }
>                       $$ = $1;
>                       $$->srcnat = $3;
>               }
> +             | '{' host_list '}'             { $$ = $2; }
>               | ANY                           {
>                       $$ = host_any();
>               }
> @@ -2288,11 +2276,12 @@ create_ike(char *name, int af, u_int8_t 
>      struct ipsec_addr_wrap *ikecfg)
>  {
>       struct ipsec_addr_wrap  *ipa, *ipb;
> +     struct ipsec_hosts      *iph;
>       struct iked_policy       pol;
>       struct iked_proposal     prop[2];
>       u_int                    j;
>       struct iked_transform    ikexforms[64], espxforms[64];
> -     struct iked_flow         flows[64];
> +     struct iked_flow         flows[64];    /* XXX */
>       static u_int             policy_id = 0;
>       struct iked_cfg         *cfg;
>  
> @@ -2485,28 +2474,32 @@ create_ike(char *name, int af, u_int8_t 
>       }
>       TAILQ_INSERT_TAIL(&pol.pol_proposals, &prop[1], prop_entry);
>  
> -     if (hosts == NULL || hosts->src == NULL || hosts->dst == NULL)
> -             fatalx("create_ike: no traffic selectors/flows");
> -
> -     for (j = 0, ipa = hosts->src, ipb = hosts->dst; ipa && ipb;
> -         ipa = ipa->next, ipb = ipb->next, j++) {
> -             memcpy(&flows[j].flow_src.addr, &ipa->address,
> -                 sizeof(ipa->address));
> -             flows[j].flow_src.addr_af = ipa->af;
> -             flows[j].flow_src.addr_mask = ipa->mask;
> -             flows[j].flow_src.addr_net = ipa->netaddress;
> -             flows[j].flow_src.addr_port = hosts->sport;
> -
> -             memcpy(&flows[j].flow_dst.addr, &ipb->address,
> -                 sizeof(ipb->address));
> -             flows[j].flow_dst.addr_af = ipb->af;
> -             flows[j].flow_dst.addr_mask = ipb->mask;
> -             flows[j].flow_dst.addr_net = ipb->netaddress;
> -             flows[j].flow_dst.addr_port = hosts->dport;
> +     for (j = 0, iph = hosts; iph; iph = iph->next) {
> +             for (ipa = iph->src, ipb = iph->dst; ipa && ipb;
> +                 ipa = ipa->next, ipb = ipb->next, j++) {
> +                     if (j >= nitems(flows))
> +                             fatalx("create_ike: flow limit reached");
> +
> +                     memcpy(&flows[j].flow_src.addr, &ipa->address,
> +                         sizeof(ipa->address));
> +                     flows[j].flow_src.addr_af = ipa->af;
> +                     flows[j].flow_src.addr_mask = ipa->mask;
> +                     flows[j].flow_src.addr_net = ipa->netaddress;
> +                     flows[j].flow_src.addr_port = hosts->sport;
> +
> +                     memcpy(&flows[j].flow_dst.addr, &ipb->address,
> +                         sizeof(ipb->address));
> +                     flows[j].flow_dst.addr_af = ipb->af;
> +                     flows[j].flow_dst.addr_mask = ipb->mask;
> +                     flows[j].flow_dst.addr_net = ipb->netaddress;
> +                     flows[j].flow_dst.addr_port = hosts->dport;
>  
> -             pol.pol_nflows++;
> -             RB_INSERT(iked_flows, &pol.pol_flows, &flows[j]);
> +                     pol.pol_nflows++;
> +                     RB_INSERT(iked_flows, &pol.pol_flows, &flows[j]);
> +             }
>       }
> +     if (j == 0)
> +             fatalx("create_ike: no traffic selectors/flows");
>  
>       for (j = 0, ipa = ikecfg; ipa; ipa = ipa->next, j++) {
>               if (j >= IKED_CFG_MAX)
> @@ -2551,4 +2544,43 @@ create_user(const char *user, const char
>  
>       rules++;
>       return (0);
> +}
> +
> +struct ipsec_hosts *
> +expand_hosts(struct ipsec_addr_wrap *from, u_int16_t fromport,
> +    struct ipsec_addr_wrap *to, u_int16_t toport) {
> +     struct ipsec_addr_wrap  *ipa, *ipb;
> +     struct ipsec_hosts      *head, *iph;
> +
> +     for (ipb = to; ipb; ipb = ipb->next) {
> +             if (ipb->srcnat) {
> +                     yyerror("no flow NAT support for"
> +                         " destination network: %s",
> +                         ipb->name);
> +                     return NULL;
> +             }
> +     }
> +
> +     for (head = NULL, ipa = from; ipa; ipa = ipa->next) {
> +             for (ipb = to; ipb; ipb = ipb->next) {
> +                     if (ipa->af != ipb->af &&
> +                         ipa->af != AF_UNSPEC && ipb->af != AF_UNSPEC)
> +                             continue;
> +
> +                     if ((iph = calloc(1, sizeof(*iph))) == NULL)
> +                             err(1, "hosts: calloc");
> +                     iph->src = ipa;
> +                     iph->sport = fromport;
> +                     iph->dst = ipb;
> +                     iph->dport = toport;
> +                     iph->tail = iph;
> +                     if (!head)
> +                             head = iph;
> +                     else {
> +                             head->tail->next = iph;
> +                             head->tail = iph;
> +                     }
> +             }
> +     }
> +     return head;
>  }

Reply via email to