Add iked connection statistics for successful and failed connections, common
authortobhe <tobhe@openbsd.org>
Mon, 19 Sep 2022 20:54:02 +0000 (20:54 +0000)
committertobhe <tobhe@openbsd.org>
Mon, 19 Sep 2022 20:54:02 +0000 (20:54 +0000)
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@

sbin/iked/config.c
sbin/iked/control.c
sbin/iked/iked.h
sbin/iked/ikev2.c
sbin/iked/ikev2_msg.c
sbin/iked/ikev2_pld.c
sbin/iked/policy.c
sbin/iked/types.h
usr.sbin/ikectl/ikectl.c
usr.sbin/ikectl/parser.c
usr.sbin/ikectl/parser.h

index 25caf3d..dd1c865 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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>
@@ -60,6 +60,7 @@ config_new_sa(struct iked *env, int initiator)
        gettimeofday(&sa->sa_timecreated, NULL);
        memcpy(&sa->sa_timeused, &sa->sa_timecreated, sizeof(sa->sa_timeused));
 
+       ikestat_inc(env, ikes_sa_created);
        return (sa);
 }
 
@@ -181,6 +182,11 @@ config_free_sa(struct iked *env, struct iked_sa *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);
 }
 
@@ -333,6 +339,7 @@ config_free_childsas(struct iked *env, struct iked_childsas *head,
                        childsa_free(ipcomp);
                }
                childsa_free(csa);
+               ikestat_inc(env, ikes_csa_removed);
        }
 }
 
index 828d68e..f88b9bf 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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>
@@ -311,6 +311,7 @@ control_dispatch_imsg(int fd, short event, void *arg)
                        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;
@@ -346,6 +347,7 @@ control_dispatch_ikev2(int fd, struct privsep_proc *p, struct imsg *imsg)
 {
        switch (imsg->hdr.type) {
        case IMSG_CTL_SHOW_SA:
+       case IMSG_CTL_SHOW_STATS:
                control_imsg_forward(imsg);
                return (0);
        default:
index 9873bc3..e6805b8 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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>
@@ -540,6 +540,41 @@ RB_HEAD(iked_dstid_sas, iked_sa);
 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;
@@ -765,6 +800,8 @@ struct iked {
        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 */
index 6f07d4f..3f718b7 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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>
@@ -187,6 +187,7 @@ int  ikev2_resp_informational(struct iked *, struct iked_sa *,
 
 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 },
@@ -519,6 +520,9 @@ ikev2_dispatch_control(int fd, struct privsep_proc *p, struct imsg *imsg)
        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);
        }
@@ -579,6 +583,13 @@ ikev2_ctl_show_sa(struct iked *env)
        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)
@@ -642,6 +653,8 @@ ikev2_recv(struct iked *env, struct iked_message *msg)
            (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;
@@ -649,8 +662,10 @@ ikev2_recv(struct iked *env, struct iked_message *msg)
            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,
@@ -679,20 +694,28 @@ ikev2_recv(struct iked *env, struct iked_message *msg)
 
        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.
@@ -723,8 +746,10 @@ ikev2_recv(struct iked *env, struct iked_message *msg)
                        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;
                /*
@@ -745,6 +770,7 @@ ikev2_recv(struct iked *env, struct iked_message *msg)
                         * 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;
@@ -753,8 +779,10 @@ ikev2_recv(struct iked *env, struct iked_message *msg)
        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;
 
@@ -1033,6 +1061,7 @@ ikev2_ike_auth_recv(struct iked *env, struct iked_sa *sa,
                    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);
@@ -4378,6 +4407,7 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg)
        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);
        }
 
@@ -4710,6 +4740,8 @@ ikev2_ikesa_enable(struct iked *env, struct iked_sa *sa, struct iked_sa *nsa)
        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 */
@@ -4887,6 +4919,7 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg)
                    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;
                }
 
@@ -5176,6 +5209,7 @@ ikev2_ike_sa_alive(struct iked *env, void *arg)
                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 */
@@ -5199,6 +5233,7 @@ ikev2_ike_sa_keepalive(struct iked *env, void *arg)
                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);
 }
 
@@ -5399,6 +5434,7 @@ ikev2_sa_negotiate_common(struct iked *env, struct iked_sa *sa, struct iked_mess
        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))
@@ -6361,6 +6397,7 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa,
 
                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;
