summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2014-02-14 09:00:04 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2014-02-14 09:00:04 +0000
commitf4e9a9ffa848780f796a2edef5fa8e2d43dcecff (patch)
tree712e5771110f6982e21a8f8bc7369a74c3ddec28
parentbc74558dd64e1cf7d15e7047cddaf618301aa4ea (diff)
initial support for IPComp
still experimental and rekeying needs some work; ok mikeb@
-rw-r--r--sbin/iked/iked.h8
-rw-r--r--sbin/iked/ikev2.c173
-rw-r--r--sbin/iked/ikev2.h3
-rw-r--r--sbin/iked/ikev2_pld.c21
-rw-r--r--sbin/iked/parse.y14
-rw-r--r--sbin/iked/pfkey.c17
-rw-r--r--sbin/iked/util.c5
7 files changed, 227 insertions, 14 deletions
diff --git a/sbin/iked/iked.h b/sbin/iked/iked.h
index 2cb80473c91..75334b87ae8 100644
--- a/sbin/iked/iked.h
+++ b/sbin/iked/iked.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: iked.h,v 1.65 2014/01/24 07:31:25 markus Exp $ */
+/* $OpenBSD: iked.h,v 1.66 2014/02/14 09:00:03 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -165,6 +165,7 @@ struct iked_childsa {
u_int8_t csa_allocated; /* from the kernel */
u_int8_t csa_persistent;/* do not rekey */
u_int8_t csa_esn; /* use ESN */
+ u_int8_t csa_transport; /* transport mode */
struct iked_spi csa_spi;
@@ -238,6 +239,7 @@ struct iked_policy {
#define IKED_POLICY_REFCNT 0x04
#define IKED_POLICY_QUICK 0x08
#define IKED_POLICY_SKIP 0x10
+#define IKED_POLICY_IPCOMP 0x20
int pol_refcnt;
@@ -404,6 +406,10 @@ struct iked_sa {
struct iked_childsas sa_childsas; /* IPSec Child SAs */
struct iked_saflows sa_flows; /* IPSec flows */
+ u_int8_t sa_ipcomp; /* IPcomp transform */
+ u_int16_t sa_cpi_out; /* IPcomp outgoing */
+ u_int16_t sa_cpi_in; /* IPcomp incoming*/
+
struct iked_timer sa_timer; /* SA timeouts */
#define IKED_IKE_SA_REKEY_TIMEOUT 300 /* 5 minutes */
#define IKED_IKE_SA_ALIVE_TIMEOUT 60 /* 1 minute */
diff --git a/sbin/iked/ikev2.c b/sbin/iked/ikev2.c
index 2714013900e..8c61528f8a6 100644
--- a/sbin/iked/ikev2.c
+++ b/sbin/iked/ikev2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ikev2.c,v 1.91 2014/01/24 07:35:55 markus Exp $ */
+/* $OpenBSD: ikev2.c,v 1.92 2014/02/14 09:00:03 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -100,10 +100,14 @@ ssize_t ikev2_add_ts(struct ibuf *, struct ikev2_payload **, ssize_t,
struct iked_sa *, int);
ssize_t ikev2_add_certreq(struct ibuf *, struct ikev2_payload **, ssize_t,
struct ibuf *, u_int8_t);
+ssize_t ikev2_add_ipcompnotify(struct iked *, struct ibuf *,
+ struct ikev2_payload **, ssize_t, struct iked_sa *);
ssize_t ikev2_add_ts_payload(struct ibuf *, u_int, struct iked_sa *);
int ikev2_add_data(struct ibuf *, void *, size_t);
int ikev2_add_buf(struct ibuf *buf, struct ibuf *);
+int ikev2_ipcomp_enable(struct iked_sa *);
+
static struct privsep_proc procs[] = {
{ "parent", PROC_PARENT, ikev2_dispatch_parent },
{ "ikev1", PROC_IKEV1, ikev2_dispatch_ikev1 },
@@ -1010,6 +1014,11 @@ ikev2_init_ike_auth(struct iked *env, struct iked_sa *sa)
goto done;
}
+ /* compression */
+ if ((pol->pol_flags & IKED_POLICY_IPCOMP) &&
+ (len = ikev2_add_ipcompnotify(env, e, &pld, len, sa)) == -1)
+ goto done;
+
if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_SA) == -1)
goto done;
@@ -1347,6 +1356,57 @@ ikev2_add_certreq(struct ibuf *e, struct ikev2_payload **pld, ssize_t len,
return (len);
}
+ssize_t
+ikev2_add_ipcompnotify(struct iked *env, struct ibuf *e,
+ struct ikev2_payload **pld, ssize_t len, struct iked_sa *sa)
+{
+ struct iked_childsa csa;
+ struct ikev2_notify *n;
+ u_int8_t *ptr;
+ u_int16_t cpi;
+ u_int32_t spi;
+ u_int8_t transform;
+
+ /* we only support deflate */
+ transform = IKEV2_IPCOMP_DEFLATE;
+
+ bzero(&csa, sizeof(csa));
+ csa.csa_saproto = IKEV2_SAPROTO_IPCOMP;
+ csa.csa_ikesa = sa;
+ csa.csa_local = &sa->sa_peer;
+ csa.csa_peer = &sa->sa_local;
+
+ if (pfkey_sa_init(env->sc_pfkey, &csa, &spi) == -1)
+ return (-1);
+ /*
+ * We get spi == 0 if the kernel does not support IPcomp,
+ * so just return the length of the current payload.
+ */
+ if (spi == 0)
+ return (len);
+ cpi = htobe16((u_int16_t)spi);
+ if (ikev2_next_payload(*pld, len, IKEV2_PAYLOAD_NOTIFY) == -1)
+ return (-1);
+ if ((*pld = ikev2_add_payload(e)) == NULL)
+ return (-1);
+ len = sizeof(*n) + sizeof(cpi) + sizeof(transform);
+ if ((ptr = ibuf_advance(e, len)) == NULL)
+ return (-1);
+ n = (struct ikev2_notify *)ptr;
+ n->n_protoid = 0;
+ n->n_spisize = 0;
+ n->n_type = htobe16(IKEV2_N_IPCOMP_SUPPORTED);
+ ptr += sizeof(*n);
+ memcpy(ptr, &cpi, sizeof(cpi));
+ ptr += sizeof(cpi);
+ memcpy(ptr, &transform, sizeof(transform));
+
+ sa->sa_cpi_in = spi; /* already on host byte order */
+ log_debug("%s: sa_cpi_in 0x%04x", __func__, sa->sa_cpi_in);
+
+ return (len);
+}
+
int
ikev2_next_payload(struct ikev2_payload *pld, size_t length,
u_int8_t nextpayload)
@@ -2075,6 +2135,11 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa)
goto done;
}
+ /* compression */
+ if (sa->sa_ipcomp &&
+ (len = ikev2_add_ipcompnotify(env, e, &pld, len, sa)) == -1)
+ goto done;
+
if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_SA) == -1)
goto done;
@@ -2692,6 +2757,9 @@ ikev2_ike_sa_alive(struct iked *env, void *arg)
/* check for incoming traffic on any child SA */
TAILQ_FOREACH(csa, &sa->sa_childsas, csa_entry) {
+ if (!csa->csa_loaded ||
+ csa->csa_saproto == IKEV2_SAPROTO_IPCOMP)
+ continue;
if (pfkey_sa_last_used(env->sc_pfkey, csa, &last_used) != 0)
continue;
gettimeofday(&tv, NULL);
@@ -3832,11 +3900,114 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator)
}
int
+ikev2_ipcomp_enable(struct iked_sa *sa)
+{
+ struct iked_childsa *other, *csa = NULL, *csb = NULL;
+ struct iked_flow *flow, *flowa = NULL, *flowb = NULL;
+
+ if ((csa = calloc(1, sizeof(*csa))) == NULL ||
+ (csb = calloc(1, sizeof(*csb))) == NULL ||
+ (flowa = calloc(1, sizeof(*flowa))) == NULL ||
+ (flowb = calloc(1, sizeof(*flowb))) == NULL) {
+ free(csa);
+ free(csb);
+ free(flowa);
+ free(flowb);
+ return (-1);
+ }
+
+ /* switch ESP SAs to transport mode */
+ TAILQ_FOREACH(other, &sa->sa_childsas, csa_entry)
+ if (!other->csa_rekey && !other->csa_loaded &&
+ other->csa_saproto == IKEV2_SAPROTO_ESP)
+ other->csa_transport = 1;
+
+ /* install IPCOMP SAs */
+ csa->csa_ikesa = sa;
+ csa->csa_saproto = IKEV2_SAPROTO_IPCOMP;
+ if (sa->sa_hdr.sh_initiator) {
+ csa->csa_dstid = &sa->sa_rid;
+ csa->csa_srcid = &sa->sa_iid;
+ } else {
+ csa->csa_dstid = &sa->sa_iid;
+ csa->csa_srcid = &sa->sa_rid;
+ }
+ csa->csa_spi.spi_size = 2;
+ csa->csa_spi.spi = sa->sa_cpi_out;
+ csa->csa_peerspi = sa->sa_cpi_in;
+ csa->csa_dir = IPSP_DIRECTION_OUT;
+ csa->csa_local = &sa->sa_local;
+ csa->csa_peer = &sa->sa_peer;
+ csb->csa_allocated = 0;
+
+ memcpy(csb, csa, sizeof(*csb));
+ csb->csa_spi.spi = csa->csa_peerspi;
+ csb->csa_peerspi = csa->csa_spi.spi;
+ csb->csa_dir = IPSP_DIRECTION_IN;
+ csb->csa_local = csa->csa_peer;
+ csb->csa_peer = csa->csa_local;
+ csb->csa_allocated = 1;
+
+ TAILQ_INSERT_TAIL(&sa->sa_childsas, csa, csa_entry);
+ TAILQ_INSERT_TAIL(&sa->sa_childsas, csb, csa_entry);
+
+ csa->csa_peersa = csb;
+ csb->csa_peersa = csa;
+
+ /* redirect flows to IPCOMP */
+ TAILQ_FOREACH(flow, &sa->sa_flows, flow_entry) {
+ if (flow->flow_loaded ||
+ flow->flow_saproto != IKEV2_SAPROTO_ESP)
+ continue;
+ log_debug("%s: flow %p saproto %d -> %d", __func__,
+ flow, flow->flow_saproto, IKEV2_SAPROTO_IPCOMP);
+ flow->flow_saproto = IKEV2_SAPROTO_IPCOMP;
+ }
+
+ /* setup ESP flows for gateways */
+ flowa->flow_dir = IPSP_DIRECTION_OUT;
+ flowa->flow_saproto = IKEV2_SAPROTO_ESP;
+ if (sa->sa_hdr.sh_initiator) {
+ flowa->flow_dstid = &sa->sa_rid;
+ flowa->flow_srcid = &sa->sa_iid;
+ } else {
+ flowa->flow_dstid = &sa->sa_iid;
+ flowa->flow_srcid = &sa->sa_rid;
+ }
+ flowa->flow_local = &sa->sa_local;
+ flowa->flow_peer = &sa->sa_peer;
+ memcpy(&flowa->flow_src, &sa->sa_local, sizeof(sa->sa_local));
+ memcpy(&flowa->flow_dst, &sa->sa_peer, sizeof(sa->sa_peer));
+ flowa->flow_src.addr_mask = flowa->flow_dst.addr_mask =
+ (sa->sa_local.addr_af == AF_INET) ? 32 : 128;
+ flowa->flow_src.addr_port = flowa->flow_dst.addr_port = 0;
+ flowa->flow_ikesa = sa;
+
+ memcpy(flowb, flowa, sizeof(*flowb));
+ flowb->flow_dir = IPSP_DIRECTION_IN;
+ memcpy(&flowb->flow_dst, &flowa->flow_src, sizeof(flowa->flow_src));
+ memcpy(&flowb->flow_src, &flowa->flow_dst, sizeof(flowa->flow_dst));
+
+ TAILQ_INSERT_TAIL(&sa->sa_flows, flowa, flow_entry);
+ TAILQ_INSERT_TAIL(&sa->sa_flows, flowb, flow_entry);
+
+ /* make sure IPCOMP CPIs are not reused */
+ sa->sa_ipcomp = 0;
+ sa->sa_cpi_in = sa->sa_cpi_out = 0;
+
+ return (0);
+}
+
+int
ikev2_childsa_enable(struct iked *env, struct iked_sa *sa)
{
struct iked_childsa *csa;
struct iked_flow *flow, *oflow;
+ if (sa->sa_ipcomp && sa->sa_cpi_in && sa->sa_cpi_out &&
+ ikev2_ipcomp_enable(sa) == -1)
+ return (-1);
+
TAILQ_FOREACH(csa, &sa->sa_childsas, csa_entry) {
if (csa->csa_rekey || csa->csa_loaded)
continue;
diff --git a/sbin/iked/ikev2.h b/sbin/iked/ikev2.h
index 439e8ab38b6..e8dbf7b5d76 100644
--- a/sbin/iked/ikev2.h
+++ b/sbin/iked/ikev2.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ikev2.h,v 1.12 2013/03/30 16:31:37 reyk Exp $ */
+/* $OpenBSD: ikev2.h,v 1.13 2014/02/14 09:00:03 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -125,6 +125,7 @@ struct ikev2_sa_proposal {
#define IKEV2_SAPROTO_ESP 3 /* ESP */
#define IKEV2_SAPROTO_FC_ESP_HEADER 4 /* RFC4595 */
#define IKEV2_SAPROTO_FC_CT_AUTH 5 /* RFC4595 */
+#define IKEV2_SAPROTO_IPCOMP 204 /* private, should be 4 */
extern struct iked_constmap ikev2_saproto_map[];
diff --git a/sbin/iked/ikev2_pld.c b/sbin/iked/ikev2_pld.c
index 9dc7b45e78f..df5ca6a5fc2 100644
--- a/sbin/iked/ikev2_pld.c
+++ b/sbin/iked/ikev2_pld.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ikev2_pld.c,v 1.36 2014/02/12 12:59:44 markus Exp $ */
+/* $OpenBSD: ikev2_pld.c,v 1.37 2014/02/14 09:00:03 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -650,6 +650,8 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld,
struct iked_spi *rekey;
u_int16_t type;
u_int16_t group;
+ u_int16_t cpi;
+ u_int8_t transform;
if ((n = ibuf_seek(msg->msg_data, offset, sizeof(*n))) == NULL)
return (-1);
@@ -753,6 +755,23 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld,
print_map(n->n_protoid, ikev2_saproto_map),
print_spi(rekey->spi, n->n_spisize));
break;
+ case IKEV2_N_IPCOMP_SUPPORTED:
+ if (len < sizeof(cpi) + sizeof(transform)) {
+ log_debug("%s: malformed ipcomp notification",
+ __func__);
+ return (0);
+ }
+ memcpy(&cpi, buf, sizeof(cpi));
+ memcpy(&transform, buf + sizeof(cpi), sizeof(transform));
+ log_debug("%s: cpi 0x%x, transform %s, len %d", __func__,
+ betoh16(cpi), print_map(transform, ikev2_ipcomp_map), len);
+ /* we only support deflate */
+ if ((msg->msg_policy->pol_flags & IKED_POLICY_IPCOMP) &&
+ (transform == IKEV2_IPCOMP_DEFLATE)) {
+ msg->msg_sa->sa_ipcomp = transform;
+ msg->msg_sa->sa_cpi_out = betoh16(cpi);
+ }
+ break;
}
return (0);
diff --git a/sbin/iked/parse.y b/sbin/iked/parse.y
index b8864672e10..e9e14f5a4c3 100644
--- a/sbin/iked/parse.y
+++ b/sbin/iked/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.35 2014/01/22 00:21:16 henning Exp $ */
+/* $OpenBSD: parse.y,v 1.36 2014/02/14 09:00:03 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -369,6 +369,7 @@ typedef struct {
%token PASSIVE ACTIVE ANY TAG TAP PROTO LOCAL GROUP NAME CONFIG EAP USER
%token IKEV1 FLOW SA TCPMD5 TUNNEL TRANSPORT COUPLE DECOUPLE SET
%token INCLUDE LIFETIME BYTES INET INET6 QUICK SKIP DEFAULT
+%token IPCOMP
%token <v.string> STRING
%token <v.number> NUMBER
%type <v.string> string
@@ -385,7 +386,7 @@ typedef struct {
%type <v.id> id
%type <v.transforms> transforms
%type <v.filters> filters
-%type <v.ikemode> ikeflags ikematch ikemode
+%type <v.ikemode> ikeflags ikematch ikemode ipcomp
%type <v.ikeauth> ikeauth
%type <v.ikekey> keyspec
%type <v.mode> ike_sa child_sa
@@ -752,7 +753,7 @@ ike_sa : /* empty */ {
encxfs = ikeencxfs;
} transforms {
if (($$ = calloc(1, sizeof(*$$))) == NULL)
- err(1, "child_sa: calloc");
+ err(1, "ike_sa: calloc");
$$->xfs = $3;
}
;
@@ -769,7 +770,7 @@ child_sa : /* empty */ {
}
;
-ikeflags : ikematch ikemode { $$ = $1 | $2; }
+ikeflags : ikematch ikemode ipcomp { $$ = $1 | $2 | $3; }
;
ikematch : /* empty */ { $$ = 0; }
@@ -783,6 +784,10 @@ ikemode : /* empty */ { $$ = IKED_POLICY_PASSIVE; }
| ACTIVE { $$ = IKED_POLICY_ACTIVE; }
;
+ipcomp : /* empty */ { $$ = 0; }
+ | IPCOMP { $$ = IKED_POLICY_IPCOMP; }
+ ;
+
ikeauth : /* empty */ {
$$.auth_method = IKEV2_AUTH_RSA_SIG;
$$.auth_length = 0;
@@ -1077,6 +1082,7 @@ lookup(char *s)
{ "include", INCLUDE },
{ "inet", INET },
{ "inet6", INET6 },
+ { "ipcomp", IPCOMP },
{ "lifetime", LIFETIME },
{ "local", LOCAL },
{ "name", NAME },
diff --git a/sbin/iked/pfkey.c b/sbin/iked/pfkey.c
index 18510859c57..1c97009d60d 100644
--- a/sbin/iked/pfkey.c
+++ b/sbin/iked/pfkey.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfkey.c,v 1.27 2014/01/22 09:25:41 markus Exp $ */
+/* $OpenBSD: pfkey.c,v 1.28 2014/02/14 09:00:03 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -99,6 +99,7 @@ static const struct pfkey_constmap pfkey_integr[] = {
static const struct pfkey_constmap pfkey_satype[] = {
{ SADB_SATYPE_AH, IKEV2_SAPROTO_AH },
{ SADB_SATYPE_ESP, IKEV2_SAPROTO_ESP },
+ { SADB_X_SATYPE_IPCOMP, IKEV2_SAPROTO_IPCOMP },
{ 0 }
};
@@ -478,8 +479,8 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa)
sadb.sadb_sa_state = SADB_SASTATE_MATURE;
sadb.sadb_sa_replay = 64;
- /* XXX we don't support transport mode, yet */
- sadb.sadb_sa_flags |= SADB_X_SAFLAGS_TUNNEL;
+ if (!sa->csa_transport)
+ sadb.sadb_sa_flags |= SADB_X_SAFLAGS_TUNNEL;
if (sa->csa_esn)
sadb.sadb_sa_flags |= SADB_X_SAFLAGS_ESN;
@@ -526,7 +527,8 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa)
return (-1);
}
- if (sa->csa_ikesa->sa_udpencap && sa->csa_ikesa->sa_natt) {
+ if (satype == SADB_SATYPE_ESP &&
+ sa->csa_ikesa->sa_udpencap && sa->csa_ikesa->sa_natt) {
sadb.sadb_sa_flags |= SADB_X_SAFLAGS_UDPENCAP;
udpencap.sadb_x_udpencap_exttype = SADB_X_EXT_UDPENCAP;
udpencap.sadb_x_udpencap_len = sizeof(udpencap) / 8;
@@ -571,6 +573,10 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa)
8 * ibuf_size(sa->csa_encrkey);
}
+ /* we only support deflate */
+ if (satype == SADB_X_SATYPE_IPCOMP)
+ sadb.sadb_sa_encrypt = SADB_X_CALG_DEFLATE;
+
/* local id */
sa_srcid = pfkey_id2ident(sa->csa_srcid, SADB_EXT_IDENTITY_SRC);
@@ -861,7 +867,8 @@ pfkey_sa_getspi(int sd, u_int8_t satype, struct iked_childsa *sa,
sa_spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE;
sa_spirange.sadb_spirange_len = sizeof(sa_spirange) / 8;
sa_spirange.sadb_spirange_min = 0x100;
- sa_spirange.sadb_spirange_max = 0xffffffff;
+ sa_spirange.sadb_spirange_max = (satype == SADB_X_SATYPE_IPCOMP) ?
+ (CPI_PRIVATE_MIN - 1) : 0xffffffff;
sa_spirange.sadb_spirange_reserved = 0;
bzero(&sa_src, sizeof(sa_src));
diff --git a/sbin/iked/util.c b/sbin/iked/util.c
index 77de1c406c3..dcdedf3a815 100644
--- a/sbin/iked/util.c
+++ b/sbin/iked/util.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: util.c,v 1.23 2013/12/03 13:55:40 markus Exp $ */
+/* $OpenBSD: util.c,v 1.24 2014/02/14 09:00:03 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -361,6 +361,9 @@ print_spi(u_int64_t spi, int size)
ptr = buf[i];
switch (size) {
+ case 2:
+ snprintf(ptr, 32, "0x%04x", (u_int16_t)spi);
+ break;
case 4:
snprintf(ptr, 32, "0x%08x", (u_int32_t)spi);
break;