From 0c1280a3aad6116bc6d1ea0d3199a43676d9b4c8 Mon Sep 17 00:00:00 2001 From: dlg Date: Mon, 7 Aug 2023 04:01:29 +0000 Subject: [PATCH] support configuring interface SAs for route-based ipsec vpns. add "Interface NUMBER" to the config parser to specify that once SAs have been negotiated with a peer, install the SAs with the sadb_x_iface extension set up, but skip installing the flows/SPD entries. this allows for the negotiation of multiple esp tunnels covering all traffic between 0.0.0.0/0 to 0.0.0.0/0, and then being able to do something useful with them using the routing table and sec(4) interfaces instead of having SPD entries fight over those packets in the kernel. this in turn allows interoperation with other ipsec/vpn solutions that require the negotiation of such tunnels. support from many including markus@ tobhe@ claudio@ sthen@ patrick@ now is a good time deraadt@ --- sbin/isakmpd/ipsec.c | 41 ++++++++++++++++++++++++++++++++++++++-- sbin/isakmpd/pf_key_v2.c | 28 ++++++++++++++++++++++++--- sbin/isakmpd/sa.h | 8 +++++++- 3 files changed, 71 insertions(+), 6 deletions(-) diff --git a/sbin/isakmpd/ipsec.c b/sbin/isakmpd/ipsec.c index 6c3e264a6e1..08a90cee65c 100644 --- a/sbin/isakmpd/ipsec.c +++ b/sbin/isakmpd/ipsec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ipsec.c,v 1.152 2022/01/16 14:30:11 naddy Exp $ */ +/* $OpenBSD: ipsec.c,v 1.153 2023/08/07 04:01:29 dlg Exp $ */ /* $EOM: ipsec.c,v 1.143 2000/12/11 23:57:42 niklas Exp $ */ /* @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -131,6 +132,7 @@ static int ipsec_validate_transform_id(u_int8_t, u_int8_t); static int ipsec_sa_check_flow(struct sa *, void *); static int ipsec_sa_check_flow_any(struct sa *, void *); static int ipsec_sa_tag(struct exchange *, struct sa *, struct sa *); +static int ipsec_sa_iface(struct exchange *, struct sa *, struct sa *); static struct doi ipsec_doi = { {0}, IPSEC_DOI_IPSEC, @@ -272,6 +274,12 @@ ipsec_sa_check_flow_any(struct sa *sa, void *v_arg) isa->dport != isa2->dport) return 0; + if ((sa->flags & SA_FLAG_IFACE) != (sa2->flags & SA_FLAG_IFACE)) + return 0; + + if (sa->flags & SA_FLAG_IFACE) + return sa->iface == sa2->iface; + /* * If at least one of the IPsec SAs is incomplete, we're done. */ @@ -379,6 +387,30 @@ ipsec_sa_tag(struct exchange *exchange, struct sa *sa, struct sa *isakmp_sa) return (error); } +static int +ipsec_sa_iface(struct exchange *exchange, struct sa *sa, struct sa *isakmp_sa) +{ + char *section, *value; + const char *errstr = NULL; + + sa->tag = NULL; + + if (exchange->name == NULL || + (section = exchange->name) == NULL || + (value = conf_get_str(section, "Interface")) == NULL) + return (0); /* ignore if not present */ + + sa->iface = strtonum(value, 0, UINT_MAX, &errstr); + if (errstr != NULL) { + log_error("[%s]:Interface %s", section, errstr); + return (-1); + } + + sa->flags |= SA_FLAG_IFACE; + + return (0); +} + /* * Do IPsec DOI specific finalizations task for the exchange where MSG was * the final message. @@ -463,6 +495,9 @@ ipsec_finalize_exchange(struct message *msg) if (ipsec_sa_tag(exchange, sa, isakmp_sa) == -1) return; + if (ipsec_sa_iface(exchange, sa, isakmp_sa) == -1) + return; + for (proto = TAILQ_FIRST(&sa->protos), last_proto = 0; proto; proto = TAILQ_NEXT(proto, link)) { @@ -514,6 +549,7 @@ ipsec_finalize_exchange(struct message *msg) * (a.k.a. flow) set up. */ if (!(sa->flags & SA_FLAG_ONDEMAND || + sa->flags & SA_FLAG_IFACE || conf_get_str("General", "Acquire-Only") || acquire_only) && pf_key_v2_enable_sa(sa, isakmp_sa)) @@ -1596,7 +1632,8 @@ ipsec_delete_spi(struct sa *sa, struct proto *proto, int incoming) * We ignore any errors from the disabling of the flow. */ if (sa->flags & SA_FLAG_READY && !(sa->flags & SA_FLAG_ONDEMAND || - sa->flags & SA_FLAG_REPLACED || acquire_only || + sa->flags & SA_FLAG_REPLACED || sa->flags & SA_FLAG_IFACE || + acquire_only || conf_get_str("General", "Acquire-Only"))) pf_key_v2_disable_sa(sa, incoming); diff --git a/sbin/isakmpd/pf_key_v2.c b/sbin/isakmpd/pf_key_v2.c index 758acf63c1a..cf7a4d59d05 100644 --- a/sbin/isakmpd/pf_key_v2.c +++ b/sbin/isakmpd/pf_key_v2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_key_v2.c,v 1.204 2022/01/31 23:51:15 sthen Exp $ */ +/* $OpenBSD: pf_key_v2.c,v 1.205 2023/08/07 04:01:30 dlg Exp $ */ /* $EOM: pf_key_v2.c,v 1.79 2000/12/12 00:33:19 niklas Exp $ */ /* @@ -890,6 +890,7 @@ pf_key_v2_set_spi(struct sa *sa, struct proto *proto, int incoming, struct sadb_protocol flowtype, tprotocol; struct sadb_x_udpencap udpencap; char *addr_str, *s; + char iface_str[32]; msg.sadb_msg_type = incoming ? SADB_UPDATE : SADB_ADD; switch (proto->proto) { @@ -1378,16 +1379,37 @@ nodid: goto cleanup; } + if (sa->flags & SA_FLAG_IFACE) { + struct sadb_x_iface *siface; + + len = sizeof(*siface); + siface = calloc(1, len); + if (siface == NULL) + goto cleanup; + + siface->sadb_x_iface_len = len / PF_KEY_V2_CHUNK; + siface->sadb_x_iface_exttype = SADB_X_EXT_IFACE; + siface->sadb_x_iface_unit = sa->iface; + siface->sadb_x_iface_direction = incoming ? + IPSP_DIRECTION_IN : IPSP_DIRECTION_OUT; + + if (pf_key_v2_msg_add(update, (struct sadb_ext *)siface, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + + snprintf(iface_str, sizeof(iface_str), "iface %u", sa->iface); + } + /* XXX Here can sensitivity extensions be setup. */ if (sockaddr2text(dst, &addr_str, 0)) addr_str = 0; LOG_DBG((LOG_SYSDEP, 10, "pf_key_v2_set_spi: " - "satype %d dst %s SPI 0x%x%s%s", msg.sadb_msg_satype, + "satype %d dst %s SPI 0x%x%s%s%s", msg.sadb_msg_satype, addr_str ? addr_str : "unknown", ntohl(ssa.sadb_sa_spi), sa->tag ? " tag " : "", - sa->tag ? sa->tag : "")); + sa->tag ? sa->tag : "", iface_str)); free(addr_str); diff --git a/sbin/isakmpd/sa.h b/sbin/isakmpd/sa.h index f9769b44384..b42bccaf12c 100644 --- a/sbin/isakmpd/sa.h +++ b/sbin/isakmpd/sa.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sa.h,v 1.54 2018/01/15 09:54:48 mpi Exp $ */ +/* $OpenBSD: sa.h,v 1.55 2023/08/07 04:01:30 dlg Exp $ */ /* $EOM: sa.h,v 1.58 2000/10/10 12:39:01 provos Exp $ */ /* @@ -211,6 +211,9 @@ struct sa { /* The add a pf tag to packets matching the established SA. */ char *tag; + + /* IPsec with Interface SAs, enabled with SA_FLAG_IFACE */ + unsigned int iface; }; /* This SA is alive. */ @@ -244,6 +247,9 @@ struct sa { #define SA_FLAG_NAT_T_ENABLE 0x100 #define SA_FLAG_NAT_T_KEEPALIVE 0x200 +/* Policy is handled by routing/filtering on the specified iface */ +#define SA_FLAG_IFACE 0x400 + extern void proto_free(struct proto * proto); extern int sa_add_transform(struct sa *, struct payload *, int, struct proto **); -- 2.20.1