From 05434fec7cb5667469bfde135b4d0a93524a9bc0 Mon Sep 17 00:00:00 2001 From: Apple Date: Sat, 7 Jun 2008 03:22:58 +0000 Subject: [PATCH] ipsec-34.0.1.tar.gz --- ipsec-tools/racoon/cfparse.y | 2 +- ipsec-tools/racoon/isakmp_quick.c | 112 +++++++++++++++++++----------- ipsec-tools/racoon/localconf.c | 4 ++ ipsec-tools/racoon/localconf.h | 1 + ipsec-tools/racoon/pfkey_racoon.c | 38 ++++------ ipsec-tools/racoon/sainfo.c | 16 +++-- ipsec-tools/racoon/sainfo.h | 2 +- 7 files changed, 106 insertions(+), 69 deletions(-) diff --git a/ipsec-tools/racoon/cfparse.y b/ipsec-tools/racoon/cfparse.y index d9ac8a4..e19032a 100644 --- a/ipsec-tools/racoon/cfparse.y +++ b/ipsec-tools/racoon/cfparse.y @@ -758,7 +758,7 @@ sainfo_statement /* duplicate check */ check = getsainfo(cur_sainfo->idsrc, cur_sainfo->iddst, - cur_sainfo->id_i); + cur_sainfo->id_i, 0); if (check && (!check->idsrc && !cur_sainfo->idsrc)) { yyerror("duplicated sainfo: %s", sainfo2str(cur_sainfo)); diff --git a/ipsec-tools/racoon/isakmp_quick.c b/ipsec-tools/racoon/isakmp_quick.c index fc3c259..a872904 100644 --- a/ipsec-tools/racoon/isakmp_quick.c +++ b/ipsec-tools/racoon/isakmp_quick.c @@ -88,7 +88,7 @@ /* 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 *)); +static int get_proposal_r __P((struct ph2handle *, int)); /* %%% * Quick Mode @@ -470,43 +470,56 @@ quick_i2recv(iph2, msg0) case ISAKMP_NPTYPE_ID: { - vchar_t *vp; - - /* check ID value */ - if (f_id == 0) { - /* for IDci */ - f_id = 1; - vp = iph2->id; - } else { - /* for IDcr */ - vp = iph2->id_p; - } - - /* These ids may not match when natt is used with some devices. - * RFC 2407 says that the protocol and port fields should be ignored - * if they are zero, therefore they need to be checked individually. - */ - struct ipsecdoi_id_b *id_ptr = (struct ipsecdoi_id_b *)vp->v; - struct ipsecdoi_pl_id *idp_ptr = (struct ipsecdoi_pl_id *)pa->ptr; - - if (id_ptr->type != idp_ptr->b.type - || (idp_ptr->b.proto_id != 0 && idp_ptr->b.proto_id != id_ptr->proto_id) - || (idp_ptr->b.port != 0 && idp_ptr->b.port != id_ptr->port) - || memcmp(vp->v + sizeof(struct ipsecdoi_id_b), (caddr_t)pa->ptr + sizeof(struct ipsecdoi_pl_id), - vp->l - sizeof(struct ipsecdoi_id_b))) { - //%%% BUG_FIX - to support some servers - if (iph2->ph1->natt_flags & NAT_DETECTED) { - plog(LLV_WARNING, LOCATION, NULL, - "mismatched ID was returned - ignored because nat traversal is being used.\n"); - break; + vchar_t *vp; + + /* check ID value */ + if (f_id == 0) { + /* for IDci */ + vp = iph2->id; + } else { + /* for IDcr */ + vp = iph2->id_p; } - plog(LLV_ERROR, LOCATION, NULL, - "mismatched ID was returned.\n"); - error = ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED; - goto end; + + /* These ids may not match when natt is used with some devices. + * RFC 2407 says that the protocol and port fields should be ignored + * if they are zero, therefore they need to be checked individually. + */ + struct ipsecdoi_id_b *id_ptr = (struct ipsecdoi_id_b *)vp->v; + struct ipsecdoi_pl_id *idp_ptr = (struct ipsecdoi_pl_id *)pa->ptr; + + if (id_ptr->type != idp_ptr->b.type + || (idp_ptr->b.proto_id != 0 && idp_ptr->b.proto_id != id_ptr->proto_id) + || (idp_ptr->b.port != 0 && idp_ptr->b.port != id_ptr->port) + || memcmp(vp->v + sizeof(struct ipsecdoi_id_b), (caddr_t)pa->ptr + sizeof(struct ipsecdoi_pl_id), + vp->l - sizeof(struct ipsecdoi_id_b))) { + // to support servers that use our external nat address as our ID + if (iph2->ph1->natt_flags & NAT_DETECTED) { + plog(LLV_WARNING, LOCATION, NULL, + "mismatched ID was returned - ignored because nat traversal is being used.\n"); + /* If I'm behind a nat and the ID is type address - save the address + * and port for when the peer rekeys. + */ + if (f_id == 0 && (iph2->ph1->natt_flags & NAT_DETECTED_ME)) { + if (lcconf->ext_nat_id) + vfree(lcconf->ext_nat_id); + lcconf->ext_nat_id = vmalloc(idp_ptr->h.len - sizeof(struct isakmp_gen)); + if (lcconf->ext_nat_id == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "memory error while allocating external nat id.\n"); + goto end; + } + memcpy(lcconf->ext_nat_id->v, &(idp_ptr->b), lcconf->ext_nat_id->l); + plog(LLV_DEBUG, LOCATION, NULL, "external nat address saved.\n"); + } + } else { + plog(LLV_ERROR, LOCATION, NULL, "mismatched ID was returned.\n"); + error = ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED; + goto end; + } } + if (f_id == 0) + f_id = 1; } - break; case ISAKMP_NPTYPE_N: @@ -1130,7 +1143,10 @@ quick_r1recv(iph2, msg0) } /* check the existence of ID payload and create responder's proposal */ - error = get_proposal_r(iph2); + error = get_proposal_r(iph2, 0); + if (error != -2 && error != 0 && (iph2->ph1->natt_flags & NAT_DETECTED_ME) && lcconf->ext_nat_id != NULL) + error = get_proposal_r(iph2, 1); + switch (error) { case -2: /* generate a policy template from peer's proposal */ @@ -1953,7 +1969,10 @@ get_sainfo_r(iph2) goto end; } - iph2->sainfo = getsainfo(idsrc, iddst, iph2->ph1->id_p); + iph2->sainfo = getsainfo(idsrc, iddst, iph2->ph1->id_p, 0); + if (iph2->sainfo == NULL) + if ((iph2->ph1->natt_flags & NAT_DETECTED_ME) && lcconf->ext_nat_id != NULL) + iph2->sainfo = getsainfo(idsrc, iddst, iph2->ph1->id_p, 1); if (iph2->sainfo == NULL) { plog(LLV_ERROR, LOCATION, NULL, "failed to get sainfo.\n"); @@ -1984,8 +2003,9 @@ end: * NOTE: This function is only for responder. */ static int -get_proposal_r(iph2) +get_proposal_r(iph2, use_remote_addr) struct ph2handle *iph2; + int use_remote_addr; { struct policyindex spidx; struct secpolicy *sp_in, *sp_out; @@ -2018,8 +2038,11 @@ get_proposal_r(iph2) /* * make destination address in spidx from either ID payload * or phase 1 address into a address in spidx. + * If behind a nat - use phase1 address because server's + * use the nat's address in the ID payload. */ if (iph2->id != NULL + && use_remote_addr == 0 && (_XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR || _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR || _XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR_SUBNET @@ -2066,7 +2089,11 @@ get_proposal_r(iph2) memcpy(&spidx.dst, iph2->src, sysdep_sa_len(iph2->src)); switch (spidx.dst.ss_family) { case AF_INET: - spidx.prefd = sizeof(struct in_addr) << 3; + { + struct sockaddr_in *s = (struct sockaddr_in *)&spidx.dst; + spidx.prefd = sizeof(struct in_addr) << 3; + s->sin_port = htons(0); + } break; #ifdef INET6 case AF_INET6: @@ -2081,6 +2108,7 @@ get_proposal_r(iph2) /* make source address in spidx */ if (iph2->id_p != NULL + && use_remote_addr == 0 && (_XIDT(iph2->id_p) == IPSECDOI_ID_IPV4_ADDR || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV4_ADDR_SUBNET @@ -2123,7 +2151,11 @@ get_proposal_r(iph2) memcpy(&spidx.src, iph2->dst, sysdep_sa_len(iph2->dst)); switch (spidx.src.ss_family) { case AF_INET: - spidx.prefs = sizeof(struct in_addr) << 3; + { + struct sockaddr_in *s = (struct sockaddr_in *)&spidx.src; + spidx.prefs = sizeof(struct in_addr) << 3; + s->sin_port = htons(0); + } break; #ifdef INET6 case AF_INET6: diff --git a/ipsec-tools/racoon/localconf.c b/ipsec-tools/racoon/localconf.c index 73f01f9..381d1e8 100644 --- a/ipsec-tools/racoon/localconf.c +++ b/ipsec-tools/racoon/localconf.c @@ -101,6 +101,10 @@ flushlcconf() vfree(lcconf->ident[i]); lcconf->ident[i] = NULL; } + if (lcconf->ext_nat_id) { + vfree(lcconf->ext_nat_id); + lcconf->ext_nat_id = NULL; + } } static void diff --git a/ipsec-tools/racoon/localconf.h b/ipsec-tools/racoon/localconf.h index f99d1a7..b206492 100644 --- a/ipsec-tools/racoon/localconf.h +++ b/ipsec-tools/racoon/localconf.h @@ -132,6 +132,7 @@ struct localconf { int wait_ph2complete; int natt_ka_interval; /* NAT-T keepalive interval. */ + vchar_t *ext_nat_id; /* our address id for our nat address */ int secret_size; int strict_address; /* strictly check addresses. */ diff --git a/ipsec-tools/racoon/pfkey_racoon.c b/ipsec-tools/racoon/pfkey_racoon.c index 7152a4e..76ecbc3 100644 --- a/ipsec-tools/racoon/pfkey_racoon.c +++ b/ipsec-tools/racoon/pfkey_racoon.c @@ -1969,7 +1969,7 @@ pk_recvacquire(mhp) delph2(iph2[n]); return -1; } - iph2[n]->sainfo = getsainfo(idsrc, iddst, NULL); + iph2[n]->sainfo = getsainfo(idsrc, iddst, NULL, 0); vfree(idsrc); vfree(iddst); if (iph2[n]->sainfo == NULL) { @@ -2747,43 +2747,35 @@ pk_checkalg(class, calg, keylen) */ static struct sadb_msg * pk_recv(so, lenp) - int so; - int *lenp; +int so; +int *lenp; { - struct sadb_msg buf, *newmsg; - int reallen; - - *lenp = recv(so, (caddr_t)&buf, sizeof(buf), MSG_PEEK); - if (*lenp < 0) + struct sadb_msg *newmsg; + int reallen = 0; + socklen_t optlen = sizeof(reallen); + + if (getsockopt(so, SOL_SOCKET, SO_NREAD, &reallen, &optlen) < 0) return NULL; /*fatal*/ - else if (*lenp < sizeof(buf)) + + if (reallen == 0) return NULL; - - reallen = PFKEY_UNUNIT64(buf.sadb_msg_len); + if ((newmsg = racoon_calloc(1, reallen)) == NULL) return NULL; - - *lenp = recv(so, (caddr_t)newmsg, reallen, MSG_PEEK); - if (*lenp < 0) { - racoon_free(newmsg); - return NULL; /*fatal*/ - } else if (*lenp != reallen) { - racoon_free(newmsg); - return NULL; - } - + *lenp = recv(so, (caddr_t)newmsg, reallen, 0); if (*lenp < 0) { racoon_free(newmsg); return NULL; /*fatal*/ - } else if (*lenp != reallen) { + } else if (*lenp != reallen || *lenp < sizeof(struct sadb_msg)) { racoon_free(newmsg); return NULL; } - + return newmsg; } + /* see handler.h */ u_int32_t pk_getseq() diff --git a/ipsec-tools/racoon/sainfo.c b/ipsec-tools/racoon/sainfo.c index 2ad8797..502914b 100644 --- a/ipsec-tools/racoon/sainfo.c +++ b/ipsec-tools/racoon/sainfo.c @@ -79,12 +79,16 @@ static LIST_HEAD(_sitree, sainfo) sitree; * First pass is for sainfo from a specified peer, second for others. */ struct sainfo * -getsainfo(src, dst, peer) +getsainfo(src, dst, peer, use_nat_addr) const vchar_t *src, *dst, *peer; + int use_nat_addr; { struct sainfo *s = NULL; struct sainfo *anonymous = NULL; int pass = 1; + + if (use_nat_addr && lcconf->ext_nat_id == NULL) + return NULL; if (peer == NULL) pass = 2; @@ -109,9 +113,13 @@ getsainfo(src, dst, peer) continue; } - if (memcmp(src->v, s->idsrc->v, s->idsrc->l) == 0 - && memcmp(dst->v, s->iddst->v, s->iddst->l) == 0) - return s; + if (memcmp(src->v, s->idsrc->v, s->idsrc->l) == 0) { + if (use_nat_addr) { + if (memcmp(lcconf->ext_nat_id->v, s->iddst->v, s->iddst->l) == 0) + return s; + } else if (memcmp(dst->v, s->iddst->v, s->iddst->l) == 0) + return s; + } } if (anonymous) { diff --git a/ipsec-tools/racoon/sainfo.h b/ipsec-tools/racoon/sainfo.h index ec2a72f..77fff23 100644 --- a/ipsec-tools/racoon/sainfo.h +++ b/ipsec-tools/racoon/sainfo.h @@ -61,7 +61,7 @@ struct sainfoalg { }; extern struct sainfo *getsainfo __P((const vchar_t *, - const vchar_t *, const vchar_t *)); + const vchar_t *, const vchar_t *, int)); extern struct sainfo *newsainfo __P((void)); extern void delsainfo __P((struct sainfo *)); extern void inssainfo __P((struct sainfo *)); -- 2.47.2