Add iked support for route based sec(4) tunnels.
authortobhe <tobhe@openbsd.org>
Fri, 11 Aug 2023 11:24:55 +0000 (11:24 +0000)
committertobhe <tobhe@openbsd.org>
Fri, 11 Aug 2023 11:24:55 +0000 (11:24 +0000)
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
sbin/iked/ikev2.c
sbin/iked/parse.y
sbin/iked/pfkey.c

index 2c7fbe1..bdfac0e 100644 (file)
@@ -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 <tobias.heider@stusta.de>
@@ -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;
 
index bf6bf0f..e243432 100644 (file)
@@ -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 <tobias.heider@stusta.de>
@@ -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" : "");
+                       }
                }
        }
 
index 075981d..5fadcd2 100644 (file)
@@ -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 <tobias.heider@stusta.de>
@@ -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");
index eaebe53..80a931d 100644 (file)
@@ -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 <reyk@openbsd.org>
@@ -25,6 +25,7 @@
 
 #include <netinet/in.h>
 #include <netinet/ip_ipsp.h>
+#include <net/if.h>
 #include <net/pfkeyv2.h>
 
 #include <err.h>
@@ -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;