@@ -6609,6 +6646,7 @@ ikev2_childsa_delete(struct iked *env, struct iked_sa *sa, uint8_t saproto,
                        childsa_free(ipcomp);
                }
                TAILQ_REMOVE(&sa->sa_childsas, csa, csa_entry);
+               ikestat_inc(env, ikes_csa_removed);
                childsa_free(csa);
        }
 
index feab4aa..c36ba5a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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>
@@ -307,7 +307,9 @@ ikev2_msg_send(struct iked *env, struct iked_message *msg)
                        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);
@@ -892,6 +894,8 @@ ikev2_send_encrypted_fragments(struct iked *env, struct iked_sa *sa,
                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++;
@@ -908,6 +912,7 @@ ikev2_send_encrypted_fragments(struct iked *env, struct iked_sa *sa,
 done:
        ikev2_msg_cleanup(env, &resp);
        ibuf_release(e);
+       ikestat_inc(env, ikes_frag_send_failures);
        return ret;
 }
 
@@ -1268,6 +1273,7 @@ ikev2_msg_retransmit_response(struct iked *env, struct iked_sa *sa,
                    (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",
@@ -1279,6 +1285,7 @@ ikev2_msg_retransmit_response(struct iked *env, struct iked_sa *sa,
        }
 
        timer_add(env, &mr->mrt_timer, IKED_RESPONSE_TIMEOUT);
+       ikestat_inc(env, ikes_retransmit_response);
        return (0);
 }
 
@@ -1309,6 +1316,7 @@ ikev2_msg_retransmit_timeout(struct iked *env, void *arg)
                                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 "
@@ -1321,10 +1329,12 @@ ikev2_msg_retransmit_timeout(struct iked *env, void *arg)
                /* 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);
        }
 }
index d2ec6bd..af4f255 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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>
@@ -1605,6 +1605,7 @@ ikev2_pld_ef(struct iked *env, struct ikev2_payload *pld,
        size_t                           frag_num, frag_total;
        size_t                           len;
        int                              ret = -1;
+       int                              processed = 0;
        ssize_t                          elen;
 
        buf = msgbuf + offset;
@@ -1616,6 +1617,8 @@ ikev2_pld_ef(struct iked *env, struct ikev2_payload *pld,
        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",
@@ -1701,10 +1704,15 @@ ikev2_pld_ef(struct iked *env, struct ikev2_payload *pld,
        } 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;
@@ -1722,6 +1730,7 @@ ikev2_frags_reassemble(struct iked *env, struct ikev2_payload *pld,
        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) {
@@ -1765,7 +1774,12 @@ ikev2_frags_reassemble(struct iked *env, struct ikev2_payload *pld,
 
        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);
 
index ad2b1dc..a4cdc27 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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>
@@ -414,6 +414,28 @@ sa_state(struct iked *env, struct iked_sa *sa, int state)
                }
        }
 
+       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
index 14f5ca5..d4fc55c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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>
@@ -130,7 +130,8 @@ enum imsg_type {
        IMSG_AUTH,
        IMSG_PRIVKEY,
        IMSG_PUBKEY,
-       IMSG_CTL_SHOW_CERTSTORE
+       IMSG_CTL_SHOW_CERTSTORE,
+       IMSG_CTL_SHOW_STATS
 };
 
 enum privsep_procid {
index 6ba3b25..cc10c62 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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>
@@ -49,6 +49,7 @@ void           monitor_id(struct imsg *);
 int             monitor(struct imsg *);
 
 int             show_string(struct imsg *);
+int             show_stats(struct imsg *, int);
 
 int             ca_opt(struct parse_result *);
 
@@ -303,6 +304,10 @@ main(int argc, char *argv[])
                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;
@@ -354,6 +359,9 @@ main(int argc, char *argv[])
                        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);
@@ -421,3 +429,55 @@ show_string(struct imsg *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);
+}
index 008f986..008bff4 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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>
@@ -215,6 +215,7 @@ static const struct token t_show[] = {
        { 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 }
 };
 
index cd20e79..2e06e35 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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>
@@ -57,7 +57,8 @@ enum actions {
        SHOW_CA_CERTIFICATES,
        SHOW_SA,
        RESET_ID,
-       SHOW_CERTSTORE
+       SHOW_CERTSTORE,
+       SHOW_STATS
 };
 
 struct parse_result {