Hi,

this diff adds a new command to ikectl(8) and iked(8) that allows to reset
SAs based on the peers ID, which is equivalent to resetting a single policy.
The expected ID format is the same as printed by 'ipsecctl -sf' in the
'dstid' field.

Example:
  $ ikectl reset id FQDN/peer1

ok?

diff --git a/sbin/iked/control.c b/sbin/iked/control.c
index 67466c6a555..42b14e261e1 100644
--- a/sbin/iked/control.c
+++ b/sbin/iked/control.c
@@ -50,7 +50,8 @@ void   control_imsg_forward(struct imsg *);
 void    control_run(struct privsep *, struct privsep_proc *, void *);
 
 static struct privsep_proc procs[] = {
-       { "parent",     PROC_PARENT, NULL }
+       { "parent",     PROC_PARENT, NULL },
+       { "ikev2",      PROC_IKEV2, NULL }
 };
 
 pid_t
@@ -305,6 +306,9 @@ control_dispatch_imsg(int fd, short event, void *arg)
                case IMSG_CTL_PASSIVE:
                        proc_forward_imsg(&env->sc_ps, &imsg, PROC_PARENT, -1);
                        break;
+               case IMSG_CTL_RESET_ID:
+                       proc_forward_imsg(&env->sc_ps, &imsg, PROC_IKEV2, -1);
+                       break;
                default:
                        log_debug("%s: error handling imsg %d",
                            __func__, imsg.hdr.type);
diff --git a/sbin/iked/ikev2.c b/sbin/iked/ikev2.c
index 2dd2b2c648d..ebe0adce0e0 100644
--- a/sbin/iked/ikev2.c
+++ b/sbin/iked/ikev2.c
@@ -49,6 +49,7 @@
 void    ikev2_run(struct privsep *, struct privsep_proc *, void *);
 int     ikev2_dispatch_parent(int, struct privsep_proc *, struct imsg *);
 int     ikev2_dispatch_cert(int, struct privsep_proc *, struct imsg *);
+int     ikev2_dispatch_control(int, struct privsep_proc *, struct imsg *);
 
 struct iked_sa *
         ikev2_getimsgdata(struct iked *, struct imsg *, struct iked_sahdr *,
@@ -155,10 +156,12 @@ int        ikev2_update_sa_addresses(struct iked *, 
struct iked_sa *);
 int     ikev2_resp_informational(struct iked *, struct iked_sa *,
            struct iked_message *);
 
+void   ikev2_ctl_reset_id(struct iked *, struct imsg *, unsigned int);
 
 static struct privsep_proc procs[] = {
        { "parent",     PROC_PARENT,    ikev2_dispatch_parent },
-       { "certstore",  PROC_CERT,      ikev2_dispatch_cert }
+       { "certstore",  PROC_CERT,      ikev2_dispatch_cert },
+       { "control",    PROC_CONTROL,   ikev2_dispatch_control }
 };
 
 pid_t
@@ -376,6 +379,22 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct 
imsg *imsg)
        return (0);
 }
 
+int
+ikev2_dispatch_control(int fd, struct privsep_proc *p, struct imsg *imsg)
+{
+       struct iked             *env = p->p_env;
+
+       switch (imsg->hdr.type) {
+       case IMSG_CTL_RESET_ID:
+               ikev2_ctl_reset_id(env, imsg, imsg->hdr.type);
+               break;
+       default:
+               return (-1);
+       }
+
+       return (0);
+}
+
 const char *
 ikev2_ikesa_info(uint64_t spi, const char *msg)
 {
@@ -390,6 +409,38 @@ ikev2_ikesa_info(uint64_t spi, const char *msg)
        return buf;
 }
 
+void
+ikev2_ctl_reset_id(struct iked *env, struct imsg *imsg, unsigned int type)
+{
+       struct iked_sa                  *sa;
+       char                            *reset_id = NULL;
+       char                             sa_id[IKED_ID_SIZE];
+
+       if ((reset_id = get_string(imsg->data, IMSG_DATA_SIZE(imsg))) == NULL)
+               return;
+
+       log_debug("%s: %s %d", __func__, reset_id, type);
+       RB_FOREACH(sa, iked_sas, &env->sc_sas) {
+               if (ikev2_print_id(IKESA_DSTID(sa), sa_id, sizeof(sa_id)) == -1)
+                       continue;
+               if (strcmp(reset_id, sa_id) != 0)
+                       continue;
+               if (sa->sa_state == IKEV2_STATE_CLOSED)
+                       continue;
+               if (sa->sa_state == IKEV2_STATE_ESTABLISHED)
+                       ikev2_disable_timer(env, sa);
+               log_info("%s: IKE SA %p id %s ispi %s rspi %s", __func__,
+                   sa, sa_id,
+                   print_spi(sa->sa_hdr.sh_ispi, 8),
+                   print_spi(sa->sa_hdr.sh_rspi, 8));
+               ikev2_ikesa_delete(env, sa, 1);
+               /* default IKED_IKE_SA_DELETE_TIMEOUT is 120s, so switch to 6s 
*/
+               timer_add(env, &sa->sa_timer, 3 * IKED_RETRANSMIT_TIMEOUT);
+       }
+       free(reset_id);
+}
+
+
 struct iked_sa *
 ikev2_getimsgdata(struct iked *env, struct imsg *imsg, struct iked_sahdr *sh,
     uint8_t *type, uint8_t **buf, size_t *size)
