X-Git-Url: https://git.saurik.com/apple/ipsec.git/blobdiff_plain/476121220b14176dcbf5f70f47b9ef8e38f8b389..HEAD:/ipsec-tools/racoon/isakmp.c diff --git a/ipsec-tools/racoon/isakmp.c b/ipsec-tools/racoon/isakmp.c index 7bcf121..52a030c 100644 --- a/ipsec-tools/racoon/isakmp.c +++ b/ipsec-tools/racoon/isakmp.c @@ -30,18 +30,19 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ -#ifdef __APPLE__ #define __APPLE_API_PRIVATE -#endif #include "config.h" #include #include #include +#include #include #include +#include +#include #include #ifndef HAVE_NETINET6_IPSEC @@ -69,9 +70,6 @@ #include #endif #include -#ifdef ENABLE_HYBRID -#include -#endif #include "var.h" #include "misc.h" @@ -80,16 +78,15 @@ #include "sockmisc.h" #include "schedule.h" #include "debug.h" +#include "session.h" +#include "fsm.h" #include "remoteconf.h" #include "localconf.h" #include "grabmyaddr.h" -#include "admin.h" -#include "privsep.h" #include "isakmp_var.h" #include "isakmp.h" #include "oakley.h" -#include "evt.h" #include "handler.h" #include "proposal.h" #include "ipsec_doi.h" @@ -98,10 +95,8 @@ #include "policy.h" #include "isakmp_ident.h" #include "isakmp_agg.h" -#include "isakmp_base.h" #include "isakmp_quick.h" #include "isakmp_inf.h" -#include "isakmp_newg.h" #include "vpn_control.h" #include "vpn_control_var.h" #ifdef ENABLE_HYBRID @@ -121,120 +116,66 @@ # include "nattraversal.h" #endif #include "ike_session.h" -# ifdef __linux__ -# include -# include -# ifndef SOL_UDP -# define SOL_UDP 17 -# endif -# endif /* __linux__ */ -# if defined(__NetBSD__) || defined(__FreeBSD__) || \ - (defined(__APPLE__) && defined(__MACH__)) # include # include # include # include # define SOL_UDP IPPROTO_UDP -# endif /* __NetBSD__ / __FreeBSD__ */ -#include "ipsecSessionTracer.h" -#include "ipsecMessageTracer.h" - -static int nostate1 __P((struct ph1handle *, vchar_t *)); -static int nostate2 __P((struct ph2handle *, vchar_t *)); - -extern caddr_t val2str(const char *, size_t); - -static int (*ph1exchange[][2][PHASE1ST_MAX]) - __P((struct ph1handle *, vchar_t *)) = { - /* error */ - { {}, {}, }, - /* Identity Protection exchange */ - { - { nostate1, ident_i1send, nostate1, ident_i2recv, ident_i2send, - ident_i3recv, ident_i3send, ident_i4recv, ident_i4send, nostate1, }, - { nostate1, ident_r1recv, ident_r1send, ident_r2recv, ident_r2send, - ident_r3recv, ident_r3send, nostate1, nostate1, nostate1, }, - }, - /* Aggressive exchange */ - { - { nostate1, agg_i1send, nostate1, agg_i2recv, agg_i2send, - nostate1, nostate1, nostate1, nostate1, nostate1, }, - { nostate1, agg_r1recv, agg_r1send, agg_r2recv, agg_r2send, - nostate1, nostate1, nostate1, nostate1, nostate1, }, - }, - /* Base exchange */ - { - { nostate1, base_i1send, nostate1, base_i2recv, base_i2send, - base_i3recv, base_i3send, nostate1, nostate1, nostate1, }, - { nostate1, base_r1recv, base_r1send, base_r2recv, base_r2send, - nostate1, nostate1, nostate1, nostate1, nostate1, }, - }, -}; - -static int (*ph2exchange[][2][PHASE2ST_MAX]) - __P((struct ph2handle *, vchar_t *)) = { - /* error */ - { {}, {}, }, - /* Quick mode for IKE */ - { - { nostate2, nostate2, quick_i1prep, nostate2, quick_i1send, - quick_i2recv, quick_i2send, quick_i3recv, nostate2, nostate2, }, - { nostate2, quick_r1recv, quick_r1prep, nostate2, quick_r2send, - quick_r3recv, quick_r3prep, quick_r3send, nostate2, nostate2, } - }, -}; - -static u_char r_ck0[] = { 0,0,0,0,0,0,0,0 }; /* used to verify the r_ck. */ - -static int isakmp_main __P((vchar_t *, struct sockaddr *, struct sockaddr *)); -static int ph1_main __P((struct ph1handle *, vchar_t *)); -static int quick_main __P((struct ph2handle *, vchar_t *)); -static int isakmp_ph1begin_r __P((vchar_t *, - struct sockaddr *, struct sockaddr *, u_int8_t)); -static int isakmp_ph2begin_i __P((struct ph1handle *, struct ph2handle *)); -static int isakmp_ph2begin_r __P((struct ph1handle *, vchar_t *)); -static int etypesw1 __P((int)); -static int etypesw2 __P((int)); +#include "power_mgmt.h" + +extern caddr_t val2str (const char *, size_t); +u_char i_ck0[] = { 0,0,0,0,0,0,0,0 }; /* used to verify the i_ck. */ +u_char r_ck0[] = { 0,0,0,0,0,0,0,0 }; /* used to verify the r_ck. */ + + +static void isakmp_main (vchar_t *, struct sockaddr_storage *, struct sockaddr_storage *); +static void ikev1_received_packet(vchar_t *, struct sockaddr_storage *, struct sockaddr_storage *); +static int ikev1_ph1begin_r (ike_session_t *session, vchar_t *, struct sockaddr_storage *, struct sockaddr_storage *, u_int8_t); +static int ikev1_ph2begin_i (phase1_handle_t *, phase2_handle_t *); +static int ikev1_ph2begin_r (phase1_handle_t *, vchar_t *); + + #ifdef ENABLE_FRAG -static int frag_handler(struct ph1handle *, - vchar_t *, struct sockaddr *, struct sockaddr *); +static void frag_handler (phase1_handle_t *, vchar_t *, struct sockaddr_storage *, struct sockaddr_storage *); #endif /* * isakmp packet handler */ -int -isakmp_handler(so_isakmp) - int so_isakmp; +void +isakmp_handler(int so_isakmp) { struct isakmp isakmp; union { + u_int64_t force_align; // Wcast-align fix - force alignment char buf[sizeof (isakmp) + 4]; u_int32_t non_esp[2]; char lbuf[sizeof(struct udphdr) + -#ifdef __linux - sizeof(struct iphdr) + -#else sizeof(struct ip) + -#endif sizeof(isakmp) + 4]; } x; struct sockaddr_storage remote; struct sockaddr_storage local; unsigned int remote_len = sizeof(remote); unsigned int local_len = sizeof(local); - int len = 0, extralen = 0; + ssize_t len = 0; + int extralen = 0; u_short port; vchar_t *buf = NULL, *tmpbuf = NULL; int error = -1; + if (slept_at || woke_at) { + plog(ASL_LEVEL_DEBUG, /* this log is high volume */ + "ignoring isakmp port until power-mgmt event is handled.\n"); + return; + } + /* read message by MSG_PEEK */ while ((len = recvfromto(so_isakmp, x.buf, sizeof(x), - MSG_PEEK, (struct sockaddr *)&remote, &remote_len, - (struct sockaddr *)&local, &local_len)) < 0) { + MSG_PEEK, &remote, &remote_len, &local, &local_len)) < 0) { if (errno == EINTR) continue; - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to receive isakmp packet: %s\n", strerror (errno)); goto end; @@ -245,41 +186,18 @@ isakmp_handler(so_isakmp) /* Pull the keep-alive packet */ if ((len = recvfrom(so_isakmp, (char *)x.buf, 1, 0, (struct sockaddr *)&remote, &remote_len)) != 1) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to receive keep alive packet: %s\n", strerror (errno)); } goto end; } - /* Lucent IKE in UDP encapsulation */ - { - struct udphdr *udp; -#ifdef __linux__ - struct iphdr *ip; - - udp = (struct udphdr *)&x.lbuf[0]; - if (ntohs(udp->dest) == 501) { - ip = (struct iphdr *)(x.lbuf + sizeof(*udp)); - extralen += sizeof(*udp) + ip->ihl; - } -#else - struct ip *ip; - - udp = (struct udphdr *)&x.lbuf[0]; - if (ntohs(udp->uh_dport) == 501) { - ip = (struct ip *)(x.lbuf + sizeof(*udp)); - extralen += sizeof(*udp) + ip->ip_hl; - } -#endif - } -#ifdef ENABLE_NATT /* we don't know about portchange yet, look for non-esp marker instead */ if (x.non_esp[0] == 0 && x.non_esp[1] != 0) extralen = NON_ESP_MARKER_LEN; -#endif /* now we know if there is an extra non-esp marker at the beginning or not */ @@ -287,13 +205,12 @@ isakmp_handler(so_isakmp) /* check isakmp header length, as well as sanity of header length */ if (len < sizeof(isakmp) || ntohl(isakmp.len) < sizeof(isakmp)) { - plog(LLV_ERROR, LOCATION, (struct sockaddr *)&remote, - "packet shorter than isakmp header size (%u, %u, %zu)\n", - len, ntohl(isakmp.len), sizeof(isakmp)); + plog(ASL_LEVEL_ERR, + "packet shorter than isakmp header size (size: %zu, minimum expected: %zu)\n", len, sizeof(isakmp)); /* dummy receive */ if ((len = recvfrom(so_isakmp, (char *)&isakmp, sizeof(isakmp), 0, (struct sockaddr *)&remote, &remote_len)) < 0) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to receive isakmp packet: %s\n", strerror (errno)); } @@ -302,11 +219,11 @@ isakmp_handler(so_isakmp) /* reject it if the size is tooooo big. */ if (ntohl(isakmp.len) > 0xffff) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "the length in the isakmp header is too big.\n"); if ((len = recvfrom(so_isakmp, (char *)&isakmp, sizeof(isakmp), 0, (struct sockaddr *)&remote, &remote_len)) < 0) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to receive isakmp packet: %s\n", strerror (errno)); } @@ -315,36 +232,40 @@ isakmp_handler(so_isakmp) /* read real message */ if ((tmpbuf = vmalloc(ntohl(isakmp.len) + extralen)) == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to allocate reading buffer (%u Bytes)\n", ntohl(isakmp.len) + extralen); /* dummy receive */ if ((len = recvfrom(so_isakmp, (char *)&isakmp, sizeof(isakmp), 0, (struct sockaddr *)&remote, &remote_len)) < 0) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to receive isakmp packet: %s\n", strerror (errno)); -#ifdef __APPLE__ error = -2; /* serious problem with socket */ -#endif } goto end; } while ((len = recvfromto(so_isakmp, (char *)tmpbuf->v, tmpbuf->l, - 0, (struct sockaddr *)&remote, &remote_len, - (struct sockaddr *)&local, &local_len)) < 0) { + 0, &remote, &remote_len, &local, &local_len)) < 0) { if (errno == EINTR) continue; - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to receive isakmp packet: %s\n", strerror (errno)); goto end; } + if (len < extralen) { + plog(ASL_LEVEL_ERR, + "invalid len (%zd Bytes) & extralen (%d Bytes)\n", + len, extralen); + goto end; + } + if ((buf = vmalloc(len - extralen)) == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to allocate reading buffer (%u Bytes)\n", + plog(ASL_LEVEL_ERR, + "failed to allocate reading buffer (%lu Bytes)\n", (len - extralen)); goto end; } @@ -354,19 +275,15 @@ isakmp_handler(so_isakmp) len -= extralen; if (len != buf->l) { - plog(LLV_ERROR, LOCATION, (struct sockaddr *)&remote, - "received invalid length (%d != %zu), why ?\n", + plog(ASL_LEVEL_ERR, "received invalid length (%zd != %zu), why ?\n", len, buf->l); goto end; } - plog(LLV_DEBUG, LOCATION, NULL, "===\n"); - plog(LLV_DEBUG, LOCATION, NULL, - "%d bytes message received %s\n", - len, saddr2str_fromto("from %s to %s", - (struct sockaddr *)&remote, - (struct sockaddr *)&local)); - plogdump(LLV_DEBUG, buf->v, buf->l); + plog(ASL_LEVEL_DEBUG, "%zd bytes message received %s\n", + len, saddr2str_fromto("from %s to %s", + (struct sockaddr *)&remote, + (struct sockaddr *)&local)); /* avoid packets with malicious port/address */ switch (remote.ss_family) { @@ -379,12 +296,12 @@ isakmp_handler(so_isakmp) break; #endif default: - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "invalid family: %d\n", remote.ss_family); goto end; } if (port == 0) { - plog(LLV_ERROR, LOCATION, (struct sockaddr *)&remote, + plog(ASL_LEVEL_ERR, "src port == 0 (valid as UDP but not with IKE)\n"); goto end; } @@ -394,9 +311,12 @@ isakmp_handler(so_isakmp) /* XXX: I don't know how to check isakmp half connection attack. */ /* simply reply if the packet was processed. */ - if (check_recvdpkt((struct sockaddr *)&remote, - (struct sockaddr *)&local, buf)) { - plog(LLV_NOTIFY, LOCATION, NULL, + + if (ike_session_check_recvdpkt(&remote, &local, buf)) { + IPSECLOGASLMSG("Received retransmitted packet from %s.\n", + saddr2str((struct sockaddr *)&remote)); + + plog(ASL_LEVEL_NOTICE, "the packet is retransmitted by %s.\n", saddr2str((struct sockaddr *)&remote)); error = 0; @@ -404,10 +324,7 @@ isakmp_handler(so_isakmp) } /* isakmp main routine */ - if (isakmp_main(buf, (struct sockaddr *)&remote, - (struct sockaddr *)&local) != 0) goto end; - - error = 0; + isakmp_main(buf, &remote, &local); end: if (tmpbuf != NULL) @@ -415,21 +332,17 @@ end: if (buf != NULL) vfree(buf); - return(error); + return; } /* * main processing to handle isakmp payload */ -static int -isakmp_main(msg, remote, local) - vchar_t *msg; - struct sockaddr *remote, *local; +static void +isakmp_main(vchar_t *msg, struct sockaddr_storage *remote, struct sockaddr_storage *local) { struct isakmp *isakmp = (struct isakmp *)msg->v; - isakmp_index *index = (isakmp_index *)isakmp; - u_int32_t msgid = isakmp->msgid; - struct ph1handle *iph1; + u_int8_t isakmp_version = isakmp->v; #ifdef HAVE_PRINT_ISAKMP_C isakmp_printpacket(msg, remote, local, 0); @@ -437,9 +350,9 @@ isakmp_main(msg, remote, local) /* the initiator's cookie must not be zero */ if (memcmp(&isakmp->i_ck, r_ck0, sizeof(cookie_t)) == 0) { - plog(LLV_ERROR, LOCATION, remote, + plog(ASL_LEVEL_ERR, "malformed cookie received.\n"); - return -1; + return; } /* Check the Major and Minor Version fields. */ @@ -448,58 +361,79 @@ isakmp_main(msg, remote, local) * I think it may no be here because the version depends * on exchange status. */ - if (isakmp->v < ISAKMP_VERSION_NUMBER) { - if (ISAKMP_GETMAJORV(isakmp->v) < ISAKMP_MAJOR_VERSION) { - plog(LLV_ERROR, LOCATION, remote, - "invalid major version %d.\n", - ISAKMP_GETMAJORV(isakmp->v)); - return -1; - } -#if ISAKMP_MINOR_VERSION > 0 - if (ISAKMP_GETMINORV(isakmp->v) < ISAKMP_MINOR_VERSION) { - plog(LLV_ERROR, LOCATION, remote, + if (ISAKMP_GETMAJORV(isakmp_version) != ISAKMP_MAJOR_VERSION_IKEV1) { + plog(ASL_LEVEL_ERR, "invalid major version %d.\n", isakmp_version); + return; + } + +#if 0 +#if ISAKMP_MINOR_VERSION > 0 //%%%%%%%% fix this + if (ISAKMP_GETMINORV(isakmp->v) < ISAKMP_MINOR_VERSION) { //%%%%%%%%%%%%%%% ?????? + plog(ASL_LEVEL_ERR, "invalid minor version %d.\n", ISAKMP_GETMINORV(isakmp->v)); - return -1; + return; } #endif - } +#endif - /* check the Flags field. */ - /* XXX How is the exclusive check, E and A ? */ - if (isakmp->flags & ~(ISAKMP_FLAG_E | ISAKMP_FLAG_C | ISAKMP_FLAG_A)) { - plog(LLV_ERROR, LOCATION, remote, - "invalid flag 0x%02x.\n", isakmp->flags); - return -1; - } + if (isakmp_version == ISAKMP_VERSION_NUMBER_IKEV1) { + /* check the Flags field. */ + /* XXX How is the exclusive check, E and A ? */ + if (isakmp->flags & ~(ISAKMP_FLAG_E | ISAKMP_FLAG_C | ISAKMP_FLAG_A)) { + plog(ASL_LEVEL_ERR, "invalid flag 0x%02x.\n", isakmp->flags); + return; + } - /* ignore commit bit. */ - if (ISSET(isakmp->flags, ISAKMP_FLAG_C)) { - if (isakmp->msgid == 0) { - isakmp_info_send_nx(isakmp, remote, local, - ISAKMP_NTYPE_INVALID_FLAGS, NULL); - plog(LLV_ERROR, LOCATION, remote, - "Commit bit on phase1 forbidden.\n"); - return -1; + /* ignore commit bit. */ + if (ISSET(isakmp->flags, ISAKMP_FLAG_C)) { + if (isakmp->msgid == 0) { + isakmp_info_send_nx(isakmp, remote, local, + ISAKMP_NTYPE_INVALID_FLAGS, NULL); + plog(ASL_LEVEL_ERR, "Commit bit on Phase 1 forbidden.\n"); + return; + } } + + ikev1_received_packet(msg, local, remote); } + return; +} - iph1 = getph1byindex(index); +/* + * ikev1_received_packet + * Handler for received IKEv1 Packets + */ +static void +ikev1_received_packet(vchar_t *msg, struct sockaddr_storage *local, struct sockaddr_storage *remote) +{ + ike_session_t *session; + phase1_handle_t *iph1; + + struct isakmp *isakmp = (struct isakmp *)msg->v; + isakmp_index *index = (isakmp_index *)isakmp; + + session = ike_session_get_session(local, remote, 0, index); + if (!session) { + session = ike_session_get_session(local, remote, 1, NULL); + } + if (!session) { + plog (ASL_LEVEL_NOTICE, "failed to allocate or find ike session.\n"); + fatal_error(-1); + } + + iph1 = ike_session_getph1byindex(session, index); if (iph1 != NULL) { /* validity check */ if (memcmp(&isakmp->r_ck, r_ck0, sizeof(cookie_t)) == 0 && iph1->side == INITIATOR) { - IPSECSESSIONTRACEREVENT(iph1->parent_session, - IPSECSESSIONEVENTCODE_IKE_PACKET_RX_FAIL, - CONSTSTR("malformed or unexpected cookie"), - CONSTSTR("Failed to process packet (malformed/unexpected cookie)")); - plog(LLV_DEBUG, LOCATION, remote, - "malformed cookie received or " + plog(ASL_LEVEL_NOTICE, + "Malformed cookie received or " "the initiator's cookies collide.\n"); - return -1; + return; } - -#ifdef ENABLE_NATT + + /* Floating ports for NAT-T */ if (NATT_AVAILABLE(iph1) && ! (iph1->natt_flags & NAT_PORTS_CHANGED) && @@ -515,28 +449,16 @@ isakmp_main(msg, remote, local) /* copy-in new addresses */ iph1->remote = dupsaddr(remote); if (iph1->remote == NULL) { - IPSECSESSIONTRACEREVENT(iph1->parent_session, - IPSECSESSIONEVENTCODE_IKE_PACKET_RX_FAIL, - CONSTSTR("failed to duplicate remote address"), - CONSTSTR("Failed to process phase1 message (can't duplicate remote address")); - plog(LLV_ERROR, LOCATION, iph1->remote, - "phase1 failed: dupsaddr failed.\n"); - remph1(iph1); - delph1(iph1); - return -1; + plog(ASL_LEVEL_ERR, + "Phase 1 failed: dupsaddr failed.\n"); + fatal_error(-1); } iph1->local = dupsaddr(local); if (iph1->local == NULL) { - IPSECSESSIONTRACEREVENT(iph1->parent_session, - IPSECSESSIONEVENTCODE_IKE_PACKET_RX_FAIL, - CONSTSTR("failed to duplicate local address"), - CONSTSTR("Failed to process phase1 message (can't duplicate local address")); - plog(LLV_ERROR, LOCATION, iph1->remote, - "phase1 failed: dupsaddr failed.\n"); - remph1(iph1); - delph1(iph1); - return -1; - } + plog(ASL_LEVEL_ERR, + "Phase 1 failed: dupsaddr failed.\n"); + fatal_error(-1); + } /* set the flag to prevent further port floating (FIXME: should we allow it? E.g. when the NAT gw @@ -544,26 +466,22 @@ isakmp_main(msg, remote, local) iph1->natt_flags |= NAT_PORTS_CHANGED | NAT_ADD_NON_ESP_MARKER; /* print some neat info */ - plog (LLV_INFO, LOCATION, NULL, + plog (ASL_LEVEL_NOTICE, "NAT-T: ports changed to: %s\n", - saddr2str_fromto ("%s<->%s", iph1->remote, iph1->local)); -#ifndef __APPLE__ - natt_keepalive_add_ph1 (iph1); -#endif + saddr2str_fromto("%s<->%s", (struct sockaddr *)iph1->remote, (struct sockaddr *)iph1->local)); } -#endif /* must be same addresses in one stream of a phase at least. */ if (cmpsaddrstrict(iph1->remote, remote) != 0) { char *saddr_db, *saddr_act; - saddr_db = racoon_strdup(saddr2str(iph1->remote)); - saddr_act = racoon_strdup(saddr2str(remote)); + saddr_db = racoon_strdup(saddr2str((struct sockaddr *)iph1->remote)); + saddr_act = racoon_strdup(saddr2str((struct sockaddr *)remote)); STRDUP_FATAL(saddr_db); STRDUP_FATAL(saddr_act); - plog(LLV_WARNING, LOCATION, remote, - "remote address mismatched. db=%s, act=%s\n", + plog(ASL_LEVEL_WARNING, + "Remote address mismatched. db=%s, act=%s\n", saddr_db, saddr_act); racoon_free(saddr_db); @@ -571,652 +489,249 @@ isakmp_main(msg, remote, local) } /* - * don't check of exchange type here because other type will be - * with same index, for example, informational exchange. + * don't check of exchange type here because other type will have + * the same index, for example, informational exchange. */ - /* XXX more acceptable check */ - -#ifdef ENABLE_DPD // received ike packets: update dpd checks - isakmp_reschedule_info_monitor_if_pending(iph1, - "ike packets received from peer"); -#endif /* DPD */ - } - - switch (isakmp->etype) { - case ISAKMP_ETYPE_IDENT: - case ISAKMP_ETYPE_AGG: - case ISAKMP_ETYPE_BASE: - /* phase 1 validity check */ - if (isakmp->msgid != 0) { - plog(LLV_ERROR, LOCATION, remote, - "message id should be zero in phase1.\n"); - return -1; - } - - /* search for isakmp status record of phase 1 */ - if (iph1 == NULL) { - /* - * the packet must be the 1st message from a initiator - * or the 2nd message from the responder. - */ - - /* search for phase1 handle by index without r_ck */ - iph1 = getph1byindex0(index); - if (iph1 == NULL) { - /*it must be the 1st message from a initiator.*/ - if (memcmp(&isakmp->r_ck, r_ck0, - sizeof(cookie_t)) != 0) { - - plog(LLV_DEBUG, LOCATION, remote, - "malformed cookie received " - "or the spi expired.\n"); - return -1; - } - - /* it must be responder's 1st exchange. */ - if (isakmp_ph1begin_r(msg, remote, local, - isakmp->etype) < 0) - return -1; - break; - - /*NOTREACHED*/ - } - - /* it must be the 2nd message from the responder. */ - if (iph1->side != INITIATOR) { - IPSECSESSIONTRACEREVENT(iph1->parent_session, - IPSECSESSIONEVENTCODE_IKE_PACKET_RX_FAIL, - CONSTSTR("malformed cookie and unexpected side"), - CONSTSTR("Failed to process phase1 message (unexpected side)")); - plog(LLV_DEBUG, LOCATION, remote, - "malformed cookie received. " - "it has to be as the initiator. %s\n", - isakmp_pindex(&iph1->index, 0)); - return -1; - } - } - - /* - * Don't delete phase 1 handler when the exchange type - * in handler is not equal to packet's one because of no - * authencication completed. - */ - if (iph1->etype != isakmp->etype) { - IPSECSESSIONTRACEREVENT(iph1->parent_session, - IPSECSESSIONEVENTCODE_IKE_PACKET_RX_FAIL, - CONSTSTR("mismatched exchange type"), - CONSTSTR("Failed to process phase1 message (mismatched exchange type)")); - plog(LLV_ERROR, LOCATION, iph1->remote, - "exchange type is mismatched: " - "db=%s packet=%s, ignore it.\n", - s_isakmp_etype(iph1->etype), - s_isakmp_etype(isakmp->etype)); - return -1; - } - -#ifdef ENABLE_FRAG - if (isakmp->np == ISAKMP_NPTYPE_FRAG) - return frag_handler(iph1, msg, remote, local); -#endif - - /* call main process of phase 1 */ - if (ph1_main(iph1, msg) < 0) { - plog(LLV_ERROR, LOCATION, iph1->remote, - "phase1 negotiation failed.\n"); - remph1(iph1); - delph1(iph1); - return -1; - } - break; - - case ISAKMP_ETYPE_AUTH: - plog(LLV_INFO, LOCATION, remote, - "unsupported exchange %d received.\n", - isakmp->etype); - break; - - case ISAKMP_ETYPE_INFO: - case ISAKMP_ETYPE_ACKINFO: - /* - * iph1 must be present for Information message. - * if iph1 is null then trying to get the phase1 status - * as the packet from responder againt initiator's 1st - * exchange in phase 1. - * NOTE: We think such informational exchange should be ignored. - */ - if (iph1 == NULL) { - iph1 = getph1byindex0(index); - if (iph1 == NULL) { - plog(LLV_ERROR, LOCATION, remote, - "unknown Informational " - "exchange received.\n"); - return -1; - } - if (cmpsaddrstrict(iph1->remote, remote) != 0) { - plog(LLV_WARNING, LOCATION, remote, - "remote address mismatched. " - "db=%s\n", - saddr2str(iph1->remote)); - } - } - -#ifdef ENABLE_FRAG - if (isakmp->np == ISAKMP_NPTYPE_FRAG) - return frag_handler(iph1, msg, remote, local); -#endif - - if (isakmp_info_recv(iph1, msg) < 0) - return -1; - break; - - case ISAKMP_ETYPE_QUICK: - { - struct ph2handle *iph2; - - if (iph1 == NULL) { - isakmp_info_send_nx(isakmp, remote, local, - ISAKMP_NTYPE_INVALID_COOKIE, NULL); - plog(LLV_ERROR, LOCATION, remote, - "can't start the quick mode, " - "there is no ISAKMP-SA, %s\n", - isakmp_pindex((isakmp_index *)&isakmp->i_ck, - isakmp->msgid)); - return -1; - } -#ifdef ENABLE_HYBRID - /* Reinit the IVM if it's still there */ - if (iph1->mode_cfg && iph1->mode_cfg->ivm) { - oakley_delivm(iph1->mode_cfg->ivm); - iph1->mode_cfg->ivm = NULL; - } -#endif -#ifdef ENABLE_FRAG - if (isakmp->np == ISAKMP_NPTYPE_FRAG) - return frag_handler(iph1, msg, remote, local); -#endif - - /* check status of phase 1 whether negotiated or not. */ - if (iph1->status != PHASE1ST_ESTABLISHED) { - IPSECSESSIONTRACEREVENT(iph1->parent_session, - IPSECSESSIONEVENTCODE_IKEV1_PH2_INIT_DROP, - CONSTSTR("can't start phase2 without valid phase1"), - CONSTSTR("Failed to start phase2 resonder (no established phase1")); - plog(LLV_ERROR, LOCATION, remote, - "can't start the quick mode, " - "there is no valid ISAKMP-SA, %s\n", - isakmp_pindex(&iph1->index, iph1->msgid)); - return -1; - } - - /* search isakmp phase 2 stauts record. */ - iph2 = getph2bymsgid(iph1, msgid); - if (iph2 == NULL) { - /* it must be new negotiation as responder */ - if (isakmp_ph2begin_r(iph1, msg) < 0) - return -1; - return 0; - /*NOTREACHED*/ - } - - /* commit bit. */ - /* XXX - * we keep to set commit bit during negotiation. - * When SA is configured, bit will be reset. - * XXX - * don't initiate commit bit. should be fixed in the future. - */ - if (ISSET(isakmp->flags, ISAKMP_FLAG_C)) - iph2->flags |= ISAKMP_FLAG_C; - - if (ISSET(isakmp->flags, ISAKMP_FLAG_E) && - (iph2->ph1 == NULL || iph2->ph1->approval == NULL)) { - IPSECSESSIONTRACEREVENT(iph2->parent_session, - IPSECSESSIONEVENTCODE_IKEV1_PH2_INIT_DROP, - CONSTSTR("can't continue phase2 without valid phase1"), - CONSTSTR("Failed to continue phase2 resonder (invalid linked phase1")); - plog(LLV_ERROR, LOCATION, remote, - "can't start the quick mode, " - "invalid linked ISAKMP-SA\n"); - return -1; - } - - /* call main process of quick mode */ - if (quick_main(iph2, msg) < 0) { - plog(LLV_ERROR, LOCATION, iph1->remote, - "phase2 negotiation failed.\n"); - unbindph12(iph2); - remph2(iph2); - delph2(iph2); - return -1; - } - } - break; - - case ISAKMP_ETYPE_NEWGRP: - if (iph1 == NULL) { - plog(LLV_ERROR, LOCATION, remote, - "Unknown new group mode exchange, " - "there is no ISAKMP-SA.\n"); - return -1; - } - -#ifdef ENABLE_FRAG - if (isakmp->np == ISAKMP_NPTYPE_FRAG) - return frag_handler(iph1, msg, remote, local); -#endif - - isakmp_newgroup_r(iph1, msg); - break; - -#ifdef ENABLE_HYBRID - case ISAKMP_ETYPE_CFG: - if (iph1 == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "mode config %d from %s, " - "but we have no ISAKMP-SA.\n", - isakmp->etype, saddr2str(remote)); - return -1; - } - -#ifdef ENABLE_FRAG - if (isakmp->np == ISAKMP_NPTYPE_FRAG) - return frag_handler(iph1, msg, remote, local); -#endif - - isakmp_cfg_r(iph1, msg); - break; -#endif - - case ISAKMP_ETYPE_NONE: - default: - plog(LLV_ERROR, LOCATION, NULL, - "Invalid exchange type %d from %s.\n", - isakmp->etype, saddr2str(remote)); - return -1; - } - - return 0; -} - -/* - * main function of phase 1. - */ -static int -ph1_main(iph1, msg) - struct ph1handle *iph1; - vchar_t *msg; -{ - int error; - int ini_contact = iph1->rmconf->ini_contact; -#ifdef ENABLE_STATS - struct timeval start, end; -#endif - int spi_cmp; - u_int rekey_lifetime; - - /* ignore a packet */ - if (iph1->status == PHASE1ST_ESTABLISHED) - return 0; - -#ifdef ENABLE_STATS - gettimeofday(&start, NULL); -#endif - /* receive */ - if (ph1exchange[etypesw1(iph1->etype)] - [iph1->side] - [iph1->status] == NULL) { - IPSECSESSIONTRACEREVENT(iph1->parent_session, - IPSECSESSIONEVENTCODE_IKE_PACKET_RX_FAIL, - CONSTSTR("unavailable function"), - CONSTSTR("Failed to process phase1 message (no state function)")); - plog(LLV_ERROR, LOCATION, iph1->remote, - "why isn't the function defined.\n"); - return -1; - } - error = (ph1exchange[etypesw1(iph1->etype)] - [iph1->side] - [iph1->status])(iph1, msg); - if (error != 0) { - - /* XXX - * When an invalid packet is received on phase1, it should - * be selected to process this packet. That is to respond - * with a notify and delete phase 1 handler, OR not to respond - * and keep phase 1 handler. However, in PHASE1ST_START when - * acting as RESPONDER we must not keep phase 1 handler or else - * it will stay forever. - */ - - if (iph1->side == RESPONDER && iph1->status == PHASE1ST_START) { - plog(LLV_ERROR, LOCATION, iph1->remote, - "failed to pre-process packet.\n"); - return -1; - } else { - /* ignore the error and keep phase 1 handler */ - return 0; - } - } - -#ifndef ENABLE_FRAG - /* free resend buffer */ - if (iph1->sendbuf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "no buffer found as sendbuf\n"); - return -1; - } -#endif - - VPTRINIT(iph1->sendbuf); - - /* turn off schedule */ - SCHED_KILL(iph1->scr); - - /* send */ - plog(LLV_DEBUG, LOCATION, NULL, "===\n"); - if ((ph1exchange[etypesw1(iph1->etype)] - [iph1->side] - [iph1->status])(iph1, msg) != 0) { - plog(LLV_ERROR, LOCATION, iph1->remote, - "failed to process packet.\n"); - return -1; - } - -#ifdef ENABLE_STATS - gettimeofday(&end, NULL); - syslog(LOG_NOTICE, "%s(%s): %8.6f", - "phase1", s_isakmp_state(iph1->etype, iph1->side, iph1->status), - timedelta(&start, &end)); -#endif - if (iph1->status == PHASE1ST_ESTABLISHED) { + isakmp_reschedule_info_monitor_if_pending(iph1, "IKE packet received from peer"); -#ifdef ENABLE_STATS - gettimeofday(&iph1->end, NULL); - syslog(LOG_NOTICE, "%s(%s): %8.6f", - "phase1", s_isakmp_etype(iph1->etype), - timedelta(&iph1->start, &iph1->end)); -#endif - -#ifdef ENABLE_VPNCONTROL_PORT - - if (iph1->side == RESPONDER && - iph1->local->sa_family == AF_INET) { - - struct redirect *addr; - - LIST_FOREACH(addr, &lcconf->redirect_addresses, chain) { - if (((struct sockaddr_in *)iph1->local)->sin_addr.s_addr == addr->cluster_address) { - vchar_t *raddr = vmalloc(sizeof(u_int32_t)); - - if (raddr == NULL) { - plog(LLV_ERROR, LOCATION, iph1->remote, - "failed to send redirect message - memory error.\n"); - } else { - memcpy(raddr->v, &addr->redirect_address, sizeof(u_int32_t)); - (void)isakmp_info_send_n1(iph1, ISAKMP_NTYPE_LOAD_BALANCE, raddr); - plog(LLV_DEBUG, LOCATION, iph1->remote, "sent redirect notification - address = %x.\n", ntohl(addr->redirect_address)); - vfree(raddr); - if (addr->force) { - (void)ike_session_update_ph1_ph2tree(iph1); - isakmp_ph1delete(iph1); - } - } - } - return 0; - } - } -#endif - /* save created date. */ - (void)time(&iph1->created); - - /* add to the schedule to expire, and save back pointer. */ - iph1->sce = sched_new(iph1->approval->lifetime, - isakmp_ph1expire_stub, iph1); - - if (iph1->rmconf->initiate_ph1rekey) { - if (iph1->side == INITIATOR) { - spi_cmp = memcmp(&iph1->index.i_ck, &iph1->index.r_ck, sizeof(iph1->index.i_ck)); - if (spi_cmp == 0) - spi_cmp = 1; - } else { - spi_cmp = memcmp(&iph1->index.r_ck, &iph1->index.i_ck, sizeof(iph1->index.r_ck)); - if (spi_cmp == 0) - spi_cmp = -1; - } - rekey_lifetime = ike_session_get_rekey_lifetime((spi_cmp > 0), - iph1->approval->lifetime); - if (rekey_lifetime) { - iph1->sce_rekey = sched_new(rekey_lifetime, - isakmp_ph1rekeyexpire_stub, - iph1); - } else { - /* iph1->approval->lifetime is too small (e.g. 1) so why bother? - * LOG ERROR - */ - plog(LLV_ERROR, LOCATION, iph1->remote, - "failed to get rekey timer - lifetime is too small... probably.\n"); - } - } - -#ifdef ENABLE_HYBRID - /* ignore xauth if it is a rekey */ - if (!iph1->is_rekey && - iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) { - switch(AUTHMETHOD(iph1)) { - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R: - case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: - case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: - case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R: - case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R: - case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R: - xauth_sendreq(iph1); - /* XXX Don't process INITIAL_CONTACT */ - ini_contact = 0; - break; - default: - break; - } - } -#endif -#ifdef ENABLE_DPD - /* Schedule the r_u_there.... */ - if(iph1->dpd_support && iph1->rmconf->dpd_interval) - isakmp_sched_r_u(iph1, 0); -#endif - - /* INITIAL-CONTACT processing */ - /* ignore initial-contact if it is a rekey */ - /* don't send anything if local test mode. */ - if (!iph1->is_rekey && !f_local && ini_contact && !getcontacted(iph1->remote)) { - /* send INITIAL-CONTACT */ - isakmp_info_send_n1(iph1, - ISAKMP_NTYPE_INITIAL_CONTACT, NULL); - /* insert a node into contacted list. */ - if (inscontacted(iph1->remote) == -1) { - plog(LLV_ERROR, LOCATION, iph1->remote, - "failed to add contacted list.\n"); - /* ignore */ - } - } - - log_ph1established(iph1); - plog(LLV_DEBUG, LOCATION, NULL, "===\n"); - - /* - * SA up shell script hook: do it now for rekeys, otherwise only - * if ISAKMP mode config wasn't requested. In the later - * case it is done when we receive the configuration. - */ - if ((iph1->status == PHASE1ST_ESTABLISHED) && - (iph1->is_rekey || !iph1->rmconf->mode_cfg)) { - switch (AUTHMETHOD(iph1)) { -#ifdef ENABLE_HYBRID - case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: - case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: - /* Unimplemeted... */ - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R: - case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R: - case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R: - case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R: - break; -#endif - default: - script_hook(iph1, SCRIPT_PHASE1_UP); - break; - } - } - - ike_session_cleanup_other_established_ph1s(iph1->parent_session, iph1); - -#ifdef ENABLE_VPNCONTROL_PORT - vpncontrol_notify_phase_change(0, FROM_LOCAL, iph1, NULL); -#endif - - } - - return 0; -} - -/* - * main function of quick mode. - */ -static int -quick_main(iph2, msg) - struct ph2handle *iph2; - vchar_t *msg; -{ - struct isakmp *isakmp = (struct isakmp *)msg->v; - int error; -#ifdef ENABLE_STATS - struct timeval start, end; -#endif - - /* ignore a packet */ - if (iph2->status == PHASE2ST_ESTABLISHED - || iph2->status == PHASE2ST_GETSPISENT) - return 0; - -#ifdef ENABLE_STATS - gettimeofday(&start, NULL); -#endif - - /* receive */ - if (ph2exchange[etypesw2(isakmp->etype)] - [iph2->side] - [iph2->status] == NULL) { - plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "why isn't the function defined.\n"); - return -1; - } - error = (ph2exchange[etypesw2(isakmp->etype)] - [iph2->side] - [iph2->status])(iph2, msg); - if (error != 0) { - plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "failed to pre-process packet.\n"); - if (error == ISAKMP_INTERNAL_ERROR) - return 0; - isakmp_info_send_n1(iph2->ph1, error, NULL); - return -1; - } - - /* when using commit bit, status will be reached here. */ - //if (iph2->status == PHASE2ST_ADDSA) //%%% BUG FIX - wrong place - // return 0; - - /* free resend buffer */ - if (iph2->sendbuf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "no buffer found as sendbuf\n"); - return -1; } - VPTRINIT(iph2->sendbuf); - - /* turn off schedule */ - SCHED_KILL(iph2->scr); - - /* when using commit bit, status will be reached here. */ - if (iph2->status == PHASE2ST_ADDSA) //%%% BUG FIX - moved to here - return 0; + + // + // Check exchange type and process accordingly + // + switch (isakmp->etype) { - /* send */ - plog(LLV_DEBUG, LOCATION, NULL, "===\n"); - if ((ph2exchange[etypesw2(isakmp->etype)] - [iph2->side] - [iph2->status])(iph2, msg) != 0) { - plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "failed to process packet.\n"); - return -1; + case ISAKMP_ETYPE_IDENT: + case ISAKMP_ETYPE_AGG: + { + /* phase 1 validity check */ + if (isakmp->msgid != 0) { + plog(ASL_LEVEL_ERR, "Message id should be zero in Phase 1.\n"); + return; + } + + /* search for isakmp status record of phase 1 */ + if (iph1 == NULL) { + /* + * the packet must be the 1st message from a initiator + * or the 2nd message from the responder. + */ + + /* search for phase1 handle by index without r_ck */ + iph1 = ike_session_getph1byindex0(session, index); + if (iph1 == NULL) { + /*it must be the 1st message from a initiator.*/ + if (memcmp(&isakmp->r_ck, r_ck0, + sizeof(cookie_t)) != 0) { + + plog(ASL_LEVEL_NOTICE, "Malformed cookie received " + "or the spi expired.\n"); + return; + } + + /* Initiation of new exchange */ + ikev1_ph1begin_r(session, msg, remote, local, isakmp->etype); + return; + } + } + + /* + * Don't delete phase 1 handler for mismatch + * because of no authentication has been completed. + */ + if (iph1->etype != isakmp->etype) { + plog(ASL_LEVEL_ERR, + "Exchange type is mismatched: " + "db=%s packet=%s, ignore it.\n", + s_isakmp_etype(iph1->etype), + s_isakmp_etype(isakmp->etype)); + return; + } + + if (isakmp->np == ISAKMP_NPTYPE_FRAG) { + frag_handler(iph1, msg, remote, local); + return; + } + fsm_ikev1_phase1_process_payloads(iph1, msg); + } + break; + + case ISAKMP_ETYPE_INFO: + case ISAKMP_ETYPE_ACKINFO: + { + /* + * iph1 must be present for Information message. + * if iph1 is null then trying to get the phase1 status + * as the packet from responder againt initiator's 1st + * exchange in phase 1. + * NOTE: We think such informational exchange should be ignored. + */ + if (iph1 == NULL) { + iph1 = ike_session_getph1byindex0(session, index); + if (iph1 == NULL) { + plog(ASL_LEVEL_ERR, "Unknown Informational exchange received.\n"); + return; + } + if (cmpsaddrstrict(iph1->remote, remote) != 0) { + plog(ASL_LEVEL_WARNING, + "Remote address mismatched. " + "db=%s\n", + saddr2str((struct sockaddr *)iph1->remote)); + } + } + if (isakmp->np == ISAKMP_NPTYPE_FRAG) + return frag_handler(iph1, msg, remote, local); + + if (isakmp_info_recv(iph1, msg) < 0) + return; + } + break; + + case ISAKMP_ETYPE_QUICK: + { + u_int32_t msgid = isakmp->msgid; + phase2_handle_t *iph2; + + if (iph1 == NULL) { + isakmp_info_send_nx(isakmp, remote, local, + ISAKMP_NTYPE_INVALID_COOKIE, NULL); + plog(ASL_LEVEL_ERR, "Can't start the quick mode, " + "there is no ISAKMP-SA, %s\n", isakmp_pindex((isakmp_index *)&isakmp->i_ck, + isakmp->msgid)); + return; + } + #ifdef ENABLE_HYBRID + /* Reinit the IVM if it's still there */ + if (iph1->mode_cfg && iph1->mode_cfg->ivm) { + oakley_delivm(iph1->mode_cfg->ivm); + iph1->mode_cfg->ivm = NULL; + } + #endif + if (isakmp->np == ISAKMP_NPTYPE_FRAG) { + frag_handler(iph1, msg, remote, local); + return; + } + + /* check status of phase 1 whether negotiated or not. */ + if (!FSM_STATE_IS_ESTABLISHED(iph1->status)) { + plog(ASL_LEVEL_ERR, "can't start the quick mode, " + "there is no valid ISAKMP-SA, %s\n", isakmp_pindex(&iph1->index, iph1->msgid)); + return; + } + + /* search isakmp phase 2 stauts record. */ + iph2 = ike_session_getph2bymsgid(iph1, msgid); + if (iph2 == NULL) { + /* it must be new negotiation as responder */ + ikev1_ph2begin_r(iph1, msg); + return; + } + + /* commit bit. */ + /* XXX + * we keep to set commit bit during negotiation. + * When SA is configured, bit will be reset. + * XXX + * don't initiate commit bit. should be fixed in the future. + */ + if (ISSET(isakmp->flags, ISAKMP_FLAG_C)) + iph2->flags |= ISAKMP_FLAG_C; + + if (ISSET(isakmp->flags, ISAKMP_FLAG_E) && + (iph2->ph1 == NULL || iph2->ph1->approval == NULL)) { + plog(ASL_LEVEL_ERR, "can't start the quick mode, " + "invalid linked ISAKMP-SA\n"); + return; + } + fsm_ikev1_phase2_process_payloads(iph2, msg); + } + break; + + case ISAKMP_ETYPE_CFG: + { + if (iph1 == NULL) { + plog(ASL_LEVEL_ERR, + "mode config %d from %s, " + "but we have no ISAKMP-SA.\n", + isakmp->etype, saddr2str((struct sockaddr *)remote)); + return; + } + if (!FSM_STATE_IS_ESTABLISHED(iph1->status)) { + plog(ASL_LEVEL_ERR, + "mode config %d from %s, " + "but ISAKMP-SA %s isn't established.\n", + isakmp->etype, saddr2str((struct sockaddr *)remote), + isakmp_pindex(&iph1->index, iph1->msgid)); + return; + } + if (isakmp->np == ISAKMP_NPTYPE_FRAG) + return frag_handler(iph1, msg, remote, local); + isakmp_cfg_r(iph1, msg); + } + break; + + case ISAKMP_ETYPE_NEWGRP: + case ISAKMP_ETYPE_AUTH: + case ISAKMP_ETYPE_NONE: + default: + plog(ASL_LEVEL_ERR, + "Invalid exchange type %d from %s.\n", + isakmp->etype, saddr2str((struct sockaddr *)remote)); + break; } - -#ifdef ENABLE_STATS - gettimeofday(&end, NULL); - syslog(LOG_NOTICE, "%s(%s): %8.6f", - "phase2", - s_isakmp_state(ISAKMP_ETYPE_QUICK, iph2->side, iph2->status), - timedelta(&start, &end)); -#endif - - return 0; } /* new negotiation of phase 1 for initiator */ int -isakmp_ph1begin_i(rmconf, remote, local, started_by_api) - struct remoteconf *rmconf; - struct sockaddr *remote, *local; - int started_by_api; +ikev1_ph1begin_i(ike_session_t *session, struct remoteconf *rmconf, struct sockaddr_storage *remote, + struct sockaddr_storage *local, int started_by_api, nw_nat64_prefix_t *nat64_prefix) { - struct ph1handle *iph1; + + phase1_handle_t *iph1; #ifdef ENABLE_STATS struct timeval start, end; #endif + if (session == NULL) { + session = ike_session_get_session(local, remote, 1, NULL); + if (!session) { + plog (ASL_LEVEL_NOTICE, "failed to allocate or find ike session.\n"); + fatal_error(-1); + } + } + /* get new entry to isakmp status table. */ - iph1 = newph1(); + iph1 = ike_session_newph1(ISAKMP_VERSION_NUMBER_IKEV1); if (iph1 == NULL) return -1; - iph1->status = PHASE1ST_START; iph1->rmconf = rmconf; -#ifdef __APPLE__ - if (link_rmconf_to_ph1(rmconf) < 0) { - plog(LLV_ERROR, LOCATION, remote, - "couldn't link " - "configuration.\n"); - iph1->rmconf = NULL; - /* don't call remph1(iph1) until after insph1(iph1) is called */ - delph1(iph1); - return -1; - } -#endif + retain_rmconf(iph1->rmconf); iph1->side = INITIATOR; iph1->started_by_api = started_by_api; - iph1->version = ISAKMP_VERSION_NUMBER; + if (nat64_prefix != NULL) { + memcpy(&iph1->nat64_prefix, nat64_prefix, sizeof(*nat64_prefix)); + } + iph1->version = ISAKMP_VERSION_NUMBER_IKEV1; iph1->msgid = 0; iph1->flags = 0; iph1->ph2cnt = 0; -#ifdef HAVE_GSSAPI - iph1->gssapi_state = NULL; -#endif + #ifdef ENABLE_HYBRID if ((iph1->mode_cfg = isakmp_cfg_mkstate()) == NULL) { /* don't call remph1(iph1) until after insph1(iph1) is called */ - delph1(iph1); + ike_session_delph1(iph1); return -1; } #endif -#ifdef ENABLE_FRAG if(rmconf->ike_frag == ISAKMP_FRAG_FORCE) iph1->frag = 1; else iph1->frag = 0; iph1->frag_chain = NULL; -#endif iph1->approval = NULL; /* XXX copy remote address */ @@ -1226,31 +741,41 @@ isakmp_ph1begin_i(rmconf, remote, local, started_by_api) return -1; } - (void)insph1(iph1); - - if (ike_session_link_ph1_to_session(iph1) != 0) { - plog(LLV_DEBUG, LOCATION, NULL, "Failed to link ph1 to session\n"); - remph1(iph1); - delph1(iph1); + if (ike_session_link_phase1(session, iph1) != 0) { + plog(ASL_LEVEL_NOTICE, "Failed to link ph1 to session\n"); + ike_session_delph1(iph1); return -1; } + // HACK!!! to track rekeys across SIGHUPs + if (started_by_api == VPN_RESTARTED_BY_API && + !iph1->is_rekey) { + iph1->parent_session->established = 1; + iph1->parent_session->ikev1_state.ph2cnt++; + iph1->is_rekey = 1; + } /* start phase 1 exchange */ iph1->etype = rmconf->etypes->type; - - plog(LLV_DEBUG, LOCATION, NULL, "===\n"); + if (iph1->etype == ISAKMP_ETYPE_IDENT) + fsm_set_state(&iph1->status, IKEV1_STATE_IDENT_I_START); + else if (iph1->etype == ISAKMP_ETYPE_AGG) + fsm_set_state(&iph1->status, IKEV1_STATE_AGG_I_START); + else + return -1; + + plog(ASL_LEVEL_DEBUG, "===\n"); { char *a; - a = racoon_strdup(saddr2str(iph1->local)); + a = racoon_strdup(saddr2str((struct sockaddr *)iph1->local)); STRDUP_FATAL(a); - plog(LLV_INFO, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, "initiate new phase 1 negotiation: %s<=>%s\n", - a, saddr2str(iph1->remote)); + a, saddr2str((struct sockaddr *)iph1->remote)); racoon_free(a); } - plog(LLV_INFO, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, "begin %s mode.\n", s_isakmp_etype(iph1->etype)); @@ -1258,21 +783,18 @@ isakmp_ph1begin_i(rmconf, remote, local, started_by_api) gettimeofday(&iph1->start, NULL); gettimeofday(&start, NULL); #endif - /* start exchange */ - if ((ph1exchange[etypesw1(iph1->etype)] - [iph1->side] - [iph1->status])(iph1, NULL) != 0) { - /* failed to start phase 1 negotiation */ - remph1(iph1); - delph1(iph1); + IPSECLOGASLMSG("IPSec Phase 1 started (Initiated by me).\n"); + + if (fsm_ikev1_phase1_send_response(iph1, NULL)) { + ike_session_unlink_phase1(iph1); return -1; } #ifdef ENABLE_STATS gettimeofday(&end, NULL); syslog(LOG_NOTICE, "%s(%s): %8.6f", - "phase1", + "Phase 1", s_isakmp_state(iph1->etype, iph1->side, iph1->status), timedelta(&start, &end)); #endif @@ -1280,21 +802,19 @@ isakmp_ph1begin_i(rmconf, remote, local, started_by_api) #ifdef ENABLE_VPNCONTROL_PORT vpncontrol_notify_phase_change(1, FROM_LOCAL, iph1, NULL); #endif - return 0; } /* new negotiation of phase 1 for responder */ static int -isakmp_ph1begin_r(msg, remote, local, etype) - vchar_t *msg; - struct sockaddr *remote, *local; - u_int8_t etype; +ikev1_ph1begin_r(ike_session_t *session, vchar_t *msg, struct sockaddr_storage *remote, + struct sockaddr_storage *local, u_int8_t etype) { - struct isakmp *isakmp = (struct isakmp *)msg->v; + + struct isakmp *isakmp = (struct isakmp *)msg->v; struct remoteconf *rmconf; - struct ph1handle *iph1; + phase1_handle_t *iph1; struct etypes *etypeok; #ifdef ENABLE_STATS struct timeval start, end; @@ -1303,7 +823,7 @@ isakmp_ph1begin_r(msg, remote, local, etype) /* look for my configuration */ rmconf = getrmconf(remote); if (rmconf == NULL) { - plog(LLV_ERROR, LOCATION, remote, + plog(ASL_LEVEL_ERR, "couldn't find " "configuration.\n"); return -1; @@ -1312,60 +832,54 @@ isakmp_ph1begin_r(msg, remote, local, etype) /* check to be acceptable exchange type */ etypeok = check_etypeok(rmconf, etype); if (etypeok == NULL) { - plog(LLV_ERROR, LOCATION, remote, + plog(ASL_LEVEL_ERR, "not acceptable %s mode\n", s_isakmp_etype(etype)); return -1; } - + /* get new entry to isakmp status table. */ - iph1 = newph1(); + iph1 = ike_session_newph1(ISAKMP_VERSION_NUMBER_IKEV1); if (iph1 == NULL) return -1; memcpy(&iph1->index.i_ck, &isakmp->i_ck, sizeof(iph1->index.i_ck)); - iph1->status = PHASE1ST_START; iph1->rmconf = rmconf; -#ifdef __APPLE__ - if (link_rmconf_to_ph1(rmconf) < 0) { - plog(LLV_ERROR, LOCATION, remote, - "couldn't link " - "configuration.\n"); - iph1->rmconf = NULL; - /* don't call remph1(iph1) until after insph1(iph1) is called */ - delph1(iph1); - return -1; - } -#endif + retain_rmconf(iph1->rmconf); iph1->flags = 0; iph1->side = RESPONDER; iph1->started_by_api = 0; iph1->etype = etypeok->type; iph1->version = isakmp->v; iph1->msgid = 0; -#ifdef HAVE_GSSAPI - iph1->gssapi_state = NULL; -#endif + + if (iph1->etype == ISAKMP_ETYPE_IDENT) { + fsm_set_state(&iph1->status, IKEV1_STATE_IDENT_R_START); + } else if (iph1->etype == ISAKMP_ETYPE_AGG) { + fsm_set_state(&iph1->status, IKEV1_STATE_AGG_R_START); + } else { + ike_session_delph1(iph1); + return -1; + } + + #ifdef ENABLE_HYBRID if ((iph1->mode_cfg = isakmp_cfg_mkstate()) == NULL) { /* don't call remph1(iph1) until after insph1(iph1) is called */ - delph1(iph1); + ike_session_delph1(iph1); return -1; } #endif -#ifdef ENABLE_FRAG + iph1->frag = 0; iph1->frag_chain = NULL; -#endif iph1->approval = NULL; -#ifdef ENABLE_NATT /* RFC3947 says that we MUST accept new phases1 on NAT-T floated port. * We have to setup this flag now to correctly generate the first reply. * Don't know if a better check could be done for that ? */ if(extract_port(local) == lcconf->port_isakmp_natt) iph1->natt_flags |= (NAT_PORTS_CHANGED); -#endif /* copy remote address */ if (copy_ph1addresses(iph1, rmconf, remote, local) < 0) { @@ -1373,27 +887,25 @@ isakmp_ph1begin_r(msg, remote, local, etype) iph1 = NULL; /* deleted in copy_ph1addresses */ return -1; } - (void)insph1(iph1); - if (ike_session_link_ph1_to_session(iph1) != 0) { - remph1(iph1); - delph1(iph1); + if (ike_session_link_phase1(session, iph1) != 0) { + ike_session_delph1(iph1); return -1; } - plog(LLV_DEBUG, LOCATION, NULL, "===\n"); + plog(ASL_LEVEL_DEBUG, "===\n"); { char *a; - a = racoon_strdup(saddr2str(iph1->local)); + a = racoon_strdup(saddr2str((struct sockaddr *)iph1->local)); STRDUP_FATAL(a); - plog(LLV_INFO, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, "respond new phase 1 negotiation: %s<=>%s\n", - a, saddr2str(iph1->remote)); + a, saddr2str((struct sockaddr *)iph1->remote)); racoon_free(a); } - plog(LLV_INFO, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, "begin %s mode.\n", s_isakmp_etype(etype)); #ifdef ENABLE_STATS @@ -1401,96 +913,53 @@ isakmp_ph1begin_r(msg, remote, local, etype) gettimeofday(&start, NULL); #endif -#ifndef ENABLE_FRAG - - /* start exchange */ - if ((ph1exchange[etypesw1(iph1->etype)] - [iph1->side] - [iph1->status])(iph1, msg) < 0 - || (ph1exchange[etypesw1(iph1->etype)] - [iph1->side] - [iph1->status])(iph1, msg) < 0) { - plog(LLV_ERROR, LOCATION, remote, - "failed to process packet.\n"); - remph1(iph1); - delph1(iph1); - return -1; - } - -#ifdef ENABLE_STATS - gettimeofday(&end, NULL); - syslog(LOG_NOTICE, "%s(%s): %8.6f", - "phase1", - s_isakmp_state(iph1->etype, iph1->side, iph1->status), - timedelta(&start, &end)); -#endif -#ifdef ENABLE_VPNCONTROL_PORT - vpncontrol_notify_phase_change(1, FROM_REMOTE, iph1, NULL); -#endif - - return 0; - -#else /* ENABLE_FRAG */ + IPSECLOGASLMSG("IPSec Phase 1 started (Initiated by peer).\n"); /* now that we have a phase1 handle, feed back into our * main receive function to catch fragmented packets */ - - return isakmp_main(msg, remote, local); - -#endif /* ENABLE_FRAG */ - + isakmp_main(msg, remote, local); + return 0; } /* new negotiation of phase 2 for initiator */ static int -isakmp_ph2begin_i(iph1, iph2) - struct ph1handle *iph1; - struct ph2handle *iph2; +ikev1_ph2begin_i(phase1_handle_t *iph1, phase2_handle_t *iph2) { + #ifdef ENABLE_HYBRID if (xauth_check(iph1) != 0) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "Attempt to start phase 2 whereas Xauth failed\n"); return -1; } #endif /* found ISAKMP-SA. */ - plog(LLV_DEBUG, LOCATION, NULL, "===\n"); - plog(LLV_DEBUG, LOCATION, NULL, "begin QUICK mode.\n"); + plog(ASL_LEVEL_DEBUG, "===\n"); + plog(ASL_LEVEL_DEBUG, "begin QUICK mode.\n"); { char *a; - a = racoon_strdup(saddr2str(iph2->src)); + a = racoon_strdup(saddr2str((struct sockaddr *)iph2->src)); STRDUP_FATAL(a); - plog(LLV_INFO, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, "initiate new phase 2 negotiation: %s<=>%s\n", - a, saddr2str(iph2->dst)); + a, saddr2str((struct sockaddr *)iph2->dst)); racoon_free(a); } #ifdef ENABLE_STATS gettimeofday(&iph2->start, NULL); #endif - /* found isakmp-sa */ - if (iph2->ph1 && iph1 != iph2->ph1) { - plog(LLV_DEBUG2, LOCATION, NULL, "phase2 already bound in %s.\n",__FUNCTION__); - rebindph12(iph1, iph2); - } else if (!iph2->ph1) { - bindph12(iph1, iph2); - } + iph2->is_dying = 0; - if (ike_session_link_ph2_to_session(iph2) != 0) { - return -1; - } - iph2->status = PHASE2ST_STATUS2; + memcpy(&iph2->nat64_prefix, &iph1->nat64_prefix, sizeof(iph2->nat64_prefix)); + fsm_set_state(&iph2->status, IKEV1_STATE_QUICK_I_START); - if ((ph2exchange[etypesw2(ISAKMP_ETYPE_QUICK)] - [iph2->side] - [iph2->status])(iph2, NULL) < 0) { + IPSECLOGASLMSG("IPSec Phase 2 started (Initiated by me).\n"); + if (quick_iprep(iph2, NULL)) return -1; - } #ifdef ENABLE_VPNCONTROL_PORT vpncontrol_notify_phase_change(1, FROM_LOCAL, NULL, iph2); @@ -1501,48 +970,46 @@ isakmp_ph2begin_i(iph1, iph2) /* new negotiation of phase 2 for responder */ static int -isakmp_ph2begin_r(iph1, msg) - struct ph1handle *iph1; - vchar_t *msg; +ikev1_ph2begin_r(phase1_handle_t *iph1, vchar_t *msg) { struct isakmp *isakmp = (struct isakmp *)msg->v; - struct ph2handle *iph2 = 0; + phase2_handle_t *iph2 = 0; int error; #ifdef ENABLE_STATS struct timeval start, end; #endif #ifdef ENABLE_HYBRID if (xauth_check(iph1) != 0) { - plog(LLV_ERROR, LOCATION, NULL, - "Attempt to start phase 2 whereas Xauth failed\n"); + plog(ASL_LEVEL_ERR, + "Attempt to start Phase 2 whereas Xauth failed\n"); return -1; } #endif - iph2 = newph2(); + iph2 = ike_session_newph2(ISAKMP_VERSION_NUMBER_IKEV1, PHASE2_TYPE_SA); if (iph2 == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to allocate phase2 entry.\n"); + plog(ASL_LEVEL_ERR, + "failed to allocate Phase 2 entry.\n"); return -1; } - iph2->ph1 = iph1; iph2->side = RESPONDER; - iph2->status = PHASE2ST_START; + iph2->version = ISAKMP_VERSION_NUMBER_IKEV1; + fsm_set_state(&iph2->status, IKEV1_STATE_QUICK_R_START); iph2->flags = isakmp->flags; iph2->msgid = isakmp->msgid; iph2->seq = pk_getseq(); iph2->ivm = oakley_newiv2(iph1, iph2->msgid); if (iph2->ivm == NULL) { - delph2(iph2); + ike_session_delph2(iph2); return -1; } iph2->dst = dupsaddr(iph1->remote); /* XXX should be considered */ if (iph2->dst == NULL) { - delph2(iph2); + ike_session_delph2(iph2); return -1; } - switch (iph2->dst->sa_family) { + switch (iph2->dst->ss_family) { case AF_INET: #ifndef ENABLE_NATT ((struct sockaddr_in *)iph2->dst)->sin_port = 0; @@ -1556,18 +1023,18 @@ isakmp_ph2begin_r(iph1, msg) break; #endif default: - plog(LLV_ERROR, LOCATION, NULL, - "invalid family: %d\n", iph2->dst->sa_family); - delph2(iph2); + plog(ASL_LEVEL_ERR, + "invalid family: %d\n", iph2->dst->ss_family); + ike_session_delph2(iph2); return -1; } iph2->src = dupsaddr(iph1->local); /* XXX should be considered */ if (iph2->src == NULL) { - delph2(iph2); + ike_session_delph2(iph2); return -1; } - switch (iph2->src->sa_family) { + switch (iph2->src->ss_family) { case AF_INET: #ifndef ENABLE_NATT ((struct sockaddr_in *)iph2->src)->sin_port = 0; @@ -1581,33 +1048,27 @@ isakmp_ph2begin_r(iph1, msg) break; #endif default: - plog(LLV_ERROR, LOCATION, NULL, - "invalid family: %d\n", iph2->src->sa_family); - delph2(iph2); - return -1; - } - - /* add new entry to isakmp status table */ - insph2(iph2); - bindph12(iph1, iph2); - iph2->is_dying = 0; - if (ike_session_link_ph2_to_session(iph2) != 0) { - unbindph12(iph2); - remph2(iph2); - delph2(iph2); + plog(ASL_LEVEL_ERR, + "invalid family: %d\n", iph2->src->ss_family); + ike_session_delph2(iph2); return -1; } - plog(LLV_DEBUG, LOCATION, NULL, "===\n"); + if (ike_session_link_ph2_to_ph1(iph1, iph2)) + return -1; + iph2->is_dying = 0; + memcpy(&iph2->nat64_prefix, &iph1->nat64_prefix, sizeof(iph2->nat64_prefix)); + + plog(ASL_LEVEL_DEBUG, "===\n"); { char *a; - a = racoon_strdup(saddr2str(iph2->src)); + a = racoon_strdup(saddr2str((struct sockaddr *)iph2->src)); STRDUP_FATAL(a); - plog(LLV_INFO, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, "respond new phase 2 negotiation: %s<=>%s\n", - a, saddr2str(iph2->dst)); + a, saddr2str((struct sockaddr *)iph2->dst)); racoon_free(a); } @@ -1615,48 +1076,145 @@ isakmp_ph2begin_r(iph1, msg) gettimeofday(&start, NULL); #endif - error = (ph2exchange[etypesw2(ISAKMP_ETYPE_QUICK)] - [iph2->side] - [iph2->status])(iph2, msg); - if (error != 0) { - plog(LLV_ERROR, LOCATION, iph1->remote, - "failed to pre-process packet.\n"); - if (error != ISAKMP_INTERNAL_ERROR) - isakmp_info_send_n1(iph2->ph1, error, NULL); - /* - * release handler because it's wrong that ph2handle is kept - * after failed to check message for responder's. - */ - unbindph12(iph2); - remph2(iph2); - delph2(iph2); - return -1; - } + IPSECLOGASLMSG("IPSec Phase 2 started (Initiated by peer).\n"); - /* send */ - plog(LLV_DEBUG, LOCATION, NULL, "===\n"); - if ((ph2exchange[etypesw2(isakmp->etype)] - [iph2->side] - [iph2->status])(iph2, msg) < 0) { - plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "failed to process packet.\n"); - /* don't release handler */ - return -1; - } -#ifdef ENABLE_STATS - gettimeofday(&end, NULL); - syslog(LOG_NOTICE, "%s(%s): %8.6f", - "phase2", - s_isakmp_state(ISAKMP_ETYPE_QUICK, iph2->side, iph2->status), - timedelta(&start, &end)); + error = fsm_ikev1_phase2_process_payloads(iph2, msg); + if (error) + return error; + +#ifdef ENABLE_VPNCONTROL_PORT + vpncontrol_notify_phase_change(1, FROM_REMOTE, NULL, iph2); #endif + return 0; +} + +int +ikev1_phase1_established(phase1_handle_t *iph1) +{ + int spi_cmp; + u_int rekey_lifetime; + int ini_contact = iph1->rmconf->ini_contact; + +#ifdef ENABLE_STATS + gettimeofday(&iph1->end, NULL); + syslog(LOG_NOTICE, "%s(%s): %8.6f", + "Phase 1", s_isakmp_etype(iph1->etype), + timedelta(&iph1->start, &iph1->end)); +#endif + +#ifdef ENABLE_VPNCONTROL_PORT + + if (iph1->side == RESPONDER && + iph1->local->ss_family == AF_INET) { + + struct redirect *addr; + + LIST_FOREACH(addr, &lcconf->redirect_addresses, chain) { + if (((struct sockaddr_in *)iph1->local)->sin_addr.s_addr == addr->cluster_address) { + vchar_t *raddr = vmalloc(sizeof(u_int32_t)); + + if (raddr == NULL) { + plog(ASL_LEVEL_ERR, + "failed to send redirect message - memory error.\n"); + } else { + memcpy(raddr->v, &addr->redirect_address, sizeof(u_int32_t)); + (void)isakmp_info_send_n1(iph1, ISAKMP_NTYPE_LOAD_BALANCE, raddr); + plog(ASL_LEVEL_NOTICE, "sent redirect notification - address = %x.\n", ntohl(addr->redirect_address)); + vfree(raddr); + if (addr->force) { + (void)ike_session_update_ph1_ph2tree(iph1); + isakmp_ph1expire(iph1); + } + } + } + return 0; + } + } +#endif + /* save created date. */ + (void)time(&iph1->created); + + /* add to the schedule to expire, and save back pointer. */ + iph1->sce = sched_new(iph1->approval->lifetime, + isakmp_ph1expire_stub, iph1); + + if (iph1->rmconf->initiate_ph1rekey) { + if (iph1->side == INITIATOR) { + spi_cmp = memcmp(&iph1->index.i_ck, &iph1->index.r_ck, sizeof(iph1->index.i_ck)); + if (spi_cmp == 0) + spi_cmp = 1; + } else { + spi_cmp = memcmp(&iph1->index.r_ck, &iph1->index.i_ck, sizeof(iph1->index.r_ck)); + if (spi_cmp == 0) + spi_cmp = -1; + } + rekey_lifetime = ike_session_get_rekey_lifetime((spi_cmp > 0), + iph1->approval->lifetime); + if (rekey_lifetime) { + iph1->sce_rekey = sched_new(rekey_lifetime, + isakmp_ph1rekeyexpire_stub, + iph1); + } else { + /* iph1->approval->lifetime is too small (e.g. 1) so why bother? + * LOG ERROR + */ + plog(ASL_LEVEL_ERR, + "failed to get rekey timer - lifetime is too small... probably.\n"); + } + } + +#ifdef ENABLE_HYBRID + /* ignore xauth if it is a rekey */ + if (!iph1->is_rekey && + iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) { + switch(AUTHMETHOD(iph1)) { + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R: + xauth_sendreq(iph1); + /* XXX Don't process INITIAL_CONTACT */ + ini_contact = 0; + break; + default: + break; + } + } +#endif +#ifdef ENABLE_DPD + /* Schedule the r_u_there.... */ + if(iph1->dpd_support && iph1->rmconf->dpd_interval) + isakmp_sched_r_u(iph1, 0); +#endif + + /* INITIAL-CONTACT processing */ + /* ignore initial-contact if it is a rekey */ + /* don't send anything if local test mode. */ + if (!iph1->is_rekey && !f_local && ini_contact && !ike_session_getcontacted(iph1->remote)) { + /* send INITIAL-CONTACT */ + isakmp_info_send_n1(iph1, + ISAKMP_NTYPE_INITIAL_CONTACT, NULL); + /* insert a node into contacted list. */ + if (ike_session_inscontacted(iph1->remote) == -1) { + plog(ASL_LEVEL_ERR, + "failed to add contacted list.\n"); + /* ignore */ + } + } + + log_ph1established(iph1); + plog(ASL_LEVEL_DEBUG, "===\n"); + + ike_session_cleanup_other_established_ph1s(iph1->parent_session, iph1); + #ifdef ENABLE_VPNCONTROL_PORT - vpncontrol_notify_phase_change(1, FROM_REMOTE, NULL, iph2); + vpncontrol_notify_phase_change(0, FROM_LOCAL, iph1, NULL); + vpncontrol_notify_peer_resp_ph1(1, iph1); #endif - - - return 0; + + return 0; } /* @@ -1673,7 +1231,7 @@ isakmp_parsewoh(np0, gen, len) vchar_t *result; struct isakmp_parse_t *p, *ep; - plog(LLV_DEBUG, LOCATION, NULL, "begin.\n"); + plog(ASL_LEVEL_DEBUG, "begin.\n"); /* * 5 is a magic number, but any value larger than 2 should be fine @@ -1681,12 +1239,13 @@ isakmp_parsewoh(np0, gen, len) */ result = vmalloc(sizeof(struct isakmp_parse_t) * 5); if (result == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get buffer.\n"); return NULL; - } - p = (struct isakmp_parse_t *)result->v; - ep = (struct isakmp_parse_t *)(result->v + result->l - sizeof(*ep)); + } + // Wcast-align fix (void*) - result = aligned buffer of struct isakmp_parse_t + p = ALIGNED_CAST(struct isakmp_parse_t *)result->v; + ep = ALIGNED_CAST(struct isakmp_parse_t *)(result->v + result->l - sizeof(*ep)); tlen = len; @@ -1694,20 +1253,20 @@ isakmp_parsewoh(np0, gen, len) while (0 < tlen && np != ISAKMP_NPTYPE_NONE) { if (tlen <= sizeof(struct isakmp_gen)) { /* don't send information, see isakmp_ident_r1() */ - plog(LLV_ERROR, LOCATION, NULL, - "invalid length of payload\n"); + plog(ASL_LEVEL_ERR, + "isakmp_parsewoh invalid length of payload (1)\n"); vfree(result); return NULL; } - plog(LLV_DEBUG, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, "seen nptype=%u(%s)\n", np, s_isakmp_nptype(np)); p->type = np; p->len = ntohs(gen->len); if (p->len < sizeof(struct isakmp_gen) || p->len > tlen) { - plog(LLV_DEBUG, LOCATION, NULL, - "invalid length of payload\n"); + plog(ASL_LEVEL_NOTICE, + "isakmp_parsewoh invalid length of payload (2)\n"); vfree(result); return NULL; } @@ -1716,17 +1275,17 @@ isakmp_parsewoh(np0, gen, len) if (ep <= p) { int off; - off = p - (struct isakmp_parse_t *)result->v; + off = p - ALIGNED_CAST(struct isakmp_parse_t *)result->v; result = vrealloc(result, result->l * 2); if (result == NULL) { - plog(LLV_DEBUG, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, "failed to realloc buffer.\n"); vfree(result); return NULL; } - ep = (struct isakmp_parse_t *) + ep = ALIGNED_CAST(struct isakmp_parse_t *) (result->v + result->l - sizeof(*ep)); - p = (struct isakmp_parse_t *)result->v; + p = ALIGNED_CAST(struct isakmp_parse_t *)result->v; p += off; } @@ -1739,7 +1298,7 @@ isakmp_parsewoh(np0, gen, len) p->len = 0; p->ptr = NULL; - plog(LLV_DEBUG, LOCATION, NULL, "succeed.\n"); + plog(ASL_LEVEL_DEBUG, "succeed.\n"); return result; } @@ -1765,37 +1324,12 @@ isakmp_parse(buf) return result; } -/* %%% */ -#ifndef __APPLE__ int -isakmp_init() +isakmp_init(void) { - /* initialize a isakmp status table */ - initph1tree(); - initph2tree(); - initctdtree(); - init_recvdpkt(); - - if (isakmp_open() < 0) - goto err; - - return(0); -err: - isakmp_close(); - return(-1); -} -#else -int -isakmp_init(int ignore_phX) -{ - /* initialize a isakmp status table */ - if (!ignore_phX) { - initph1tree(); - initph2tree(); - } - initctdtree(); - init_recvdpkt(); + ike_session_initctdtree(); + ike_session_init_recvdpkt(); if (isakmp_open() < 0) goto err; @@ -1806,13 +1340,12 @@ err: isakmp_close(); return(-1); } -#endif /* __APPLE__ */ void isakmp_cleanup() { - clear_recvdpkt(); - clear_contacted(); + ike_session_clear_recvdpkt(); + ike_session_clear_contacted(); } /* @@ -1849,9 +1382,10 @@ isakmp_pindex(index, msgid) return buf; } + /* open ISAKMP sockets. */ int -isakmp_open() +isakmp_open(void) { const int yes = 1; int ifnum = 0, encap_ifnum = 0; @@ -1859,210 +1393,268 @@ isakmp_open() int pktinfo; #endif struct myaddrs *p; - + int tentative_failures = 0; + int s; + for (p = lcconf->myaddrs; p; p = p->next) { if (!p->addr) continue; - -#ifdef __APPLE__ if (p->sock != -1) { ifnum++; if (p->udp_encap) encap_ifnum++; continue; // socket already open } -#endif /* warn if wildcard address - should we forbid this? */ - switch (p->addr->sa_family) { + switch (p->addr->ss_family) { case AF_INET: if (((struct sockaddr_in *)p->addr)->sin_addr.s_addr == 0) - plog(LLV_WARNING, LOCATION, NULL, + plog(ASL_LEVEL_WARNING, "listening to wildcard address," "broadcast IKE packet may kill you\n"); break; #ifdef INET6 case AF_INET6: if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)p->addr)->sin6_addr)) - plog(LLV_WARNING, LOCATION, NULL, + plog(ASL_LEVEL_WARNING, "listening to wildcard address, " "broadcast IKE packet may kill you\n"); break; #endif default: - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "unsupported address family %d\n", lcconf->default_af); goto err_and_next; } #ifdef INET6 - if (p->addr->sa_family == AF_INET6 && + if (p->addr->ss_family == AF_INET6 && IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *) p->addr)->sin6_addr)) { - plog(LLV_DEBUG, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, "Ignoring multicast address %s\n", - saddr2str(p->addr)); + saddr2str((struct sockaddr *)p->addr)); racoon_free(p->addr); p->addr = NULL; continue; } #endif - if ((p->sock = socket(p->addr->sa_family, SOCK_DGRAM, 0)) < 0) { - plog(LLV_ERROR, LOCATION, NULL, + if ((p->sock = socket(p->addr->ss_family, SOCK_DGRAM, 0)) < 0) { + plog(ASL_LEVEL_ERR, "socket (%s)\n", strerror(errno)); goto err_and_next; } if (fcntl(p->sock, F_SETFL, O_NONBLOCK) == -1) - plog(LLV_WARNING, LOCATION, NULL, - "failed to put socket in non-blocking mode\n"); + plog(ASL_LEVEL_ERR, "failed to put socket in non-blocking mode\n"); /* receive my interface address on inbound packets. */ - switch (p->addr->sa_family) { - case AF_INET: + switch (p->addr->ss_family) { + case AF_INET: { + int ifindex = if_nametoindex(p->ifname); + if (ifindex != 0 && + setsockopt(p->sock, IPPROTO_IP, + IP_BOUND_IF, &ifindex, sizeof(ifindex)) < 0) { + plog(ASL_LEVEL_ERR, + "setsockopt IP_BOUND_IF (%s)\n", + strerror(errno)); + goto err_and_next; + } if (setsockopt(p->sock, IPPROTO_IP, -#ifdef __linux__ - IP_PKTINFO, -#else IP_RECVDSTADDR, -#endif (const void *)&yes, sizeof(yes)) < 0) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "setsockopt IP_RECVDSTADDR (%s)\n", strerror(errno)); goto err_and_next; } break; + } #ifdef INET6 - case AF_INET6: + case AF_INET6: { #ifdef INET6_ADVAPI -#ifdef IPV6_RECVPKTINFO pktinfo = IPV6_RECVPKTINFO; -#else /* old adv. API */ - pktinfo = IPV6_PKTINFO; -#endif /* IPV6_RECVPKTINFO */ #else pktinfo = IPV6_RECVDSTADDR; #endif + int ifindex = if_nametoindex(p->ifname); + if (ifindex != 0 && + setsockopt(p->sock, IPPROTO_IPV6, + IPV6_BOUND_IF, &ifindex, sizeof(ifindex)) < 0) { + plog(ASL_LEVEL_ERR, + "setsockopt IPV6_BOUND_IF (%s)\n", + strerror(errno)); + goto err_and_next; + } if (setsockopt(p->sock, IPPROTO_IPV6, pktinfo, (const void *)&yes, sizeof(yes)) < 0) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "setsockopt IPV6_RECVDSTADDR (%d):%s\n", pktinfo, strerror(errno)); goto err_and_next; } break; + } #endif } #ifdef IPV6_USE_MIN_MTU - if (p->addr->sa_family == AF_INET6 && + if (p->addr->ss_family == AF_INET6 && setsockopt(p->sock, IPPROTO_IPV6, IPV6_USE_MIN_MTU, (void *)&yes, sizeof(yes)) < 0) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "setsockopt IPV6_USE_MIN_MTU (%s)\n", strerror(errno)); return -1; } #endif - if (setsockopt_bypass(p->sock, p->addr->sa_family) < 0) + if (setsockopt_bypass(p->sock, p->addr->ss_family) < 0) goto err_and_next; -#ifdef __APPLE__ + if (setsockopt(p->sock, SOL_SOCKET, SO_REUSEADDR, (const void *)&yes, sizeof(yes)) < 0) { + plog(ASL_LEVEL_ERR, "setsockopt SO_REUSEADDR (%s)\n", strerror(errno)); + goto err_and_next; + } + + if (setsockopt(p->sock, SOL_SOCKET, SO_REUSEPORT, (const void *)&yes, sizeof(yes)) < 0) { + plog(ASL_LEVEL_ERR, "setsockopt SO_REUSEPORT (%s)\n", strerror(errno)); + goto err_and_next; + } + if (extract_port(p->addr) == PORT_ISAKMP) { if (setsockopt(p->sock, SOL_SOCKET, SO_NOTIFYCONFLICT, (void *)&yes, sizeof(yes)) < 0) { - plog(LLV_ERROR, LOCATION, p->addr, + plog(ASL_LEVEL_ERR, "setsockopt (%s)\n", strerror(errno)); goto err_and_next; } } -#endif - if (bind(p->sock, p->addr, sysdep_sa_len(p->addr)) < 0) { - plog(LLV_ERROR, LOCATION, p->addr, + if (bind(p->sock, (struct sockaddr *)p->addr, sysdep_sa_len((struct sockaddr *)p->addr)) < 0) { + int tmp_errno = errno; + plog(ASL_LEVEL_ERR, "failed to bind to address %s (%s).\n", - saddr2str(p->addr), strerror(errno)); + saddr2str((struct sockaddr *)p->addr), strerror(tmp_errno)); +#ifdef INET6 + // if bind failed b/c of a tentative v6 address, try again later + if (tmp_errno == EADDRNOTAVAIL && p->addr->ss_family == AF_INET6) { + struct in6_ifreq ifr6; + + bzero(&ifr6, sizeof(ifr6)); + strlcpy(ifr6.ifr_name, p->ifname, sizeof(ifr6.ifr_name)); + memcpy(&ifr6.ifr_addr, p->addr, sizeof(ifr6.ifr_addr)); + if (ioctl(p->sock, SIOCGIFAFLAG_IN6, &ifr6) >= 0) { + /* + * the tentative flag may have cleared between the bind() and ioctl() calls (i.e due to timing), so + * try infering that it was tentative from ensuring the absense other cases of EADDRNOTAVAIL. + */ + if ((ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_ANYCAST | IN6_IFF_DUPLICATED | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED)) == 0) { + // address may have been tentantive... invalidate sock but leave address around for another try later + plog(ASL_LEVEL_ERR, + "failed to bind to address %s: because interface address is/was not ready (flags %x).\n", + saddr2str((struct sockaddr *)p->addr), ifr6.ifr_ifru.ifru_flags6); + close(p->sock); + p->sock = -1; + tentative_failures = 1; + continue; + } else { + plog(ASL_LEVEL_ERR, + "failed to bind to address %s: because of interface address error, flags %x.\n", + saddr2str((struct sockaddr *)p->addr), ifr6.ifr_ifru.ifru_flags6); + } + } else { + plog(ASL_LEVEL_ERR, + "failed to bind to address %s: can't read interface address flags.\n", + saddr2str((struct sockaddr *)p->addr)); + } + } +#endif close(p->sock); p->sock = -1; goto err_and_next; } ifnum++; -#ifdef __APPLE__ if (p->udp_encap) encap_ifnum++; -#endif - - plog(LLV_INFO, LOCATION, NULL, + + s = p->sock; + + if (p->source != NULL) { + dispatch_source_cancel(p->source); + p->source = NULL; + } + p->source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, p->sock, 0, dispatch_get_main_queue()); + if (p->source == NULL) { + plog(ASL_LEVEL_ERR, "could not create isakmp socket source."); + return -1; + } + dispatch_source_set_event_handler(p->source, + ^{ + isakmp_handler(s); + }); + dispatch_source_t the_source = p->source; + dispatch_source_set_cancel_handler(p->source, + ^{ + close(s); + dispatch_release(the_source); + }); dispatch_resume(p->source); + + plog(ASL_LEVEL_NOTICE, "%s used as isakmp port (fd=%d)\n", - saddr2str(p->addr), p->sock); - -#ifndef __APPLE__ -#ifdef ENABLE_NATT - if (p->addr->sa_family == AF_INET) { - int option = -1; - - if(p->udp_encap) - option = UDP_ENCAP_ESPINUDP; -#if defined(ENABLE_NATT_00) || defined(ENABLE_NATT_01) - else - option = UDP_ENCAP_ESPINUDP_NON_IKE; -#endif - if(option != -1){ - if (setsockopt (p->sock, SOL_UDP, - UDP_ENCAP, &option, sizeof (option)) < 0) { - plog(LLV_WARNING, LOCATION, NULL, - "setsockopt(%s): UDP_ENCAP %s\n", - option == UDP_ENCAP_ESPINUDP ? "UDP_ENCAP_ESPINUDP" : "UDP_ENCAP_ESPINUDP_NON_IKE", - strerror(errno)); - goto skip_encap; - } - else { - plog(LLV_INFO, LOCATION, NULL, - "%s used for NAT-T\n", - saddr2str(p->addr)); - encap_ifnum++; - } - } - } -skip_encap: -#endif -#endif /* __APPLE__ */ - + saddr2str((struct sockaddr *)p->addr), p->sock); continue; err_and_next: racoon_free(p->addr); p->addr = NULL; - if (! lcconf->autograbaddr && lcconf->strict_address) + p->sock = -1; + if (! lcconf->autograbaddr && lcconf->strict_address) { return -1; + } + continue; } if (!ifnum) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "no address could be bound.\n"); + return -1; } #ifdef ENABLE_NATT if (natt_enabled_in_rmconf() && !encap_ifnum) { - plog(LLV_WARNING, LOCATION, NULL, + plog(ASL_LEVEL_WARNING, "NAT-T is enabled in at least one remote{} section,\n"); - plog(LLV_WARNING, LOCATION, NULL, + plog(ASL_LEVEL_WARNING, "but no 'isakmp_natt' address was specified!\n"); } #endif + if (tentative_failures) + sched_new(5, update_myaddrs, NULL); + return 0; } +void +isakmp_suspend_sockets() +{ + struct myaddrs *p; + + for (p = lcconf->myaddrs; p; p = p->next) { + if (p->source) + dispatch_suspend(p->source); + } +} + void isakmp_close() { @@ -2080,12 +1672,13 @@ isakmp_close_sockets() if (!p->addr) continue; - if (p->sock >= 0) { - close(p->sock); - p->sock = -1; - } + if (p->source) { + dispatch_source_cancel(p->source); + p->source = NULL; + p->in_use = 0; + p->sock = -1; + } } - } @@ -2099,25 +1692,26 @@ isakmp_close_unused() for (p = lcconf->myaddrs; p; p = next) { next = p->next; if (p->in_use == 0) { // not in use ? - - if (p->sock >= 0) - close(p->sock); - *prev = p->next; + if (p->source) { + dispatch_source_cancel(p->source); + p->source = NULL; + } + *prev = p->next; delmyaddr(p); } else - prev = &(p->next); + prev = &(p->next); } } int isakmp_send(iph1, sbuf) - struct ph1handle *iph1; + phase1_handle_t *iph1; vchar_t *sbuf; { int len = 0; int s; vchar_t *vbuf = NULL; - + #ifdef ENABLE_NATT size_t extralen = NON_ESP_MARKER_USE(iph1) ? NON_ESP_MARKER_LEN : 0; @@ -2131,38 +1725,38 @@ isakmp_send(iph1, sbuf) extralen = 0; #endif if (extralen) - plog (LLV_DEBUG, LOCATION, NULL, "Adding NON-ESP marker\n"); + plog (ASL_LEVEL_DEBUG, "Adding NON-ESP marker\n"); /* If NAT-T port floating is in use, 4 zero bytes (non-ESP marker) must added just before the packet itself. For this we must allocate a new buffer and release it at the end. */ if (extralen) { if ((vbuf = vmalloc (sbuf->l + extralen)) == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "vbuf allocation failed\n"); return -1; } - *(u_int32_t *)vbuf->v = 0; + *ALIGNED_CAST(u_int32_t *)vbuf->v = 0; memcpy (vbuf->v + extralen, sbuf->v, sbuf->l); sbuf = vbuf; } #endif /* select the socket to be sent */ - s = getsockmyaddr(iph1->local); + s = getsockmyaddr((struct sockaddr *)iph1->local); if (s == -1){ if ( vbuf != NULL ) vfree(vbuf); return -1; } - plog (LLV_DEBUG, LOCATION, NULL, "%zu bytes %s\n", sbuf->l, - saddr2str_fromto("from %s to %s", iph1->local, iph1->remote)); + plog (ASL_LEVEL_DEBUG, "%zu bytes %s\n", sbuf->l, + saddr2str_fromto("from %s to %s", (struct sockaddr *)iph1->local, (struct sockaddr *)iph1->remote)); #ifdef ENABLE_FRAG if (iph1->frag && sbuf->l > ISAKMP_FRAG_MAXLEN) { if (isakmp_sendfrags(iph1, sbuf) == -1) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "isakmp_sendfrags failed\n"); if ( vbuf != NULL ) vfree(vbuf); @@ -2174,7 +1768,7 @@ isakmp_send(iph1, sbuf) len = sendfromto(s, sbuf->v, sbuf->l, iph1->local, iph1->remote, lcconf->count_persend); if (len == -1) { - plog(LLV_ERROR, LOCATION, NULL, "sendfromto failed\n"); + plog(ASL_LEVEL_ERR, "sendfromto failed\n"); if ( vbuf != NULL ) vfree(vbuf); return -1; @@ -2192,76 +1786,62 @@ void isakmp_ph1resend_stub(p) void *p; { - struct ph1handle *iph1; + phase1_handle_t *iph1; - iph1=(struct ph1handle *)p; + iph1=(phase1_handle_t *)p; if(isakmp_ph1resend(iph1) < 0){ - if(iph1->scr != NULL){ + if(iph1->scr != 0){ /* Should not happen... */ - sched_kill(iph1->scr); - iph1->scr=NULL; + SCHED_KILL(iph1->scr); } - remph1(iph1); - delph1(iph1); + ike_session_unlink_phase1(iph1); } } int isakmp_ph1resend(iph1) - struct ph1handle *iph1; + phase1_handle_t *iph1; { + time_t retry_interval; + + // make sure there is a buffer to send + // isakmp_plist_set_all() could have returned NULL + if (iph1->sendbuf == NULL) + return -1; + /* Note: NEVER do the rem/del here, it will be done by the caller or by the _stub function */ if (iph1->retry_counter <= 0) { - IPSECSESSIONTRACEREVENT(iph1->parent_session, - IPSECSESSIONEVENTCODE_IKEV1_PH1_MAX_RETRANSMIT, - CONSTSTR("Phase1 Maximum Retransmits"), - CONSTSTR("Phase1 negotiation failed (Maximum retransmits)")); - - plog(LLV_ERROR, LOCATION, NULL, - "phase1 negotiation failed due to time up. %s\n", + plog(ASL_LEVEL_ERR, + "Phase 1 negotiation failed due to time up. %s\n", isakmp_pindex(&iph1->index, iph1->msgid)); - EVT_PUSH(iph1->local, iph1->remote, - EVTT_PEER_NO_RESPONSE, NULL); if (iph1->side == INITIATOR && iph1->is_rekey && iph1->parent_session && iph1->parent_session->is_client) { /* to get around a bug on the peer, in which rekeys to port 4500 are dropped */ if (isakmp_ph1rekeyretry(iph1) == 0) return 0; } return -1; + } else { + ike_session_ph1_retransmits(iph1); } if (isakmp_send(iph1, iph1->sendbuf) < 0){ - if (iph1->rmconf->retry_counter != iph1->retry_counter) { - IPSECSESSIONTRACEREVENT(iph1->parent_session, - IPSECSESSIONEVENTCODE_IKE_PACKET_TX_FAIL, - CONSTSTR("Phase1 Retransmit"), - CONSTSTR("Failed to retrasmit Phase1")); - } - plog(LLV_ERROR, LOCATION, iph1->remote, - "phase1 negotiation failed due to send error. %s\n", + plog(ASL_LEVEL_ERR, + "Phase 1 negotiation failed due to send error. %s\n", isakmp_pindex(&iph1->index, iph1->msgid)); - EVT_PUSH(iph1->local, iph1->remote, - EVTT_PEER_NO_RESPONSE, NULL); return -1; } - if (iph1->rmconf->retry_counter != iph1->retry_counter) { - IPSECSESSIONTRACEREVENT(iph1->parent_session, - IPSECSESSIONEVENTCODE_IKE_PACKET_TX_SUCC, - CONSTSTR("Phase1 Retransmit"), - CONSTSTR(NULL)); - } - - plog(LLV_DEBUG, LOCATION, iph1->remote, - "resend phase1 packet %s\n", + plog(ASL_LEVEL_NOTICE, + "Resend Phase 1 packet %s\n", isakmp_pindex(&iph1->index, iph1->msgid)); iph1->retry_counter--; - - iph1->scr = sched_new(iph1->rmconf->retry_interval, + retry_interval = ike_session_get_exp_retx_interval((iph1->rmconf->retry_counter - iph1->retry_counter), + iph1->rmconf->retry_interval); + iph1->scr = sched_new(retry_interval, isakmp_ph1resend_stub, iph1); return 0; @@ -2272,87 +1852,68 @@ void isakmp_ph2resend_stub(p) void *p; { - struct ph2handle *iph2; + phase2_handle_t *iph2; - iph2=(struct ph2handle *)p; + iph2=(phase2_handle_t *)p; if(isakmp_ph2resend(iph2) < 0){ - unbindph12(iph2); - remph2(iph2); - delph2(iph2); + ike_session_unlink_phase2(iph2); } } int isakmp_ph2resend(iph2) - struct ph2handle *iph2; + phase2_handle_t *iph2; { + time_t retry_interval; + /* Note: NEVER do the unbind/rem/del here, it will be done by the caller or by the _stub function */ //%%% BUG FIX - related to commit bit usage - crash happened here if (iph2->ph1 == 0) { - plog(LLV_ERROR, LOCATION, NULL, - "internal error - attempt to re-send phase2 with no phase1 bound.\n"); + plog(ASL_LEVEL_ERR, + "Internal error - attempt to re-send Phase 2 with no Phase 1 bound.\n"); return -1; } - - if (iph2->ph1->status == PHASE1ST_EXPIRED){ - IPSECSESSIONTRACEREVENT(iph2->ph1->parent_session, - IPSECSESSIONEVENTCODE_IKEV1_PH2_MAX_RETRANSMIT, - CONSTSTR("Underlying Phase1 expired"), - CONSTSTR("Failed to retransmit phase2 (underlying phase1 expired)")); - plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "phase2 negotiation failed due to phase1 expired. %s\n", + + if (FSM_STATE_IS_EXPIRED(iph2->ph1->status)){ + plog(ASL_LEVEL_ERR, + "Phase 2 negotiation failed due to Phase 1 expired. %s\n", isakmp_pindex(&iph2->ph1->index, iph2->msgid)); return -1; } if (iph2->retry_counter <= 0) { - IPSECSESSIONTRACEREVENT(iph2->ph1->parent_session, - IPSECSESSIONEVENTCODE_IKEV1_PH2_MAX_RETRANSMIT, - CONSTSTR("Phase2 maximum retransmits"), - CONSTSTR("Phase2 negotiation failed (maximum retransmits)")); - plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "phase2 negotiation failed due to time up. %s\n", + plog(ASL_LEVEL_ERR, + "Phase 2 negotiation failed due to time up. %s\n", isakmp_pindex(&iph2->ph1->index, iph2->msgid)); - EVT_PUSH(iph2->src, iph2->dst, EVTT_PEER_NO_RESPONSE, NULL); return -1; + } else { + ike_session_ph2_retransmits(iph2); } if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0){ - if (iph2->ph1->rmconf->retry_counter != iph2->retry_counter) { - IPSECSESSIONTRACEREVENT(iph2->ph1->parent_session, - IPSECSESSIONEVENTCODE_IKE_PACKET_TX_FAIL, - CONSTSTR("Phase2 Retransmit"), - CONSTSTR("Failed to retransmit Phase2 message")); - } - plog(LLV_ERROR, LOCATION, NULL, - "phase2 negotiation failed due to send error. %s\n", + plog(ASL_LEVEL_ERR, + "Phase 2 negotiation failed due to send error. %s\n", isakmp_pindex(&iph2->ph1->index, iph2->msgid)); - EVT_PUSH(iph2->src, iph2->dst, EVTT_PEER_NO_RESPONSE, NULL); return -1; } - if (iph2->ph1->rmconf->retry_counter != iph2->retry_counter) { - IPSECSESSIONTRACEREVENT(iph2->ph1->parent_session, - IPSECSESSIONEVENTCODE_IKE_PACKET_TX_SUCC, - CONSTSTR("Phase2 Retransmit"), - CONSTSTR(NULL)); - } - plog(LLV_DEBUG, LOCATION, NULL, - "resend phase2 packet %s\n", + plog(ASL_LEVEL_NOTICE, + "Resend Phase 2 packet %s\n", isakmp_pindex(&iph2->ph1->index, iph2->msgid)); iph2->retry_counter--; - - iph2->scr = sched_new(iph2->ph1->rmconf->retry_interval, + retry_interval = ike_session_get_exp_retx_interval((iph2->ph1->rmconf->retry_counter - iph2->ph1->retry_counter), + iph2->ph1->rmconf->retry_interval); + iph2->scr = sched_new(retry_interval, isakmp_ph2resend_stub, iph2); #ifdef ENABLE_DPD if (iph2->scr) { isakmp_reschedule_info_monitor_if_pending(iph2->ph1, - "phase2 packets sent to peer: retransmit timer armed"); + "Phase 2 packets sent to peer: retransmit timer armed"); } #endif /* DPD */ @@ -2365,40 +1926,41 @@ isakmp_ph1expire_stub(p) void *p; { - isakmp_ph1expire((struct ph1handle *)p); + isakmp_ph1expire((phase1_handle_t *)p); } void isakmp_ph1expire(iph1) - struct ph1handle *iph1; + phase1_handle_t *iph1; { char *src, *dst; + phase1_handle_t *new_iph1; SCHED_KILL(iph1->sce); #ifdef ENABLE_DPD SCHED_KILL(iph1->dpd_r_u); #endif - if(iph1->status != PHASE1ST_EXPIRED){ - src = racoon_strdup(saddr2str(iph1->local)); - dst = racoon_strdup(saddr2str(iph1->remote)); + if(!FSM_STATE_IS_EXPIRED(iph1->status)){ + src = racoon_strdup(saddr2str((struct sockaddr *)iph1->local)); + dst = racoon_strdup(saddr2str((struct sockaddr *)iph1->remote)); STRDUP_FATAL(src); STRDUP_FATAL(dst); - plog(LLV_INFO, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, "ISAKMP-SA expired %s-%s spi:%s\n", src, dst, isakmp_pindex(&iph1->index, 0)); racoon_free(src); racoon_free(dst); - iph1->status = PHASE1ST_EXPIRED; - (void)ike_session_update_ph1_ph2tree(iph1); + fsm_set_state(&iph1->status, IKEV1_STATE_PHASE1_EXPIRED); + new_iph1 = ike_session_update_ph1_ph2tree(iph1); } /* * the phase1 deletion is postponed until there is no phase2. */ - if (LIST_FIRST(&iph1->ph2tree) != NULL) { + if (LIST_FIRST(&iph1->bound_ph2tree) != NULL) { iph1->sce = sched_new(1, isakmp_ph1expire_stub, iph1); return; } @@ -2412,105 +1974,127 @@ isakmp_ph1rekeyexpire_stub(p) void *p; { - isakmp_ph1rekeyexpire((struct ph1handle *)p); + isakmp_ph1rekeyexpire((phase1_handle_t *)p, FALSE); } void -isakmp_ph1rekeyexpire(iph1) -struct ph1handle *iph1; +isakmp_ph1rekeyexpire(iph1, ignore_sess_drop_policy) +phase1_handle_t *iph1; +int ignore_sess_drop_policy; { char *src, *dst; struct remoteconf *rmconf; SCHED_KILL(iph1->sce_rekey); + // We are going to start the rekey. Let's fire off the + // phase1 expiration timer if it is not done yet. + if (!iph1->sce && iph1->approval->lifetimegap) { + iph1->sce = sched_new(iph1->approval->lifetimegap, + isakmp_ph1expire_stub, iph1); + } + // early exit if iph2->sce == NULL, iph2 isn't established or if entire session is going down - if (iph1->sce == NULL || - iph1->status != PHASE1ST_ESTABLISHED || + if (iph1->sce == 0 || + !FSM_STATE_IS_ESTABLISHED(iph1->status) || iph1->is_dying) { return; } - src = racoon_strdup(saddr2str(iph1->local)); - dst = racoon_strdup(saddr2str(iph1->remote)); + src = racoon_strdup(saddr2str((struct sockaddr *)iph1->local)); + dst = racoon_strdup(saddr2str((struct sockaddr *)iph1->remote)); STRDUP_FATAL(src); STRDUP_FATAL(dst); - plog(LLV_INFO, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, "ISAKMP-SA rekey-timer expired %s-%s spi:%s\n", src, dst, isakmp_pindex(&iph1->index, 0)); racoon_free(src); racoon_free(dst); + + if (!ignore_sess_drop_policy && ike_session_drop_rekey(iph1->parent_session, IKE_SESSION_REKEY_TYPE_PH1)) { + return; + } // exit if there is another ph1 that is established (with a pending rekey timer) if (ike_session_has_other_established_ph1(iph1->parent_session, iph1)) { - plog(LLV_INFO, LOCATION, iph1->remote, - "request for ISAKMP-SA rekey was ignored " + plog(ASL_LEVEL_NOTICE, + "Request for ISAKMP-SA rekey was ignored " "due to another established ph1.\n"); return; } // if there is another ph1 that is negotiating, postpone this rekey for a few seconds later if (ike_session_has_other_negoing_ph1(iph1->parent_session, iph1)) { - plog(LLV_DEBUG, LOCATION, NULL, "reschedule Phase1 rekey.\n"); + plog(ASL_LEVEL_DEBUG, "Reschedule Phase 1 rekey.\n"); iph1->sce_rekey = sched_new(1, isakmp_ph1rekeyexpire_stub, iph1); return; } - // get rmconf to initiate rekey with - rmconf = iph1->rmconf; - if (!rmconf || rmconf->to_delete || rmconf->to_remove) { - rmconf = getrmconf(iph1->remote); - } - if (rmconf) { - /* begin quick mode */ - plog(LLV_DEBUG, LOCATION, NULL, "begin Phase1 rekey.\n"); + // get rmconf to initiate rekey with + rmconf = iph1->rmconf; + if (!rmconf) + rmconf = getrmconf(iph1->remote); + + if (rmconf) { + /* begin quick mode */ + plog(ASL_LEVEL_NOTICE, "Begin Phase 1 rekey.\n"); /* start phase 1 negotiation as a initiator. */ - if (isakmp_ph1begin_i(rmconf, iph1->remote, iph1->local, 0) < 0) { - plog(LLV_DEBUG, LOCATION, NULL, "Phase1 rekey Failed.\n"); + if (ikev1_ph1begin_i(iph1->parent_session, rmconf, iph1->remote, iph1->local, 0, &iph1->nat64_prefix) < 0) { + plog(ASL_LEVEL_NOTICE, "Phase 1 rekey Failed.\n"); } + iph1->is_rekey = TRUE; } else { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "Phase1 rekey failed: no configuration found for %s.\n", - saddrwop2str(iph1->remote)); + saddrwop2str((struct sockaddr *)iph1->remote)); } } int isakmp_ph1rekeyretry(iph1) -struct ph1handle *iph1; +phase1_handle_t *iph1; { char *src, *dst; struct remoteconf *rmconf; // this code path is meant for floated ph1 rekeys that are failing on the first message - if (iph1->sce != NULL || - iph1->sce_rekey != NULL || - (iph1->status != PHASE1ST_MSG1SENT || (iph1->natt_flags & NAT_PORTS_CHANGED == 0)) || - (extract_port(iph1->local) != PORT_ISAKMP_NATT && extract_port(iph1->remote) != PORT_ISAKMP_NATT) || - iph1->is_dying) { + if (iph1->sce != 0 || + iph1->sce_rekey != 0 || + ((iph1->status != IKEV1_STATE_IDENT_I_MSG1SENT && + iph1->status != IKEV1_STATE_AGG_I_MSG1SENT) + || ((iph1->natt_flags & NAT_PORTS_CHANGED) == 0)) + || (extract_port(iph1->local) != PORT_ISAKMP_NATT && extract_port(iph1->remote) != PORT_ISAKMP_NATT) + || iph1->is_dying) { return -1; } - src = racoon_strdup(saddr2str(iph1->local)); - dst = racoon_strdup(saddr2str(iph1->remote)); + src = racoon_strdup(saddr2str((struct sockaddr *)iph1->local)); + dst = racoon_strdup(saddr2str((struct sockaddr *)iph1->remote)); STRDUP_FATAL(src); STRDUP_FATAL(dst); - plog(LLV_INFO, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, "ISAKMP-SA rekey failed... retrying %s-%s spi:%s\n", src, dst, isakmp_pindex(&iph1->index, 0)); racoon_free(src); racoon_free(dst); + if (ike_session_drop_rekey(iph1->parent_session, IKE_SESSION_REKEY_TYPE_PH1)) { + plog(ASL_LEVEL_NOTICE, + "request for ISAKMP-SA rekey was ignored " + "due to idleness.\n"); + return 0; + } + // exit if there is another ph1 that is established (with a pending rekey timer) if (ike_session_has_other_established_ph1(iph1->parent_session, iph1)) { - plog(LLV_INFO, LOCATION, iph1->remote, + plog(ASL_LEVEL_NOTICE, "request to retry ISAKMP-SA rekey was ignored " "due to another established ph1.\n"); return -1; @@ -2527,17 +2111,18 @@ struct ph1handle *iph1; rmconf = getrmconf(iph1->remote); if (rmconf) { /* begin quick mode */ - plog(LLV_DEBUG, LOCATION, NULL, "begin Phase1 rekey retry.\n"); + plog(ASL_LEVEL_NOTICE, "begin Phase 1 rekey retry.\n"); /* start phase 1 negotiation as a initiator. */ - if (isakmp_ph1begin_i(rmconf, iph1->remote, iph1->local, 0) < 0) { - plog(LLV_DEBUG, LOCATION, NULL, "Phase1 rekey retry Failed.\n"); + if (ikev1_ph1begin_i(iph1->parent_session, rmconf, iph1->remote, iph1->local, 0, &iph1->nat64_prefix) < 0) { + plog(ASL_LEVEL_NOTICE, "Phase 1 rekey retry Failed.\n"); return -1; } + iph1->is_rekey = TRUE; } else { - plog(LLV_ERROR, LOCATION, NULL, - "Phase1 rekey retry failed: no configuration found for %s.\n", - saddrwop2str(iph1->remote)); + plog(ASL_LEVEL_ERR, + "Phase 1 rekey retry failed: no configuration found for %s.\n", + saddrwop2str((struct sockaddr *)iph1->remote)); return -1; } return 0; @@ -2549,12 +2134,12 @@ isakmp_ph1delete_stub(p) void *p; { - isakmp_ph1delete((struct ph1handle *)p); + isakmp_ph1delete((phase1_handle_t *)p); } void isakmp_ph1delete(iph1) - struct ph1handle *iph1; + phase1_handle_t *iph1; { char *src, *dst; @@ -2564,29 +2149,30 @@ isakmp_ph1delete(iph1) SCHED_KILL(iph1->dpd_r_u); #endif - if (LIST_FIRST(&iph1->ph2tree) != NULL) { + if (LIST_FIRST(&iph1->bound_ph2tree) != NULL) { iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1); return; } - + isakmp_info_send_d1(iph1); /* don't re-negosiation when the phase 1 SA expires. */ - src = racoon_strdup(saddr2str(iph1->local)); - dst = racoon_strdup(saddr2str(iph1->remote)); + src = racoon_strdup(saddr2str((struct sockaddr *)iph1->local)); + dst = racoon_strdup(saddr2str((struct sockaddr *)iph1->remote)); STRDUP_FATAL(src); STRDUP_FATAL(dst); - plog(LLV_INFO, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, + "ISAKMP-SA deleted spi:%s\n", + isakmp_pindex(&iph1->index, 0)); + plog(ASL_LEVEL_DEBUG, "ISAKMP-SA deleted %s-%s spi:%s\n", src, dst, isakmp_pindex(&iph1->index, 0)); - EVT_PUSH(iph1->local, iph1->remote, EVTT_PHASE1_DOWN, NULL); racoon_free(src); racoon_free(dst); - - remph1(iph1); - delph1(iph1); + + ike_session_unlink_phase1(iph1); return; } @@ -2602,45 +2188,48 @@ isakmp_ph2expire_stub(p) void *p; { - isakmp_ph2expire((struct ph2handle *)p); + isakmp_ph2expire((phase2_handle_t *)p); } void isakmp_ph2expire(iph2) - struct ph2handle *iph2; + phase2_handle_t *iph2; { char *src, *dst; + if (FSM_STATE_IS_EXPIRED(iph2->status)) { + return; + } + SCHED_KILL(iph2->sce); - src = racoon_strdup(saddrwop2str(iph2->src)); - dst = racoon_strdup(saddrwop2str(iph2->dst)); + src = racoon_strdup(saddrwop2str((struct sockaddr *)iph2->src)); + dst = racoon_strdup(saddrwop2str((struct sockaddr *)iph2->dst)); STRDUP_FATAL(src); STRDUP_FATAL(dst); - plog(LLV_INFO, LOCATION, NULL, - "phase2 sa expired %s-%s\n", src, dst); + plog(ASL_LEVEL_NOTICE, + "Phase 2 sa expired %s-%s\n", src, dst); racoon_free(src); racoon_free(dst); // delete outgoing SAs - if (iph2->status == PHASE2ST_ESTABLISHED && iph2->approval) { + if (FSM_STATE_IS_ESTABLISHED(iph2->status) && iph2->approval) { struct saproto *pr; for (pr = iph2->approval->head; pr != NULL; pr = pr->next) { if (pr->ok) { pfkey_send_delete(lcconf->sock_pfkey, - ipsecdoi2pfkey_proto(pr->proto_id), - IPSEC_MODE_ANY, - iph2->src, iph2->dst, pr->spi_p /* pr->reqid_out */); + ipsecdoi2pfkey_proto(pr->proto_id), + IPSEC_MODE_ANY, + iph2->src, iph2->dst, pr->spi_p /* pr->reqid_out */); } } } - - iph2->status = PHASE2ST_EXPIRED; - + if (iph2->version == ISAKMP_VERSION_NUMBER_IKEV1) + fsm_set_state(&iph2->status, IKEV1_STATE_PHASE2_EXPIRED); iph2->sce = sched_new(1, isakmp_ph2delete_stub, iph2); - + return; } @@ -2650,30 +2239,28 @@ isakmp_ph2delete_stub(p) void *p; { - isakmp_ph2delete((struct ph2handle *)p); + isakmp_ph2delete((phase2_handle_t *)p); } void isakmp_ph2delete(iph2) - struct ph2handle *iph2; + phase2_handle_t *iph2; { char *src, *dst; SCHED_KILL(iph2->sce); - src = racoon_strdup(saddrwop2str(iph2->src)); - dst = racoon_strdup(saddrwop2str(iph2->dst)); + src = racoon_strdup(saddrwop2str((struct sockaddr *)iph2->src)); + dst = racoon_strdup(saddrwop2str((struct sockaddr *)iph2->dst)); STRDUP_FATAL(src); STRDUP_FATAL(dst); - plog(LLV_INFO, LOCATION, NULL, - "phase2 sa deleted %s-%s\n", src, dst); + plog(ASL_LEVEL_NOTICE, + "Phase 2 sa deleted %s-%s\n", src, dst); racoon_free(src); racoon_free(dst); - unbindph12(iph2); - remph2(iph2); - delph2(iph2); + ike_session_unlink_phase2(iph2); return; } @@ -2686,98 +2273,90 @@ isakmp_ph2delete(iph2) * if phase1 has been finished, begin phase2. */ int -isakmp_post_acquire(iph2) - struct ph2handle *iph2; +isakmp_post_acquire(phase2_handle_t *iph2) { struct remoteconf *rmconf; - struct ph1handle *iph1 = NULL; + phase1_handle_t *iph1 = NULL; - plog(LLV_DEBUG, LOCATION, NULL, "in post_acquire\n"); + plog(ASL_LEVEL_DEBUG, "In post_acquire\n"); /* search appropreate configuration with masking port. */ rmconf = getrmconf(iph2->dst); if (rmconf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "no configuration found for %s.\n", - saddrwop2str(iph2->dst)); + plog(ASL_LEVEL_ERR, + "No configuration found for %s.\n", + saddrwop2str((struct sockaddr *)iph2->dst)); return -1; } - /* if passive mode, ignore the acquire message */ if (rmconf->passive) { - plog(LLV_DEBUG, LOCATION, NULL, - "because of passive mode, " - "ignore the acquire message for %s.\n", - saddrwop2str(iph2->dst)); + plog(ASL_LEVEL_NOTICE, + "Because of passive mode, ignore the acquire message for %s.\n", + saddrwop2str((struct sockaddr *)iph2->dst)); return 0; } - if (ike_session_verify_ph2_parent_session(iph2)) { - plog(LLV_INFO, LOCATION, iph2->dst, - "request for establishing IPsec-SA was ignored " - "because there was a failure verifying parent session.\n"); - return -1; - } - - // what if there is another ph2 that is negotiating - if (ike_session_has_other_negoing_ph2(iph2->parent_session, iph2)) { - // TODO: postpone this rekey for a second later - plog(LLV_INFO, LOCATION, iph2->dst, - "request for establishing IPsec-SA was ignored " - "due to another negoing ph2.\n"); - return -1; - } + + // what if there is another ph2 that is negotiating + if (ike_session_has_other_negoing_ph2(iph2->parent_session, iph2)) { + // TODO: postpone this rekey for a second later + plog(ASL_LEVEL_NOTICE, + "Request for establishing IPsec-SA was ignored due to another negoing ph2.\n"); + return -1; + } // if this is a phase2 rekeys (the policy may not have the current port number). // so, use the appropriate ports. if (iph2->is_rekey) { ike_session_update_ph2_ports(iph2); } + if (iph2->version == ISAKMP_VERSION_NUMBER_IKEV1) + iph1 = ike_session_update_ph2_ph1bind(iph2); - iph1 = ike_session_update_ph2_ph1bind(iph2); - - /* no ISAKMP-SA found. */ + /* no IKE-SA found. */ if (iph1 == NULL) { - struct sched *sc; - iph2->retry_checkph1 = lcconf->retry_checkph1; - sc = sched_new(1, isakmp_chkph1there_stub, iph2); - plog(LLV_INFO, LOCATION, NULL, - "IPsec-SA request for %s queued " - "due to no phase1 found.\n", - saddrwop2str(iph2->dst)); - + /* start phase 1 negotiation as a initiator. */ - if (isakmp_ph1begin_i(rmconf, iph2->dst, iph2->src, 0) < 0) { - SCHED_KILL(sc); - return -1; + sched_new(1, isakmp_chkph1there_stub, iph2); + + plog(ASL_LEVEL_NOTICE, + "IPsec-SA request for %s queued due to no Phase 1 found.\n", + saddrwop2str((struct sockaddr *)iph2->dst)); + + // exit if there is another ph1 that is established (with a pending rekey timer) + if (ike_session_has_negoing_ph1(iph2->parent_session)) { + plog(ASL_LEVEL_NOTICE, + "Request for Phase 1 was ignored due to another negotiating Phase 1.\n"); + return 0; + } + + if (ikev1_ph1begin_i(iph2->parent_session, rmconf, iph2->dst, iph2->src, 0, &iph2->nat64_prefix) < 0) { + plog(ASL_LEVEL_NOTICE, + "Request for Phase 1 failed. Will try later.\n"); } - return 0; /*NOTREACHED*/ } /* found ISAKMP-SA, but on negotiation. */ - if (iph1->status != PHASE1ST_ESTABLISHED) { + if (!FSM_STATE_IS_ESTABLISHED(iph1->status)) { iph2->retry_checkph1 = lcconf->retry_checkph1; sched_new(1, isakmp_chkph1there_stub, iph2); - plog(LLV_INFO, LOCATION, iph2->dst, - "request for establishing IPsec-SA was queued " - "due to no phase1 found.\n"); + plog(ASL_LEVEL_NOTICE, + "Request for establishing IPsec-SA was queued due to no phase1 found.\n"); return 0; /*NOTREACHED*/ } /* found established ISAKMP-SA */ - /* i.e. iph1->status == PHASE1ST_ESTABLISHED */ /* found ISAKMP-SA. */ - plog(LLV_DEBUG, LOCATION, NULL, "begin QUICK mode.\n"); /* begin quick mode */ - if (isakmp_ph2begin_i(iph1, iph2)) + plog(ASL_LEVEL_NOTICE, "Begin QUICK mode.\n"); + if (ikev1_ph2begin_i(iph1, iph2)) return -1; - return 0; } @@ -2785,32 +2364,41 @@ isakmp_post_acquire(iph2) * receive GETSPI from kernel. */ int -isakmp_post_getspi(iph2) - struct ph2handle *iph2; +isakmp_post_getspi(phase2_handle_t *iph2) { #ifdef ENABLE_STATS struct timeval start, end; #endif - - /* don't process it because there is no suitable phase1-sa. */ - if (iph2->ph1->status == PHASE1ST_EXPIRED) { - plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "the negotiation is stopped, " - "because there is no suitable ISAKMP-SA.\n"); - return -1; - } - + int error = 0; + + /* don't process it because there is no suitable phase1-sa. */ + if (FSM_STATE_IS_EXPIRED(iph2->ph1->status)) { + plog(ASL_LEVEL_ERR, + "the negotiation is stopped, " + "because there is no suitable ISAKMP-SA.\n"); + return -1; + } + fsm_set_state(&iph2->status, iph2->side == INITIATOR ? + IKEV1_STATE_QUICK_I_GETSPIDONE : IKEV1_STATE_QUICK_R_GETSPIDONE); + #ifdef ENABLE_STATS - gettimeofday(&start, NULL); -#endif - if ((ph2exchange[etypesw2(ISAKMP_ETYPE_QUICK)] - [iph2->side] - [iph2->status])(iph2, NULL) != 0) + gettimeofday(&start, NULL); +#endif + switch (iph2->side) { + case INITIATOR: + error = quick_i1send(iph2, NULL); + break; + case RESPONDER: + error = quick_r2send(iph2, NULL); + break; + } + + if (error) //%%%%%%%% log something ??? return -1; #ifdef ENABLE_STATS gettimeofday(&end, NULL); - syslog(LOG_NOTICE, "%s(%s): %8.6f", - "phase2", + plog(ASL_LEVEL_NOTICE, "%s(%s): %8.6f", + "Phase 2", s_isakmp_state(ISAKMP_ETYPE_QUICK, iph2->side, iph2->status), timedelta(&start, &end)); #endif @@ -2823,41 +2411,44 @@ void isakmp_chkph1there_stub(p) void *p; { - isakmp_chkph1there((struct ph2handle *)p); + isakmp_chkph1there((phase2_handle_t *)p); } void isakmp_chkph1there(iph2) - struct ph2handle *iph2; + phase2_handle_t *iph2; { - struct ph1handle *iph1; + phase1_handle_t *iph1; + + if ((iph2->version == ISAKMP_VERSION_NUMBER_IKEV1 && iph2->status != IKEV1_STATE_QUICK_I_START) || + iph2->is_dying) { + plog(ASL_LEVEL_NOTICE, "CHKPH1THERE: ph2 handle has advanced too far (status %d, START %d, dying %d)... ignoring\n", iph2->status, IKEV1_STATE_QUICK_I_START, iph2->is_dying); + return; + } iph2->retry_checkph1--; - if (iph2->retry_checkph1 < 0 || - ike_session_verify_ph2_parent_session(iph2)) { + + if (iph2->retry_checkph1 < 0 /* %%%%|| + ike_session_verify_ph2_parent_session(iph2) */) { if (iph2->retry_checkph1 < 0) { - plog(LLV_ERROR, LOCATION, iph2->dst, - "phase2 negotiation failed " - "due to time up waiting for phase1. %s\n", + plog(ASL_LEVEL_ERR, + "Phase 2 negotiation failed " + "due to time up waiting for Phase 1. %s\n", sadbsecas2str(iph2->dst, iph2->src, iph2->satype, 0, 0)); } else { - plog(LLV_ERROR, LOCATION, iph2->dst, - "phase2 negotiation failed " + plog(ASL_LEVEL_ERR, + "Phase 2 negotiation failed " "due to invalid parent session. %s\n", sadbsecas2str(iph2->dst, iph2->src, iph2->satype, 0, 0)); } - plog(LLV_INFO, LOCATION, NULL, - "delete phase 2 handler.\n"); + plog(ASL_LEVEL_NOTICE, + "delete Phase 2 handler.\n"); /* send acquire to kernel as error */ pk_sendeacquire(iph2); - - unbindph12(iph2); - remph2(iph2); - delph2(iph2); - + ike_session_unlink_phase2(iph2); return; } @@ -2866,39 +2457,40 @@ isakmp_chkph1there(iph2) /* XXX Even if ph1 as responder is there, should we not start * phase 2 negotiation ? */ if (iph1 != NULL - && iph1->status == PHASE1ST_ESTABLISHED) { + && FSM_STATE_IS_ESTABLISHED(iph1->status)) { /* found isakmp-sa */ - plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: got a ph1 handler, setting ports.\n"); - plog(LLV_DEBUG2, LOCATION, NULL, "iph1->local: %s\n", saddr2str(iph1->local)); - plog(LLV_DEBUG2, LOCATION, NULL, "iph1->remote: %s\n", saddr2str(iph1->remote)); - plog(LLV_DEBUG2, LOCATION, NULL, "before:\n"); - plog(LLV_DEBUG2, LOCATION, NULL, "src: %s\n", saddr2str(iph2->src)); - plog(LLV_DEBUG2, LOCATION, NULL, "dst: %s\n", saddr2str(iph2->dst)); + plog(ASL_LEVEL_DEBUG, "CHKPH1THERE: got a ph1 handler, setting ports.\n"); + plog(ASL_LEVEL_DEBUG, "iph1->local: %s\n", saddr2str((struct sockaddr *)iph1->local)); + plog(ASL_LEVEL_DEBUG, "iph1->remote: %s\n", saddr2str((struct sockaddr *)iph1->remote)); + plog(ASL_LEVEL_DEBUG, "before:\n"); + plog(ASL_LEVEL_DEBUG, "src: %s\n", saddr2str((struct sockaddr *)iph2->src)); + plog(ASL_LEVEL_DEBUG, "dst: %s\n", saddr2str((struct sockaddr *)iph2->dst)); set_port(iph2->src, extract_port(iph1->local)); set_port(iph2->dst, extract_port(iph1->remote)); - plog(LLV_DEBUG2, LOCATION, NULL, "After:\n"); - plog(LLV_DEBUG2, LOCATION, NULL, "src: %s\n", saddr2str(iph2->src)); - plog(LLV_DEBUG2, LOCATION, NULL, "dst: %s\n", saddr2str(iph2->dst)); + plog(ASL_LEVEL_DEBUG, "After:\n"); + plog(ASL_LEVEL_DEBUG, "src: %s\n", saddr2str((struct sockaddr *)iph2->src)); + plog(ASL_LEVEL_DEBUG, "dst: %s\n", saddr2str((struct sockaddr *)iph2->dst)); /* begin quick mode */ - if (isakmp_ph2begin_i(iph1, iph2)) { - unbindph12(iph2); - remph2(iph2); - delph2(iph2); + if (ikev1_ph2begin_i(iph1, iph2)) { + ike_session_unlink_phase2(iph2); } return; } if (!ike_session_has_negoing_ph1(iph2->parent_session)) { struct remoteconf *rmconf = getrmconf(iph2->dst); /* start phase 1 negotiation as a initiator. */ - if (rmconf == NULL || - isakmp_ph1begin_i(rmconf, iph2->dst, iph2->src, 0) < 0) { - plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: no established/negoing ph1 handler found... failed to initiate new one\n"); + if (rmconf) { + if (ikev1_ph1begin_i(iph2->parent_session, rmconf, iph2->dst, iph2->src, 0, iph1 != NULL ? &iph1->nat64_prefix : NULL) < 0) { + plog(ASL_LEVEL_NOTICE, "CHKPH1THERE: no established/negoing ph1 handler found... failed to initiate new one\n"); + } + } else if (rmconf == NULL) { + plog(ASL_LEVEL_NOTICE, "CHKPH1THERE: no remoteconf found... failed to initiate new one\n"); } } - plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: no established ph1 handler found\n"); + plog(ASL_LEVEL_NOTICE, "CHKPH1THERE: no established ph1 handler found\n"); /* no isakmp-sa found */ sched_new(1, isakmp_chkph1there_stub, iph2); @@ -2961,7 +2553,7 @@ isakmp_add_attr_v(buf0, type, val, len) } else buf = vmalloc(tlen); if (!buf) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get a attribute buffer.\n"); return NULL; } @@ -2994,7 +2586,7 @@ isakmp_add_attr_l(buf0, type, val) } else buf = vmalloc(tlen); if (!buf) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get a attribute buffer.\n"); return NULL; } @@ -3012,8 +2604,8 @@ isakmp_add_attr_l(buf0, type, val) int isakmp_newcookie(place, remote, local) caddr_t place; - struct sockaddr *remote; - struct sockaddr *local; + struct sockaddr_storage *remote; + struct sockaddr_storage *local; { vchar_t *buf = NULL, *buf2 = NULL; char *p; @@ -3025,13 +2617,13 @@ isakmp_newcookie(place, remote, local) u_short port; - if (remote->sa_family != local->sa_family) { - plog(LLV_ERROR, LOCATION, NULL, + if (remote->ss_family != local->ss_family) { + plog(ASL_LEVEL_ERR, "address family mismatch, remote:%d local:%d\n", - remote->sa_family, local->sa_family); + remote->ss_family, local->ss_family); goto end; } - switch (remote->sa_family) { + switch (remote->ss_family) { case AF_INET: alen = sizeof(struct in_addr); sa1 = (caddr_t)&((struct sockaddr_in *)remote)->sin_addr; @@ -3045,15 +2637,15 @@ isakmp_newcookie(place, remote, local) break; #endif default: - plog(LLV_ERROR, LOCATION, NULL, - "invalid family: %d\n", remote->sa_family); + plog(ASL_LEVEL_ERR, + "invalid family: %d\n", remote->ss_family); goto end; } blen = (alen + sizeof(u_short)) * 2 + sizeof(time_t) + lcconf->secret_size; buf = vmalloc(blen); if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get a cookie.\n"); goto end; } @@ -3090,7 +2682,7 @@ isakmp_newcookie(place, remote, local) memcpy(place, buf2->v, sizeof(cookie_t)); sa1 = val2str(place, sizeof (cookie_t)); - plog(LLV_DEBUG, LOCATION, NULL, "new cookie:\n%s\n", sa1); + plog(ASL_LEVEL_DEBUG, "new cookie:\n%s\n", sa1); racoon_free(sa1); error = 0; @@ -3112,14 +2704,21 @@ isakmp_p2ph(buf, gen) { /* XXX to be checked in each functions for logging. */ if (*buf) { - plog(LLV_WARNING, LOCATION, NULL, + plog(ASL_LEVEL_WARNING, "ignore this payload, same payload type exist.\n"); return -1; } + if (ntohs(gen->len) < sizeof(*gen)) { + plog(ASL_LEVEL_ERR, + "ignore this payload, invalid payload len %d.\n", + ntohs(gen->len)); + return -1; + } + *buf = vmalloc(ntohs(gen->len) - sizeof(*gen)); if (*buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get buffer.\n"); return -1; } @@ -3130,13 +2729,13 @@ isakmp_p2ph(buf, gen) u_int32_t isakmp_newmsgid2(iph1) - struct ph1handle *iph1; + phase1_handle_t *iph1; { u_int32_t msgid2; do { msgid2 = eay_random(); - } while (getph2bymsgid(iph1, msgid2)); + } while (ike_session_getph2bymsgid(iph1, msgid2)); return msgid2; } @@ -3147,7 +2746,7 @@ isakmp_newmsgid2(iph1) static caddr_t set_isakmp_header(vbuf, iph1, nptype, etype, flags, msgid) vchar_t *vbuf; - struct ph1handle *iph1; + phase1_handle_t *iph1; int nptype; u_int8_t etype; u_int8_t flags; @@ -3178,7 +2777,7 @@ set_isakmp_header(vbuf, iph1, nptype, etype, flags, msgid) caddr_t set_isakmp_header1(vbuf, iph1, nptype) vchar_t *vbuf; - struct ph1handle *iph1; + phase1_handle_t *iph1; int nptype; { return set_isakmp_header (vbuf, iph1, nptype, iph1->etype, iph1->flags, iph1->msgid); @@ -3190,7 +2789,7 @@ set_isakmp_header1(vbuf, iph1, nptype) caddr_t set_isakmp_header2(vbuf, iph2, nptype) vchar_t *vbuf; - struct ph2handle *iph2; + phase2_handle_t *iph2; int nptype; { return set_isakmp_header (vbuf, iph2->ph1, nptype, ISAKMP_ETYPE_QUICK, iph2->flags, iph2->msgid); @@ -3208,7 +2807,7 @@ set_isakmp_payload(buf, src, nptype) struct isakmp_gen *gen; caddr_t p = buf; - plog(LLV_DEBUG, LOCATION, NULL, "add payload of len %zu, next type %d\n", + plog(ASL_LEVEL_DEBUG, "add payload of len %zu, next type %d\n", src->l, nptype); gen = (struct isakmp_gen *)p; @@ -3221,46 +2820,17 @@ set_isakmp_payload(buf, src, nptype) return p; } -static int -etypesw1(etype) - int etype; -{ - switch (etype) { - case ISAKMP_ETYPE_IDENT: - return 1; - case ISAKMP_ETYPE_AGG: - return 2; - case ISAKMP_ETYPE_BASE: - return 3; - default: - return 0; - } - /*NOTREACHED*/ -} - -static int -etypesw2(etype) - int etype; -{ - switch (etype) { - case ISAKMP_ETYPE_QUICK: - return 1; - default: - return 0; - } - /*NOTREACHED*/ -} #ifdef HAVE_PRINT_ISAKMP_C /* for print-isakmp.c */ char *snapend; -extern void isakmp_print __P((const u_char *, u_int, const u_char *)); +extern void isakmp_print(const u_char *, u_int, const u_char *); -char *getname __P((const u_char *)); +char *getname(const u_char *); #ifdef INET6 -char *getname6 __P((const u_char *)); +char *getname6(const u_char *); #endif -int safeputchar __P((int)); +int safeputchar(int); /* * Return a name for the IP address pointed to by ap. This address @@ -3274,12 +2844,10 @@ getname(ap) static char ntop_buf[NI_MAXHOST]; memset(&addr, 0, sizeof(addr)); -#ifndef __linux__ addr.sin_len = sizeof(struct sockaddr_in); -#endif addr.sin_family = AF_INET; memcpy(&addr.sin_addr, ap, sizeof(addr.sin_addr)); - if (getnameinfo((struct sockaddr *)&addr, sizeof(addr), + if (getnameinfo(&addr, sizeof(addr), ntop_buf, sizeof(ntop_buf), NULL, 0, NI_NUMERICHOST | niflags)) strlcpy(ntop_buf, "?", sizeof(ntop_buf)); @@ -3303,7 +2871,7 @@ getname6(ap) addr.sin6_len = sizeof(struct sockaddr_in6); addr.sin6_family = AF_INET6; memcpy(&addr.sin6_addr, ap, sizeof(addr.sin6_addr)); - if (getnameinfo((struct sockaddr *)&addr, addr.sin6_len, + if (getnameinfo(&addr, addr.sin6_len, ntop_buf, sizeof(ntop_buf), NULL, 0, NI_NUMERICHOST | niflags)) strlcpy(ntop_buf, "?", sizeof(ntop_buf)); @@ -3328,8 +2896,8 @@ safeputchar(c) void isakmp_printpacket(msg, from, my, decoded) vchar_t *msg; - struct sockaddr *from; - struct sockaddr *my; + struct sockaddr_storage *from; + struct sockaddr_storage *my; int decoded; { #ifdef YIPS_DEBUG @@ -3341,18 +2909,18 @@ isakmp_printpacket(msg, from, my, decoded) vchar_t *buf; #endif - if (loglevel < LLV_DEBUG) + if (loglevel < ASL_LEVEL_DEBUG) return; #ifdef YIPS_DEBUG - plog(LLV_DEBUG, LOCATION, NULL, "begin.\n"); + plog(ASL_LEVEL_DEBUG, "begin.\n"); gettimeofday(&tv, NULL); s = tv.tv_sec % 3600; printf("%02d:%02d.%06u ", s / 60, s % 60, (u_int32_t)tv.tv_usec); if (from) { - if (getnameinfo(from, sysdep_sa_len(from), hostbuf, sizeof(hostbuf), + if (getnameinfo(from, sysdep_sa_len((struct sockaddr *)from), hostbuf, sizeof(hostbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV | niflags)) { strlcpy(hostbuf, "?", sizeof(hostbuf)); @@ -3363,7 +2931,7 @@ isakmp_printpacket(msg, from, my, decoded) printf("?"); printf(" -> "); if (my) { - if (getnameinfo(my, sysdep_sa_len(my), hostbuf, sizeof(hostbuf), + if (getnameinfo(my, sysdep_sa_len((struct sockaddr *)my), hostbuf, sizeof(hostbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV | niflags)) { strlcpy(hostbuf, "?", sizeof(hostbuf)); @@ -3405,16 +2973,16 @@ isakmp_printpacket(msg, from, my, decoded) int copy_ph1addresses(iph1, rmconf, remote, local) - struct ph1handle *iph1; + phase1_handle_t *iph1; struct remoteconf *rmconf; - struct sockaddr *remote, *local; + struct sockaddr_storage *remote, *local; { u_short *port = NULL; /* address portion must be grabbed from real remote address "remote" */ iph1->remote = dupsaddr(remote); if (iph1->remote == NULL) { - delph1(iph1); + ike_session_delph1(iph1); return -1; } @@ -3425,7 +2993,7 @@ copy_ph1addresses(iph1, rmconf, remote, local) * if remote has port # (in case of responder - from recvfrom(2)) * respect content of "remote". */ - switch (iph1->remote->sa_family) { + switch (iph1->remote->ss_family) { case AF_INET: port = &((struct sockaddr_in *)iph1->remote)->sin_port; if (*port) @@ -3447,22 +3015,22 @@ copy_ph1addresses(iph1, rmconf, remote, local) break; #endif default: - plog(LLV_ERROR, LOCATION, NULL, - "invalid family: %d\n", iph1->remote->sa_family); - delph1(iph1); + plog(ASL_LEVEL_ERR, + "invalid family: %d\n", iph1->remote->ss_family); + ike_session_delph1(iph1); return -1; } if (local == NULL) - iph1->local = getlocaladdr(iph1->remote); + iph1->local = getlocaladdr((struct sockaddr *)iph1->remote); else iph1->local = dupsaddr(local); if (iph1->local == NULL) { - delph1(iph1); + ike_session_delph1(iph1); return -1; } port = NULL; - switch (iph1->local->sa_family) { + switch (iph1->local->ss_family) { case AF_INET: port = &((struct sockaddr_in *)iph1->local)->sin_port; if (*port) @@ -3484,14 +3052,14 @@ copy_ph1addresses(iph1, rmconf, remote, local) break; #endif default: - plog(LLV_ERROR, LOCATION, NULL, - "invalid family: %d\n", iph1->local->sa_family); - delph1(iph1); + plog(ASL_LEVEL_ERR, + "invalid family: %d\n", iph1->local->ss_family); + ike_session_delph1(iph1); return -1; } #ifdef ENABLE_NATT if ( port != NULL && *port == htons(lcconf->port_isakmp_natt) ) { - plog (LLV_DEBUG, LOCATION, NULL, "Marking ports as changed\n"); + plog (ASL_LEVEL_NOTICE, "Marking ports as changed\n"); iph1->natt_flags |= NAT_ADD_NON_ESP_MARKER; } #endif @@ -3499,48 +3067,31 @@ copy_ph1addresses(iph1, rmconf, remote, local) return 0; } -static int -nostate1(iph1, msg) - struct ph1handle *iph1; - vchar_t *msg; -{ - plog(LLV_ERROR, LOCATION, iph1->remote, "wrong state %u.\n", - iph1->status); - return -1; -} - -static int -nostate2(iph2, msg) - struct ph2handle *iph2; - vchar_t *msg; -{ - plog(LLV_ERROR, LOCATION, iph2->ph1->remote, "wrong state %u.\n", - iph2->status); - return -1; -} - void log_ph1established(iph1) - const struct ph1handle *iph1; + const phase1_handle_t *iph1; { char *src, *dst; - src = racoon_strdup(saddr2str(iph1->local)); - dst = racoon_strdup(saddr2str(iph1->remote)); + src = racoon_strdup(saddr2str((struct sockaddr *)iph1->local)); + dst = racoon_strdup(saddr2str((struct sockaddr *)iph1->remote)); STRDUP_FATAL(src); STRDUP_FATAL(dst); - plog(LLV_INFO, LOCATION, NULL, - "ISAKMP-SA established %s-%s spi:%s\n", - src, dst, + plog(ASL_LEVEL_NOTICE, + "ISAKMP-SA established spi:%s\n", isakmp_pindex(&iph1->index, 0)); - EVT_PUSH(iph1->local, iph1->remote, EVTT_PHASE1_UP, NULL); - if(!iph1->rmconf->mode_cfg) - EVT_PUSH(iph1->local, iph1->remote, EVTT_NO_ISAKMP_CFG, NULL); + plog(ASL_LEVEL_DEBUG, + "ISAKMP-SA established %s-%s spi:%s\n", + src, dst, + isakmp_pindex(&iph1->index, 0)); racoon_free(src); racoon_free(dst); + IPSECLOGASLMSG("IPSec Phase 1 established (Initiated by %s).\n", + (iph1->side == INITIATOR)? "me" : "peer"); + return; } @@ -3565,7 +3116,7 @@ isakmp_plist_append (struct payload_list *plist, vchar_t *payload, int payload_t } vchar_t * -isakmp_plist_set_all (struct payload_list **plist, struct ph1handle *iph1) +isakmp_plist_set_all (struct payload_list **plist, phase1_handle_t *iph1) { struct payload_list *ptr = *plist, *first; size_t tlen = sizeof (struct isakmp), n = 0; @@ -3584,7 +3135,7 @@ isakmp_plist_set_all (struct payload_list **plist, struct ph1handle *iph1) buf = vmalloc(tlen); if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get buffer to send.\n"); goto end; } @@ -3615,190 +3166,61 @@ end: } #ifdef ENABLE_FRAG -int +void frag_handler(iph1, msg, remote, local) - struct ph1handle *iph1; + phase1_handle_t *iph1; vchar_t *msg; - struct sockaddr *remote; - struct sockaddr *local; + struct sockaddr_storage *remote; + struct sockaddr_storage *local; { vchar_t *newmsg; if (isakmp_frag_extract(iph1, msg) == 1) { if ((newmsg = isakmp_frag_reassembly(iph1)) == NULL) { - plog(LLV_ERROR, LOCATION, remote, + plog(ASL_LEVEL_ERR, "Packet reassembly failed\n"); - return -1; + return; } - return isakmp_main(newmsg, remote, local); - } - - return 0; -} -#endif - -void -script_hook(iph1, script) - struct ph1handle *iph1; - int script; -{ -#define IP_MAX 40 -#define PORT_MAX 6 - char addrstr[IP_MAX]; - char portstr[PORT_MAX]; - char **envp = NULL; - int envc = 1; - struct sockaddr_in *sin; - char **c; - - if (iph1 == NULL || - iph1->rmconf == NULL || - iph1->rmconf->script[script] == NULL) - return; - -#ifdef ENABLE_HYBRID - (void)isakmp_cfg_setenv(iph1, &envp, &envc); -#endif - /* local address */ - sin = (struct sockaddr_in *)iph1->local; - inet_ntop(sin->sin_family, &sin->sin_addr, addrstr, IP_MAX); - snprintf(portstr, sizeof(portstr), "%d", ntohs(sin->sin_port)); - - if (script_env_append(&envp, &envc, "LOCAL_ADDR", addrstr) != 0) { - plog(LLV_ERROR, LOCATION, NULL, "Cannot set LOCAL_ADDR\n"); - goto out; - } - - if (script_env_append(&envp, &envc, "LOCAL_PORT", portstr) != 0) { - plog(LLV_ERROR, LOCATION, NULL, "Cannot set LOCAL_PORT\n"); - goto out; - } + /* simply reply if the packet was processed. */ + if (ike_session_check_recvdpkt(remote, local, newmsg) > 0) { + IPSECLOGASLMSG("Received (reassembled) retransmitted packet from %s.\n", + saddr2str((struct sockaddr *)remote)); - /* Peer address */ - if (iph1->remote != NULL) { - sin = (struct sockaddr_in *)iph1->remote; - inet_ntop(sin->sin_family, &sin->sin_addr, addrstr, IP_MAX); - snprintf(portstr, sizeof(portstr), "%d", ntohs(sin->sin_port)); - - if (script_env_append(&envp, &envc, - "REMOTE_ADDR", addrstr) != 0) { - plog(LLV_ERROR, LOCATION, NULL, - "Cannot set REMOTE_ADDR\n"); - goto out; + plog(ASL_LEVEL_NOTICE, + "the reassembled packet is retransmitted by %s.\n", + saddr2str((struct sockaddr *)remote)); + vfree(newmsg); + return; } - if (script_env_append(&envp, &envc, - "REMOTE_PORT", portstr) != 0) { - plog(LLV_ERROR, LOCATION, NULL, - "Cannot set REMOTEL_PORT\n"); - goto out; - } + isakmp_main(newmsg, remote, local); + vfree(newmsg); } - if (privsep_script_exec(iph1->rmconf->script[script]->v, - script, envp) != 0) - plog(LLV_ERROR, LOCATION, NULL, - "Script %s execution failed\n", script_names[script]); - -out: - for (c = envp; *c; c++) - racoon_free(*c); - - racoon_free(envp); - return; } - -int -script_env_append(envp, envc, name, value) - char ***envp; - int *envc; - char *name; - char *value; -{ - char *envitem; - char **newenvp; - int newenvc; - int envitem_len; - - envitem_len = strlen(name) + 1 + strlen(value) + 1; - envitem = racoon_malloc(envitem_len); - if (envitem == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "Cannot allocate memory: %s\n", strerror(errno)); - return -1; - } - snprintf(envitem, envitem_len, "%s=%s", name, value); - - newenvc = (*envc) + 1; - newenvp = racoon_realloc(*envp, newenvc * sizeof(char *)); - if (newenvp == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "Cannot allocate memory: %s\n", strerror(errno)); - racoon_free(envitem); - return -1; - } - - newenvp[newenvc - 2] = envitem; - newenvp[newenvc - 1] = NULL; - - *envp = newenvp; - *envc = newenvc; - return 0; -} - -int -script_exec(script, name, envp) - char *script; - int name; - char *const envp[]; -{ - char *argv[] = { NULL, NULL, NULL }; - - argv[0] = script; - argv[1] = script_names[name]; - argv[2] = NULL; - - switch (fork()) { - case 0: - execve(argv[0], argv, envp); - plog(LLV_ERROR, LOCATION, NULL, - "execve(\"%s\") failed: %s\n", - argv[0], strerror(errno)); - _exit(1); - break; - case -1: - plog(LLV_ERROR, LOCATION, NULL, - "Cannot fork: %s\n", strerror(errno)); - return -1; - break; - default: - break; - } - - return 0; -} +#endif void purge_remote(iph1) - struct ph1handle *iph1; + phase1_handle_t *iph1; { vchar_t *buf = NULL; struct sadb_msg *msg, *next, *end; struct sadb_sa *sa; - struct sockaddr *src, *dst; + struct sockaddr_storage *src, *dst; caddr_t mhp[SADB_EXT_MAX + 1]; u_int proto_id; - struct ph2handle *iph2; - struct ph1handle *new_iph1; + phase2_handle_t *iph2; + phase1_handle_t *new_iph1; - plog(LLV_INFO, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, "purging ISAKMP-SA spi=%s.\n", isakmp_pindex(&(iph1->index), iph1->msgid)); /* Mark as expired. */ - iph1->status = PHASE1ST_EXPIRED; + fsm_set_state(&iph1->status, IKEV1_STATE_PHASE1_EXPIRED); new_iph1 = ike_session_update_ph1_ph2tree(iph1); @@ -3808,39 +3230,39 @@ purge_remote(iph1) */ buf = pfkey_dump_sadb(SADB_SATYPE_UNSPEC); if (buf == NULL) { - plog(LLV_DEBUG, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, "pfkey_dump_sadb returned nothing.\n"); return; } - msg = (struct sadb_msg *)buf->v; - end = (struct sadb_msg *)(buf->v + buf->l); + msg = ALIGNED_CAST(struct sadb_msg *)buf->v; + end = ALIGNED_CAST(struct sadb_msg *)(buf->v + buf->l); while (msg < end) { if ((msg->sadb_msg_len << 3) < sizeof(*msg)) break; - next = (struct sadb_msg *)((caddr_t)msg + (msg->sadb_msg_len << 3)); + next = ALIGNED_CAST(struct sadb_msg *)((caddr_t)msg + (msg->sadb_msg_len << 3)); if (msg->sadb_msg_type != SADB_DUMP) { msg = next; continue; } if (pfkey_align(msg, mhp) || pfkey_check(mhp)) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "pfkey_check (%s)\n", ipsec_strerror()); msg = next; continue; } - sa = (struct sadb_sa *)(mhp[SADB_EXT_SA]); + sa = ALIGNED_CAST(struct sadb_sa *)(mhp[SADB_EXT_SA]); if (!sa || !mhp[SADB_EXT_ADDRESS_SRC] || !mhp[SADB_EXT_ADDRESS_DST]) { msg = next; continue; } - src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); - dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); + src = ALIGNED_CAST(struct sockaddr_storage *)PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); + dst = ALIGNED_CAST(struct sockaddr_storage *)PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); if (sa->sadb_sa_state != SADB_SASTATE_LARVAL && sa->sadb_sa_state != SADB_SASTATE_MATURE && @@ -3861,14 +3283,14 @@ purge_remote(iph1) } proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype); - iph2 = getph2bysaidx(src, dst, proto_id, sa->sadb_sa_spi); + iph2 = ike_session_getph2bysaidx(src, dst, proto_id, sa->sadb_sa_spi); /* Check if there is another valid ISAKMP-SA */ if (new_iph1 != NULL) { if (iph2 == NULL) { /* No handler... still send a pfkey_delete message, but log this !*/ - plog(LLV_INFO, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, "Unknown IPsec-SA spi=%u, hmmmm?\n", ntohl(sa->sadb_sa_spi)); }else{ @@ -3883,10 +3305,9 @@ purge_remote(iph1) } /* If the ph2handle is established, do not purge IPsec-SA */ - if (iph2->status == PHASE2ST_ESTABLISHED || - iph2->status == PHASE2ST_EXPIRED) { + if (FSM_STATE_IS_ESTABLISHED_OR_EXPIRED(iph2->status)) { - plog(LLV_INFO, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, "keeping IPsec-SA spi=%u - found valid ISAKMP-SA spi=%s.\n", ntohl(sa->sadb_sa_spi), isakmp_pindex(&(new_iph1->index), new_iph1->msgid)); @@ -3905,12 +3326,10 @@ purge_remote(iph1) /* delete a relative phase 2 handle. */ if (iph2 != NULL) { delete_spd(iph2); - unbindph12(iph2); - remph2(iph2); - delph2(iph2); + ike_session_unlink_phase2(iph2); } - plog(LLV_INFO, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, "purged IPsec-SA spi=%u.\n", ntohl(sa->sadb_sa_spi)); @@ -3921,7 +3340,7 @@ purge_remote(iph1) vfree(buf); /* Mark the phase1 handler as EXPIRED */ - plog(LLV_INFO, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, "purged ISAKMP-SA spi=%s.\n", isakmp_pindex(&(iph1->index), iph1->msgid)); @@ -3932,7 +3351,7 @@ purge_remote(iph1) void delete_spd(iph2) - struct ph2handle *iph2; + phase2_handle_t *iph2; { if (iph2 == NULL) return; @@ -3940,31 +3359,34 @@ delete_spd(iph2) /* Delete the SPD entry if we generated it */ if (iph2->generated_spidx) { - struct policyindex spidx; + union { + u_int64_t force_align; // Wcast-align fix - force alignment + struct policyindex spidx; + } u; struct sockaddr_storage addr; u_int8_t pref; - struct sockaddr *src = iph2->src; - struct sockaddr *dst = iph2->dst; + struct sockaddr_storage *src = iph2->src; + struct sockaddr_storage *dst = iph2->dst; int error; int idi2type = 0;/* switch whether copy IDs into id[src,dst]. */ - plog(LLV_INFO, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, "generated policy, deleting it.\n"); - memset(&spidx, 0, sizeof(spidx)); - iph2->spidx_gen = (caddr_t )&spidx; + memset(&u.spidx, 0, sizeof(u.spidx)); + iph2->spidx_gen = &u.spidx; /* make inbound policy */ iph2->src = dst; iph2->dst = src; - spidx.dir = IPSEC_DIR_INBOUND; - spidx.ul_proto = 0; + u.spidx.dir = IPSEC_DIR_INBOUND; + u.spidx.ul_proto = 0; /* * Note: code from get_proposal_r */ -#define _XIDT(d) ((struct ipsecdoi_id_b *)(d)->v)->type +#define _XIDT(d) (ALIGNED_CAST(struct ipsecdoi_id_b *)((d)->v))->type /* * make destination address in spidx from either ID payload @@ -3976,9 +3398,8 @@ delete_spd(iph2) || _XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR_SUBNET || _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR_SUBNET)) { /* get a destination address of a policy */ - error = ipsecdoi_id2sockaddr(iph2->id, - (struct sockaddr *)&spidx.dst, - &spidx.prefd, &spidx.ul_proto); + error = ipsecdoi_id2sockaddr(iph2->id, &u.spidx.dst, + &u.spidx.prefd, &u.spidx.ul_proto, iph2->version); if (error) goto purge; @@ -3991,8 +3412,7 @@ delete_spd(iph2) */ if (_XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR) { if ((error = - setscopeid((struct sockaddr *)&spidx.dst, - iph2->src)) != 0) + setscopeid(&u.spidx.dst, iph2->src)) != 0) goto purge; } #endif @@ -4003,9 +3423,9 @@ delete_spd(iph2) } else { - plog(LLV_DEBUG, LOCATION, NULL, - "get a destination address of SP index " - "from phase1 address " + plog(ASL_LEVEL_NOTICE, + "Get a destination address of SP index " + "from Phase 1 address " "due to no ID payloads found " "OR because ID type is not address.\n"); @@ -4014,20 +3434,20 @@ delete_spd(iph2) * DESTINATION address of the key to search the * SPD because the direction of policy is inbound. */ - memcpy(&spidx.dst, iph2->src, sysdep_sa_len(iph2->src)); - switch (spidx.dst.ss_family) { + memcpy(&u.spidx.dst, iph2->src, sysdep_sa_len((struct sockaddr *)iph2->src)); + switch (u.spidx.dst.ss_family) { case AF_INET: - spidx.prefd = + u.spidx.prefd = sizeof(struct in_addr) << 3; break; #ifdef INET6 case AF_INET6: - spidx.prefd = + u.spidx.prefd = sizeof(struct in6_addr) << 3; break; #endif default: - spidx.prefd = 0; + u.spidx.prefd = 0; break; } } @@ -4039,9 +3459,8 @@ delete_spd(iph2) || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV4_ADDR_SUBNET || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR_SUBNET)) { /* get a source address of inbound SA */ - error = ipsecdoi_id2sockaddr(iph2->id_p, - (struct sockaddr *)&spidx.src, - &spidx.prefs, &spidx.ul_proto); + error = ipsecdoi_id2sockaddr(iph2->id_p, &u.spidx.src, + &u.spidx.prefs, &u.spidx.ul_proto, iph2->version); if (error) goto purge; @@ -4052,8 +3471,7 @@ delete_spd(iph2) */ if (_XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR) { error = - setscopeid((struct sockaddr *)&spidx.src, - iph2->dst); + setscopeid(&u.spidx.src, iph2->dst); if (error) goto purge; } @@ -4061,58 +3479,62 @@ delete_spd(iph2) /* make id[src,dst] if both ID types are IP address and same */ if (_XIDT(iph2->id_p) == idi2type - && spidx.dst.ss_family == spidx.src.ss_family) { + && u.spidx.dst.ss_family == u.spidx.src.ss_family) { iph2->src_id = - dupsaddr((struct sockaddr *)&spidx.dst); + dupsaddr(&u.spidx.dst); iph2->dst_id = - dupsaddr((struct sockaddr *)&spidx.src); + dupsaddr(&u.spidx.src); } } else { - plog(LLV_DEBUG, LOCATION, NULL, - "get a source address of SP index " - "from phase1 address " + plog(ASL_LEVEL_NOTICE, + "Get a source address of SP index " + "from Phase 1 address " "due to no ID payloads found " "OR because ID type is not address.\n"); /* see above comment. */ - memcpy(&spidx.src, iph2->dst, sysdep_sa_len(iph2->dst)); - switch (spidx.src.ss_family) { + memcpy(&u.spidx.src, iph2->dst, sysdep_sa_len((struct sockaddr *)iph2->dst)); + switch (u.spidx.src.ss_family) { case AF_INET: - spidx.prefs = + u.spidx.prefs = sizeof(struct in_addr) << 3; break; #ifdef INET6 case AF_INET6: - spidx.prefs = + u.spidx.prefs = sizeof(struct in6_addr) << 3; break; #endif default: - spidx.prefs = 0; + u.spidx.prefs = 0; break; } } #undef _XIDT - plog(LLV_DEBUG, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, + "get src/dst address from ID payload " + "prefixlen=%u ul_proto=%u\n", + u.spidx.prefs, u.spidx.ul_proto); + plog(ASL_LEVEL_DEBUG, "get a src address from ID payload " "%s prefixlen=%u ul_proto=%u\n", - saddr2str((struct sockaddr *)&spidx.src), - spidx.prefs, spidx.ul_proto); - plog(LLV_DEBUG, LOCATION, NULL, + saddr2str((struct sockaddr *)&u.spidx.src), + u.spidx.prefs, u.spidx.ul_proto); + plog(ASL_LEVEL_DEBUG, "get dst address from ID payload " "%s prefixlen=%u ul_proto=%u\n", - saddr2str((struct sockaddr *)&spidx.dst), - spidx.prefd, spidx.ul_proto); + saddr2str((struct sockaddr *)&u.spidx.dst), + u.spidx.prefd, u.spidx.ul_proto); /* * convert the ul_proto if it is 0 * because 0 in ID payload means a wild card. */ - if (spidx.ul_proto == 0) - spidx.ul_proto = IPSEC_ULPROTO_ANY; + if (u.spidx.ul_proto == 0) + u.spidx.ul_proto = IPSEC_ULPROTO_ANY; #undef _XIDT @@ -4120,22 +3542,22 @@ delete_spd(iph2) */ if (pk_sendspddelete(iph2) < 0) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "pfkey spddelete(inbound) failed.\n"); }else{ - plog(LLV_DEBUG, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, "pfkey spddelete(inbound) sent.\n"); } #ifdef HAVE_POLICY_FWD /* make forward policy if required */ if (tunnel_mode_prop(iph2->approval)) { - spidx.dir = IPSEC_DIR_FWD; + u.spidx.dir = IPSEC_DIR_FWD; if (pk_sendspddelete(iph2) < 0) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "pfkey spddelete(forward) failed.\n"); }else{ - plog(LLV_DEBUG, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, "pfkey spddelete(forward) sent.\n"); } } @@ -4144,19 +3566,19 @@ delete_spd(iph2) /* make outbound policy */ iph2->src = src; iph2->dst = dst; - spidx.dir = IPSEC_DIR_OUTBOUND; - addr = spidx.src; - spidx.src = spidx.dst; - spidx.dst = addr; - pref = spidx.prefs; - spidx.prefs = spidx.prefd; - spidx.prefd = pref; + u.spidx.dir = IPSEC_DIR_OUTBOUND; + addr = u.spidx.src; + u.spidx.src = u.spidx.dst; + u.spidx.dst = addr; + pref = u.spidx.prefs; + u.spidx.prefs = u.spidx.prefd; + u.spidx.prefd = pref; if (pk_sendspddelete(iph2) < 0) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "pfkey spddelete(outbound) failed.\n"); }else{ - plog(LLV_DEBUG, LOCATION, NULL, + plog(ASL_LEVEL_NOTICE, "pfkey spddelete(outbound) sent.\n"); } purge: @@ -4167,7 +3589,7 @@ purge: #ifdef INET6 u_int32_t setscopeid(sp_addr0, sa_addr0) - struct sockaddr *sp_addr0, *sa_addr0; + struct sockaddr_storage *sp_addr0, *sa_addr0; { struct sockaddr_in6 *sp_addr, *sa_addr; @@ -4181,13 +3603,13 @@ setscopeid(sp_addr0, sa_addr0) /* this check should not be here ? */ if (sa_addr->sin6_family != AF_INET6) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "can't get scope ID: family mismatch\n"); return -1; } if (!IN6_IS_ADDR_LINKLOCAL(&sa_addr->sin6_addr)) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "scope ID is not supported except of lladdr.\n"); return -1; } @@ -4197,3 +3619,46 @@ setscopeid(sp_addr0, sa_addr0) return 0; } #endif + +vchar_t * +isakmp_plist_append_initial_contact (iph1, plist) + phase1_handle_t *iph1; + struct payload_list *plist; +{ + if (!iph1->is_rekey && iph1->rmconf->ini_contact && !ike_session_getcontacted(iph1->remote)) { + vchar_t *notp_ini = NULL; + struct isakmp_pl_n np, *nptr; + char *cptr; + + np.doi = htonl(iph1->rmconf->doitype); + np.proto_id = IPSECDOI_PROTO_ISAKMP; + np.spi_size = sizeof(isakmp_index); + np.type = htons(ISAKMP_NTYPE_INITIAL_CONTACT); + if ((notp_ini = vmalloc(sizeof(struct isakmp_pl_n) - sizeof(struct isakmp_gen) + + sizeof(isakmp_index)))) { + nptr = &np; + memcpy(notp_ini->v, &nptr->doi, sizeof(struct isakmp_pl_n) - sizeof(struct isakmp_gen)); + cptr = notp_ini->v + sizeof(struct isakmp_pl_n) - sizeof(struct isakmp_gen); + memcpy(cptr, &iph1->index, sizeof(isakmp_index)); + plist = isakmp_plist_append(plist, notp_ini, ISAKMP_NPTYPE_N); + plog(ASL_LEVEL_NOTICE, + "added initial-contact payload.\n"); + + /* insert a node into contacted list. */ + if (ike_session_inscontacted(iph1->remote) == -1) { + plog(ASL_LEVEL_ERR, + "failed to add contacted list.\n"); + /* ignore */ + } + return notp_ini; + } else { + plog(ASL_LEVEL_ERR, + "failed to allocate notification payload.\n"); + return NULL; + } + } else { + plog(ASL_LEVEL_NOTICE, "failed to add initial-contact payload: rekey %d, ini-contact %d, contacted %d.\n", + iph1->is_rekey? 1:0, iph1->rmconf->ini_contact, ike_session_getcontacted(iph1->remote)? 1:0); + } + return NULL; +}