Hello all.

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.

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