summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2016-06-01 11:16:42 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2016-06-01 11:16:42 +0000
commit4575b37ca8b82872b7a79df6fc7fbe1c9c06d09e (patch)
treee846e0590421658ee857868b589ee09854279133
parentc2ffcb36fc8b8cd9ae7e69149b01f49ff053623b (diff)
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@
-rw-r--r--sbin/iked/config.c6
-rw-r--r--sbin/iked/iked.h8
-rw-r--r--sbin/iked/ikev2.c85
-rw-r--r--sbin/iked/policy.c10
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 <reyk@openbsd.org>
@@ -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 <reyk@openbsd.org>
@@ -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 <reyk@openbsd.org>
@@ -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 <reyk@openbsd.org>
@@ -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);