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; };