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