From 4575b37ca8b82872b7a79df6fc7fbe1c9c06d09e Mon Sep 17 00:00:00 2001 From: Patrick Wildt Date: Wed, 1 Jun 2016 11:16:42 +0000 Subject: Implement a second address pool specifically for IPv6, so that clients can be given an IPv4 and IPv6 address at the same time, thus enabling dual stack usage. ok markus@ mikeb@ --- sbin/iked/config.c | 6 +++- sbin/iked/iked.h | 8 ++++- sbin/iked/ikev2.c | 85 ++++++++++++++++++++++++++++++++++++++++-------------- sbin/iked/policy.c | 10 ++++++- 4 files changed, 84 insertions(+), 25 deletions(-) diff --git a/sbin/iked/config.c b/sbin/iked/config.c index 16502585894..c28c68f91a7 100644 --- a/sbin/iked/config.c +++ b/sbin/iked/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.41 2015/12/07 12:46:37 reyk Exp $ */ +/* $OpenBSD: config.c,v 1.42 2016/06/01 11:16:41 patrick Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -104,6 +104,10 @@ config_free_sa(struct iked *env, struct iked_sa *sa) (void)RB_REMOVE(iked_addrpool, &env->sc_addrpool, sa); free(sa->sa_addrpool); } + if (sa->sa_addrpool6) { + (void)RB_REMOVE(iked_addrpool6, &env->sc_addrpool6, sa); + free(sa->sa_addrpool6); + } if (sa->sa_policy) { TAILQ_REMOVE(&sa->sa_policy->pol_sapeers, sa, sa_peer_entry); diff --git a/sbin/iked/iked.h b/sbin/iked/iked.h index b1c31525a81..1c13cb960cb 100644 --- a/sbin/iked/iked.h +++ b/sbin/iked/iked.h @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.h,v 1.95 2015/12/07 12:46:37 reyk Exp $ */ +/* $OpenBSD: iked.h,v 1.96 2016/06/01 11:16:41 patrick Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -449,9 +449,13 @@ struct iked_sa { struct iked_addr *sa_addrpool; /* address from pool */ RB_ENTRY(iked_sa) sa_addrpool_entry; /* pool entries */ + + struct iked_addr *sa_addrpool6; /* address from pool */ + RB_ENTRY(iked_sa) sa_addrpool6_entry; /* pool entries */ }; RB_HEAD(iked_sas, iked_sa); RB_HEAD(iked_addrpool, iked_sa); +RB_HEAD(iked_addrpool6, iked_sa); struct iked_message { struct ibuf *msg_data; @@ -599,6 +603,7 @@ struct iked { char *sc_ocsp_url; struct iked_addrpool sc_addrpool; + struct iked_addrpool6 sc_addrpool6; }; struct iked_socket { @@ -691,6 +696,7 @@ struct iked_user * user_lookup(struct iked *, const char *); RB_PROTOTYPE(iked_sas, iked_sa, sa_entry, sa_cmp); RB_PROTOTYPE(iked_addrpool, iked_sa, sa_addrpool_entry, sa_addrpool_cmp); +RB_PROTOTYPE(iked_addrpool6, iked_sa, sa_addrpool6_entry, sa_addrpool6_cmp); RB_PROTOTYPE(iked_users, iked_user, user_entry, user_cmp); RB_PROTOTYPE(iked_activesas, iked_childsa, csa_node, childsa_cmp); RB_PROTOTYPE(iked_flows, iked_flow, flow_node, flow_cmp); diff --git a/sbin/iked/ikev2.c b/sbin/iked/ikev2.c index 5ce13082c12..88fa7894f14 100644 --- a/sbin/iked/ikev2.c +++ b/sbin/iked/ikev2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.c,v 1.129 2016/06/01 10:52:28 patrick Exp $ */ +/* $OpenBSD: ikev2.c,v 1.130 2016/06/01 11:16:41 patrick Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -122,7 +122,7 @@ int ikev2_add_buf(struct ibuf *buf, struct ibuf *); int ikev2_ipcomp_enable(struct iked *, struct iked_sa *); void ikev2_ipcomp_csa_free(struct iked *, struct iked_childsa *); -int ikev2_cp_setaddr(struct iked *, struct iked_sa *); +int ikev2_cp_setaddr(struct iked *, struct iked_sa *, sa_family_t); int ikev2_cp_fixaddr(struct iked_sa *, struct iked_addr *, struct iked_addr *); @@ -1739,9 +1739,9 @@ ikev2_add_cp(struct iked *env, struct iked_sa *sa, struct ibuf *buf) in6 = (ikecfg->cfg.address.addr_mask != 128 && (ikecfg->cfg_type == IKEV2_CFG_INTERNAL_IP6_ADDRESS) && - sa->sa_addrpool && - sa->sa_addrpool->addr_af == AF_INET6) ? - (struct sockaddr_in6 *)&sa->sa_addrpool->addr : + sa->sa_addrpool6 && + sa->sa_addrpool6->addr_af == AF_INET6) ? + (struct sockaddr_in6 *)&sa->sa_addrpool6->addr : (struct sockaddr_in6 *)&ikecfg->cfg.address.addr; cfg->cfg_length = htobe16(17); if (ibuf_add(buf, &in6->sin6_addr.s6_addr, 16) == -1) @@ -2184,7 +2184,8 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) else if (!sa_stateok(sa, IKEV2_STATE_VALID)) return (0); /* ignore */ - if (ikev2_cp_setaddr(env, sa) < 0) + if (ikev2_cp_setaddr(env, sa, AF_INET) < 0 || + ikev2_cp_setaddr(env, sa, AF_INET6) < 0) return (-1); if (ikev2_childsa_negotiate(env, sa, &sa->sa_kex, &sa->sa_proposals, @@ -2943,6 +2944,12 @@ ikev2_ikesa_enable(struct iked *env, struct iked_sa *sa, struct iked_sa *nsa) sa->sa_addrpool = NULL; RB_INSERT(iked_addrpool, &env->sc_addrpool, nsa); } + if (sa->sa_addrpool6) { + RB_REMOVE(iked_addrpool6, &env->sc_addrpool6, sa); + nsa->sa_addrpool6 = sa->sa_addrpool6; + sa->sa_addrpool6 = NULL; + RB_INSERT(iked_addrpool6, &env->sc_addrpool6, nsa); + } log_debug("%s: activating new IKE SA", __func__); sa_state(env, nsa, IKEV2_STATE_ESTABLISHED); @@ -5029,7 +5036,7 @@ ikev2_print_id(struct iked_id *id, char *idstr, size_t idstrlen) * and remember it in the sa_addrpool attribute. */ int -ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa) +ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa, sa_family_t family) { struct iked_cfg *ikecfg = NULL; struct iked_policy *pol = sa->sa_policy; @@ -5040,18 +5047,32 @@ ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa) uint32_t mask, host, lower, upper, start; size_t i; - if (sa->sa_addrpool || pol->pol_ncfg == 0) + switch (family) { + case AF_INET: + if (sa->sa_addrpool) + return (0); + break; + case AF_INET6: + if (sa->sa_addrpool6) + return (0); + break; + default: + return (-1); + } + if (pol->pol_ncfg == 0) return (0); /* check for an address pool config (address w/ prefixlen != 32) */ bzero(&addr, sizeof(addr)); for (i = 0; i < pol->pol_ncfg; i++) { ikecfg = &pol->pol_cfg[i]; - if (ikecfg->cfg_type == IKEV2_CFG_INTERNAL_IP4_ADDRESS && + if (family == AF_INET && + ikecfg->cfg_type == IKEV2_CFG_INTERNAL_IP4_ADDRESS && ikecfg->cfg.address.addr_mask != 32) { addr.addr_af = AF_INET; break; } - if (ikecfg->cfg_type == IKEV2_CFG_INTERNAL_IP6_ADDRESS && + if (family == AF_INET6 && + ikecfg->cfg_type == IKEV2_CFG_INTERNAL_IP6_ADDRESS && ikecfg->cfg.address.addr_mask != 128) { addr.addr_af = AF_INET6; break; @@ -5081,6 +5102,7 @@ ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa) in4->sin_family = AF_INET; in4->sin_len = sizeof(*in4); lower = ntohl(cfg4->sin_addr.s_addr & ~mask); + key.sa_addrpool = &addr; break; case AF_INET6: cfg6 = (struct sockaddr_in6 *)&ikecfg->cfg.address.addr; @@ -5088,6 +5110,7 @@ ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa) in6->sin6_family = AF_INET6; in6->sin6_len = sizeof(*in6); lower = cfg6->sin6_addr.s6_addr[3]; + key.sa_addrpool6 = &addr; break; default: return (-1); @@ -5100,8 +5123,6 @@ ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa) /* Randomly select start from [lower, upper-1] */ start = arc4random_uniform(upper - lower) + lower; - key.sa_addrpool = &addr; - for (host = start;;) { log_debug("%s: mask %x start %x lower %x host %x upper %x", __func__, mask, start, lower, host, upper); @@ -5115,7 +5136,10 @@ ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa) in6->sin6_addr.s6_addr[3] = htonl(host); break; } - if (!RB_FIND(iked_addrpool, &env->sc_addrpool, &key)) + if ((addr.addr_af == AF_INET && + !RB_FIND(iked_addrpool, &env->sc_addrpool, &key)) || + (addr.addr_af == AF_INET6 && + !RB_FIND(iked_addrpool6, &env->sc_addrpool6, &key))) break; /* try next address */ host++; @@ -5125,12 +5149,27 @@ ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa) if (host == start) return (-1); /* exhausted */ } - if (!key.sa_addrpool) - return (-1); /* cannot happen? */ - if ((sa->sa_addrpool = calloc(1, sizeof(addr))) == NULL) + + switch (addr.addr_af) { + case AF_INET: + if (!key.sa_addrpool) + return (-1); /* cannot happen? */ + if ((sa->sa_addrpool = calloc(1, sizeof(addr))) == NULL) + return (-1); + memcpy(sa->sa_addrpool, &addr, sizeof(addr)); + RB_INSERT(iked_addrpool, &env->sc_addrpool, sa); + break; + case AF_INET6: + if (!key.sa_addrpool6) + return (-1); /* cannot happen? */ + if ((sa->sa_addrpool6 = calloc(1, sizeof(addr))) == NULL) + return (-1); + memcpy(sa->sa_addrpool6, &addr, sizeof(addr)); + RB_INSERT(iked_addrpool6, &env->sc_addrpool6, sa); + break; + default: return (-1); - memcpy(sa->sa_addrpool, &addr, sizeof(addr)); - RB_INSERT(iked_addrpool, &env->sc_addrpool, sa); + } return (0); } @@ -5145,21 +5184,23 @@ ikev2_cp_fixaddr(struct iked_sa *sa, struct iked_addr *addr, struct sockaddr_in *in4; struct sockaddr_in6 *in6; - if (sa->sa_addrpool == NULL || - sa->sa_addrpool->addr_af != addr->addr_af) - return (-1); switch (addr->addr_af) { case AF_INET: + if (sa->sa_addrpool == NULL) + return (-1); in4 = (struct sockaddr_in *)&addr->addr; if (in4->sin_addr.s_addr) return (-1); + memcpy(patched, sa->sa_addrpool, sizeof(*patched)); break; case AF_INET6: + if (sa->sa_addrpool6 == NULL) + return (-1); in6 = (struct sockaddr_in6 *)&addr->addr; if (!IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr)) return (-1); + memcpy(patched, sa->sa_addrpool6, sizeof(*patched)); break; } - memcpy(patched, sa->sa_addrpool, sizeof(*patched)); return (0); } diff --git a/sbin/iked/policy.c b/sbin/iked/policy.c index 0d82d787589..c9987f09e1f 100644 --- a/sbin/iked/policy.c +++ b/sbin/iked/policy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: policy.c,v 1.41 2015/10/20 06:42:59 reyk Exp $ */ +/* $OpenBSD: policy.c,v 1.42 2016/06/01 11:16:41 patrick Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -522,6 +522,13 @@ sa_addrpool_cmp(struct iked_sa *a, struct iked_sa *b) (struct sockaddr *)&b->sa_addrpool->addr, -1)); } +static __inline int +sa_addrpool6_cmp(struct iked_sa *a, struct iked_sa *b) +{ + return (sockaddr_cmp((struct sockaddr *)&a->sa_addrpool6->addr, + (struct sockaddr *)&b->sa_addrpool6->addr, -1)); +} + struct iked_user * user_lookup(struct iked *env, const char *user) { @@ -584,6 +591,7 @@ flow_cmp(struct iked_flow *a, struct iked_flow *b) RB_GENERATE(iked_sas, iked_sa, sa_entry, sa_cmp); RB_GENERATE(iked_addrpool, iked_sa, sa_addrpool_entry, sa_addrpool_cmp); +RB_GENERATE(iked_addrpool6, iked_sa, sa_addrpool6_entry, sa_addrpool6_cmp); RB_GENERATE(iked_users, iked_user, usr_entry, user_cmp); RB_GENERATE(iked_activesas, iked_childsa, csa_node, childsa_cmp); RB_GENERATE(iked_flows, iked_flow, flow_node, flow_cmp); -- cgit v1.2.3