From 80318cb73f9fe1670dff6eb1801ec47bbf0ff285 Mon Sep 17 00:00:00 2001 From: Apple Date: Thu, 17 Jun 2010 16:16:37 +0000 Subject: [PATCH] ipsec-93.8.tar.gz --- ipsec-tools/racoon/handler.c | 15 ++- ipsec-tools/racoon/ike_session.c | 198 +++++++++++++++++++++++++++++- ipsec-tools/racoon/ike_session.h | 4 + ipsec-tools/racoon/isakmp.c | 4 + ipsec-tools/racoon/isakmp_agg.c | 5 +- ipsec-tools/racoon/isakmp_base.c | 8 +- ipsec-tools/racoon/isakmp_ident.c | 8 +- ipsec-tools/racoon/isakmp_inf.c | 2 +- ipsec-tools/racoon/isakmp_quick.c | 36 ++++-- ipsec-tools/racoon/nattraversal.c | 10 +- ipsec-tools/racoon/pfkey_racoon.c | 18 ++- ipsec-tools/racoon/proposal.c | 149 ++++++++++++++++++---- ipsec-tools/racoon/proposal.h | 1 + 13 files changed, 415 insertions(+), 43 deletions(-) diff --git a/ipsec-tools/racoon/handler.c b/ipsec-tools/racoon/handler.c index 9dc7f92..3eb3a0b 100644 --- a/ipsec-tools/racoon/handler.c +++ b/ipsec-tools/racoon/handler.c @@ -780,7 +780,9 @@ flushph2(int ignore_established_handles) for (p = LIST_FIRST(&ph2tree); p; p = next) { next = LIST_NEXT(p, chain); - + if (p->is_dying || p->status == PHASE2ST_EXPIRED) { + continue; + } if (p->status == PHASE2ST_ESTABLISHED){ if (ignore_established_handles) { plog(LLV_DEBUG2, LOCATION, NULL, @@ -820,6 +822,9 @@ deleteallph2(src, dst, proto_id) for (iph2 = LIST_FIRST(&ph2tree); iph2 != NULL; iph2 = next) { next = LIST_NEXT(iph2, chain); + if (iph2->is_dying || iph2->status == PHASE2ST_EXPIRED) { + continue; + } if (iph2->proposal == NULL && iph2->approval == NULL) continue; if (cmpsaddrwop(src, iph2->src) != 0 || @@ -1325,12 +1330,15 @@ purgephXbyspid(u_int32_t spid, // do ph2's first... we need the ph1s for notifications LIST_FOREACH(iph2, &ph2tree, chain) { if (spid == iph2->spid) { + if (iph2->is_dying || iph2->status == PHASE2ST_EXPIRED) { + continue; + } if (iph2->status == PHASE2ST_ESTABLISHED) { isakmp_info_send_d2(iph2); } - isakmp_ph2expire(iph2); // iph2 will go down 1 second later. ike_session_stopped_by_controller(iph2->parent_session, ike_session_stopped_by_flush); + isakmp_ph2expire(iph2); // iph2 will go down 1 second later. } } @@ -1339,6 +1347,9 @@ purgephXbyspid(u_int32_t spid, if (spid == iph2->spid) { if (del_boundph1 && iph2->parent_session) { for (iph1 = LIST_FIRST(&iph2->parent_session->ikev1_state.ph1tree); iph1; iph1 = LIST_NEXT(iph1, ph1ofsession_chain)) { + if (iph1->is_dying || iph1->status == PHASE1ST_EXPIRED) { + continue; + } if (iph1->status == PHASE1ST_ESTABLISHED) { isakmp_info_send_d1(iph1); } diff --git a/ipsec-tools/racoon/ike_session.c b/ipsec-tools/racoon/ike_session.c index ffc1516..97e5be7 100644 --- a/ipsec-tools/racoon/ike_session.c +++ b/ipsec-tools/racoon/ike_session.c @@ -904,7 +904,7 @@ ike_session_cleanup_other_established_ph1s (ike_session_t *session, * TODO: currently, most recently established SA wins. Need to revisit to see if * alternative selections is better (e.g. largest p->index stays). */ - if (p != new_iph1) { + if (p != new_iph1 && !p->is_dying) { SCHED_KILL(p->sce); SCHED_KILL(p->sce_rekey); p->is_dying = 1; @@ -943,6 +943,10 @@ ike_session_cleanup_ph2 (struct ph2handle *iph2) SCHED_KILL(iph2->sce); + plog(LLV_ERROR, LOCATION, NULL, + "about to cleanup ph2: status %d, seq %d dying %d\n", + iph2->status, iph2->seq, iph2->is_dying); + /* send delete information */ if (iph2->status == PHASE2ST_ESTABLISHED) { isakmp_info_send_d2(iph2); @@ -993,7 +997,7 @@ ike_session_cleanup_other_established_ph2s (ike_session_t *session, * TODO: currently, most recently established SA wins. Need to revisit to see if * alternative selections is better. */ - if (p != new_iph2 && p->spid == new_iph2->spid) { + if (p != new_iph2 && p->spid == new_iph2->spid && !p->is_dying) { SCHED_KILL(p->sce); p->is_dying = 1; @@ -1067,6 +1071,9 @@ ike_session_purge_ph2s_by_ph1 (struct ph1handle *iph1) for (p = LIST_FIRST(&iph1->parent_session->ikev1_state.ph2tree); p; p = next) { // take next pointer now, since delete change the underlying ph2tree list next = LIST_NEXT(p, ph2ofsession_chain); + if (p->is_dying) { + continue; + } SCHED_KILL(p->sce); p->is_dying = 1; @@ -1401,6 +1408,47 @@ ike_session_is_id_ipany (vchar_t *ext_id) return 0; } +static int +ike_session_is_id_portany (vchar_t *ext_id) +{ + struct id { + u_int8_t type; /* ID Type */ + u_int8_t proto_id; /* Protocol ID */ + u_int16_t port; /* Port */ + u_int32_t addr; /* IPv4 address */ + u_int32_t mask; + } *id_ptr; + + /* ignore addr */ + id_ptr = (struct id *)ext_id->v; + if (id_ptr->type == IPSECDOI_ID_IPV4_ADDR && + id_ptr->port == 0) { + return 1; + } + plog(LLV_DEBUG2, LOCATION, NULL, "not portany_ids in %s: type %d, port %x.\n", + __FUNCTION__, id_ptr->type, id_ptr->port); + return 0; +} + +static void +ike_session_set_id_portany (vchar_t *ext_id) +{ + struct id { + u_int8_t type; /* ID Type */ + u_int8_t proto_id; /* Protocol ID */ + u_int16_t port; /* Port */ + u_int32_t addr; /* IPv4 address */ + u_int32_t mask; + } *id_ptr; + + /* ignore addr */ + id_ptr = (struct id *)ext_id->v; + if (id_ptr->type == IPSECDOI_ID_IPV4_ADDR) { + id_ptr->port = 0; + return; + } +} + static int ike_session_cmp_ph2_ids_ipany (vchar_t *ext_id, vchar_t *ext_id_p) @@ -1412,10 +1460,19 @@ ike_session_cmp_ph2_ids_ipany (vchar_t *ext_id, return 0; } -static int +/* + * ipsec rekeys for l2tp-over-ipsec fail particularly when client is behind nat because the client's configs and policies don't + * match the server's view of the client's address and port. + * servers behave differently when using this address-port info to generate ids during phase2 rekeys, so try to match the incoming id to + * a variety of info saved in the older phase2. + */ +int ike_session_cmp_ph2_ids (struct ph2handle *iph2, struct ph2handle *older_ph2) { + vchar_t *portany_id = NULL; + vchar_t *portany_id_p = NULL; + if (iph2->id && older_ph2->id && iph2->id->l == older_ph2->id->l && memcmp(iph2->id->v, older_ph2->id->v, iph2->id->l) == 0 && @@ -1440,6 +1497,82 @@ ike_session_cmp_ph2_ids (struct ph2handle *iph2, memcmp(iph2->id_p->v, older_ph2->ext_nat_id_p->v, iph2->id_p->l) == 0) { return 0; } + if (iph2->id && older_ph2->ext_nat_id && + iph2->id->l == older_ph2->ext_nat_id->l && + memcmp(iph2->id->v, older_ph2->ext_nat_id->v, iph2->id->l) == 0 && + iph2->id_p && older_ph2->id_p && + iph2->id_p->l == older_ph2->id_p->l && + memcmp(iph2->id_p->v, older_ph2->id_p->v, iph2->id_p->l) == 0) { + return 0; + } + if (iph2->id && older_ph2->id && + iph2->id->l == older_ph2->id->l && + memcmp(iph2->id->v, older_ph2->id->v, iph2->id->l) == 0 && + iph2->id_p && older_ph2->ext_nat_id_p && + iph2->id_p->l == older_ph2->ext_nat_id_p->l && + memcmp(iph2->id_p->v, older_ph2->ext_nat_id_p->v, iph2->id_p->l) == 0) { + return 0; + } + + /* check if the external id has a wildcard port and compare ids accordingly */ + if ((older_ph2->ext_nat_id && ike_session_is_id_portany(older_ph2->ext_nat_id)) || + (older_ph2->ext_nat_id_p && ike_session_is_id_portany(older_ph2->ext_nat_id_p))) { + // try ignoring ports in iph2->id and iph2->id + if (iph2->id && (portany_id = vdup(iph2->id))) { + ike_session_set_id_portany(portany_id); + } + if (iph2->id_p && (portany_id_p = vdup(iph2->id_p))) { + ike_session_set_id_portany(portany_id_p); + } + if (portany_id && older_ph2->ext_nat_id && + portany_id->l == older_ph2->ext_nat_id->l && + memcmp(portany_id->v, older_ph2->ext_nat_id->v, portany_id->l) == 0 && + portany_id_p && older_ph2->ext_nat_id_p && + portany_id_p->l == older_ph2->ext_nat_id_p->l && + memcmp(portany_id_p->v, older_ph2->ext_nat_id_p->v, portany_id_p->l) == 0) { + if (portany_id) { + vfree(portany_id); + } + if (portany_id_p) { + vfree(portany_id_p); + } + return 0; + } + if (iph2->id && older_ph2->ext_nat_id && + iph2->id->l == older_ph2->ext_nat_id->l && + memcmp(portany_id->v, older_ph2->ext_nat_id->v, portany_id->l) == 0 && + iph2->id_p && older_ph2->id_p && + iph2->id_p->l == older_ph2->id_p->l && + memcmp(iph2->id_p->v, older_ph2->id_p->v, iph2->id_p->l) == 0) { + if (portany_id) { + vfree(portany_id); + } + if (portany_id_p) { + vfree(portany_id_p); + } + return 0; + } + if (iph2->id && older_ph2->id && + iph2->id->l == older_ph2->id->l && + memcmp(iph2->id->v, older_ph2->id->v, iph2->id->l) == 0 && + iph2->id_p && older_ph2->ext_nat_id_p && + iph2->id_p->l == older_ph2->ext_nat_id_p->l && + memcmp(portany_id_p->v, older_ph2->ext_nat_id_p->v, portany_id_p->l) == 0) { + if (portany_id) { + vfree(portany_id); + } + if (portany_id_p) { + vfree(portany_id_p); + } + return 0; + } + if (portany_id) { + vfree(portany_id); + } + if (portany_id_p) { + vfree(portany_id_p); + } + } return -1; } @@ -1461,6 +1594,18 @@ ike_session_get_sainfo_r (struct ph2handle *iph2) ike_session_cmp_ph2_ids(iph2, p) == 0) { plog(LLV_DEBUG2, LOCATION, NULL, "candidate ph2 matched in %s.\n", __FUNCTION__); iph2->sainfo = p->sainfo; + if (p->ext_nat_id) { + if (iph2->ext_nat_id) { + vfree(iph2->ext_nat_id); + } + iph2->ext_nat_id = vdup(p->ext_nat_id); + } + if (p->ext_nat_id_p) { + if (iph2->ext_nat_id_p) { + vfree(iph2->ext_nat_id_p); + } + iph2->ext_nat_id_p = vdup(p->ext_nat_id_p); + } return 0; } } @@ -1469,6 +1614,53 @@ ike_session_get_sainfo_r (struct ph2handle *iph2) return -1; } +int +ike_session_get_proposal_r (struct ph2handle *iph2) +{ + if (iph2->parent_session && + iph2->parent_session->is_client && + iph2->id && iph2->id_p) { + struct ph2handle *p; + int ipany_ids = ike_session_cmp_ph2_ids_ipany(iph2->id, iph2->id_p); + plog(LLV_DEBUG2, LOCATION, NULL, "ipany_ids %d in %s.\n", ipany_ids, __FUNCTION__); + + for (p = LIST_FIRST(&iph2->parent_session->ikev1_state.ph2tree); p; p = LIST_NEXT(p, ph2ofsession_chain)) { + if (iph2 != p && !p->is_dying && p->status >= PHASE2ST_ESTABLISHED && + p->approval) { + plog(LLV_DEBUG2, LOCATION, NULL, "candidate ph2 found in %s.\n", __FUNCTION__); + if (ipany_ids || + ike_session_cmp_ph2_ids(iph2, p) == 0) { + plog(LLV_DEBUG2, LOCATION, NULL, "candidate ph2 matched in %s.\n", __FUNCTION__); + iph2->proposal = dupsaprop(p->approval, 1); + return 0; + } + } + } + } + return -1; +} + +void +ike_session_update_natt_version (struct ph1handle *iph1) +{ + if (iph1->parent_session) { + if (iph1->natt_options) { + iph1->parent_session->natt_version = iph1->natt_options->version; + } else { + iph1->parent_session->natt_version = 0; + } + } +} + +int +ike_session_get_natt_version (struct ph1handle *iph1) +{ + if (iph1->parent_session) { + return(iph1->parent_session->natt_version); + } + return 0; +} + int ike_session_drop_rekey (ike_session_t *session) { diff --git a/ipsec-tools/racoon/ike_session.h b/ipsec-tools/racoon/ike_session.h index 4d4854c..bc018d6 100644 --- a/ipsec-tools/racoon/ike_session.h +++ b/ipsec-tools/racoon/ike_session.h @@ -98,6 +98,7 @@ struct ike_session { int is_client:1; time_t last_time_data_sc_detected; u_int32_t natt_flags; + u_int32_t natt_version; char *term_reason; struct timeval start_timestamp; @@ -153,6 +154,9 @@ extern int ike_session_is_client_ph1_rekey __P((struct ph1handle extern void ike_session_start_xauth_timer __P((struct ph1handle *)); extern void ike_session_stop_xauth_timer __P((struct ph1handle *)); extern int ike_session_get_sainfo_r __P((struct ph2handle *)); +extern int ike_session_get_proposal_r __P((struct ph2handle *)); +extern void ike_session_update_natt_version __P((struct ph1handle *)); +extern int ike_session_get_natt_version __P((struct ph1handle *)); extern int ike_session_drop_rekey __P((ike_session_t *)); extern void ike_session_ph2_retransmits __P((struct ph2handle *)); diff --git a/ipsec-tools/racoon/isakmp.c b/ipsec-tools/racoon/isakmp.c index f499850..050ca42 100644 --- a/ipsec-tools/racoon/isakmp.c +++ b/ipsec-tools/racoon/isakmp.c @@ -2618,6 +2618,10 @@ isakmp_ph2expire(iph2) { char *src, *dst; + if (iph2->status == PHASE2ST_EXPIRED) { + return; + } + SCHED_KILL(iph2->sce); src = racoon_strdup(saddrwop2str(iph2->src)); diff --git a/ipsec-tools/racoon/isakmp_agg.c b/ipsec-tools/racoon/isakmp_agg.c index 7dddea3..d2c59b7 100644 --- a/ipsec-tools/racoon/isakmp_agg.c +++ b/ipsec-tools/racoon/isakmp_agg.c @@ -631,6 +631,7 @@ agg_i2recv(iph1, msg) if (iph1->natt_flags & NAT_DETECTED) natt_float_ports (iph1); + ike_session_update_natt_version(iph1); } #endif @@ -1106,10 +1107,12 @@ agg_r1recv(iph1, msg) } #ifdef ENABLE_NATT - if (NATT_AVAILABLE(iph1)) + if (NATT_AVAILABLE(iph1)) { plog(LLV_INFO, LOCATION, iph1->remote, "Selected NAT-T version: %s\n", vid_string_by_id(iph1->natt_options->version)); + ike_session_update_natt_version(iph1); + } #endif /* check SA payload and set approval SA for use */ diff --git a/ipsec-tools/racoon/isakmp_base.c b/ipsec-tools/racoon/isakmp_base.c index 3ac9e7c..5a26c50 100644 --- a/ipsec-tools/racoon/isakmp_base.c +++ b/ipsec-tools/racoon/isakmp_base.c @@ -397,10 +397,12 @@ base_i2recv(iph1, msg) } #ifdef ENABLE_NATT - if (NATT_AVAILABLE(iph1)) + if (NATT_AVAILABLE(iph1)) { plog(LLV_INFO, LOCATION, iph1->remote, "Selected NAT-T version: %s\n", vid_string_by_id(iph1->natt_options->version)); + ike_session_update_natt_version(iph1); + } #endif /* check SA payload and set approval SA for use */ @@ -938,10 +940,12 @@ base_r1recv(iph1, msg) } #ifdef ENABLE_NATT - if (NATT_AVAILABLE(iph1)) + if (NATT_AVAILABLE(iph1)) { plog(LLV_INFO, LOCATION, iph1->remote, "Selected NAT-T version: %s\n", vid_string_by_id(iph1->natt_options->version)); + ike_session_update_natt_version(iph1); + } #endif /* check SA payload and set approval SA for use */ diff --git a/ipsec-tools/racoon/isakmp_ident.c b/ipsec-tools/racoon/isakmp_ident.c index 6488207..ff155e6 100644 --- a/ipsec-tools/racoon/isakmp_ident.c +++ b/ipsec-tools/racoon/isakmp_ident.c @@ -364,10 +364,12 @@ ident_i2recv(iph1, msg) } #ifdef ENABLE_NATT - if (NATT_AVAILABLE(iph1)) + if (NATT_AVAILABLE(iph1)) { plog(LLV_INFO, LOCATION, iph1->remote, "Selected NAT-T version: %s\n", vid_string_by_id(iph1->natt_options->version)); + ike_session_update_natt_version(iph1); + } #endif /* check SA payload and set approval SA for use */ @@ -1190,10 +1192,12 @@ ident_r1recv(iph1, msg) } #ifdef ENABLE_NATT - if (NATT_AVAILABLE(iph1)) + if (NATT_AVAILABLE(iph1)) { plog(LLV_INFO, LOCATION, iph1->remote, "Selected NAT-T version: %s\n", vid_string_by_id(iph1->natt_options->version)); + ike_session_update_natt_version(iph1); + } #endif /* check SA payload and set approval SA for use */ diff --git a/ipsec-tools/racoon/isakmp_inf.c b/ipsec-tools/racoon/isakmp_inf.c index 44fa30f..003e3ce 100644 --- a/ipsec-tools/racoon/isakmp_inf.c +++ b/ipsec-tools/racoon/isakmp_inf.c @@ -1447,7 +1447,7 @@ purge_isakmp_spi(proto, spi, n) for (i = 0; i < n; i++) { iph1 = getph1byindex(&spi[i]); - if (!iph1) + if (!iph1 || iph1->is_dying || iph1->status == PHASE1ST_EXPIRED) continue; plog(LLV_INFO, LOCATION, NULL, diff --git a/ipsec-tools/racoon/isakmp_quick.c b/ipsec-tools/racoon/isakmp_quick.c index 44f8fed..2b73f65 100644 --- a/ipsec-tools/racoon/isakmp_quick.c +++ b/ipsec-tools/racoon/isakmp_quick.c @@ -97,7 +97,8 @@ /* quick mode */ static vchar_t *quick_ir1mx __P((struct ph2handle *, vchar_t *, vchar_t *)); static int get_sainfo_r __P((struct ph2handle *)); -static int get_proposal_r __P((struct ph2handle *, int)); +static int get_proposal_r __P((struct ph2handle *)); +static int get_proposal_r_remote __P((struct ph2handle *, int)); /* %%% * Quick Mode @@ -568,6 +569,7 @@ quick_i2recv(iph2, msg0) goto end; } plog(LLV_DEBUG, LOCATION, NULL, "external nat address saved.\n"); + plogdump(LLV_DEBUG, iph2->ext_nat_id->v, iph2->ext_nat_id->l); } else if (f_id && (iph2->ph1->natt_flags & NAT_DETECTED_PEER)) { if (iph2->ext_nat_id_p) vfree(iph2->ext_nat_id_p); @@ -578,6 +580,7 @@ quick_i2recv(iph2, msg0) } memcpy(iph2->ext_nat_id_p->v, &(idp_ptr->b), iph2->ext_nat_id_p->l); plog(LLV_DEBUG, LOCATION, NULL, "peer's external nat address saved.\n"); + plogdump(LLV_DEBUG, iph2->ext_nat_id_p->v, iph2->ext_nat_id_p->l); } } else { plog(LLV_ERROR, LOCATION, NULL, "mismatched ID was returned.\n"); @@ -1369,12 +1372,7 @@ quick_r1recv(iph2, msg0) } /* check the existence of ID payload and create responder's proposal */ - error = get_proposal_r(iph2, 0); - if (error != -2 && error != 0 && - (((iph2->ph1->natt_flags & NAT_DETECTED_ME) && lcconf->ext_nat_id != NULL) || - (iph2->parent_session && iph2->parent_session->is_client))) - error = get_proposal_r(iph2, 1); - + error = get_proposal_r(iph2); switch (error) { case -2: /* generate a policy template from peer's proposal */ @@ -1602,6 +1600,8 @@ quick_r2send(iph2, msg) } #endif + plog(LLV_DEBUG, LOCATION, NULL, "Approved SA\n"); + printsaprop0(LLV_DEBUG, iph2->approval); body = vmalloc(tlen); if (body == NULL) { @@ -1634,9 +1634,13 @@ quick_r2send(iph2, msg) if (iph2->id_p != NULL) { /* IDci */ p = set_isakmp_payload(p, iph2->id_p, ISAKMP_NPTYPE_ID); + plog(LLV_DEBUG, LOCATION, NULL, "sending IDci2:\n"); + plogdump(LLV_DEBUG, iph2->id_p->v, iph2->id_p->l); /* IDcr */ np_p = &((struct isakmp_gen *)p)->np; /* XXX */ p = set_isakmp_payload(p, iph2->id, (natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE)); + plog(LLV_DEBUG, LOCATION, NULL, "sending IDcr2:\n"); + plogdump(LLV_DEBUG, iph2->id->v, iph2->id->l); } /* add a RESPONDER-LIFETIME notify payload if needed */ @@ -2369,6 +2373,22 @@ end: return error; } +static int +get_proposal_r(iph2) + struct ph2handle *iph2; +{ + int error = get_proposal_r_remote(iph2, 0); + if (error != -2 && error != 0 && + (((iph2->ph1->natt_flags & NAT_DETECTED_ME) && lcconf->ext_nat_id != NULL) || + (iph2->parent_session && iph2->parent_session->is_client))) { + if (iph2->parent_session && iph2->parent_session->is_client) + error = ike_session_get_proposal_r(iph2); + if (error != -2 && error != 0) + error = get_proposal_r_remote(iph2, 1); + } + return error; +} + /* * Copy both IP addresses in ID payloads into [src,dst]_id if both ID types * are IP address and same address family. @@ -2380,7 +2400,7 @@ end: * NOTE: This function is only for responder. */ static int -get_proposal_r(iph2, use_remote_addr) +get_proposal_r_remote(iph2, use_remote_addr) struct ph2handle *iph2; int use_remote_addr; { diff --git a/ipsec-tools/racoon/nattraversal.c b/ipsec-tools/racoon/nattraversal.c index 3a57fdb..4dfd089 100644 --- a/ipsec-tools/racoon/nattraversal.c +++ b/ipsec-tools/racoon/nattraversal.c @@ -496,6 +496,8 @@ natt_float_ports (struct ph1handle *iph1) void natt_handle_vendorid (struct ph1handle *iph1, int vid_numeric) { + int version; + if (! iph1->natt_options) iph1->natt_options = racoon_calloc (1, sizeof (*iph1->natt_options)); @@ -504,7 +506,13 @@ natt_handle_vendorid (struct ph1handle *iph1, int vid_numeric) "Allocating memory for natt_options failed!\n"); return; } - + + // stick to the version we already selected on a previous phase1 + version = ike_session_get_natt_version(iph1); + if (version) { + vid_numeric = version; + } + if (iph1->natt_options->version < vid_numeric) if (natt_fill_options (iph1->natt_options, vid_numeric) == 0) iph1->natt_flags |= NAT_ANNOUNCED; diff --git a/ipsec-tools/racoon/pfkey_racoon.c b/ipsec-tools/racoon/pfkey_racoon.c index 4ff5db3..ef64f60 100644 --- a/ipsec-tools/racoon/pfkey_racoon.c +++ b/ipsec-tools/racoon/pfkey_racoon.c @@ -998,6 +998,13 @@ pk_recvgetspi(mhp) return -1; } + if (iph2->is_dying) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatch phase2 dying (db:%d msg:%d)\n", + iph2->status, PHASE2ST_GETSPISENT); + return -1; + } + if (iph2->status != PHASE2ST_GETSPISENT) { plog(LLV_ERROR, LOCATION, NULL, "status mismatch (db:%d msg:%d)\n", @@ -1340,6 +1347,13 @@ pk_recvupdate(mhp) return -1; } + if (iph2->is_dying) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatch phase2 dying (db:%d msg:%d)\n", + iph2->status, PHASE2ST_ADDSA); + return -1; + } + if (iph2->status != PHASE2ST_ADDSA) { plog(LLV_ERROR, LOCATION, NULL, "status mismatch (db:%d msg:%d)\n", @@ -1809,7 +1823,7 @@ pk_recvexpire(mhp) sa_mode)); return 0; } - if (iph2->status != PHASE2ST_ESTABLISHED) { + if (iph2->is_dying || iph2->status != PHASE2ST_ESTABLISHED) { /* * If the status is not equal to PHASE2ST_ESTABLISHED, * racoon ignores this expire message. There are two reason. @@ -1820,7 +1834,7 @@ pk_recvexpire(mhp) */ plog(LLV_WARNING, LOCATION, NULL, "the expire message is received " - "but the handler has not been established.\n"); + "but the handler is dying or has not been established.\n"); return 0; } diff --git a/ipsec-tools/racoon/proposal.c b/ipsec-tools/racoon/proposal.c index 7ade887..7a299e0 100644 --- a/ipsec-tools/racoon/proposal.c +++ b/ipsec-tools/racoon/proposal.c @@ -180,6 +180,50 @@ inssatrns(pr, new) return; } +#ifdef ENABLE_NATT +static void +saprop_udp_encap (struct saproto *pr) +{ + switch (pr->encmode) { + case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC: + case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT: + pr->encmode = IPSECDOI_ATTR_ENC_MODE_TUNNEL; + pr->udp_encap = 1; + break; + case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC: + case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT: + pr->encmode = IPSECDOI_ATTR_ENC_MODE_TRNS; + pr->udp_encap = 1; + break; + } +} + +static void +saprop_adjust_encmode (struct saproto *pr2, struct saproto *pr1) +{ + int prev; + + if (natt_udp_encap(pr2->encmode)) { + prev = pr2->encmode; + saprop_udp_encap(pr2); + plog(LLV_INFO, LOCATION, NULL, "Adjusting my encmode %s(%d)->%s(%d)\n", + s_ipsecdoi_encmode(prev), + prev, + s_ipsecdoi_encmode(pr2->encmode), + pr2->encmode); + } + if (natt_udp_encap(pr1->encmode)) { + prev = pr1->encmode; + saprop_udp_encap(pr1); + plog(LLV_INFO, LOCATION, NULL, "Adjusting peer's encmode %s(%d)->%s(%d)\n", + s_ipsecdoi_encmode(prev), + prev, + s_ipsecdoi_encmode(pr1->encmode), + pr1->encmode); + } +} +#endif // ENABLE_NATT + /* * take a single match between saprop. allocate a new proposal and return it * for future use (like picking single proposal from a bundle). @@ -388,27 +432,9 @@ cmpsaprop_alloc(ph1, pp1, pp2, side) goto err; } -#ifdef ENABLE_NATT - if ((ph1->natt_flags & NAT_DETECTED) && - natt_udp_encap (pr2->encmode)) - { - plog(LLV_INFO, LOCATION, NULL, "Adjusting my encmode %s->%s\n", - s_ipsecdoi_encmode(pr2->encmode), - s_ipsecdoi_encmode(pr2->encmode - ph1->natt_options->mode_udp_diff)); - pr2->encmode -= ph1->natt_options->mode_udp_diff; - pr2->udp_encap = 1; - } - - if ((ph1->natt_flags & NAT_DETECTED) && - natt_udp_encap (pr1->encmode)) - { - plog(LLV_INFO, LOCATION, NULL, "Adjusting peer's encmode %s(%d)->%s(%d)\n", - s_ipsecdoi_encmode(pr1->encmode), - pr1->encmode, - s_ipsecdoi_encmode(pr1->encmode - ph1->natt_options->mode_udp_diff), - pr1->encmode - ph1->natt_options->mode_udp_diff); - pr1->encmode -= ph1->natt_options->mode_udp_diff; - pr1->udp_encap = 1; +#ifdef ENABLE_NATT + if (ph1->natt_flags & NAT_DETECTED) { + saprop_adjust_encmode(pr2, pr1); } #endif @@ -1208,3 +1234,84 @@ tunnel_mode_prop(p) return 1; return 0; } + +void +dupsatrns(newpr, head) + struct saproto *newpr; + struct satrns *head; +{ + struct satrns *p, *newtr; + + for (p = head; p != NULL; p = p->next) { + newtr = newsatrns(); + if (newtr) { + newtr->trns_no = p->trns_no; + newtr->trns_id = p->trns_id; + newtr->encklen = p->encklen; + newtr->authtype = p->authtype; + inssatrns(newpr, newtr); + } else { + break; + } + + } + + return; +} + +void +dupsaproto(newpp, head, ignore_spis) + struct saprop *newpp; + struct saproto *head; + int ignore_spis; +{ + struct saproto *p, *newpr; + + for (p = head; p != NULL; p = p->next) { + newpr = newsaproto(); + if (newpr) { + newpr->proto_id = p->proto_id; + newpr->spisize = p->spisize; + newpr->encmode = p->encmode; + newpr->udp_encap = p->udp_encap; + if (!ignore_spis) { + newpr->spi = p->spi; + newpr->spi_p = p->spi_p; + newpr->reqid_in = p->reqid_in; + newpr->reqid_out = p->reqid_out; + } + dupsatrns(newpr, p->head); + inssaproto(newpp, newpr); + } else { + break; + } + + } + + return; +} + +struct saprop * +dupsaprop(head, ignore_spis) + struct saprop *head; + int ignore_spis; +{ + struct saprop *p, *newpp; + + for (p = head, newpp = NULL; p != NULL; p = p->next) { + struct saprop *tmp = newsaprop(); + if (tmp) { + tmp->prop_no = p->prop_no; + tmp->lifetime = p->lifetime; + tmp->lifebyte = p->lifebyte; + tmp->pfs_group = p->pfs_group; + tmp->claim = p->claim; + dupsaproto(tmp, p->head, ignore_spis); + inssaprop(&newpp, tmp); + } else { + break; + } + } + + return newpp; +} diff --git a/ipsec-tools/racoon/proposal.h b/ipsec-tools/racoon/proposal.h index 72df73a..a9cc8da 100644 --- a/ipsec-tools/racoon/proposal.h +++ b/ipsec-tools/racoon/proposal.h @@ -207,5 +207,6 @@ extern int set_proposal_from_policy __P((struct ph2handle *, struct secpolicy *, struct secpolicy *)); extern int set_proposal_from_proposal __P((struct ph2handle *)); extern int tunnel_mode_prop __P((struct saprop *)); +extern struct saprop *dupsaprop __P((struct saprop *, int)); #endif /* _PROPOSAL_H */ -- 2.45.2