diff --git a/sbin/iked/types.h b/sbin/iked/types.h
index e8881a74e9a..07cec6a5902 100644
--- a/sbin/iked/types.h
+++ b/sbin/iked/types.h
@@ -105,6 +105,7 @@ enum imsg_type {
        IMSG_CTL_MOBIKE,
        IMSG_CTL_FRAGMENTATION,
        IMSG_CTL_NATTPORT,
+       IMSG_CTL_RESET_ID,
        IMSG_COMPILE,
        IMSG_UDP_SOCKET,
        IMSG_PFKEY_SOCKET,
diff --git a/usr.sbin/ikectl/ikectl.8 b/usr.sbin/ikectl/ikectl.8
index 40d30ac0e21..9956b42b3c0 100644
--- a/usr.sbin/ikectl/ikectl.8
+++ b/usr.sbin/ikectl/ikectl.8
@@ -88,6 +88,8 @@ Flush the configured policies.
 Flush the running SAs.
 .It Cm reset user
 Flush the local user database.
+.It Cm reset id Ar ikeid
+Delete all IKE SAs with matching ID.
 .El
 .Sh PKI AND CERTIFICATE AUTHORITY COMMANDS
 In order to use public key based authentication with IKEv2,
diff --git a/usr.sbin/ikectl/ikectl.c b/usr.sbin/ikectl/ikectl.c
index dbcf60d70b4..977d875e6b2 100644
--- a/usr.sbin/ikectl/ikectl.c
+++ b/usr.sbin/ikectl/ikectl.c
@@ -291,6 +291,10 @@ main(int argc, char *argv[])
                imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1,
                    res->path, strlen(res->path));
                break;
+       case RESET_ID:
+               imsg_compose(ibuf, IMSG_CTL_RESET_ID, 0, 0, -1,
+                   res->id, strlen(res->id));
+               break;
        case RELOAD:
                imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
                break;
diff --git a/usr.sbin/ikectl/parser.c b/usr.sbin/ikectl/parser.c
index 05baadb93c9..bf84130bc5f 100644
--- a/usr.sbin/ikectl/parser.c
+++ b/usr.sbin/ikectl/parser.c
@@ -44,7 +44,8 @@ enum token_type {
        PEER,
        ADDRESS,
        FQDN,
-       PASSWORD
+       PASSWORD,
+       IKEID
 };
 
 struct token {
@@ -56,6 +57,7 @@ struct token {
 
 static const struct token t_main[];
 static const struct token t_reset[];
+static const struct token t_reset_id[];
 static const struct token t_log[];
 static const struct token t_load[];
 static const struct token t_ca[];
@@ -104,9 +106,14 @@ static const struct token t_reset[] = {
        { KEYWORD,      "policy",       RESETPOLICY,    NULL },
        { KEYWORD,      "sa",           RESETSA,        NULL },
        { KEYWORD,      "user",         RESETUSER,      NULL },
+       { KEYWORD,      "id",           RESET_ID,       t_reset_id },
        { ENDTOKEN,     "",             NONE,           NULL }
 };
 
+static const struct token t_reset_id[] = {
+       { IKEID,        "",             NONE,           NULL },
+       { ENDTOKEN,     "",             NONE,           NULL }
+};
 static const struct token t_load[] = {
        { PATH,         "",             NONE,           NULL },
        { ENDTOKEN,     "",             NONE,           NULL }
@@ -344,6 +351,13 @@ match_token(char *word, const struct token table[])
                                t = &table[i];
                        }
                        break;
+               case IKEID:
+                       if (!match && word != NULL && strlen(word) > 0) {
+                               res.id = strdup(word);
+                               match++;
+                               t = &table[i];
+                       }
+                       break;
                case ENDTOKEN:
                        break;
                }
@@ -393,6 +407,9 @@ show_valid_args(const struct token table[])
                case FQDN:
                        fprintf(stderr, "  <fqdn>\n");
                        break;
+               case IKEID:
+                       fprintf(stderr, "  <ikeid>\n");
+                       break;
                case ENDTOKEN:
                        break;
                }
diff --git a/usr.sbin/ikectl/parser.h b/usr.sbin/ikectl/parser.h
index f87ee3662ee..2d89ac7bdbc 100644
--- a/usr.sbin/ikectl/parser.h
+++ b/usr.sbin/ikectl/parser.h
@@ -54,7 +54,8 @@ enum actions {
        CA_KEY_INSTALL,
        CA_KEY_IMPORT,
        SHOW_CA,
-       SHOW_CA_CERTIFICATES
+       SHOW_CA_CERTIFICATES,
+       RESET_ID
 };
 
 struct parse_result {
@@ -65,6 +66,7 @@ struct parse_result {
        char            *pass;
        char            *host;
        char            *peer;
+       char            *id;
        int              htype;
        int              quiet;
 };

Reply via email to