From 1c18b69367c703c733c6898fbefe53a795dd7913 Mon Sep 17 00:00:00 2001 From: tobhe Date: Fri, 11 Aug 2023 11:24:55 +0000 Subject: [PATCH] Add iked support for route based sec(4) tunnels. To use sec(4) instead of policy based tunnels, create a sec(4) interface and add 'iface secXX' to your policy config. sec(4) interfaces also support auto configuration for dynamic client IPs via 'request any' like all other interfaces. The config won't work without traffic selectors, 'from any to any' should work for now but I plan to make this optional in the future. ok dlg@ --- sbin/iked/iked.h | 3 +- sbin/iked/ikev2.c | 106 +++++++++++++++++++++++----------------------- sbin/iked/parse.y | 6 ++- sbin/iked/pfkey.c | 35 ++++++++++++++- 4 files changed, 94 insertions(+), 56 deletions(-) diff --git a/sbin/iked/iked.h b/sbin/iked/iked.h index 2c7fbe14af3..bdfac0ee74e 100644 --- a/sbin/iked/iked.h +++ b/sbin/iked/iked.h @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.h,v 1.223 2023/07/28 11:23:03 claudio Exp $ */ +/* $OpenBSD: iked.h,v 1.224 2023/08/11 11:24:55 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider @@ -260,6 +260,7 @@ struct iked_policy { #define IKED_POLICY_SKIP 0x10 #define IKED_POLICY_IPCOMP 0x20 #define IKED_POLICY_TRANSPORT 0x40 +#define IKED_POLICY_ROUTING 0x80 int pol_refcnt; diff --git a/sbin/iked/ikev2.c b/sbin/iked/ikev2.c index bf6bf0fb0d4..e243432a742 100644 --- a/sbin/iked/ikev2.c +++ b/sbin/iked/ikev2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.c,v 1.377 2023/08/04 19:06:25 claudio Exp $ */ +/* $OpenBSD: ikev2.c,v 1.378 2023/08/11 11:24:55 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider @@ -6532,63 +6532,65 @@ ikev2_childsa_enable(struct iked *env, struct iked_sa *sa) peer_changed = (memcmp(&sa->sa_peer_loaded, &sa->sa_peer, sizeof(sa->sa_peer_loaded)) != 0); - TAILQ_FOREACH(flow, &sa->sa_flows, flow_entry) { - /* re-load the flow if the peer for the flow has changed */ - reload = 0; - if (flow->flow_loaded) { - if (!peer_changed) { - log_debug("%s: flow already loaded %p", - __func__, flow); - continue; + if (!(sa->sa_policy->pol_flags & IKED_POLICY_ROUTING)) { + TAILQ_FOREACH(flow, &sa->sa_flows, flow_entry) { + /* re-load the flow if the peer for the flow has changed */ + reload = 0; + if (flow->flow_loaded) { + if (!peer_changed) { + log_debug("%s: flow already loaded %p", + __func__, flow); + continue; + } + RB_REMOVE(iked_flows, &env->sc_activeflows, flow); + (void)pfkey_flow_delete(env, flow); + flow->flow_loaded = 0; /* we did RB_REMOVE */ + reload = 1; } - RB_REMOVE(iked_flows, &env->sc_activeflows, flow); - (void)pfkey_flow_delete(env, flow); - flow->flow_loaded = 0; /* we did RB_REMOVE */ - reload = 1; - } - if (pfkey_flow_add(env, flow) != 0) { - log_debug("%s: failed to load flow", __func__); - goto done; - } + if (pfkey_flow_add(env, flow) != 0) { + log_debug("%s: failed to load flow", __func__); + goto done; + } - if ((oflow = RB_FIND(iked_flows, &env->sc_activeflows, flow)) - != NULL) { - log_debug("%s: replaced old flow %p with %p", - __func__, oflow, flow); - oflow->flow_loaded = 0; - RB_REMOVE(iked_flows, &env->sc_activeflows, oflow); - } + if ((oflow = RB_FIND(iked_flows, &env->sc_activeflows, flow)) + != NULL) { + log_debug("%s: replaced old flow %p with %p", + __func__, oflow, flow); + oflow->flow_loaded = 0; + RB_REMOVE(iked_flows, &env->sc_activeflows, oflow); + } - RB_INSERT(iked_flows, &env->sc_activeflows, flow); + RB_INSERT(iked_flows, &env->sc_activeflows, flow); - log_debug("%s: %sloaded flow %p", __func__, - reload ? "re" : "", flow); + log_debug("%s: %sloaded flow %p", __func__, + reload ? "re" : "", flow); - /* append flow to log buffer */ - if (flow->flow_dir == IPSP_DIRECTION_OUT && - flow->flow_prenat.addr_af != 0) - snprintf(prenat_mask, sizeof(prenat_mask), "%d", - flow->flow_prenat.addr_mask); - else - prenat_mask[0] = '\0'; - if (flow->flow_dir == IPSP_DIRECTION_OUT) { - if (ftello(flowf) > 0) - fputs(", ", flowf); - fprintf(flowf, "%s-%s/%d%s%s%s%s%s=%s/%d(%u)%s", - print_map(flow->flow_saproto, ikev2_saproto_map), - print_addr(&flow->flow_src.addr), - flow->flow_src.addr_mask, - flow->flow_prenat.addr_af != 0 ? "[": "", - flow->flow_prenat.addr_af != 0 ? - print_addr(&flow->flow_prenat.addr) : "", - flow->flow_prenat.addr_af != 0 ? "/" : "", - flow->flow_prenat.addr_af != 0 ? prenat_mask : "", - flow->flow_prenat.addr_af != 0 ? "]": "", - print_addr(&flow->flow_dst.addr), - flow->flow_dst.addr_mask, - flow->flow_ipproto, - reload ? "-R" : ""); + /* append flow to log buffer */ + if (flow->flow_dir == IPSP_DIRECTION_OUT && + flow->flow_prenat.addr_af != 0) + snprintf(prenat_mask, sizeof(prenat_mask), "%d", + flow->flow_prenat.addr_mask); + else + prenat_mask[0] = '\0'; + if (flow->flow_dir == IPSP_DIRECTION_OUT) { + if (ftello(flowf) > 0) + fputs(", ", flowf); + fprintf(flowf, "%s-%s/%d%s%s%s%s%s=%s/%d(%u)%s", + print_map(flow->flow_saproto, ikev2_saproto_map), + print_addr(&flow->flow_src.addr), + flow->flow_src.addr_mask, + flow->flow_prenat.addr_af != 0 ? "[": "", + flow->flow_prenat.addr_af != 0 ? + print_addr(&flow->flow_prenat.addr) : "", + flow->flow_prenat.addr_af != 0 ? "/" : "", + flow->flow_prenat.addr_af != 0 ? prenat_mask : "", + flow->flow_prenat.addr_af != 0 ? "]": "", + print_addr(&flow->flow_dst.addr), + flow->flow_dst.addr_mask, + flow->flow_ipproto, + reload ? "-R" : ""); + } } } diff --git a/sbin/iked/parse.y b/sbin/iked/parse.y index 075981db320..5fadcd200e6 100644 --- a/sbin/iked/parse.y +++ b/sbin/iked/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.143 2023/06/14 14:09:29 claudio Exp $ */ +/* $OpenBSD: parse.y,v 1.144 2023/08/11 11:24:55 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider @@ -2519,6 +2519,10 @@ create_ike(char *name, int af, struct ipsec_addr_wrap *ipproto, } if (iface != NULL) { + /* sec(4) */ + if (strncmp("sec", iface, strlen("sec")) == 0) + pol.pol_flags |= IKED_POLICY_ROUTING; + pol.pol_iface = if_nametoindex(iface); if (pol.pol_iface == 0) { yyerror("invalid iface"); diff --git a/sbin/iked/pfkey.c b/sbin/iked/pfkey.c index eaebe53a990..80a931d5132 100644 --- a/sbin/iked/pfkey.c +++ b/sbin/iked/pfkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfkey.c,v 1.82 2023/06/13 12:34:12 tb Exp $ */ +/* $OpenBSD: pfkey.c,v 1.83 2023/08/11 11:24:55 tobhe Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -40,7 +41,7 @@ #include "ikev2.h" #define ROUNDUP(x) (((x) + (PFKEYV2_CHUNK - 1)) & ~(PFKEYV2_CHUNK - 1)) -#define IOV_CNT 27 +#define IOV_CNT 28 #define PFKEYV2_CHUNK sizeof(uint64_t) #define PFKEY_REPLY_TIMEOUT 1000 @@ -453,6 +454,7 @@ pfkey_flow(struct iked *env, uint8_t satype, uint8_t action, struct iked_flow *f int pfkey_sa(struct iked *env, uint8_t satype, uint8_t action, struct iked_childsa *sa) { + char iface[IF_NAMESIZE]; struct sadb_msg smsg; struct sadb_sa sadb; struct sadb_address sa_src, sa_dst, sa_pxy; @@ -460,6 +462,7 @@ pfkey_sa(struct iked *env, uint8_t satype, uint8_t action, struct iked_childsa * struct sadb_lifetime sa_ltime_hard, sa_ltime_soft; struct sadb_x_udpencap udpencap; struct sadb_x_tag sa_tag; + struct sadb_x_iface sa_iface; char *tag = NULL; struct sadb_x_tap sa_tap; struct sadb_x_rdomain sa_rdomain; @@ -469,6 +472,8 @@ pfkey_sa(struct iked *env, uint8_t satype, uint8_t action, struct iked_childsa * struct iked_policy *pol; struct iked_addr *dst; struct iovec iov[IOV_CNT]; + const char *errstr = NULL; + uint32_t ifminor; uint32_t jitter; int iov_cnt; int ret, dotap = 0; @@ -549,6 +554,7 @@ pfkey_sa(struct iked *env, uint8_t satype, uint8_t action, struct iked_childsa * bzero(&udpencap, sizeof udpencap); bzero(&sa_ltime_hard, sizeof(sa_ltime_hard)); bzero(&sa_ltime_soft, sizeof(sa_ltime_soft)); + bzero(&sa_iface, sizeof(sa_iface)); if (pol->pol_rdomain >= 0) { bzero(&sa_rdomain, sizeof(sa_rdomain)); @@ -688,6 +694,24 @@ pfkey_sa(struct iked *env, uint8_t satype, uint8_t action, struct iked_childsa * sa_tap.sadb_x_tap_unit = pol->pol_tap; } + if (pol->pol_flags & IKED_POLICY_ROUTING) { + sa_iface.sadb_x_iface_exttype = SADB_X_EXT_IFACE; + sa_iface.sadb_x_iface_len = sizeof(sa_iface) / 8; + if (if_indextoname(pol->pol_iface, iface) == NULL) { + log_warnx("%s: unsupported interface %s", + __func__, iface); + return (-1); + } + ifminor = strtonum(iface + strlen("sec"), 0, UINT_MAX, &errstr); + if (errstr != NULL) { + log_warnx("%s: unsupported interface %s", + __func__, iface); + return (-1); + } + sa_iface.sadb_x_iface_unit = ifminor; + sa_iface.sadb_x_iface_direction = sa->csa_dir; + } + send: #define PAD(len) \ @@ -816,6 +840,13 @@ pfkey_sa(struct iked *env, uint8_t satype, uint8_t action, struct iked_childsa * PAD(strlen(tag) + 1); } + if (sa_iface.sadb_x_iface_len) { + iov[iov_cnt].iov_base = &sa_iface; + iov[iov_cnt].iov_len = sa_iface.sadb_x_iface_len * 8; + smsg.sadb_msg_len += sa_iface.sadb_x_iface_len; + iov_cnt++; + } + if (dotap != 0) { /* enc(4) device tap unit */ iov[iov_cnt].iov_base = &sa_tap; -- 2.20.1