diff options
-rw-r--r-- | sbin/iked/config.c | 15 | ||||
-rw-r--r-- | sbin/iked/iked.h | 14 | ||||
-rw-r--r-- | sbin/iked/ikev2.c | 46 | ||||
-rw-r--r-- | sbin/iked/ikev2.h | 4 | ||||
-rw-r--r-- | sbin/iked/parse.y | 52 | ||||
-rw-r--r-- | sbin/iked/policy.c | 48 |
6 files changed, 135 insertions, 44 deletions
diff --git a/sbin/iked/config.c b/sbin/iked/config.c index 9ebf24616d2..306af791338 100644 --- a/sbin/iked/config.c +++ b/sbin/iked/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.50 2019/05/11 16:30:23 patrick Exp $ */ +/* $OpenBSD: config.c,v 1.51 2019/12/03 12:38:34 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de> @@ -188,6 +188,8 @@ config_new_policy(struct iked *env) /* XXX caller does this again */ TAILQ_INIT(&pol->pol_proposals); TAILQ_INIT(&pol->pol_sapeers); + TAILQ_INIT(&pol->pol_tssrc); + TAILQ_INIT(&pol->pol_tsdst); RB_INIT(&pol->pol_flows); return (pol); @@ -197,6 +199,7 @@ void config_free_policy(struct iked *env, struct iked_policy *pol) { struct iked_sa *sa; + struct iked_ts *tsi; if (pol->pol_flags & IKED_POLICY_REFCNT) goto remove; @@ -216,6 +219,14 @@ config_free_policy(struct iked *env, struct iked_policy *pol) return; remove: + while ((tsi = TAILQ_FIRST(&pol->pol_tssrc))) { + TAILQ_REMOVE(&pol->pol_tssrc, tsi, ts_entry); + free(tsi); + } + while ((tsi = TAILQ_FIRST(&pol->pol_tsdst))) { + TAILQ_REMOVE(&pol->pol_tsdst, tsi, ts_entry); + free(tsi); + } config_free_proposals(&pol->pol_proposals, 0); config_free_flows(env, &pol->pol_flows); free(pol); @@ -732,6 +743,8 @@ config_getpolicy(struct iked *env, struct imsg *imsg) memcpy(pol, buf, sizeof(*pol)); offset += sizeof(*pol); + TAILQ_INIT(&pol->pol_tssrc); + TAILQ_INIT(&pol->pol_tsdst); TAILQ_INIT(&pol->pol_proposals); TAILQ_INIT(&pol->pol_sapeers); RB_INIT(&pol->pol_flows); diff --git a/sbin/iked/iked.h b/sbin/iked/iked.h index e580fb96269..163f63196f1 100644 --- a/sbin/iked/iked.h +++ b/sbin/iked/iked.h @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.h,v 1.127 2019/11/30 15:44:07 tobhe Exp $ */ +/* $OpenBSD: iked.h,v 1.128 2019/12/03 12:38:34 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de> @@ -140,6 +140,13 @@ struct iked_addr { in_port_t addr_port; }; +struct iked_ts { + struct iked_addr ts_addr; + uint8_t ts_ipproto; + TAILQ_ENTRY(iked_ts) ts_entry; +}; +TAILQ_HEAD(iked_tss, iked_ts); + struct iked_flow { struct iked_addr flow_src; struct iked_addr flow_dst; @@ -277,6 +284,10 @@ struct iked_policy { struct iked_flows pol_flows; size_t pol_nflows; + struct iked_tss pol_tssrc; /* Traffic Selectors Initiator*/ + size_t pol_tssrc_count; + struct iked_tss pol_tsdst; /* Traffic Selectors Responder*/ + size_t pol_tsdst_count; struct iked_cfg pol_cfg[IKED_CFG_MAX]; unsigned int pol_ncfg; @@ -759,6 +770,7 @@ void policy_init(struct iked *); int policy_lookup(struct iked *, struct iked_message *); struct iked_policy * policy_test(struct iked *, struct iked_policy *); +int policy_generate_ts(struct iked_policy *); void policy_calc_skip_steps(struct iked_policies *); void policy_ref(struct iked *, struct iked_policy *); void policy_unref(struct iked *, struct iked_policy *); diff --git a/sbin/iked/ikev2.c b/sbin/iked/ikev2.c index b5744f35877..8847a7bdd34 100644 --- a/sbin/iked/ikev2.c +++ b/sbin/iked/ikev2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.c,v 1.182 2019/11/30 15:44:07 tobhe Exp $ */ +/* $OpenBSD: ikev2.c,v 1.183 2019/12/03 12:38:34 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de> @@ -188,6 +188,7 @@ int ikev2_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) { struct iked *env = p->p_env; + struct iked_policy *pol; switch (imsg->hdr.type) { case IMSG_CTL_RESET: @@ -200,6 +201,10 @@ ikev2_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) if (config_getmode(env, imsg->hdr.type) == -1) return (0); /* ignore error */ timer_del(env, &env->sc_inittmr); + TAILQ_FOREACH(pol, &env->sc_policies, pol_entry) { + if (policy_generate_ts(pol) == -1) + fatalx("%s: too many traffic selectors", __func__); + } if (!env->sc_passive) { timer_set(env, &env->sc_inittmr, ikev2_init_ike_sa, NULL); @@ -1471,7 +1476,6 @@ ikev2_add_ts_payload(struct ibuf *buf, unsigned int type, struct iked_sa *sa) struct iked_policy *pol = sa->sa_policy; struct ikev2_tsp *tsp; struct ikev2_ts *ts; - struct iked_flow *flow; struct iked_addr *addr; struct iked_addr pooladdr; uint8_t *ptr; @@ -1479,28 +1483,38 @@ ikev2_add_ts_payload(struct ibuf *buf, unsigned int type, struct iked_sa *sa) uint32_t av[4], bv[4], mv[4]; struct sockaddr_in *in4; struct sockaddr_in6 *in6; + struct iked_tss *tss; + struct iked_ts *tsi; if ((tsp = ibuf_advance(buf, sizeof(*tsp))) == NULL) return (-1); tsp->tsp_count = pol->pol_nflows; len = sizeof(*tsp); - RB_FOREACH(flow, iked_flows, &pol->pol_flows) { + if (type == IKEV2_PAYLOAD_TSi) { + if (sa->sa_hdr.sh_initiator) { + tss = &pol->pol_tssrc; + tsp->tsp_count = pol->pol_tssrc_count; + } else { + tss = &pol->pol_tsdst; + tsp->tsp_count = pol->pol_tsdst_count; + } + } else if (type == IKEV2_PAYLOAD_TSr) { + if (sa->sa_hdr.sh_initiator) { + tss = &pol->pol_tsdst; + tsp->tsp_count = pol->pol_tsdst_count; + } else { + tss = &pol->pol_tssrc; + tsp->tsp_count = pol->pol_tssrc_count; + } + } else + return (-1); + + TAILQ_FOREACH(tsi, tss, ts_entry) { if ((ts = ibuf_advance(buf, sizeof(*ts))) == NULL) return (-1); - if (type == IKEV2_PAYLOAD_TSi) { - if (sa->sa_hdr.sh_initiator) - addr = &flow->flow_src; - else - addr = &flow->flow_dst; - } else if (type == IKEV2_PAYLOAD_TSr) { - if (sa->sa_hdr.sh_initiator) - addr = &flow->flow_dst; - else - addr = &flow->flow_src; - } else - return (-1); + addr = &tsi->ts_addr; /* patch remote address (if configured to 0.0.0.0) */ if ((type == IKEV2_PAYLOAD_TSi && !sa->sa_hdr.sh_initiator) || @@ -1509,7 +1523,7 @@ ikev2_add_ts_payload(struct ibuf *buf, unsigned int type, struct iked_sa *sa) addr = &pooladdr; } - ts->ts_protoid = flow->flow_ipproto; + ts->ts_protoid = tsi->ts_ipproto; if (addr->addr_port) { ts->ts_startport = addr->addr_port; diff --git a/sbin/iked/ikev2.h b/sbin/iked/ikev2.h index 90d683b9ce4..1a0a987e978 100644 --- a/sbin/iked/ikev2.h +++ b/sbin/iked/ikev2.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.h,v 1.30 2019/05/11 16:30:23 patrick Exp $ */ +/* $OpenBSD: ikev2.h,v 1.31 2019/12/03 12:38:34 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de> @@ -256,6 +256,8 @@ extern struct iked_constmap ikev2_xformdh_map[]; #define IKEV2_IPV6_OVERHEAD (40 + 8 + 28) /* IPv6 + UDP + IKE_HDR*/ #define IKEV2_MAXLEN_IPV6_FRAG (1280 - IKEV2_IPV6_OVERHEAD) +#define IKEV2_MAXNUM_TSS 255 /* 8 bit Number of TSs field */ + #define IKEV2_XFORMESN_NONE 0 /* No ESN */ #define IKEV2_XFORMESN_ESN 1 /* ESN */ diff --git a/sbin/iked/parse.y b/sbin/iked/parse.y index b2e1eeb48e7..fe052068922 100644 --- a/sbin/iked/parse.y +++ b/sbin/iked/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.87 2019/11/28 15:52:49 kn Exp $ */ +/* $OpenBSD: parse.y,v 1.88 2019/12/03 12:38:34 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de> @@ -2675,13 +2675,12 @@ create_ike(char *name, int af, uint8_t ipproto, struct ipsec_hosts *hosts, struct iked_transform *xf; unsigned int i, j, xfi, noauth; unsigned int ikepropid = 1, ipsecpropid = 1; - struct iked_flow flows[64]; + struct iked_flow *flow, *ftmp; static unsigned int policy_id = 0; struct iked_cfg *cfg; int ret = -1; bzero(&pol, sizeof(pol)); - bzero(&flows, sizeof(flows)); bzero(idstr, sizeof(idstr)); pol.pol_id = ++policy_id; @@ -2919,38 +2918,39 @@ create_ike(char *name, int af, uint8_t ipproto, struct ipsec_hosts *hosts, 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++) { - if (j >= nitems(flows)) - fatalx("create_ike: too many flows"); - memcpy(&flows[j].flow_src.addr, &ipa->address, + for (ipa = hosts->src, ipb = hosts->dst; ipa && ipb; + ipa = ipa->next, ipb = ipb->next) { + if ((flow = calloc(1, sizeof(struct iked_flow))) == NULL) + fatalx("%s: falied to alloc flow.", __func__); + + memcpy(&flow->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; + flow->flow_src.addr_af = ipa->af; + flow->flow_src.addr_mask = ipa->mask; + flow->flow_src.addr_net = ipa->netaddress; + flow->flow_src.addr_port = hosts->sport; - memcpy(&flows[j].flow_dst.addr, &ipb->address, + memcpy(&flow->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; + flow->flow_dst.addr_af = ipb->af; + flow->flow_dst.addr_mask = ipb->mask; + flow->flow_dst.addr_net = ipb->netaddress; + flow->flow_dst.addr_port = hosts->dport; ippn = ipa->srcnat; if (ippn) { - memcpy(&flows[j].flow_prenat.addr, &ippn->address, + memcpy(&flow->flow_prenat.addr, &ippn->address, sizeof(ippn->address)); - flows[j].flow_prenat.addr_af = ippn->af; - flows[j].flow_prenat.addr_mask = ippn->mask; - flows[j].flow_prenat.addr_net = ippn->netaddress; + flow->flow_prenat.addr_af = ippn->af; + flow->flow_prenat.addr_mask = ippn->mask; + flow->flow_prenat.addr_net = ippn->netaddress; } else { - flows[j].flow_prenat.addr_af = 0; + flow->flow_prenat.addr_af = 0; } - flows[j].flow_ipproto = ipproto; + flow->flow_ipproto = ipproto; - if (RB_INSERT(iked_flows, &pol.pol_flows, &flows[j]) == NULL) + if (RB_INSERT(iked_flows, &pol.pol_flows, flow) == NULL) pol.pol_nflows++; else warnx("create_ike: duplicate flow"); @@ -3042,6 +3042,10 @@ done: free(hosts); } iaw_free(ikecfg); + RB_FOREACH_SAFE(flow, iked_flows, &pol.pol_flows, ftmp) { + RB_REMOVE(iked_flows, &pol.pol_flows, flow); + free(flow); + } return (ret); } diff --git a/sbin/iked/policy.c b/sbin/iked/policy.c index 450abb90a0f..45c2330dc21 100644 --- a/sbin/iked/policy.c +++ b/sbin/iked/policy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: policy.c,v 1.50 2019/11/30 15:44:07 tobhe Exp $ */ +/* $OpenBSD: policy.c,v 1.51 2019/12/03 12:38:34 tobhe Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -41,6 +41,10 @@ static __inline int childsa_cmp(struct iked_childsa *, struct iked_childsa *); static __inline int flow_cmp(struct iked_flow *, struct iked_flow *); +static __inline int + addr_cmp(struct iked_addr *, struct iked_addr *, int); +static __inline int + ts_insert_unique(struct iked_addr *, struct iked_tss *, int); void @@ -387,6 +391,48 @@ sa_new(struct iked *env, uint64_t ispi, uint64_t rspi, return (sa); } +int +policy_generate_ts(struct iked_policy *pol) +{ + struct iked_flow *flow; + + /* Generate list of traffic selectors from flows */ + RB_FOREACH(flow, iked_flows, &pol->pol_flows) { + if (ts_insert_unique(&flow->flow_src, &pol->pol_tssrc, + flow->flow_ipproto) == 1) + pol->pol_tssrc_count++; + if (ts_insert_unique(&flow->flow_dst, &pol->pol_tsdst, + flow->flow_ipproto) == 1) + pol->pol_tsdst_count++; + } + if (pol->pol_tssrc_count > IKEV2_MAXNUM_TSS || + pol->pol_tsdst_count > IKEV2_MAXNUM_TSS) + return (-1); + + return (0); +} + +int +ts_insert_unique(struct iked_addr *addr, struct iked_tss *tss, int ipproto) +{ + struct iked_ts *ts; + + /* Remove duplicates */ + TAILQ_FOREACH(ts, tss, ts_entry) { + if (addr_cmp(addr, &ts->ts_addr, 1) == 0) + return (0); + } + + if ((ts = calloc(1, sizeof(*ts))) == NULL) + return (-1); + + ts->ts_ipproto = ipproto; + ts->ts_addr = *addr; + + TAILQ_INSERT_TAIL(tss, ts, ts_entry); + return (1); +} + void sa_free(struct iked *env, struct iked_sa *sa) { |