-/* $OpenBSD: config.c,v 1.48 2017/04/13 07:04:09 patrick Exp $ */
+/* $OpenBSD: config.c,v 1.49 2017/11/27 18:39:35 patrick Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
return (0);
}
+int
+config_setmobike(struct iked *env)
+{
+ unsigned int boolval;
+
+ boolval = env->sc_mobike;
+ proc_compose(&env->sc_ps, PROC_IKEV2, IMSG_CTL_MOBIKE,
+ &boolval, sizeof(boolval));
+ return (0);
+}
+
+int
+config_getmobike(struct iked *env, struct imsg *imsg)
+{
+ unsigned int boolval;
+
+ IMSG_SIZE_CHECK(imsg, &boolval);
+ memcpy(&boolval, imsg->data, sizeof(boolval));
+ env->sc_mobike = boolval;
+ log_debug("%s: %smobike", __func__, env->sc_mobike ? "" : "no ");
+ return (0);
+}
+
int
config_setocsp(struct iked *env)
{
-/* $OpenBSD: iked.c,v 1.35 2017/11/08 16:57:41 patrick Exp $ */
+/* $OpenBSD: iked.c,v 1.36 2017/11/27 18:39:35 patrick Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
if (pledge("stdio rpath proc dns inet route sendfd", NULL) == -1)
fatal("pledge");
+ config_setmobike(env);
config_setcoupled(env, env->sc_decoupled ? 0 : 1);
config_setmode(env, env->sc_passive ? 1 : 0);
config_setocsp(env);
/* Re-compile policies and skip steps */
config_setcompile(env, PROC_IKEV2);
+ config_setmobike(env);
config_setcoupled(env, env->sc_decoupled ? 0 : 1);
config_setmode(env, env->sc_passive ? 1 : 0);
config_setocsp(env);
-.\" $OpenBSD: iked.conf.5,v 1.50 2017/06/01 15:23:43 sthen Exp $
+.\" $OpenBSD: iked.conf.5,v 1.51 2017/11/27 18:39:35 patrick Exp $
.\"
.\" Copyright (c) 2010 - 2014 Reyk Floeter <reyk@openbsd.org>
.\" Copyright (c) 2004 Mathieu Sauve-Frankel All rights reserved.
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: June 1 2017 $
+.Dd $Mdocdate: November 27 2017 $
.Dt IKED.CONF 5
.Os
.Sh NAME
.It Ic set decouple
Don't load the negotiated SAs and flows from the kernel.
This mode is only useful for testing and debugging.
+.It Ic set mobike
+Enable MOBIKE (RFC 4555) support.
+This is the default.
+MOBIKE allows the peer IP address to be changed for IKE and IPsec SAs.
+Currently
+.Xr iked 8
+only supports MOBIKE when acting as a responder.
+.It Ic set nomobike
+Disables MOBIKE support.
.It Ic set ocsp Ar URL
Enable OCSP and set the URL of the OCSP responder.
Please note that the matching responder and issuer certificates
-/* $OpenBSD: iked.h,v 1.115 2017/04/26 10:42:38 henning Exp $ */
+/* $OpenBSD: iked.h,v 1.116 2017/11/27 18:39:35 patrick Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
RB_ENTRY(iked_flow) flow_node;
TAILQ_ENTRY(iked_flow) flow_entry;
+
+ int flow_replacing; /* cf flow_replace() */
int flow_ipcomp;
};
RB_HEAD(iked_flows, iked_flow);
#define IKED_SATYPE_LOCAL 1 /* Local SA */
struct iked_addr sa_peer;
+ struct iked_addr sa_peer_loaded;/* MOBIKE */
struct iked_addr sa_local;
int sa_fd;
uint16_t sa_cpi_out; /* IPcomp outgoing */
uint16_t sa_cpi_in; /* IPcomp incoming*/
+ int sa_mobike; /* MOBIKE */
+
struct iked_timer sa_timer; /* SA timeouts */
#define IKED_IKE_SA_EXCHANGE_TIMEOUT 300 /* 5 minutes */
#define IKED_IKE_SA_REKEY_TIMEOUT 120 /* 2 minutes */
int msg_response;
int msg_responded;
int msg_natt;
+ int msg_natt_rcvd;
int msg_error;
int msg_e;
struct iked_message *msg_parent;
struct iked_id msg_cert;
struct ibuf *msg_cookie;
+ /* MOBIKE */
+ int msg_update_sa_addresses;
+ struct ibuf *msg_cookie2;
+
/* Parse stack */
struct iked_proposal *msg_prop;
uint16_t msg_attrlength;
uint8_t sc_passive;
uint8_t sc_decoupled;
+ uint8_t sc_mobike; /* MOBIKE */
+
struct iked_policies sc_policies;
struct iked_policy *sc_defaultcon;
int config_getocsp(struct iked *, struct imsg *);
int config_setkeys(struct iked *);
int config_getkey(struct iked *, struct imsg *);
+int config_setmobike(struct iked *);
+int config_getmobike(struct iked *, struct imsg *);
/* policy.c */
void policy_init(struct iked *);
childsa_lookup(struct iked_sa *, uint64_t, uint8_t);
void flow_free(struct iked_flow *);
int flow_equal(struct iked_flow *, struct iked_flow *);
+int flow_replace(struct iked *, struct iked_flow *);
struct iked_sa *
sa_lookup(struct iked *, uint64_t, uint64_t, unsigned int);
struct iked_user *
int pfkey_block(int, int, unsigned int);
int pfkey_sa_init(int, struct iked_childsa *, uint32_t *);
int pfkey_sa_add(int, struct iked_childsa *, struct iked_childsa *);
+int pfkey_sa_update_addresses(int, struct iked_childsa *);
int pfkey_sa_delete(int, struct iked_childsa *);
int pfkey_sa_last_used(int, struct iked_childsa *, uint64_t *);
int pfkey_flush(int);
-/* $OpenBSD: ikev2.c,v 1.157 2017/11/08 09:35:19 patrick Exp $ */
+/* $OpenBSD: ikev2.c,v 1.158 2017/11/27 18:39:35 patrick Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
ssize_t ikev2_add_nat_detection(struct iked *, struct ibuf *,
struct ikev2_payload **, struct iked_message *, ssize_t);
+ssize_t ikev2_add_mobike(struct iked *, struct ibuf *,
+ struct ikev2_payload **, ssize_t, struct iked_sa *);
+int ikev2_update_sa_addresses(struct iked *, struct iked_sa *);
+int ikev2_resp_informational(struct iked *, struct iked_sa *,
+ struct iked_message *);
+
+
static struct privsep_proc procs[] = {
{ "parent", PROC_PARENT, ikev2_dispatch_parent },
{ "certstore", PROC_CERT, ikev2_dispatch_cert }
IKED_INITIATOR_INITIAL);
}
return (0);
+ case IMSG_CTL_MOBIKE:
+ return (config_getmobike(env, imsg));
case IMSG_UDP_SOCKET:
return (config_getsocket(env, imsg, ikev2_msg_cb));
case IMSG_PFKEY_SOCKET:
return (len);
}
+ssize_t
+ikev2_add_mobike(struct iked *env, struct ibuf *e,
+ struct ikev2_payload **pld, ssize_t len, struct iked_sa *sa)
+{
+ struct ikev2_notify *n;
+ uint8_t *ptr;
+
+ if (*pld)
+ if (ikev2_next_payload(*pld, len, IKEV2_PAYLOAD_NOTIFY) == -1)
+ return (-1);
+ if ((*pld = ikev2_add_payload(e)) == NULL)
+ return (-1);
+ len = sizeof(*n);
+ 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_MOBIKE_SUPPORTED);
+ log_debug("%s: done", __func__);
+
+ return (len);
+}
+
ssize_t
ikev2_add_sighashnotify(struct ibuf *e, struct ikev2_payload **pld,
ssize_t len)
return (0);
}
+int
+ikev2_resp_informational(struct iked *env, struct iked_sa *sa,
+ struct iked_message *msg)
+{
+ struct ikev2_notify *n;
+ struct ikev2_payload *pld = NULL;
+ struct ike_header *hdr;
+ struct ibuf *buf = NULL;
+ ssize_t len = 0;
+ int ret = -1;
+ int oflags = 0;
+ uint8_t firstpayload = IKEV2_PAYLOAD_NONE;
+
+ if (!sa_stateok(sa, IKEV2_STATE_AUTH_REQUEST) ||
+ msg->msg_responded || msg->msg_error)
+ goto done;
+
+ if ((buf = ibuf_static()) == NULL)
+ goto done;
+ /*
+ * Include NAT_DETECTION notification on UPDATE_SA_ADDRESSES or if
+ * the peer did include them, too (RFC 455, 3.8).
+ */
+ if (sa->sa_mobike &&
+ (msg->msg_update_sa_addresses || msg->msg_natt_rcvd)) {
+ /*
+ * XXX workaround so ikev2_msg_frompeer() fails for
+ * XXX ikev2_nat_detection(), and the correct src/dst are
+ * XXX used for the nat detection payload.
+ */
+ if (msg->msg_parent == NULL)
+ goto done;
+ if ((hdr = ibuf_seek(msg->msg_parent->msg_data, 0,
+ sizeof(*hdr))) == NULL)
+ goto done;
+ oflags = hdr->ike_flags;
+ if (sa->sa_hdr.sh_initiator)
+ hdr->ike_flags |= IKEV2_FLAG_INITIATOR;
+ else
+ hdr->ike_flags &= ~IKEV2_FLAG_INITIATOR;
+ /* NAT-T notify payloads */
+ len = ikev2_add_nat_detection(env, buf, &pld, msg, len);
+ hdr->ike_flags = oflags; /* XXX undo workaround */
+ if (len == -1)
+ goto done;
+ firstpayload = IKEV2_PAYLOAD_NOTIFY;
+ }
+ /* Reflect COOKIE2 */
+ if (msg->msg_cookie2) {
+ if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NOTIFY) == -1)
+ goto done;
+ if ((pld = ikev2_add_payload(buf)) == NULL)
+ goto done;
+ if ((n = ibuf_advance(buf, sizeof(*n))) == NULL)
+ goto done;
+ n->n_protoid = IKEV2_SAPROTO_IKE;
+ n->n_spisize = 0;
+ n->n_type = htobe16(IKEV2_N_COOKIE2);
+ if (ikev2_add_buf(buf, msg->msg_cookie2) == -1)
+ goto done;
+ len = sizeof(*n) + ibuf_size(msg->msg_cookie2);
+ log_debug("%s: added cookie2", __func__);
+ if (firstpayload == IKEV2_PAYLOAD_NONE)
+ firstpayload = IKEV2_PAYLOAD_NOTIFY;
+ }
+ /* add terminator, if there is already a payload */
+ if (firstpayload != IKEV2_PAYLOAD_NONE)
+ if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONE) == -1)
+ goto done;
+ ret = ikev2_msg_send_encrypt(env, sa, &buf,
+ IKEV2_EXCHANGE_INFORMATIONAL, firstpayload, 1);
+ if (ret != -1)
+ msg->msg_responded = 1;
+ done:
+ ibuf_release(buf);
+ return (ret);
+}
+
void
ikev2_resp_recv(struct iked *env, struct iked_message *msg,
struct ike_header *hdr)
ikev2_send_error(env, sa, msg, hdr->ike_exchange);
break;
case IKEV2_EXCHANGE_INFORMATIONAL:
- if (sa_stateok(sa, IKEV2_STATE_AUTH_REQUEST) &&
- !msg->msg_responded && !msg->msg_error) {
- (void)ikev2_send_ike_e(env, sa, NULL,
- IKEV2_PAYLOAD_NONE, IKEV2_EXCHANGE_INFORMATIONAL,
- 1);
- msg->msg_responded = 1;
- }
+ if (msg->msg_update_sa_addresses)
+ ikev2_update_sa_addresses(env, sa);
+ (void)ikev2_resp_informational(env, sa, msg);
break;
default:
break;
(len = ikev2_add_ipcompnotify(env, e, &pld, len, sa)) == -1)
goto done;
+ /* MOBIKE */
+ if (sa->sa_mobike &&
+ (len = ikev2_add_mobike(env, e, &pld, len, sa)) == -1)
+ goto done;
+
if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_SA) == -1)
goto done;
nsa->sa_natt = sa->sa_natt;
nsa->sa_udpencap = sa->sa_udpencap;
nsa->sa_usekeepalive = sa->sa_usekeepalive;
+ nsa->sa_mobike = sa->sa_mobike;
/* Transfer old addresses */
memcpy(&nsa->sa_local, &sa->sa_local, sizeof(nsa->sa_local));
memcpy(&nsa->sa_peer, &sa->sa_peer, sizeof(nsa->sa_peer));
+ memcpy(&nsa->sa_peer_loaded, &sa->sa_peer_loaded,
+ sizeof(nsa->sa_peer_loaded));
/* Transfer all Child SAs and flows from the old IKE SA */
for (flow = TAILQ_FIRST(&sa->sa_flows); flow != NULL;
{
struct iked_childsa *csa, *ocsa;
struct iked_flow *flow, *oflow;
+ int peer_changed, reload;
if (sa->sa_ipcomp && sa->sa_cpi_in && sa->sa_cpi_out &&
ikev2_ipcomp_enable(env, sa) == -1)
print_spi(csa->csa_spi.spi, csa->csa_spi.spi_size));
}
+ peer_changed = (memcmp(&sa->sa_peer_loaded, &sa->sa_peer,
+ sizeof(sa->sa_peer_loaded)) != 0);
+
TAILQ_FOREACH(flow, &sa->sa_flows, flow_entry) {
- if (flow->flow_loaded)
- continue;
+ /* 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);
+ /* flow might be shared w/other SA */
+ if (!flow->flow_replacing ||
+ flow_replace(env, flow) != 0)
+ (void)pfkey_flow_delete(env->sc_pfkey, flow);
+ flow->flow_loaded = 0; /* we did RB_REMOVE */
+ reload = 1;
+ }
if (pfkey_flow_add(env->sc_pfkey, flow) != 0) {
log_debug("%s: failed to load flow", __func__);
log_debug("%s: replaced old flow %p with %p",
__func__, oflow, flow);
oflow->flow_loaded = 0;
+ oflow->flow_replacing = 0;
RB_REMOVE(iked_flows, &env->sc_activeflows, oflow);
+ flow->flow_replacing = 1;
}
RB_INSERT(iked_flows, &env->sc_activeflows, flow);
- log_debug("%s: loaded flow %p", __func__, flow);
+ log_debug("%s: %sloaded flow %p", __func__,
+ reload ? "re" : "", flow);
+ }
+
+ /* remember the current address for ikev2_update_sa_addresses() */
+ if (peer_changed) {
+ memcpy(&sa->sa_peer_loaded, &sa->sa_peer,
+ sizeof(sa->sa_peer_loaded));
+ log_debug("%s: remember SA peer %s", __func__,
+ print_host((struct sockaddr *)&sa->sa_peer_loaded.addr,
+ NULL, 0));
}
return (0);
}
return (0);
}
+
+int
+ikev2_update_sa_addresses(struct iked *env, struct iked_sa *sa)
+{
+ struct iked_childsa *csa;
+ struct iked_flow *flow, *oflow;
+ struct iked_message *msg;
+
+ if (!sa_stateok(sa, IKEV2_STATE_ESTABLISHED))
+ return -1;
+
+ log_info("%s: old %s new %s", __func__,
+ print_host((struct sockaddr *)&sa->sa_peer_loaded.addr, NULL, 0),
+ print_host((struct sockaddr *)&sa->sa_peer.addr, NULL, 0));
+
+ TAILQ_FOREACH(csa, &sa->sa_childsas, csa_entry) {
+ if (!csa->csa_loaded)
+ continue;
+ if (pfkey_sa_update_addresses(env->sc_pfkey, csa) != 0)
+ log_debug("%s: failed to update sa", __func__);
+ }
+
+ /* delete and re-add flows */
+ TAILQ_FOREACH(flow, &sa->sa_flows, flow_entry) {
+ if (flow->flow_loaded) {
+ RB_REMOVE(iked_flows, &env->sc_activeflows, flow);
+ /* flow might be shared w/other SA */
+ if (!flow->flow_replacing ||
+ flow_replace(env, flow) != 0)
+ (void)pfkey_flow_delete(env->sc_pfkey, flow);
+ flow->flow_loaded = 0;
+ }
+ /* update IPcomp flows */
+ if (flow->flow_ipcomp) {
+ struct iked_addr *addr =
+ (flow->flow_dir == IPSP_DIRECTION_OUT) ?
+ &flow->flow_dst :
+ &flow->flow_src;
+ memcpy(addr, &sa->sa_peer, sizeof(sa->sa_peer));
+ socket_setport((struct sockaddr *)&addr->addr, 0);
+ addr->addr_port = 0;
+ addr->addr_mask = (addr->addr_af == AF_INET) ? 32 : 128;
+ }
+ if (pfkey_flow_add(env->sc_pfkey, flow) != 0)
+ log_debug("%s: failed to add flow %p", __func__, flow);
+ if (!flow->flow_loaded)
+ continue;
+ 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;
+ oflow->flow_replacing = 0;
+ RB_REMOVE(iked_flows, &env->sc_activeflows, oflow);
+ flow->flow_replacing = 1;
+ }
+ RB_INSERT(iked_flows, &env->sc_activeflows, flow);
+ }
+
+ /* update pending requests and responses */
+ TAILQ_FOREACH(msg, &sa->sa_requests, msg_entry) {
+ msg->msg_local = sa->sa_local.addr;
+ msg->msg_locallen = sa->sa_local.addr.ss_len;
+ msg->msg_peer = sa->sa_peer.addr;
+ msg->msg_peerlen = sa->sa_peer.addr.ss_len;
+ }
+ TAILQ_FOREACH(msg, &sa->sa_responses, msg_entry) {
+ msg->msg_local = sa->sa_local.addr;
+ msg->msg_locallen = sa->sa_local.addr.ss_len;
+ msg->msg_peer = sa->sa_peer.addr;
+ msg->msg_peerlen = sa->sa_peer.addr.ss_len;
+ }
+
+ /* Update sa_peer_loaded, to match in-kernel information */
+ memcpy(&sa->sa_peer_loaded, &sa->sa_peer, sizeof(sa->sa_peer_loaded));
+
+ return 0;
+}
-/* $OpenBSD: ikev2_msg.c,v 1.52 2017/04/26 10:42:38 henning Exp $ */
+/* $OpenBSD: ikev2_msg.c,v 1.53 2017/11/27 18:39:35 patrick Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
ibuf_release(msg->msg_id.id_buf);
ibuf_release(msg->msg_cert.id_buf);
ibuf_release(msg->msg_cookie);
+ ibuf_release(msg->msg_cookie2);
msg->msg_nonce = NULL;
msg->msg_ke = NULL;
msg->msg_id.id_buf = NULL;
msg->msg_cert.id_buf = NULL;
msg->msg_cookie = NULL;
+ msg->msg_cookie2 = NULL;
config_free_proposals(&msg->msg_proposals, 0);
}
-/* $OpenBSD: ikev2_pld.c,v 1.62 2017/04/13 07:04:09 patrick Exp $ */
+/* $OpenBSD: ikev2_pld.c,v 1.63 2017/11/27 18:39:35 patrick Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
msg->msg_sa->sa_usekeepalive = 1;
}
print_hex(md, 0, sizeof(md));
+ /* remember for MOBIKE */
+ msg->msg_parent->msg_natt_rcvd = 1;
break;
case IKEV2_N_AUTHENTICATION_FAILED:
if (!msg->msg_e) {
msg->msg_sa->sa_cpi_out = betoh16(cpi);
}
break;
+ case IKEV2_N_MOBIKE_SUPPORTED:
+ if (!msg->msg_e) {
+ log_debug("%s: N_MOBIKE_SUPPORTED not encrypted",
+ __func__);
+ return (-1);
+ }
+ if (len != 0) {
+ log_debug("%s: ignoring malformed mobike"
+ " notification: %zu", __func__, len);
+ return (0);
+ }
+ if (!env->sc_mobike) {
+ log_debug("%s: mobike disabled", __func__);
+ return (0);
+ }
+ msg->msg_sa->sa_mobike = 1;
+ /* enforce natt */
+ msg->msg_sa->sa_natt = 1;
+ break;
+ case IKEV2_N_UPDATE_SA_ADDRESSES:
+ if (!msg->msg_e) {
+ log_debug("%s: N_UPDATE_SA_ADDRESSES not encrypted",
+ __func__);
+ return (-1);
+ }
+ if (!msg->msg_sa->sa_mobike) {
+ log_debug("%s: ignoring update sa addresses"
+ " notification w/o mobike: %zu", __func__, len);
+ return (0);
+ }
+ if (len != 0) {
+ log_debug("%s: ignoring malformed update sa addresses"
+ " notification: %zu", __func__, len);
+ return (0);
+ }
+ msg->msg_parent->msg_update_sa_addresses = 1;
+ break;
+ case IKEV2_N_COOKIE2:
+ if (!msg->msg_e) {
+ log_debug("%s: N_COOKIE2 not encrypted",
+ __func__);
+ return (-1);
+ }
+ if (!msg->msg_sa->sa_mobike) {
+ log_debug("%s: ignoring cookie2 notification"
+ " w/o mobike: %zu", __func__, len);
+ return (0);
+ }
+ if (len < IKED_COOKIE2_MIN || len > IKED_COOKIE2_MAX) {
+ log_debug("%s: ignoring malformed cookie2"
+ " notification: %zu", __func__, len);
+ return (0);
+ }
+ ibuf_release(msg->msg_cookie2); /* should not happen */
+ if ((msg->msg_cookie2 = ibuf_new(buf, len)) == NULL) {
+ log_debug("%s: failed to get peer cookie2", __func__);
+ return (-1);
+ }
+ msg->msg_parent->msg_cookie2 = msg->msg_cookie2;
+ break;
case IKEV2_N_COOKIE:
if (msg->msg_e) {
log_debug("%s: N_COOKIE encrypted",
-/* $OpenBSD: parse.y,v 1.66 2017/11/15 15:45:02 patrick Exp $ */
+/* $OpenBSD: parse.y,v 1.67 2017/11/27 18:39:35 patrick Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
static int rules = 0;
static int passive = 0;
static int decouple = 0;
+static int mobike = 1;
static char *ocsp_url = NULL;
struct ipsec_xf {
%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
+%token IPCOMP OCSP IKELIFETIME MOBIKE NOMOBIKE
%token <v.string> STRING
%token <v.number> NUMBER
%type <v.string> string
| SET PASSIVE { passive = 1; }
| SET COUPLE { decouple = 0; }
| SET DECOUPLE { decouple = 1; }
+ | SET MOBIKE { mobike = 1; }
+ | SET NOMOBIKE { mobike = 0; }
| SET OCSP STRING {
if ((ocsp_url = strdup($3)) == NULL) {
yyerror("cannot set ocsp_url");
{ "ipcomp", IPCOMP },
{ "lifetime", LIFETIME },
{ "local", LOCAL },
+ { "mobike", MOBIKE },
{ "name", NAME },
+ { "nomobike", NOMOBIKE },
{ "ocsp", OCSP },
{ "passive", PASSIVE },
{ "peer", PEER },
free(ocsp_url);
+ mobike = 1;
decouple = passive = 0;
ocsp_url = NULL;
env->sc_passive = passive ? 1 : 0;
env->sc_decoupled = decouple ? 1 : 0;
+ env->sc_mobike = mobike;
env->sc_ocsp_url = ocsp_url;
if (!rules)
-/* $OpenBSD: pfkey.c,v 1.58 2017/04/18 02:29:56 deraadt Exp $ */
+/* $OpenBSD: pfkey.c,v 1.59 2017/11/27 18:39:35 patrick Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
#define PFKEYV2_CHUNK sizeof(uint64_t)
#define PFKEY_REPLY_TIMEOUT 1000
+/* only used internally */
+#define IKED_SADB_UPDATE_SA_ADDRESSES 0xff
+
static uint32_t sadb_msg_seq = 0;
static unsigned int sadb_decoupled = 0;
static unsigned int sadb_ipv6refcnt = 0;
{
struct sadb_msg smsg;
struct sadb_sa sadb;
- struct sadb_address sa_src, sa_dst;
+ struct sadb_address sa_src, sa_dst, sa_pxy;
struct sadb_key sa_authkey, sa_enckey;
struct sadb_lifetime sa_ltime_hard, sa_ltime_soft;
struct sadb_x_udpencap udpencap;
struct sadb_x_tag sa_tag;
char *tag = NULL;
struct sadb_x_tap sa_tap;
- struct sockaddr_storage ssrc, sdst;
+ struct sockaddr_storage ssrc, sdst, spxy;
struct sadb_ident *sa_srcid, *sa_dstid;
struct iked_lifetime *lt;
struct iked_policy *pol;
+ struct iked_addr *dst;
struct iovec iov[IOV_CNT];
uint32_t jitter;
int iov_cnt;
return (-1);
}
+ dst = (action == IKED_SADB_UPDATE_SA_ADDRESSES &&
+ sa->csa_dir == IPSP_DIRECTION_OUT) ?
+ &sa->csa_ikesa->sa_peer_loaded :
+ sa->csa_peer;
bzero(&sdst, sizeof(sdst));
- memcpy(&sdst, &sa->csa_peer->addr, sizeof(sdst));
+ memcpy(&sdst, &dst->addr, sizeof(sdst));
if (socket_af((struct sockaddr *)&sdst, 0) == -1) {
log_warn("%s: invalid address", __func__);
return (-1);
}
+ bzero(&spxy, sizeof(spxy));
+ if (dst != sa->csa_peer) {
+ memcpy(&spxy, &sa->csa_peer->addr, sizeof(spxy));
+ if (socket_af((struct sockaddr *)&spxy, 0) == -1) {
+ log_warn("%s: invalid address", __func__);
+ return (-1);
+ }
+ }
+
bzero(&smsg, sizeof(smsg));
smsg.sadb_msg_version = PF_KEY_V2;
smsg.sadb_msg_seq = ++sadb_msg_seq;
sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8;
sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST;
+ bzero(&sa_pxy, sizeof(sa_pxy));
+ sa_pxy.sadb_address_len = (sizeof(sa_pxy) + ROUNDUP(spxy.ss_len)) / 8;
+ sa_pxy.sadb_address_exttype = SADB_EXT_ADDRESS_PROXY;
+
bzero(&sa_authkey, sizeof(sa_authkey));
bzero(&sa_enckey, sizeof(sa_enckey));
bzero(&udpencap, sizeof udpencap);
ntohs(udpencap.sadb_x_udpencap_port));
}
+ if (action == IKED_SADB_UPDATE_SA_ADDRESSES) {
+ smsg.sadb_msg_type = SADB_UPDATE;
+ goto send;
+ }
+
if ((action == SADB_ADD || action == SADB_UPDATE) &&
!sa->csa_persistent && (lt->lt_bytes || lt->lt_seconds)) {
sa_ltime_hard.sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD;
smsg.sadb_msg_len += sa_dst.sadb_address_len;
iov_cnt++;
+ if (spxy.ss_len) {
+ /* pxy addr */
+ iov[iov_cnt].iov_base = &sa_pxy;
+ iov[iov_cnt].iov_len = sizeof(sa_pxy);
+ iov_cnt++;
+ iov[iov_cnt].iov_base = &spxy;
+ iov[iov_cnt].iov_len = ROUNDUP(spxy.ss_len);
+ smsg.sadb_msg_len += sa_pxy.sadb_address_len;
+ iov_cnt++;
+ }
+
if (sa_ltime_soft.sadb_lifetime_len) {
/* soft lifetime */
iov[iov_cnt].iov_base = &sa_ltime_soft;
return (0);
}
+int
+pfkey_sa_update_addresses(int fd, struct iked_childsa *sa)
+{
+ uint8_t satype;
+
+ if (!sa->csa_ikesa)
+ return (-1);
+ /* check if peer has changed */
+ if (sa->csa_ikesa->sa_peer_loaded.addr.ss_family == AF_UNSPEC ||
+ memcmp(&sa->csa_ikesa->sa_peer_loaded, &sa->csa_ikesa->sa_peer,
+ sizeof(sa->csa_ikesa->sa_peer_loaded)) == 0)
+ return (0);
+ if (pfkey_map(pfkey_satype, sa->csa_saproto, &satype) == -1)
+ return (-1);
+ log_debug("%s: spi %s", __func__, print_spi(sa->csa_spi.spi, 4));
+ return pfkey_sa(fd, satype, IKED_SADB_UPDATE_SA_ADDRESSES, sa);
+}
+
int
pfkey_sa_delete(int fd, struct iked_childsa *sa)
{
-/* $OpenBSD: policy.c,v 1.46 2017/03/13 18:48:16 mikeb Exp $ */
+/* $OpenBSD: policy.c,v 1.47 2017/11/27 18:39:35 patrick Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
config_free_sa(env, sa);
}
+/* oflow did replace active flow, so we need to re-activate a matching flow */
+int
+flow_replace(struct iked *env, struct iked_flow *oflow)
+{
+ struct iked_sa *sa;
+ struct iked_flow *flow, *other;
+
+ if (!oflow->flow_loaded)
+ return (-1);
+ RB_FOREACH(sa, iked_sas, &env->sc_sas) {
+ if (oflow->flow_ikesa == sa ||
+ sa->sa_state != IKEV2_STATE_ESTABLISHED)
+ continue;
+ TAILQ_FOREACH(flow, &sa->sa_flows, flow_entry) {
+ if (flow == oflow ||
+ flow->flow_loaded || !flow_equal(flow, oflow))
+ continue;
+ if ((other = RB_FIND(iked_flows, &env->sc_activeflows,
+ flow)) != NULL) {
+ /* XXX should not happen */
+ log_debug("%s: found flow %p for %p/%p",
+ __func__, other, flow, other);
+ return (-1);
+ }
+ if (pfkey_flow_add(env->sc_pfkey, flow) != 0) {
+ log_debug("%s: failed to load flow", __func__);
+ return (-1);
+ }
+ RB_INSERT(iked_flows, &env->sc_activeflows, flow);
+ log_debug("%s: loaded flow %p replaces %p", __func__,
+ flow, oflow);
+ /* check for matching flow if we get deleted, too */
+ flow->flow_replacing = 1;
+ return (0);
+ }
+ }
+ return (-1);
+}
+
void
sa_free_flows(struct iked *env, struct iked_saflows *head)
{
if (flow->flow_loaded)
RB_REMOVE(iked_flows, &env->sc_activeflows, flow);
TAILQ_REMOVE(head, flow, flow_entry);
- (void)pfkey_flow_delete(env->sc_pfkey, flow);
+ if (!flow->flow_replacing ||
+ flow_replace(env, flow) != 0)
+ (void)pfkey_flow_delete(env->sc_pfkey, flow);
flow_free(flow);
}
}
-/* $OpenBSD: types.h,v 1.28 2017/03/27 10:43:53 mikeb Exp $ */
+/* $OpenBSD: types.h,v 1.29 2017/11/27 18:39:35 patrick Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
#define IKED_COOKIE_MIN 1 /* min 1 bytes */
#define IKED_COOKIE_MAX 64 /* max 64 bytes */
+#define IKED_COOKIE2_MIN 8 /* min 8 bytes */
+#define IKED_COOKIE2_MAX 64 /* max 64 bytes */
+
#define IKED_ID_SIZE 1024 /* XXX should be dynamic */
#define IKED_PSK_SIZE 1024 /* XXX should be dynamic */
#define IKED_MSGBUF_MAX 8192
IMSG_CTL_DECOUPLE,
IMSG_CTL_ACTIVE,
IMSG_CTL_PASSIVE,
+ IMSG_CTL_MOBIKE,
IMSG_COMPILE,
IMSG_UDP_SOCKET,
IMSG_PFKEY_SOCKET,