diff options
author | tobhe <tobhe@cvs.openbsd.org> | 2020-04-23 20:17:49 +0000 |
---|---|---|
committer | tobhe <tobhe@cvs.openbsd.org> | 2020-04-23 20:17:49 +0000 |
commit | 48e8336a93ee5477612ac36b8db972172f57c91a (patch) | |
tree | 55aecda502ed961a760f8f743cb655e3122d500f /sbin/iked | |
parent | eed9d5297e393aa212e99b0d044ac49035fa8f83 (diff) |
Add support for switching rdomain on IPsec encryption/decryption.
It can be configured per policy with the new 'rdomain' option
(see iked.conf(5)).
Only the unencrypted (inner) rdomain has to be configured, the
encrypted rdomain is always the one the responsible iked instance
is running in.
The configured rdomain must exist before iked activates the IPsec SAs,
otherwise pfkey will return an error.
ok markus@, patrick@
Diffstat (limited to 'sbin/iked')
-rw-r--r-- | sbin/iked/iked.conf.5 | 16 | ||||
-rw-r--r-- | sbin/iked/iked.h | 4 | ||||
-rw-r--r-- | sbin/iked/ikev2.c | 6 | ||||
-rw-r--r-- | sbin/iked/parse.y | 35 | ||||
-rw-r--r-- | sbin/iked/pfkey.c | 104 | ||||
-rw-r--r-- | sbin/iked/policy.c | 4 |
6 files changed, 151 insertions, 18 deletions
diff --git a/sbin/iked/iked.conf.5 b/sbin/iked/iked.conf.5 index b0128610c81..5ab4e2c676d 100644 --- a/sbin/iked/iked.conf.5 +++ b/sbin/iked/iked.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: iked.conf.5,v 1.63 2020/02/21 15:17:34 tobhe Exp $ +.\" $OpenBSD: iked.conf.5,v 1.64 2020/04/23 20:17:48 tobhe Exp $ .\" .\" Copyright (c) 2010 - 2014 Reyk Floeter <reyk@openbsd.org> .\" Copyright (c) 2004 Mathieu Sauve-Frankel All rights reserved. @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: February 21 2020 $ +.Dd $Mdocdate: April 23 2020 $ .Dt IKED.CONF 5 .Os .Sh NAME @@ -311,6 +311,18 @@ For a list of all the protocol name to number mappings used by .Xr iked 8 , see the file .Pa /etc/protocols . +.It Ic rdomain Ar number +Specify a different routing domain for unencrypted traffic. +The resulting IPsec SAs will match outgoing packets in the specified +.Ic rdomain Ar number +and move the encrypted packets to the rdomain the +.Xr iked 8 +instance is running in. +Vice versa, incoming +.Xr ipsec 4 +traffic is moved to +.Ic rdomain Ar number +after decryption. .It Xo .Ic from Ar src .Op Ic port Ar sport diff --git a/sbin/iked/iked.h b/sbin/iked/iked.h index e234af3b509..8264960cca7 100644 --- a/sbin/iked/iked.h +++ b/sbin/iked/iked.h @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.h,v 1.146 2020/04/20 20:03:38 tobhe Exp $ */ +/* $OpenBSD: iked.h,v 1.147 2020/04/23 20:17:48 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de> @@ -151,6 +151,7 @@ struct iked_flow { struct iked_addr flow_src; struct iked_addr flow_dst; unsigned int flow_dir; /* in/out */ + int flow_rdomain; struct iked_addr flow_prenat; unsigned int flow_loaded; /* pfkey done */ @@ -261,6 +262,7 @@ struct iked_policy { uint8_t pol_certreqtype; int pol_af; + int pol_rdomain; uint8_t pol_saproto; unsigned int pol_ipproto; diff --git a/sbin/iked/ikev2.c b/sbin/iked/ikev2.c index 4478ae1beee..3d586904e35 100644 --- a/sbin/iked/ikev2.c +++ b/sbin/iked/ikev2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.c,v 1.217 2020/04/22 16:52:04 tobhe Exp $ */ +/* $OpenBSD: ikev2.c,v 1.218 2020/04/23 20:17:48 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de> @@ -5412,6 +5412,7 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, flowa->flow_dir = IPSP_DIRECTION_OUT; flowa->flow_saproto = ic ? IKEV2_SAPROTO_IPCOMP : prop->prop_protoid; + flowa->flow_rdomain = sa->sa_policy->pol_rdomain; flowa->flow_local = &sa->sa_local; flowa->flow_peer = &sa->sa_peer; flowa->flow_ikesa = sa; @@ -6481,7 +6482,7 @@ ikev2_info_flow(struct iked *env, int dolog, const char *msg, struct iked_flow * int buflen; buflen = asprintf(&buf, - "%s: %p %s %s %s/%d -> %s/%d [%u] (%s) @%p\n", msg, flow, + "%s: %p %s %s %s/%d -> %s/%d [%u]@%d (%s) @%p\n", msg, flow, print_map(flow->flow_saproto, ikev2_saproto_map), flow->flow_dir == IPSP_DIRECTION_IN ? "in" : "out", print_host((struct sockaddr *)&flow->flow_src.addr, NULL, 0), @@ -6489,6 +6490,7 @@ ikev2_info_flow(struct iked *env, int dolog, const char *msg, struct iked_flow * print_host((struct sockaddr *)&flow->flow_dst.addr, NULL, 0), flow->flow_dst.addr_mask, flow->flow_ipproto, + flow->flow_rdomain, flow->flow_loaded ? "L" : "", flow->flow_ikesa); diff --git a/sbin/iked/parse.y b/sbin/iked/parse.y index bf1d601e651..5c7a22d0746 100644 --- a/sbin/iked/parse.y +++ b/sbin/iked/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.93 2020/04/14 11:30:15 tobhe Exp $ */ +/* $OpenBSD: parse.y,v 1.94 2020/04/23 20:17:48 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de> @@ -351,7 +351,8 @@ void copy_transforms(unsigned int, const struct ipsec_xf **, unsigned int, struct iked_transform **, unsigned int *, struct iked_transform *, size_t); -int create_ike(char *, int, uint8_t, struct ipsec_hosts *, +int create_ike(char *, int, uint8_t, + int, struct ipsec_hosts *, struct ipsec_hosts *, struct ipsec_mode *, struct ipsec_mode *, uint8_t, uint8_t, char *, char *, @@ -408,7 +409,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 OCSP IKELIFETIME MOBIKE NOMOBIKE +%token IPCOMP OCSP IKELIFETIME MOBIKE NOMOBIKE RDOMAIN %token FRAGMENTATION NOFRAGMENTATION %token <v.string> STRING %token <v.number> NUMBER @@ -418,7 +419,7 @@ typedef struct { %type <v.number> protoval %type <v.hosts> hosts hosts_list %type <v.port> port -%type <v.number> portval af +%type <v.number> portval af rdomain %type <v.peers> peers %type <v.anyhost> anyhost %type <v.host> host host_spec @@ -491,12 +492,12 @@ user : USER STRING STRING { } ; -ikev2rule : IKEV2 name ikeflags satype af proto hosts_list peers +ikev2rule : IKEV2 name ikeflags satype af proto rdomain hosts_list peers ike_sas child_sas ids ikelifetime lifetime ikeauth ikecfg filters { - if (create_ike($2, $5, $6, $7, &$8, $9, $10, $4, $3, - $11.srcid, $11.dstid, $12, &$13, &$14, - $16, $15) == -1) { + if (create_ike($2, $5, $6, $7, $8, &$9, $10, $11, $4, + $3, $12.srcid, $12.dstid, $13, &$14, &$15, + $17, $16) == -1) { yyerror("create_ike failed"); YYERROR; } @@ -577,6 +578,15 @@ protoval : STRING { } ; +rdomain : /* empty */ { $$ = -1; } + | RDOMAIN NUMBER { + if ($2 > 255 || $2 < 0) { + yyerror("rdomain outside range"); + YYERROR; + } + $$ = $2; + } + hosts_list : hosts { $$ = $1; } | hosts_list comma hosts { if ($3 == NULL) @@ -1264,6 +1274,7 @@ lookup(char *s) { "proto", PROTO }, { "psk", PSK }, { "quick", QUICK }, + { "rdomain", RDOMAIN }, { "sa", SA }, { "set", SET }, { "skip", SKIP }, @@ -2499,6 +2510,9 @@ print_policy(struct iked_policy *pol) print_verbose(" inet6"); } + if (pol->pol_rdomain) + print_verbose(" rdomain %d", pol->pol_rdomain); + RB_FOREACH(flow, iked_flows, &pol->pol_flows) { print_verbose(" from %s", print_host((struct sockaddr *)&flow->flow_src.addr, NULL, @@ -2681,7 +2695,8 @@ copy_transforms(unsigned int type, } int -create_ike(char *name, int af, uint8_t ipproto, struct ipsec_hosts *hosts, +create_ike(char *name, int af, uint8_t ipproto, + int rdomain, struct ipsec_hosts *hosts, struct ipsec_hosts *peers, struct ipsec_mode *ike_sa, struct ipsec_mode *ipsec_sa, uint8_t saproto, uint8_t flags, char *srcid, char *dstid, @@ -2711,6 +2726,7 @@ create_ike(char *name, int af, uint8_t ipproto, struct ipsec_hosts *hosts, pol.pol_saproto = saproto; pol.pol_ipproto = ipproto; pol.pol_flags = flags; + pol.pol_rdomain = rdomain; memcpy(&pol.pol_auth, authtype, sizeof(struct iked_auth)); if (name != NULL) { @@ -2971,6 +2987,7 @@ create_ike(char *name, int af, uint8_t ipproto, struct ipsec_hosts *hosts, } flow->flow_ipproto = ipproto; + flow->flow_rdomain = rdomain; if (RB_INSERT(iked_flows, &pol.pol_flows, flow) == NULL) pol.pol_nflows++; diff --git a/sbin/iked/pfkey.c b/sbin/iked/pfkey.c index b4d2ffff537..8415bf3d926 100644 --- a/sbin/iked/pfkey.c +++ b/sbin/iked/pfkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfkey.c,v 1.63 2020/01/14 22:28:29 tobhe Exp $ */ +/* $OpenBSD: pfkey.c,v 1.64 2020/04/23 20:17:48 tobhe Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -40,7 +40,7 @@ #include "ikev2.h" #define ROUNDUP(x) (((x) + (PFKEYV2_CHUNK - 1)) & ~(PFKEYV2_CHUNK - 1)) -#define IOV_CNT 20 +#define IOV_CNT 21 #define PFKEYV2_CHUNK sizeof(uint64_t) #define PFKEY_REPLY_TIMEOUT 1000 @@ -51,6 +51,8 @@ static uint32_t sadb_msg_seq = 0; static unsigned int sadb_decoupled = 0; +static int iked_rdomain = 0; + static struct event pfkey_timer_ev; static struct timeval pfkey_timer_tv; @@ -184,6 +186,7 @@ pfkey_flow(int sd, uint8_t satype, uint8_t action, struct iked_flow *flow) struct sadb_address sa_src, sa_dst, sa_local, sa_peer, sa_smask, sa_dmask; struct sadb_protocol sa_flowtype, sa_protocol; + struct sadb_x_rdomain sa_rdomain; struct sadb_ident *sa_srcid, *sa_dstid; struct sockaddr_storage ssrc, sdst, slocal, speer, smask, dmask; struct iovec iov[IOV_CNT]; @@ -335,6 +338,14 @@ pfkey_flow(int sd, uint8_t satype, uint8_t action, struct iked_flow *flow) SADB_EXT_IDENTITY_DST); } + if (flow->flow_rdomain >= 0) { + /* install flow in specific rdomain */ + bzero(&sa_rdomain, sizeof(sa_rdomain)); + sa_rdomain.sadb_x_rdomain_exttype = SADB_X_EXT_RDOMAIN; + sa_rdomain.sadb_x_rdomain_len = sizeof(sa_rdomain) / 8; + sa_rdomain.sadb_x_rdomain_dom1 = flow->flow_rdomain; + } + iov_cnt = 0; /* header */ @@ -427,6 +438,13 @@ pfkey_flow(int sd, uint8_t satype, uint8_t action, struct iked_flow *flow) iov_cnt++; } + if (flow->flow_rdomain >= 0) { + iov[iov_cnt].iov_base = &sa_rdomain; + iov[iov_cnt].iov_len = sizeof(sa_rdomain); + smsg.sadb_msg_len += sa_rdomain.sadb_x_rdomain_len; + iov_cnt++; + } + ret = pfkey_write(sd, &smsg, iov, iov_cnt, NULL, NULL); free(sa_srcid); @@ -447,6 +465,7 @@ pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) struct sadb_x_tag sa_tag; char *tag = NULL; struct sadb_x_tap sa_tap; + struct sadb_x_rdomain sa_rdomain; struct sockaddr_storage ssrc, sdst, spxy; struct sadb_ident *sa_srcid, *sa_dstid; struct iked_lifetime *lt; @@ -532,6 +551,24 @@ pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) bzero(&sa_ltime_hard, sizeof(sa_ltime_hard)); bzero(&sa_ltime_soft, sizeof(sa_ltime_soft)); + if (pol->pol_rdomain >= 0) { + bzero(&sa_rdomain, sizeof(sa_rdomain)); + sa_rdomain.sadb_x_rdomain_exttype = SADB_X_EXT_RDOMAIN; + sa_rdomain.sadb_x_rdomain_len = sizeof(sa_rdomain) / 8; + if (satype == SADB_X_SATYPE_IPCOMP) { + /* IPCOMP SAs are always in the pol_rdomain */ + sa_rdomain.sadb_x_rdomain_dom1 = pol->pol_rdomain; + sa_rdomain.sadb_x_rdomain_dom2 = pol->pol_rdomain; + } else if (sa->csa_dir == IPSP_DIRECTION_OUT) { + /* switch rdomain on encrypt/decrypt */ + sa_rdomain.sadb_x_rdomain_dom1 = pol->pol_rdomain; + sa_rdomain.sadb_x_rdomain_dom2 = iked_rdomain; + } else { + sa_rdomain.sadb_x_rdomain_dom1 = iked_rdomain; + sa_rdomain.sadb_x_rdomain_dom2 = pol->pol_rdomain; + } + } + if (action == SADB_DELETE) goto send; @@ -775,6 +812,13 @@ pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) iov_cnt++; } + if (pol->pol_rdomain >= 0) { + iov[iov_cnt].iov_base = &sa_rdomain; + iov[iov_cnt].iov_len = sizeof(sa_rdomain); + smsg.sadb_msg_len += sa_rdomain.sadb_x_rdomain_len; + iov_cnt++; + } + ret = pfkey_write(sd, &smsg, iov, iov_cnt, NULL, NULL); free(sa_srcid); @@ -786,15 +830,17 @@ pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) int pfkey_sa_last_used(int sd, struct iked_childsa *sa, uint64_t *last_used) { + struct iked_policy *pol = sa->csa_ikesa->sa_policy; struct sadb_msg *msg, smsg; struct sadb_address sa_src, sa_dst; struct sadb_sa sadb; + struct sadb_x_rdomain sa_rdomain; struct sadb_lifetime *sa_life; struct sockaddr_storage ssrc, sdst; struct iovec iov[IOV_CNT]; uint8_t *data; ssize_t n; - int iov_cnt, ret = -1; + int iov_cnt, ret = -1, rdomain; uint8_t satype; *last_used = 0; @@ -831,6 +877,15 @@ pfkey_sa_last_used(int sd, struct iked_childsa *sa, uint64_t *last_used) sadb.sadb_sa_state = SADB_SASTATE_MATURE; sadb.sadb_sa_replay = 64; + if (pol->pol_rdomain >= 0) { + rdomain = (sa->csa_dir == IPSP_DIRECTION_IN) ? + iked_rdomain : pol->pol_rdomain; + bzero(&sa_rdomain, sizeof(sa_rdomain)); + sa_rdomain.sadb_x_rdomain_exttype = SADB_X_EXT_RDOMAIN; + sa_rdomain.sadb_x_rdomain_len = sizeof(sa_rdomain) / 8; + sa_rdomain.sadb_x_rdomain_dom1 = rdomain; + } + bzero(&sa_src, sizeof(sa_src)); sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; @@ -870,6 +925,13 @@ pfkey_sa_last_used(int sd, struct iked_childsa *sa, uint64_t *last_used) smsg.sadb_msg_len += sa_dst.sadb_address_len; iov_cnt++; + if (pol->pol_rdomain >= 0) { + iov[iov_cnt].iov_base = &sa_rdomain; + iov[iov_cnt].iov_len = sizeof(sa_rdomain); + smsg.sadb_msg_len += sa_rdomain.sadb_x_rdomain_len; + iov_cnt++; + } + if ((ret = pfkey_write(sd, &smsg, iov, iov_cnt, &data, &n)) != 0) return (-1); @@ -1010,8 +1072,11 @@ pfkey_sagroup(int sd, uint8_t satype1, uint8_t action, struct sadb_address sa_dst1, sa_dst2; struct sockaddr_storage sdst1, sdst2; struct sadb_protocol sa_proto; + struct sadb_x_rdomain sa_rdomain; + struct iked_policy *pol; struct iovec iov[IOV_CNT]; int iov_cnt; + int group_rdomain; uint8_t satype2; if (pfkey_map(pfkey_satype, sa2->csa_saproto, &satype2) == -1) @@ -1052,6 +1117,28 @@ pfkey_sagroup(int sd, uint8_t satype1, uint8_t action, sadb2.sadb_sa_exttype = SADB_X_EXT_SA2; sadb2.sadb_sa_spi = htonl(sa2->csa_spi.spi); sadb2.sadb_sa_state = SADB_SASTATE_MATURE; + + /* Incoming SA1 (IPCOMP) and SA2 (ESP) are in different/other rdomain */ + group_rdomain = + (pol = sa1->csa_ikesa->sa_policy) != NULL && + pol->pol_rdomain >= 0 && + satype1 == SADB_X_SATYPE_IPCOMP && + satype2 == SADB_SATYPE_ESP; + if (group_rdomain) { + bzero(&sa_rdomain, sizeof(sa_rdomain)); + sa_rdomain.sadb_x_rdomain_exttype = SADB_X_EXT_RDOMAIN; + sa_rdomain.sadb_x_rdomain_len = sizeof(sa_rdomain) / 8; + if (sa1->csa_dir == IPSP_DIRECTION_IN) { + /* only ESP SA is iked's rdomain */ + sa_rdomain.sadb_x_rdomain_dom1 = pol->pol_rdomain; + sa_rdomain.sadb_x_rdomain_dom2 = iked_rdomain; + } else { + /* both SAs are in pol_rdomain */ + sa_rdomain.sadb_x_rdomain_dom1 = pol->pol_rdomain; + sa_rdomain.sadb_x_rdomain_dom2 = pol->pol_rdomain; + } + } + iov_cnt = 0; bzero(&sa_dst1, sizeof(sa_dst1)); @@ -1111,6 +1198,14 @@ pfkey_sagroup(int sd, uint8_t satype1, uint8_t action, smsg.sadb_msg_len += sa_proto.sadb_protocol_len; iov_cnt++; + /* SA1 and SA2 are from different rdomains */ + if (group_rdomain) { + iov[iov_cnt].iov_base = &sa_rdomain; + iov[iov_cnt].iov_len = sizeof(sa_rdomain); + smsg.sadb_msg_len += sa_rdomain.sadb_x_rdomain_len; + iov_cnt++; + } + return (pfkey_write(sd, &smsg, iov, iov_cnt, NULL, NULL)); } @@ -1467,6 +1562,8 @@ pfkey_init(struct iked *env, int fd) struct sadb_msg smsg; struct iovec iov; + iked_rdomain = getrtable(); + /* Set up a timer to process messages deferred by the pfkey_reply */ pfkey_timer_tv.tv_sec = 1; pfkey_timer_tv.tv_usec = 0; @@ -1787,6 +1884,7 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) goto out; } flow.flow_dir = sa_proto->sadb_protocol_direction; + flow.flow_rdomain = -1; /* XXX get from kernel */ log_debug("%s: flow %s from %s/%s to %s/%s via %s", __func__, flow.flow_dir == IPSP_DIRECTION_IN ? "in" : "out", diff --git a/sbin/iked/policy.c b/sbin/iked/policy.c index 3a05d947927..aa320248dd5 100644 --- a/sbin/iked/policy.c +++ b/sbin/iked/policy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: policy.c,v 1.58 2020/04/04 20:36:34 tobhe Exp $ */ +/* $OpenBSD: policy.c,v 1.59 2020/04/23 20:17:48 tobhe Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -875,6 +875,8 @@ flow_cmp(struct iked_flow *a, struct iked_flow *b) int diff = 0; if (!diff) + diff = a->flow_rdomain - b->flow_rdomain; + if (!diff) diff = (int)a->flow_ipproto - (int)b->flow_ipproto; if (!diff) diff = (int)a->flow_saproto - (int)b->flow_saproto; |