diff --git a/programs/pluto/ikev1_main.c b/programs/pluto/ikev1_main.c index de20a83..31d959b 100644 --- a/programs/pluto/ikev1_main.c +++ b/programs/pluto/ikev1_main.c @@ -2983,13 +2983,12 @@ bool accept_delete(struct msg_digest *md, * IPSEC (ESP/AH) */ ipsec_spi_t spi; /* network order */ - bool bogus; - struct state *dst; if (!in_raw(&spi, sizeof(spi), &p->pbs, "SPI")) return self_delete; - dst = find_phase2_state_to_delete(st, + bool bogus; + struct state *dst = find_phase2_state_to_delete(st, d->isad_protoid, spi, &bogus); @@ -2997,14 +2996,19 @@ bool accept_delete(struct msg_digest *md, passert(dst != st); /* st is an IKE SA */ if (dst == NULL) { loglog(RC_LOG_SERIOUS, - "ignoring Delete SA payload: %s SA(0x%08" PRIx32 ") not found (%s)", + "ignoring Delete SA payload: %s SA(0x%08" PRIx32 ") not found (maybe expired)", enum_show(&protocol_names, d->isad_protoid), - ntohl(spi), - bogus ? - "our SPI - bogus implementation" : - "maybe expired"); + ntohl(spi)); } else { + if (bogus) { + loglog(RC_LOG_SERIOUS, + "warning: Delete SA payload: %s SA(0x%08" PRIx32 ") is our own SPI (bogus implementation) - deleting anyway", + enum_show(&protocol_names, + d->isad_protoid), + ntohl(spi)); + } + struct connection *rc = dst->st_connection; struct connection *oldc = cur_connection; diff --git a/programs/pluto/state.c b/programs/pluto/state.c index b2eac62..c5d4484 100644 --- a/programs/pluto/state.c +++ b/programs/pluto/state.c @@ -1537,37 +1537,52 @@ struct state *find_likely_sender(size_t packet_len, u_char *packet) return NULL; } +/* + * find_phase2_state_to_delete: find an AH or ESP SA to delete + * + * We are supposed to be given the other side's SPI. + * Certain CISCO implementations send our side's SPI instead. + * We'll accept this, but mark it as bogus. + */ struct state *find_phase2_state_to_delete(const struct state *p1st, u_int8_t protoid, ipsec_spi_t spi, bool *bogus) { - struct state *st; + struct state *bogusst = NULL; int i; *bogus = FALSE; for (i = 0; i < STATE_TABLE_SIZE; i++) { + struct state *st; + FOR_EACH_ENTRY(st, i, { if (IS_IPSEC_SA_ESTABLISHED(st->st_state) && p1st->st_connection->host_pair == st->st_connection->host_pair && same_peer_ids(p1st->st_connection, - st->st_connection, NULL)) { + st->st_connection, NULL)) + { struct ipsec_proto_info *pr = protoid == PROTO_IPSEC_AH ? &st->st_ah : &st->st_esp; if (pr->present) { - if (pr->attrs.spi == spi) + if (pr->attrs.spi == spi) { + *bogus = FALSE; return st; + } - if (pr->our_spi == spi) + if (pr->our_spi == spi) { *bogus = TRUE; + bogusst = st; + /* don't return! */ + } } } }); } - return NULL; + return bogusst; } /*