error types and other events that help analyze errors in larger setups.
The counters can be printed with 'ikectl show stats'.
ok bluhm@ patrick@
from and ok markus@
-/* $OpenBSD: config.c,v 1.86 2022/07/08 19:51:11 tobhe Exp $ */
+/* $OpenBSD: config.c,v 1.87 2022/09/19 20:54:02 tobhe Exp $ */
/*
* Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de>
gettimeofday(&sa->sa_timecreated, NULL);
memcpy(&sa->sa_timeused, &sa->sa_timecreated, sizeof(sa->sa_timeused));
+ ikestat_inc(env, ikes_sa_created);
return (sa);
}
free(sa->sa_cp_dns);
free(sa->sa_tag);
+
+ if (sa->sa_state == IKEV2_STATE_ESTABLISHED)
+ ikestat_dec(env, ikes_sa_established_current);
+ ikestat_inc(env, ikes_sa_removed);
+
free(sa);
}
childsa_free(ipcomp);
}
childsa_free(csa);
+ ikestat_inc(env, ikes_csa_removed);
}
}
-/* $OpenBSD: control.c,v 1.32 2021/11/21 22:44:08 tobhe Exp $ */
+/* $OpenBSD: control.c,v 1.33 2022/09/19 20:54:02 tobhe Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
proc_forward_imsg(&env->sc_ps, &imsg, PROC_IKEV2, -1);
break;
case IMSG_CTL_SHOW_SA:
+ case IMSG_CTL_SHOW_STATS:
proc_forward_imsg(&env->sc_ps, &imsg, PROC_IKEV2, -1);
c->flags |= CTL_CONN_NOTIFY;
break;
{
switch (imsg->hdr.type) {
case IMSG_CTL_SHOW_SA:
+ case IMSG_CTL_SHOW_STATS:
control_imsg_forward(imsg);
return (0);
default:
-/* $OpenBSD: iked.h,v 1.206 2022/07/22 15:53:33 tobhe Exp $ */
+/* $OpenBSD: iked.h,v 1.207 2022/09/19 20:54:02 tobhe Exp $ */
/*
* Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de>
RB_HEAD(iked_addrpool, iked_sa);
RB_HEAD(iked_addrpool6, iked_sa);
+/* stats */
+
+struct iked_stats {
+ uint64_t ikes_sa_created;
+ uint64_t ikes_sa_established_total;
+ uint64_t ikes_sa_established_current; /* gauge */
+ uint64_t ikes_sa_established_failures;
+ uint64_t ikes_sa_proposals_negotiate_failures;
+ uint64_t ikes_sa_rekeyed;
+ uint64_t ikes_sa_removed;
+ uint64_t ikes_csa_created;
+ uint64_t ikes_csa_removed;
+ uint64_t ikes_msg_sent;
+ uint64_t ikes_msg_send_failures;
+ uint64_t ikes_msg_rcvd;
+ uint64_t ikes_msg_rcvd_busy;
+ uint64_t ikes_msg_rcvd_dropped;
+ uint64_t ikes_retransmit_request;
+ uint64_t ikes_retransmit_response;
+ uint64_t ikes_retransmit_limit;
+ uint64_t ikes_frag_sent;
+ uint64_t ikes_frag_send_failures;
+ uint64_t ikes_frag_rcvd;
+ uint64_t ikes_frag_rcvd_drop;
+ uint64_t ikes_frag_reass_ok;
+ uint64_t ikes_frag_reass_drop;
+ uint64_t ikes_update_addresses_sent;
+ uint64_t ikes_dpd_sent;
+ uint64_t ikes_keepalive_sent;
+};
+
+#define ikestat_add(env, c, n) do { env->sc_stats.c += (n); } while(0)
+#define ikestat_inc(env, c) ikestat_add(env, c, 1)
+#define ikestat_dec(env, c) ikestat_add(env, c, -1)
+
struct iked_certreq {
struct ibuf *cr_data;
uint8_t cr_type;
struct iked_flows sc_activeflows;
struct iked_users sc_users;
+ struct iked_stats sc_stats;
+
void *sc_priv; /* per-process */
int sc_pfkey; /* ike process */
-/* $OpenBSD: ikev2.c,v 1.351 2022/09/14 13:07:49 tobhe Exp $ */
+/* $OpenBSD: ikev2.c,v 1.352 2022/09/19 20:54:02 tobhe Exp $ */
/*
* Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de>
void ikev2_ctl_reset_id(struct iked *, struct imsg *, unsigned int);
void ikev2_ctl_show_sa(struct iked *);
+void ikev2_ctl_show_stats(struct iked *);
static struct privsep_proc procs[] = {
{ "parent", PROC_PARENT, ikev2_dispatch_parent },
case IMSG_CTL_SHOW_SA:
ikev2_ctl_show_sa(env);
break;
+ case IMSG_CTL_SHOW_STATS:
+ ikev2_ctl_show_stats(env);
+ break;
default:
return (-1);
}
ikev2_info(env, 0);
}
+void
+ikev2_ctl_show_stats(struct iked *env)
+{
+ proc_compose(&env->sc_ps, PROC_CONTROL, IMSG_CTL_SHOW_STATS,
+ &env->sc_stats, sizeof(env->sc_stats));
+}
+
struct iked_sa *
ikev2_getimsgdata(struct iked *env, struct imsg *imsg, struct iked_sahdr *sh,
uint8_t *type, uint8_t **buf, size_t *size)
(betoh32(hdr->ike_length) - msg->msg_offset))
return;
+ ikestat_inc(env, ikes_msg_rcvd);
+
initiator = (hdr->ike_flags & IKEV2_FLAG_INITIATOR) ? 0 : 1;
msg->msg_response = (hdr->ike_flags & IKEV2_FLAG_RESPONSE) ? 1 : 0;
msg->msg_exchange = hdr->ike_exchange;
betoh64(hdr->ike_ispi), betoh64(hdr->ike_rspi),
initiator);
msg->msg_msgid = betoh32(hdr->ike_msgid);
- if (policy_lookup(env, msg, NULL, NULL, 0) != 0)
+ if (policy_lookup(env, msg, NULL, NULL, 0) != 0) {
+ ikestat_inc(env, ikes_msg_rcvd_dropped);
return;
+ }
logit(hdr->ike_exchange == IKEV2_EXCHANGE_INFORMATIONAL ?
LOG_DEBUG : LOG_INFO,
if (hdr->ike_exchange != IKEV2_EXCHANGE_IKE_SA_INIT &&
hdr->ike_nextpayload != IKEV2_PAYLOAD_SK &&
- hdr->ike_nextpayload != IKEV2_PAYLOAD_SKF)
+ hdr->ike_nextpayload != IKEV2_PAYLOAD_SKF) {
+ ikestat_inc(env, ikes_msg_rcvd_dropped);
return;
+ }
if (msg->msg_response) {
- if (msg->msg_msgid > sa->sa_reqid)
+ if (msg->msg_msgid > sa->sa_reqid) {
+ ikestat_inc(env, ikes_msg_rcvd_dropped);
return;
+ }
mr = ikev2_msg_lookup(env, &sa->sa_requests, msg,
hdr->ike_exchange);
if (hdr->ike_exchange != IKEV2_EXCHANGE_INFORMATIONAL &&
- mr == NULL && sa->sa_fragments.frag_count == 0)
+ mr == NULL && sa->sa_fragments.frag_count == 0) {
+ ikestat_inc(env, ikes_msg_rcvd_dropped);
return;
+ }
if (flag) {
- if ((sa->sa_stateflags & flag) == 0)
+ if ((sa->sa_stateflags & flag) == 0) {
+ ikestat_inc(env, ikes_msg_rcvd_dropped);
return;
+ }
/*
* We have initiated this exchange, even if
* we are not the initiator of the IKE SA.
msg->msg_sa = sa = NULL;
goto done;
}
- if (msg->msg_msgid < sa->sa_msgid)
+ if (msg->msg_msgid < sa->sa_msgid) {
+ ikestat_inc(env, ikes_msg_rcvd_dropped);
return;
+ }
if (flag)
initiator = 0;
/*
* Response is being worked on, most likely we're
* waiting for the CA process to get back to us
*/
+ ikestat_inc(env, ikes_msg_rcvd_busy);
return;
}
sa->sa_msgid_current = msg->msg_msgid;
if (sa_address(sa, &sa->sa_peer, (struct sockaddr *)&msg->msg_peer)
== -1 ||
sa_address(sa, &sa->sa_local, (struct sockaddr *)&msg->msg_local)
- == -1)
+ == -1) {
+ ikestat_inc(env, ikes_msg_rcvd_dropped);
return;
+ }
sa->sa_fd = msg->msg_fd;
0, -1) != 0) {
log_info("%s: no proposal chosen", __func__);
msg->msg_error = IKEV2_N_NO_PROPOSAL_CHOSEN;
+ ikestat_inc(env, ikes_sa_proposals_negotiate_failures);
return (-1);
} else
sa_stateflags(sa, IKED_REQ_SA);
if (proposals_negotiate(&sa->sa_proposals, &sa->sa_proposals,
&msg->msg_proposals, 1, -1) != 0) {
log_info("%s: no proposal chosen", SPI_SA(sa, __func__));
+ ikestat_inc(env, ikes_sa_proposals_negotiate_failures);
return (-1);
}
sa_state(env, nsa, IKEV2_STATE_ESTABLISHED);
ikev2_enable_timer(env, nsa);
+ ikestat_inc(env, ikes_sa_rekeyed);
+
nsa->sa_stateflags = nsa->sa_statevalid; /* XXX */
/* unregister DPD keep alive timer & rekey first */
1, msg->msg_dhgroup) != 0) {
log_info("%s: no proposal chosen", __func__);
msg->msg_error = IKEV2_N_NO_PROPOSAL_CHOSEN;
+ ikestat_inc(env, ikes_sa_proposals_negotiate_failures);
goto fail;
}
ikev2_send_ike_e(env, sa, NULL, IKEV2_PAYLOAD_NONE,
IKEV2_EXCHANGE_INFORMATIONAL, 0);
sa->sa_stateflags |= IKED_REQ_INF;
+ ikestat_inc(env, ikes_dpd_sent);
}
/* re-register */
log_debug("%s: peer %s local %s", __func__,
print_host((struct sockaddr *)&sa->sa_peer.addr, NULL, 0),
print_host((struct sockaddr *)&sa->sa_local.addr, NULL, 0));
+ ikestat_inc(env, ikes_keepalive_sent);
timer_add(env, &sa->sa_keepalive, IKED_IKE_SA_KEEPALIVE_TIMEOUT);
}
if (proposals_negotiate(&sa->sa_proposals,
&msg->msg_policy->pol_proposals, &msg->msg_proposals, 0, -1) != 0) {
log_info("%s: proposals_negotiate", __func__);
+ ikestat_inc(env, ikes_sa_proposals_negotiate_failures);
return (-1);
}
if (sa_stateok(sa, IKEV2_STATE_SA_INIT))
TAILQ_INSERT_TAIL(&sa->sa_childsas, csa, csa_entry);
TAILQ_INSERT_TAIL(&sa->sa_childsas, csb, csa_entry);
+ ikestat_add(env, ikes_csa_created, 2);
csa->csa_peersa = csb;
csb->csa_peersa = csa;
childsa_free(ipcomp);
}
TAILQ_REMOVE(&sa->sa_childsas, csa, csa_entry);
+ ikestat_inc(env, ikes_csa_removed);
childsa_free(csa);
}
-/* $OpenBSD: ikev2_msg.c,v 1.85 2022/03/14 12:58:55 tobhe Exp $ */
+/* $OpenBSD: ikev2_msg.c,v 1.86 2022/09/19 20:54:02 tobhe Exp $ */
/*
* Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de>
timer_add(env, &sa->sa_timer,
IKED_IKE_SA_DELETE_TIMEOUT);
}
- }
+ ikestat_inc(env, ikes_msg_send_failures);
+ } else
+ ikestat_inc(env, ikes_msg_sent);
if (sa == NULL)
return (0);
if (ikev2_msg_send(env, &resp) == -1)
goto done;
+ ikestat_inc(env, ikes_frag_sent);
+
offset += MINIMUM(left, max_len);
left -= MINIMUM(left, max_len);
frag_num++;
done:
ikev2_msg_cleanup(env, &resp);
ibuf_release(e);
+ ikestat_inc(env, ikes_frag_send_failures);
return ret;
}
(struct sockaddr *)&m->msg_peer, m->msg_peerlen,
(struct sockaddr *)&m->msg_local, m->msg_locallen) == -1) {
log_warn("%s: sendtofrom", __func__);
+ ikestat_inc(env, ikes_msg_send_failures);
return (-1);
}
log_info("%sretransmit %s res %u local %s peer %s",
}
timer_add(env, &mr->mrt_timer, IKED_RESPONSE_TIMEOUT);
+ ikestat_inc(env, ikes_retransmit_response);
return (0);
}
log_warn("%s: sendtofrom", __func__);
ikev2_ike_sa_setreason(sa, "retransmit failed");
sa_free(env, sa);
+ ikestat_inc(env, ikes_msg_send_failures);
return;
}
log_info("%sretransmit %d %s req %u peer %s "
/* Exponential timeout */
timer_add(env, &mr->mrt_timer,
IKED_RETRANSMIT_TIMEOUT * (2 << (mr->mrt_tries++)));
+ ikestat_inc(env, ikes_retransmit_request);
} else {
log_debug("%s: retransmit limit reached for req %u",
__func__, msg->msg_msgid);
ikev2_ike_sa_setreason(sa, "retransmit limit reached");
+ ikestat_inc(env, ikes_retransmit_limit);
sa_free(env, sa);
}
}
-/* $OpenBSD: ikev2_pld.c,v 1.124 2022/07/04 09:23:15 tobhe Exp $ */
+/* $OpenBSD: ikev2_pld.c,v 1.125 2022/09/19 20:54:02 tobhe Exp $ */
/*
* Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de>
size_t frag_num, frag_total;
size_t len;
int ret = -1;
+ int processed = 0;
ssize_t elen;
buf = msgbuf + offset;
buf = msgbuf + offset;
len = left - sizeof(frag);
+ ikestat_inc(env, ikes_frag_rcvd);
+
/* Limit number of total fragments to avoid DOS */
if (frag_total > IKED_FRAG_TOTAL_MAX ) {
log_debug("%s: Total Fragments too big %zu",
} else {
ret = 0;
}
+ processed = 1;
+
done:
+ if (!processed)
+ ikestat_inc(env, ikes_frag_rcvd_drop);
ibuf_release(e);
return (ret);
dropall:
+ ikestat_add(env, ikes_frag_rcvd_drop, sa_frag->frag_count + 1);
config_free_fragments(sa_frag);
ibuf_release(e);
return -1;
size_t i;
struct iked_message emsg;
int ret = -1;
+ int processed = 0;
/* Reassemble fragments to single buffer */
if ((e = ibuf_new(NULL, sa_frag->frag_total_size)) == NULL) {
ret = ikev2_pld_payloads(env, &emsg, 0, ibuf_size(e),
sa_frag->frag_nextpayload);
+ processed = 1;
done:
+ if (processed)
+ ikestat_add(env, ikes_frag_reass_ok, sa_frag->frag_total);
+ else
+ ikestat_add(env, ikes_frag_reass_drop, sa_frag->frag_total);
config_free_fragments(sa_frag);
ibuf_release(e);
-/* $OpenBSD: policy.c,v 1.90 2022/09/14 13:07:50 tobhe Exp $ */
+/* $OpenBSD: policy.c,v 1.91 2022/09/19 20:54:02 tobhe Exp $ */
/*
* Copyright (c) 2020-2021 Tobias Heider <tobhe@openbsd.org>
}
}
+ if (ostate != sa->sa_state) {
+ switch (sa->sa_state) {
+ case IKEV2_STATE_ESTABLISHED:
+ ikestat_inc(env, ikes_sa_established_total);
+ ikestat_inc(env, ikes_sa_established_current);
+ break;
+ case IKEV2_STATE_CLOSED:
+ case IKEV2_STATE_CLOSING:
+ switch (ostate) {
+ case IKEV2_STATE_ESTABLISHED:
+ ikestat_dec(env, ikes_sa_established_current);
+ break;
+ case IKEV2_STATE_CLOSED:
+ case IKEV2_STATE_CLOSING:
+ break;
+ default:
+ ikestat_inc(env, ikes_sa_established_failures);
+ break;
+ }
+ break;
+ }
+ }
}
void
-/* $OpenBSD: types.h,v 1.50 2022/07/22 15:53:33 tobhe Exp $ */
+/* $OpenBSD: types.h,v 1.51 2022/09/19 20:54:02 tobhe Exp $ */
/*
* Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de>
IMSG_AUTH,
IMSG_PRIVKEY,
IMSG_PUBKEY,
- IMSG_CTL_SHOW_CERTSTORE
+ IMSG_CTL_SHOW_CERTSTORE,
+ IMSG_CTL_SHOW_STATS
};
enum privsep_procid {
-/* $OpenBSD: ikectl.c,v 1.27 2021/11/21 22:44:08 tobhe Exp $ */
+/* $OpenBSD: ikectl.c,v 1.28 2022/09/19 20:54:02 tobhe Exp $ */
/*
* Copyright (c) 2007-2013 Reyk Floeter <reyk@openbsd.org>
int monitor(struct imsg *);
int show_string(struct imsg *);
+int show_stats(struct imsg *, int);
int ca_opt(struct parse_result *);
imsg_compose(ibuf, IMSG_CTL_SHOW_SA, 0, 0, -1, NULL, 0);
done = 0;
break;
+ case SHOW_STATS:
+ imsg_compose(ibuf, IMSG_CTL_SHOW_STATS, 0, 0, -1, NULL, 0);
+ done = 0;
+ break;
case SHOW_CERTSTORE:
imsg_compose(ibuf, IMSG_CTL_SHOW_CERTSTORE, 0, 0, -1, NULL, 0);
done = 0;
case MONITOR:
done = monitor(&imsg);
break;
+ case SHOW_STATS:
+ done = show_stats(&imsg, quiet);
+ break;
case SHOW_SA:
case SHOW_CERTSTORE:
done = show_string(&imsg);
return (done);
}
+
+static char *
+plural(u_int64_t n)
+{
+ return (n != 1 ? "s" : "");
+}
+
+/*
+ * Dump IKE statistics structure.
+ */
+int
+show_stats(struct imsg *imsg, int quiet)
+{
+ struct iked_stats *stat;
+ int done = 1;
+
+ if (IMSG_DATA_SIZE(imsg) != sizeof(*stat))
+ return (done);
+ stat = imsg->data;
+ printf("ike:\n");
+#define p(f, m) if (stat->f || !quiet) \
+ printf(m, stat->f, plural(stat->f))
+
+ p(ikes_sa_created, "\t%llu IKE SA%s created\n");
+ p(ikes_sa_established_total, "\t%llu IKE SA%s established\n");
+ p(ikes_sa_established_current, "\t%llu IKE SA%s currently established\n");
+ p(ikes_sa_established_failures, "\t%llu IKE SA%s failed to establish\n");
+ p(ikes_sa_proposals_negotiate_failures, "\t%llu failed proposal negotiation%s\n");
+ p(ikes_sa_rekeyed, "\t%llu IKE SA%s rekeyed\n");
+ p(ikes_sa_removed, "\t%llu IKE SA%s removed\n");
+ p(ikes_csa_created, "\t%llu Child SA%s created\n");
+ p(ikes_csa_removed, "\t%llu Child SA%s removed\n");
+ p(ikes_msg_sent, "\t%llu message%s sent\n");
+ p(ikes_msg_send_failures, "\t%llu message%s could not be sent\n");
+ p(ikes_msg_rcvd, "\t%llu message%s received\n");
+ p(ikes_msg_rcvd_dropped, "\t%llu message%s dropped\n");
+ p(ikes_msg_rcvd_busy, "\t%llu request%s dropped, response being worked on\n");
+ p(ikes_retransmit_response, "\t%llu response%s retransmitted\n");
+ p(ikes_retransmit_request, "\t%llu request%s retransmitted\n");
+ p(ikes_retransmit_limit, "\t%llu request%s timed out\n");
+ p(ikes_frag_sent, "\t%llu fragment%s sent\n");
+ p(ikes_frag_send_failures, "\t%llu fragment%s could not be sent\n");
+ p(ikes_frag_rcvd, "\t%llu fragment%s received\n");
+ p(ikes_frag_rcvd_drop, "\t%llu fragment%s dropped\n");
+ p(ikes_frag_reass_ok, "\t%llu fragment%s reassembled\n");
+ p(ikes_frag_reass_drop, "\t%llu fragment%s could not be reassembled\n");
+ p(ikes_update_addresses_sent, "\t%llu update addresses request%s sent\n");
+ p(ikes_dpd_sent, "\t%llu dpd request%s sent\n");
+ p(ikes_keepalive_sent, "\t%llu keepalive message%s sent\n");
+#undef p
+ return (done);
+}
-/* $OpenBSD: parser.c,v 1.20 2021/11/21 22:44:08 tobhe Exp $ */
+/* $OpenBSD: parser.c,v 1.21 2022/09/19 20:54:02 tobhe Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
{ KEYWORD, "ca", SHOW_CA, t_show_ca },
{ KEYWORD, "sa", SHOW_SA, NULL },
{ KEYWORD, "certstore", SHOW_CERTSTORE,NULL },
+ { KEYWORD, "stats", SHOW_STATS, NULL },
{ ENDTOKEN, "", NONE, NULL }
};
-/* $OpenBSD: parser.h,v 1.17 2021/11/21 22:44:08 tobhe Exp $ */
+/* $OpenBSD: parser.h,v 1.18 2022/09/19 20:54:02 tobhe Exp $ */
/*
* Copyright (c) 2007-2013 Reyk Floeter <reyk@openbsd.org>
SHOW_CA_CERTIFICATES,
SHOW_SA,
RESET_ID,
- SHOW_CERTSTORE
+ SHOW_CERTSTORE,
+ SHOW_STATS
};
struct parse_result {