Revised notify_delete-2.00.diff, was Re: delete-sa-01 test
Sam Sgro <[email protected]>
| Newsgroups | gmane.network.freeswan.devel |
|---|---|
| Message-ID | <[email protected]> |
-----BEGIN PGP SIGNED MESSAGE----- On Sun, 9 Feb 2003, Ken Bantoft wrote: > My fault :( I should have inspected the code more when I was porting > up the patch. Thanks for the updated patch, I've updated freeswan.ca with > it as well. Well, if it makes you feel any better, I uploaded the wrong diff. :) Here is the corrected version. - -- Sam Sgro [email protected] -----BEGIN PGP SIGNATURE----- Version: 2.6.3ia Charset: noconv Comment: For the matching public key, finger the Reply-To: address. iQCVAwUBPkdpukOSC4btEQUtAQHebAP+K0DEP6eoTG1HRjYJKaeJpdk+mzRO5DVt H3kHrAZZSb3jvqt/Ux14FpDXxWf9El7MYwo3D0+pU9+dAbM9YvZCIHDHGxLi379F kmKCXGwxm5qGwYoYl9Ve0BJx++WZk8KrZ+TjVwMT8WwwSMHhtbG1y+CBZ7fcg0NB oB0EDBKn9bE= =5O0P -----END PGP SIGNATURE-----
notify_delete-2.00.diff
(text/plain, 34.1 KB)
Index: programs/pluto/connections.c
===================================================================
RCS file: /freeswan/MASTER/freeswan/programs/pluto/connections.c,v
retrieving revision 1.152
diff -u -r1.152 connections.c
--- programs/pluto/connections.c 30 Jan 2003 21:54:25 -0000 1.152
+++ programs/pluto/connections.c 1 Feb 2003 01:29:27 -0000
@@ -713,6 +713,7 @@
}
/* set internal fields */
+ c->initiated = FALSE;
c->instance_serial = 0;
c->ac_next = connections;
connections = c;
@@ -1201,6 +1202,7 @@
* This is a fudge, but not yet important.
* If we are to proceed asynchronously, whackfd will be NULL_FD.
*/
+ c->initiated = TRUE;
c->policy |= POLICY_UP;
ipsecdoi_initiate(whackfd, c, c->policy, 1, SOS_NOBODY);
whackfd = NULL_FD; /* protect from close */
@@ -1531,6 +1533,7 @@
{
set_cur_connection(c);
log("terminating SAs using this connection");
+ c->initiated = FALSE;
c->policy &= ~POLICY_UP;
flush_pending_by_connection(c);
delete_states_by_connection(c);
Index: programs/pluto/connections.h
===================================================================
RCS file: /freeswan/MASTER/freeswan/programs/pluto/connections.h,v
retrieving revision 1.67
diff -u -r1.67 connections.h
--- programs/pluto/connections.h 26 Jan 2003 18:41:41 -0000 1.67
+++ programs/pluto/connections.h 1 Feb 2003 01:29:27 -0000
@@ -118,6 +118,7 @@
enum connection_kind kind;
const struct iface *interface; /* filled in iff oriented */
enum routing_t routing; /* level of routing in place */
+ bool initiated;
so_serial_t /* state object serial number */
newest_isakmp_sa,
Index: programs/pluto/demux.c
===================================================================
RCS file: /freeswan/MASTER/freeswan/programs/pluto/demux.c,v
retrieving revision 1.136
diff -u -r1.136 demux.c
--- programs/pluto/demux.c 9 Nov 2002 22:48:10 -0000 1.136
+++ programs/pluto/demux.c 1 Feb 2003 01:29:29 -0000
@@ -783,7 +783,7 @@
static stf_status
informational(struct msg_digest *md UNUSED)
{
- loglog(RC_LOG_SERIOUS, "received and ignored informational message");
+ /* loglog(RC_LOG_SERIOUS, "received and ignored informational message"); */
return STF_IGNORE;
}
@@ -1035,12 +1035,27 @@
struct state *st = NULL;
enum state_kind from_state = STATE_UNDEFINED; /* state we started in */
+#define SEND_NOTIFICATION(t) { \
+ if (st) send_notification_from_state(st, from_state, t); \
+ else send_notification_from_md(md, t); }
+
if (!in_struct(&md->hdr, &isakmp_hdr_desc, &md->packet_pbs, &md->message_pbs))
{
- /* XXX specific failures (special notification?):
+ /* Identify specific failures:
* - bad ISAKMP major/minor version numbers
- * - size of packet vs size of message
*/
+ if (md->packet_pbs.roof - md->packet_pbs.cur >= (ptrdiff_t)isakmp_hdr_desc.size) {
+ struct isakmp_hdr *hdr = (struct isakmp_hdr *)md->packet_pbs.cur;
+ if ((hdr->isa_version >> ISA_MAJ_SHIFT) != ISAKMP_MAJOR_VERSION) {
+ SEND_NOTIFICATION(INVALID_MAJOR_VERSION);
+ return;
+ }
+ else if ((hdr->isa_version & ISA_MIN_MASK) != ISAKMP_MINOR_VERSION) {
+ SEND_NOTIFICATION(INVALID_MINOR_VERSION);
+ return;
+ }
+ }
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
return;
}
@@ -1048,6 +1063,7 @@
{
log("size (%u) differs from size specified in ISAKMP HDR (%u)"
, (unsigned) pbs_room(&md->packet_pbs), md->hdr.isa_length);
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
return;
}
@@ -1063,14 +1079,14 @@
{
log("Message ID was 0x%08lx but should be zero in Main Mode",
(unsigned long) md->hdr.isa_msgid);
- /* XXX Could send notification back */
+ SEND_NOTIFICATION(INVALID_MESSAGE_ID);
return;
}
if (is_zero_cookie(md->hdr.isa_icookie))
{
log("Initiator Cookie must not be zero in Main Mode message");
- /* XXX Could send notification back */
+ SEND_NOTIFICATION(INVALID_COOKIE);
return;
}
@@ -1083,6 +1099,7 @@
{
log("initial Main Mode message is invalid:"
" its Encrypted Flag is on");
+ SEND_NOTIFICATION(INVALID_FLAGS);
return;
}
@@ -1185,7 +1202,7 @@
{
log("Quick Mode message is invalid because"
" it has an Initiator Cookie of 0");
- /* XXX Could send notification back */
+ SEND_NOTIFICATION(INVALID_COOKIE);
return;
}
@@ -1193,7 +1210,7 @@
{
log("Quick Mode message is invalid because"
" it has a Responder Cookie of 0");
- /* XXX Could send notification back */
+ SEND_NOTIFICATION(INVALID_COOKIE);
return;
}
@@ -1201,7 +1218,7 @@
{
log("Quick Mode message is invalid because"
" it has a Message ID of 0");
- /* XXX Could send notification back */
+ SEND_NOTIFICATION(INVALID_MESSAGE_ID);
return;
}
@@ -1231,7 +1248,7 @@
{
loglog(RC_LOG_SERIOUS, "Quick Mode message is unacceptable because"
" it is for an incomplete ISAKMP SA");
- /* XXX Could send notification back */
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED /* XXX ? */);
return;
}
@@ -1242,7 +1259,7 @@
" it uses a previously used Message ID 0x%08lx"
" (perhaps this is a duplicated packet)"
, (unsigned long) md->hdr.isa_msgid);
- /* XXX Could send notification INVALID_MESSAGE_ID back */
+ SEND_NOTIFICATION(INVALID_MESSAGE_ID);
return;
}
@@ -1268,6 +1285,7 @@
default:
log("unsupported exchange type %s in message"
, enum_show(&exchange_names, md->hdr.isa_xchg));
+ SEND_NOTIFICATION(UNSUPPORTED_EXCHANGE_TYPE);
return;
}
@@ -1364,14 +1382,14 @@
if (st == NULL)
{
log("discarding encrypted message for an unknown ISAKMP SA");
- /* XXX Could send notification back */
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED /* XXX ? */);
return;
}
if (st->st_skeyid_e.ptr == (u_char *) NULL)
{
loglog(RC_LOG_SERIOUS, "discarding encrypted message"
" because we haven't yet negotiated keying materiel");
- /* XXX Could send notification back */
+ SEND_NOTIFICATION(INVALID_FLAGS);
return;
}
@@ -1403,7 +1421,7 @@
if (pbs_left(&md->message_pbs) % e->blocksize != 0)
{
loglog(RC_LOG_SERIOUS, "malformed message: not a multiple of encryption blocksize");
- /* XXX Could send notification back */
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
return;
}
@@ -1438,7 +1456,7 @@
if (smc->flags & SMF_INPUT_ENCRYPTED)
{
loglog(RC_LOG_SERIOUS, "packet rejected: should have been encrypted");
- /* XXX Could send notification back */
+ SEND_NOTIFICATION(INVALID_FLAGS);
return;
}
}
@@ -1465,6 +1483,7 @@
if (pd == &md->digest[PAYLIMIT])
{
loglog(RC_LOG_SERIOUS, "more than %d payloads in message; ignored", PAYLIMIT);
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
return;
}
@@ -1481,6 +1500,7 @@
loglog(RC_LOG_SERIOUS, "%smessage ignored because it contains an unknown or"
" unexpected payload type (%s) at the outermost level"
, excuse, enum_show(&payload_names, np));
+ SEND_NOTIFICATION(INVALID_PAYLOAD_TYPE);
return;
}
}
@@ -1494,6 +1514,7 @@
loglog(RC_LOG_SERIOUS, "%smessage ignored because it contains a"
" payload type (%s) unexpected in this message"
, excuse, enum_show(&payload_names, np));
+ SEND_NOTIFICATION(INVALID_PAYLOAD_TYPE);
return;
}
needed &= ~s;
@@ -1502,6 +1523,7 @@
if (!in_struct(&pd->payload, sd, &md->message_pbs, &pd->pbs))
{
loglog(RC_LOG_SERIOUS, "%smalformed payload in packet", excuse);
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
return;
}
@@ -1541,6 +1563,7 @@
loglog(RC_LOG_SERIOUS, "message for %s is missing payloads %s"
, enum_show(&state_names, from_state)
, bitnamesof(payload_name, needed));
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
return;
}
}
@@ -1556,6 +1579,7 @@
&& md->hdr.isa_np != ISAKMP_NEXT_SA)
{
loglog(RC_LOG_SERIOUS, "malformed Phase 1 message: does not start with an SA payload");
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
return;
}
}
@@ -1579,6 +1603,7 @@
if (md->hdr.isa_np != ISAKMP_NEXT_HASH)
{
loglog(RC_LOG_SERIOUS, "malformed Quick Mode message: does not start with a HASH payload");
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
return;
}
@@ -1592,6 +1617,7 @@
if (p != &md->digest[i])
{
loglog(RC_LOG_SERIOUS, "malformed Quick Mode message: SA payload is in wrong position");
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
return;
}
}
@@ -1612,12 +1638,14 @@
loglog(RC_LOG_SERIOUS, "malformed Quick Mode message:"
" if any ID payload is present,"
" there must be exactly two");
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
return;
}
if (id+1 != id->next)
{
loglog(RC_LOG_SERIOUS, "malformed Quick Mode message:"
" the ID payloads are not adjacent");
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
return;
}
}
@@ -1642,7 +1670,7 @@
for (p = md->chain[ISAKMP_NEXT_D]; p != NULL; p = p->next)
{
- loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload");
+ accept_delete(st, md, p);
DBG_cond_dump(DBG_PARSING, "del:", p->pbs.cur, pbs_left(&p->pbs));
}
@@ -1934,13 +1962,14 @@
result = STF_FAIL;
/* FALL THROUGH ... */
case STF_FAIL:
- /* XXX Could send notification back
- * As it is, we act as if this message never happened:
+ /* As it is, we act as if this message never happened:
* whatever retrying was in place, remains in place.
*/
whack_log(RC_NOTIFICATION + md->note
, "%s: %s", enum_name(&state_names, st->st_state)
, enum_name(&ipsec_notification_names, md->note));
+
+ SEND_NOTIFICATION(md->note);
DBG(DBG_CONTROL,
DBG_log("state transition function for %s failed: %s"
Index: programs/pluto/ipsec_doi.c
===================================================================
RCS file: /freeswan/MASTER/freeswan/programs/pluto/ipsec_doi.c,v
retrieving revision 1.179
diff -u -r1.179 ipsec_doi.c
--- programs/pluto/ipsec_doi.c 17 Dec 2002 14:26:54 -0000 1.179
+++ programs/pluto/ipsec_doi.c 1 Feb 2003 01:29:31 -0000
@@ -228,7 +228,6 @@
{
loglog(RC_LOG_SERIOUS, "KE has %u byte DH public value; %u required"
, (unsigned) pbs_left(pbs), (unsigned) gr->bytes);
- /* XXX Could send notification back */
#ifdef DODGE_DH_MISSING_ZERO_BUG
if (pbs_left(pbs) > gr->bytes)
#endif
@@ -290,76 +289,198 @@
* Send a notification to the peer. We could make a decision on
* whether to send the notification, based on the type and the
* destination, if we care to.
- * XXX It doesn't handle DELETE notifications (which are also
- * XXX informational exchanges).
- * XXX Not modified to support ip_address and related (IPv4+IPv6) functions.
- */
-#if 0 /* not currently used */
-//static void
-//send_notification(int sock,
-// u_int16_t type,
-// u_char *spi,
-// u_char spilen,
-// u_char protoid,
-// u_char *icookie,
-// u_char *rcookie,
-// msgid_t /*network order*/ msgid,
-// struct sockaddr sa)
-//{
-// u_char buffer[sizeof(struct isakmp_hdr) +
-// sizeof(struct isakmp_notification)];
-// struct isakmp_hdr *isa = (struct isakmp_hdr *) buffer;
-// struct isakmp_notification *isan = (struct isakmp_notification *)
-// (buffer + sizeof(struct isakmp_hdr));
-//
-// memset(buffer, '\0', sizeof(struct isakmp_hdr) +
-// sizeof(struct isakmp_notification));
-//
-// if (icookie != (u_char *) NULL)
-// memcpy(isa->isa_icookie, icookie, COOKIE_SIZE);
-//
-// if (rcookie != (u_char *) NULL)
-// memcpy(isa->isa_rcookie, rcookie, COOKIE_SIZE);
-//
-// /* Standard header */
-// isa->isa_np = ISAKMP_NEXT_N;
-// isa->isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
-// isa->isa_xchg = ISAKMP_XCHG_INFO;
-// isa->isa_msgid = msgid;
-// isa->isa_length = htonl(sizeof(struct isakmp_hdr) +
-// sizeof(struct isakmp_notification) +
-// spilen);
-//
-// /* Notification header */
-// isan->isan_type = htons(type);
-// isan->isan_doi = htonl(ISAKMP_DOI_IPSEC);
-// isan->isan_length = htons(sizeof(struct isakmp_notification) + spilen);
-// isan->isan_spisize = spilen;
-// memcpy((u_char *)isan + sizeof(struct isakmp_notification), spi, spilen);
-// isan->isan_protoid = protoid;
-//
-// DBG(DBG_CONTROL, DBG_log("sending INFO type %s to %s",
-// enum_show(¬ification_names, type),
-// show_sa(&sa)));
-//
-// if (sendto(sock, buffer, ntohl(isa->isa_length), 0, &sa,
-// sizeof(sa)) != ntohl(isa->isa_length))
-// log_errno((e, "sendto() failed in send_notification() to %s",
-// show_sa(&sa)));
-// else
-// {
-// DBG(DBG_CONTROL, DBG_log("transmitted %d bytes", ntohl(isa->isa_length)));
-// }
-//}
-#endif /* not currently used */
+ * It doesn't handle DELETE notifications (see send_ipsec_delete)
+ */
+static void
+send_notification(struct state *sndst, u_int16_t type, struct state *encst,
+ msgid_t msgid, u_char *icookie, u_char *rcookie,
+ u_char *spi, size_t spisize, u_char protoid)
+{
+ u_char buffer[1024];
+ pb_stream pbs, r_hdr_pbs;
+ u_char *r_hashval, *r_hash_start;
+
+ passert((sndst) && (sndst->st_connection));
+
+ log("sending %snotification %s to %s:%u",
+ encst ? "encrypted " : "",
+ enum_name(&ipsec_notification_names, type),
+ ip_str(&sndst->st_connection->that.host_addr),
+ (unsigned)sndst->st_connection->that.host_port);
+
+ memset(buffer, 0, sizeof(buffer));
+ init_pbs(&pbs, buffer, sizeof(buffer), "notification msg");
+
+ /* HDR* */
+ {
+ struct isakmp_hdr hdr;
+
+ hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
+ hdr.isa_np = encst ? ISAKMP_NEXT_HASH : ISAKMP_NEXT_N;
+ hdr.isa_xchg = ISAKMP_XCHG_INFO;
+ hdr.isa_msgid = msgid;
+ hdr.isa_flags = encst ? ISAKMP_FLAG_ENCRYPTION : 0;
+ if (icookie)
+ memcpy(hdr.isa_icookie, icookie, COOKIE_SIZE);
+ if (rcookie)
+ memcpy(hdr.isa_rcookie, rcookie, COOKIE_SIZE);
+ if (!out_struct(&hdr, &isakmp_hdr_desc, &pbs, &r_hdr_pbs))
+ impossible();
+ }
+
+ /* HASH -- value to be filled later */
+ if (encst)
+ {
+ pb_stream hash_pbs;
+ if (!out_generic(ISAKMP_NEXT_N, &isakmp_hash_desc, &r_hdr_pbs,
+ &hash_pbs))
+ impossible();
+ r_hashval = hash_pbs.cur; /* remember where to plant value */
+ if (!out_zero(
+#ifdef _IKE_ALG_H
+ encst->st_oakley.hasher->hash_digest_size,
+#else
+ encst->st_oakley.hasher->hash_digest_len,
+#endif
+ &hash_pbs, "HASH(1)"))
+ impossible();
+ close_output_pbs(&hash_pbs);
+ r_hash_start = r_hdr_pbs.cur; /* hash from after HASH(1) */
+ }
+
+ /* Notification Payload */
+ {
+ pb_stream not_pbs;
+ struct isakmp_notification isan;
+
+ isan.isan_doi = ISAKMP_DOI_IPSEC;
+ isan.isan_np = ISAKMP_NEXT_NONE;
+ isan.isan_type = type;
+ isan.isan_spisize = spisize;
+ isan.isan_protoid = protoid;
+
+ if (!out_struct(&isan, &isakmp_notification_desc, &r_hdr_pbs, ¬_pbs)
+ || !out_raw(spi, spisize, ¬_pbs, "spi"))
+ impossible();
+ close_output_pbs(¬_pbs);
+ }
+
+ /* calculate hash value and patch into Hash Payload */
+ if (encst)
+ {
+ struct hmac_ctx ctx;
+ hmac_init_chunk(&ctx, encst->st_oakley.hasher, encst->st_skeyid_a);
+ hmac_update(&ctx, (u_char *) &msgid, sizeof(msgid_t));
+ hmac_update(&ctx, r_hash_start, r_hdr_pbs.cur-r_hash_start);
+ hmac_final(r_hashval, &ctx);
+
+#ifdef _IKE_ALG_H
+ DBG(DBG_CRYPT,
+ DBG_log("HASH(1) computed:");
+ DBG_dump("", r_hashval, ctx.hmac_digest_size);
+ )
+ }
+#else
+ DBG(DBG_CRYPT,
+ DBG_log("HASH(1) computed:");
+ DBG_dump("", r_hashval, ctx.hmac_digest_len);
+ )
+ }
+#endif
+
+ /* Encrypt message (preserve st_iv) */
+ if (encst)
+ {
+ u_char old_iv[MAX_DIGEST_LEN];
+ if (encst->st_iv_len > MAX_DIGEST_LEN)
+ impossible();
+ memcpy(old_iv, encst->st_iv, encst->st_iv_len);
+ init_phase2_iv(encst, &msgid);
+ if (!encrypt_message(&r_hdr_pbs, encst))
+ impossible();
+ memcpy(encst->st_iv, old_iv, encst->st_iv_len);
+ }
+ else
+ {
+ close_output_pbs(&r_hdr_pbs);
+ }
+
+ /* Send packet (preserve st_tpacket) */
+ {
+ chunk_t saved_tpacket = sndst->st_tpacket;
+
+ setchunk(sndst->st_tpacket, pbs.start, pbs_offset(&pbs));
+ send_packet(sndst, "notification packet");
+ sndst->st_tpacket = saved_tpacket;
+ }
+}
+
+void
+send_notification_from_state(struct state *st, enum state_kind state,
+ u_int16_t type)
+{
+ struct state *p1st;
+
+ passert(st);
+
+ if (state == STATE_UNDEFINED)
+ state = st->st_state;
+
+ if (IS_QUICK(state)) {
+ p1st = find_phase1_state(st->st_connection, TRUE);
+ if ((p1st == NULL) || (!IS_ISAKMP_SA_ESTABLISHED(p1st->st_state))) {
+ loglog(RC_LOG_SERIOUS,
+ "no Phase1 state for Quick mode notification");
+ return;
+ }
+ send_notification(st, type, p1st, generate_msgid(p1st),
+ st->st_icookie, st->st_rcookie, NULL, 0, PROTO_ISAKMP);
+ }
+ else if (IS_ISAKMP_SA_ESTABLISHED(state)) {
+ send_notification(st, type, st, generate_msgid(st),
+ st->st_icookie, st->st_rcookie, NULL, 0, PROTO_ISAKMP);
+ }
+ else {
+ /* no ISAKMP SA established - don't encrypt notification */
+ send_notification(st, type, NULL, 0,
+ st->st_icookie, st->st_rcookie, NULL, 0, PROTO_ISAKMP);
+ }
+}
+
+void
+send_notification_from_md(struct msg_digest *md, u_int16_t type)
+{
+ /**
+ * Create a dummy state to be able to use send_packet in
+ * send_notification
+ *
+ * we need to set:
+ * st_connection->that.host_addr
+ * st_connection->that.host_port
+ * st_connection->interface
+ */
+ struct state st;
+ struct connection cnx;
+
+ passert(md);
+
+ memset(&st, 0, sizeof(st));
+ memset(&cnx, 0, sizeof(cnx));
+ st.st_connection = &cnx;
+ cnx.that.host_addr = md->sender;
+ cnx.that.host_port = md->sender_port;
+ cnx.interface = md->iface;
+
+ send_notification(&st, type, NULL, 0,
+ md->hdr.isa_icookie, md->hdr.isa_rcookie, NULL, 0, PROTO_ISAKMP);
+}
-/* Send a Delete Notification to announce deletion of inbound IPSEC SAs.
+/* Send a Delete Notification to announce deletion of inbound IPSEC/ISAKMP SAs.
* Ignores states that don't have any.
- * Delete Notifications cannot announce deletion of outbound IPSEC SAs.
- * We don't bother announcing deletion of ISAKMP SAs at this point.
+ * Delete Notifications cannot announce deletion of outbound IPSEC/ISAKMP SAs.
*/
void
-send_ipsec_delete(struct state *p2st)
+send_delete(struct state *st)
{
pb_stream reply_pbs;
pb_stream r_hdr_pbs;
@@ -371,49 +492,42 @@
u_char
*r_hashval, /* where in reply to jam hash value */
*r_hash_start; /* start of what is to be hashed */
+ bool isakmp_sa = FALSE;
- if (!IS_IPSEC_SA_ESTABLISHED(p2st->st_state))
- return; /* nothing to do */
-
- /* find an ISAKMP SA that we can use -- must be established */
- p1st = find_phase1_state(p2st->st_connection, ISAKMP_SA_ESTABLISHED_STATES);
- if (p1st == NULL)
- {
- DBG(DBG_CONTROL, DBG_log("no Phase 1 state for Delete"));
- return;
+ if (IS_IPSEC_SA_ESTABLISHED(st->st_state)) {
+ p1st = find_phase1_state(st->st_connection, ISAKMP_SA_ESTABLISHED_STATES);
+ if (p1st == NULL)
+ {
+ DBG(DBG_CONTROL, DBG_log("no Phase 1 state for Delete"));
+ return;
+ }
+
+ if (st->st_ah.present)
+ {
+ ns->spi = st->st_ah.our_spi;
+ ns->dst = st->st_connection->this.host_addr;
+ ns->proto = PROTO_IPSEC_AH;
+ ns++;
+ }
+ if (st->st_esp.present)
+ {
+ ns->spi = st->st_esp.our_spi;
+ ns->dst = st->st_connection->this.host_addr;
+ ns->proto = PROTO_IPSEC_ESP;
+ ns++;
+ }
+
+ passert(ns != said); /* there must be some SAs to delete */
+ }
+ else if (IS_ISAKMP_SA_ESTABLISHED(st->st_state)) {
+ p1st = st;
+ isakmp_sa = TRUE;
}
-
- msgid = generate_msgid(p1st);
-
- if (p2st->st_ah.present)
- {
- ns->spi = p2st->st_ah.attrs.spi;
- ns->dst = p2st->st_connection->this.host_addr;
- ns->proto = PROTO_IPSEC_AH;
- ns++;
- }
- if (p2st->st_esp.present)
- {
- ns->spi = p2st->st_esp.attrs.spi;
- ns->dst = p2st->st_connection->this.host_addr;
- ns->proto = PROTO_IPSEC_ESP;
- ns++;
- }
- /* I doubt that it makes sense to delete an IPCOMP with a well-known CPI.
- * Maybe it never makes sense to delete a CPI.
- */
-#if 0
- if (p2st->st_ipcomp.present)
- {
- ns->spi = p2st->st_ipcomp.attrs.spi;
- ns->dst = p2st->st_connection->this.host_addr;
- ns->proto = PROTO_IPCOMP;
- ns++;
+ else {
+ return; /* nothing to do */
}
-#endif
- /* IPIP isn't a real SA, so we don't mention it */
- passert(ns != said); /* there must be some SAs to delete */
+ msgid = generate_msgid(p1st);
zero(buffer);
init_pbs(&reply_pbs, buffer, sizeof(buffer), "delete msg");
@@ -447,7 +561,27 @@
}
/* Delete Payloads */
- while (ns != said) {
+ if (isakmp_sa) {
+ pb_stream del_pbs;
+ struct isakmp_delete isad;
+ u_char isakmp_spi[2*COOKIE_SIZE];
+
+ isad.isad_doi = ISAKMP_DOI_IPSEC;
+ isad.isad_np = ISAKMP_NEXT_NONE;
+ isad.isad_spisize = (2 * COOKIE_SIZE);
+ isad.isad_protoid = PROTO_ISAKMP;
+ isad.isad_nospi = 1;
+
+ memcpy(isakmp_spi, st->st_icookie, COOKIE_SIZE);
+ memcpy(isakmp_spi+COOKIE_SIZE, st->st_rcookie, COOKIE_SIZE);
+
+ if (!out_struct(&isad, &isakmp_delete_desc, &r_hdr_pbs, &del_pbs)
+ || !out_raw(&isakmp_spi, (2*COOKIE_SIZE), &del_pbs, "delete payload"))
+ impossible();
+ close_output_pbs(&del_pbs);
+ }
+ else while (ns != said) {
+
pb_stream del_pbs;
struct isakmp_delete isad;
@@ -504,6 +638,132 @@
}
}
+void
+accept_delete(struct state *st, struct msg_digest *md, struct payload_digest *p)
+{
+ struct isakmp_delete *d = &(p->payload.delete);
+ size_t sizespi = 0;
+ u_char *spi;
+ struct state *dst = NULL;
+ int i;
+
+ if ((!st) && (!(md->hdr.isa_flags & ISAKMP_FLAG_ENCRYPTION))) {
+ loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: not encrypted");
+ return;
+ }
+
+ if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) {
+ /* can't happen (if msg is encrypt), but just to be sure */
+ loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: "
+ "ISAKMP SA not established");
+ return;
+ }
+
+ if (d->isad_nospi == 0) {
+ loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: no SPI");
+ return;
+ }
+
+ if (pbs_left(&p->pbs) != ((unsigned)d->isad_spisize * d->isad_nospi)) {
+ loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: invalid size");
+ return;
+ }
+
+ switch (d->isad_protoid) {
+ case PROTO_ISAKMP:
+ sizespi = (2*COOKIE_SIZE);
+ break;
+ case PROTO_IPSEC_AH:
+ case PROTO_IPSEC_ESP:
+ sizespi = sizeof(ipsec_spi_t);
+ break;
+ default:
+ loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: "
+ "unknown Protocol ID (%s)",
+ enum_show(&protocol_names, d->isad_protoid));
+ return;
+ break;
+ }
+
+ if (d->isad_spisize != sizespi) {
+ loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: "
+ "bad size (%d) for Protocol (%s)",
+ d->isad_spisize,
+ enum_show(&protocol_names, d->isad_protoid));
+ return;
+ }
+
+ for (i=0; i<d->isad_nospi; i++) {
+ spi = p->pbs.cur + (i * sizespi);
+ if (d->isad_protoid == PROTO_ISAKMP) {
+ /**
+ * ISAKMP
+ */
+ dst = find_phase1_state_to_delete(st, spi /*iCookie*/,
+ spi+COOKIE_SIZE /*rCookie*/);
+ if (dst) {
+ loglog(RC_LOG_SERIOUS, "received Delete SA payload: "
+ "deleting ISAKMP State #%lu", dst->st_serialno);
+ delete_state(dst);
+ }
+ else {
+ loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: "
+ "ISAKMP SA not found (maybe expired)");
+ }
+ }
+ else {
+ /**
+ * IPSEC (ESP/AH)
+ */
+ bool bogus;
+ ipsec_spi_t ipsec_spi = *((ipsec_spi_t *)spi);
+
+ dst = find_phase2_state_to_delete(st, d->isad_protoid, ipsec_spi, &bogus);
+ if (dst) {
+ struct connection *rc = dst->st_connection;
+ if ((rc) && (rc->newest_ipsec_sa == dst->st_serialno) &&
+ (rc->initiated)) {
+ /*
+ * Last IPSec SA for a permanent connection that we
+ * have initiated. Replace it in a few seconds.
+ *
+ * Usefull if the other peer is rebooting
+ */
+#define DELETE_SA_DELAY EVENT_RETRANSMIT_DELAY_0
+ if ((dst->st_event) &&
+ (dst->st_event->ev_type == EVENT_SA_REPLACE) &&
+ (dst->st_event->ev_time <= DELETE_SA_DELAY + now())) {
+ /*
+ * Patch from Angus Lees to ignore retransmited Delete SA.
+ */
+ loglog(RC_LOG_SERIOUS, "received Delete SA payload: "
+ "already replacing IPSEC State #%lu in %d seconds",
+ dst->st_serialno, (int)(dst->st_event->ev_time - now()));
+ }
+ else {
+ loglog(RC_LOG_SERIOUS, "received Delete SA payload: "
+ "replace IPSEC State #%lu in %d seconds",
+ dst->st_serialno, DELETE_SA_DELAY);
+ dst->st_margin = DELETE_SA_DELAY;
+ delete_event(dst);
+ event_schedule(EVENT_SA_REPLACE, DELETE_SA_DELAY, dst);
+ }
+ }
+ else {
+ loglog(RC_LOG_SERIOUS, "received Delete SA payload: "
+ "deleting IPSEC State #%lu", dst->st_serialno);
+ delete_state(dst);
+ }
+ }
+ else {
+ loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: "
+ "IPSEC SA not found (%s)",
+ bogus ? "our spi - bogus implementation" : "maybe expired");
+ }
+ }
+ }
+}
+
/* The whole message must be a multiple of 4 octets.
* I'm not sure where this is spelled out, but look at
* rfc2408 3.6 Transform Payload.
@@ -1355,7 +1615,6 @@
if (s.best_ugh[0] == '9')
{
loglog(RC_LOG_SERIOUS, "%s", s.best_ugh + 1);
- /* XXX Could send notification back */
return STF_FAIL + INVALID_HASH_INFORMATION;
}
else
@@ -1402,7 +1661,6 @@
{ \
DBG_cond_dump(DBG_CRYPT, "received " hash_name ":", hash_pbs->cur, pbs_left(hash_pbs)); \
loglog(RC_LOG_SERIOUS, "received " hash_name " does not match computed value in " msg_name); \
- /* XXX Could send notification back */ \
return STF_FAIL + INVALID_HASH_INFORMATION; \
} \
}
@@ -1805,7 +2063,6 @@
{
loglog(RC_LOG_SERIOUS, "improper %s identification payload: %s"
, enum_show(&ident_names, peer.kind), ugh);
- /* XXX Could send notification back */
return FALSE;
}
}
@@ -1832,7 +2089,6 @@
break;
default:
- /* XXX Could send notification back */
loglog(RC_LOG_SERIOUS, "Unacceptable identity type (%s) in Phase 1 ID Payload"
, enum_show(&ident_names, peer.kind));
return FALSE;
@@ -1937,7 +2193,6 @@
/* XXX support more */
loglog(RC_LOG_SERIOUS, "unsupported ID type %s"
, idtypename);
- /* XXX Could send notification back */
return FALSE;
}
@@ -1973,7 +2228,6 @@
{
loglog(RC_LOG_SERIOUS, "%s ID payload %s has wrong length in Quick I1 (%s)"
, which, idtypename, ugh);
- /* XXX Could send notification back */
return FALSE;
}
happy(initsubnet(&temp_address, afi->mask_cnt, '0', net));
@@ -1997,7 +2251,6 @@
{
loglog(RC_LOG_SERIOUS, "%s ID payload %s wrong length in Quick I1"
, which, idtypename);
- /* XXX Could send notification back */
return FALSE;
}
ugh = initaddr(id_pbs->cur
@@ -2012,7 +2265,6 @@
{
loglog(RC_LOG_SERIOUS, "%s ID payload %s bad subnet in Quick I1 (%s)"
, which, idtypename, ugh);
- /* XXX Could send notification back */
return FALSE;
}
DBG(DBG_PARSING | DBG_CONTROL,
@@ -2035,7 +2287,6 @@
{
loglog(RC_LOG_SERIOUS, "%s ID payload %s wrong length in Quick I1"
, which, idtypename);
- /* XXX Could send notification back */
return FALSE;
}
ugh = initaddr(id_pbs->cur, afi->ia_sz, afi->af, &temp_address_from);
@@ -2046,7 +2297,6 @@
{
loglog(RC_LOG_SERIOUS, "%s ID payload %s malformed (%s) in Quick I1"
, which, idtypename, ugh);
- /* XXX Could send notification back */
return FALSE;
}
@@ -2711,7 +2961,6 @@
DBG_cond_dump(DBG_CRYPT, "received HASH:"
, hash_pbs->cur, pbs_left(hash_pbs));
loglog(RC_LOG_SERIOUS, "received Hash Payload does not match computed value");
- /* XXX Could send notification back */
r = STF_FAIL + INVALID_HASH_INFORMATION;
}
}
Index: programs/pluto/ipsec_doi.h
===================================================================
RCS file: /freeswan/MASTER/freeswan/programs/pluto/ipsec_doi.h,v
retrieving revision 1.29
diff -u -r1.29 ipsec_doi.h
--- programs/pluto/ipsec_doi.h 28 Jul 2002 03:56:25 -0000 1.29
+++ programs/pluto/ipsec_doi.h 1 Feb 2003 01:29:32 -0000
@@ -41,6 +41,13 @@
quick_inR1_outI2,
quick_inI2;
-extern void send_ipsec_delete(struct state *p2st);
+extern void send_delete(struct state *st);
+extern void accept_delete(struct state *st, struct msg_digest *md,
+ struct payload_digest *p);
+
+extern void send_notification_from_state(struct state *st,
+ enum state_kind state, u_int16_t type);
+extern void send_notification_from_md(struct msg_digest *md, u_int16_t type);
+
extern const char *init_pluto_vendorid(void);
Index: programs/pluto/spdb.c
===================================================================
RCS file: /freeswan/MASTER/freeswan/programs/pluto/spdb.c,v
retrieving revision 1.80
diff -u -r1.80 spdb.c
--- programs/pluto/spdb.c 9 Nov 2002 22:48:10 -0000 1.80
+++ programs/pluto/spdb.c 1 Feb 2003 01:29:33 -0000
@@ -679,7 +679,6 @@
if (sa->isasa_doi != ISAKMP_DOI_IPSEC)
{
loglog(RC_LOG_SERIOUS, "Unknown/unsupported DOI %s", enum_show(&doi_names, sa->isasa_doi));
- /* XXX Could send notification back */
return DOI_NOT_SUPPORTED;
}
@@ -693,7 +692,6 @@
{
loglog(RC_LOG_SERIOUS, "unsupported IPsec DOI situation (%s)"
, bitnamesof(sit_bit_names, ipsecdoisit));
- /* XXX Could send notification back */
return SITUATION_NOT_SUPPORTED;
}
@@ -1485,7 +1483,6 @@
if (sa->isasa_doi != ISAKMP_DOI_IPSEC)
{
loglog(RC_LOG_SERIOUS, "Unknown or unsupported DOI %s", enum_show(&doi_names, sa->isasa_doi));
- /* XXX Could send notification back */
return DOI_NOT_SUPPORTED;
}
@@ -1497,7 +1494,6 @@
{
loglog(RC_LOG_SERIOUS, "unsupported IPsec DOI situation (%s)"
, bitnamesof(sit_bit_names, ipsecdoisit));
- /* XXX Could send notification back */
return SITUATION_NOT_SUPPORTED;
}
Index: programs/pluto/state.c
===================================================================
RCS file: /freeswan/MASTER/freeswan/programs/pluto/state.c,v
retrieving revision 1.102
diff -u -r1.102 state.c
--- programs/pluto/state.c 9 Nov 2002 23:19:02 -0000 1.102
+++ programs/pluto/state.c 1 Feb 2003 01:29:33 -0000
@@ -293,8 +293,9 @@
}
/* tell the other side of any IPSEC SAs that are going down */
- if (IS_IPSEC_SA_ESTABLISHED(st->st_state))
- send_ipsec_delete(st);
+ if (IS_IPSEC_SA_ESTABLISHED(st->st_state) ||
+ IS_ISAKMP_SA_ESTABLISHED(st->st_state))
+ send_delete(st);
delete_event(st); /* delete any pending timer event */
@@ -531,6 +532,55 @@
&& memcmp(st->st_tpacket.ptr, packet, packet_len) == 0)
return st;
+ return NULL;
+}
+
+struct state *
+find_phase2_state_to_delete(const struct state *p1st, u_int8_t protoid,
+ ipsec_spi_t spi, bool *bogus)
+{
+ struct state *st;
+ int i;
+
+ if (bogus) *bogus = FALSE;
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ for (st = statetable[i]; st != NULL; st = st->st_hashchain_next)
+ 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)))
+ {
+ if ((protoid == PROTO_IPSEC_ESP) && (st->st_esp.present)
+ &&(st->st_esp.attrs.spi == spi))
+ return st;
+ else if ((protoid == PROTO_IPSEC_AH) && (st->st_ah.present)
+ && (st->st_ah.attrs.spi == spi))
+ return st;
+ else if ((protoid == PROTO_IPSEC_ESP) && (st->st_esp.present)
+ && (st->st_esp.our_spi == spi) && (bogus))
+ *bogus = TRUE;
+ else if ((protoid == PROTO_IPSEC_AH) && (st->st_ah.present)
+ && (st->st_ah.our_spi == spi) && (bogus))
+ *bogus = TRUE;
+ }
+ return NULL;
+}
+
+struct state *
+find_phase1_state_to_delete(const struct state *p1st,
+ const u_char *icookie, const u_char *rcookie)
+{
+ struct state *st;
+ int i;
+
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ for (st = statetable[i]; st != NULL; st = st->st_hashchain_next)
+ if ( (IS_ISAKMP_SA_ESTABLISHED(st->st_state))
+ && (memcmp(icookie, st->st_icookie, COOKIE_SIZE) == 0)
+ && (memcmp(rcookie, st->st_rcookie, COOKIE_SIZE) == 0)
+ && (p1st->st_connection->host_pair == st->st_connection->host_pair)
+ && (same_peer_ids(p1st->st_connection, st->st_connection, NULL)) ) {
+ return st;
+ }
return NULL;
}
Index: programs/pluto/state.h
===================================================================
RCS file: /freeswan/MASTER/freeswan/programs/pluto/state.h,v
retrieving revision 1.61
diff -u -r1.61 state.h
--- programs/pluto/state.h 9 Nov 2002 23:19:02 -0000 1.61
+++ programs/pluto/state.h 1 Feb 2003 01:29:33 -0000
@@ -224,6 +224,11 @@
const ip_address *peer,
msgid_t msgid),
*state_with_serialno(so_serial_t sn),
+ *find_phase2_state_to_delete(const struct state *p1st, u_int8_t protoid,
+ ipsec_spi_t spi, bool *bogus),
+ *find_phase1_state_to_delete(const struct state *p1st,
+ const u_char *icookie, const u_char *rcookie),
+
*find_phase1_state(const struct connection *c, lset_t ok_states),
*find_sender(size_t packet_len, u_char *packet);