aboutsummaryrefslogtreecommitdiff
path: root/src/racoon/isakmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/racoon/isakmp.c')
-rw-r--r--src/racoon/isakmp.c3643
1 files changed, 0 insertions, 3643 deletions
diff --git a/src/racoon/isakmp.c b/src/racoon/isakmp.c
deleted file mode 100644
index b9fc5ee..0000000
--- a/src/racoon/isakmp.c
+++ /dev/null
@@ -1,3643 +0,0 @@
-/* $NetBSD: isakmp.c,v 1.20.6.13 2008/09/25 09:34:39 vanhu Exp $ */
-
-/* Id: isakmp.c,v 1.74 2006/05/07 21:32:59 manubsd Exp */
-
-/*
- * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the project nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <sys/queue.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include PATH_IPSEC_H
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#if TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-#else
-# if HAVE_SYS_TIME_H
-# include <sys/time.h>
-# else
-# include <time.h>
-# endif
-#endif
-#include <netdb.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <ctype.h>
-#ifdef ENABLE_HYBRID
-#include <resolv.h>
-#endif
-
-#include "var.h"
-#include "misc.h"
-#include "vmbuf.h"
-#include "plog.h"
-#include "sockmisc.h"
-#include "schedule.h"
-#include "debug.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 "ipsec_doi.h"
-#include "pfkey.h"
-#include "crypto_openssl.h"
-#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"
-#ifdef ENABLE_HYBRID
-#include "vendorid.h"
-#include "isakmp_xauth.h"
-#include "isakmp_unity.h"
-#include "isakmp_cfg.h"
-#endif
-#ifdef ENABLE_FRAG
-#include "isakmp_frag.h"
-#endif
-#include "strnames.h"
-
-#include <fcntl.h>
-
-#ifdef ENABLE_NATT
-# include "nattraversal.h"
-#endif
-# ifdef __linux__
-# include <linux/udp.h>
-# include <linux/ip.h>
-# ifndef SOL_UDP
-# define SOL_UDP 17
-# endif
-#if defined(__ANDROID__)
-#include <netinet/udp.h>
-#endif
-# endif /* __linux__ */
-# if defined(__NetBSD__) || defined(__FreeBSD__) || \
- (defined(__APPLE__) && defined(__MACH__))
-# include <netinet/in.h>
-# include <netinet/udp.h>
-# include <netinet/in_systm.h>
-# include <netinet/ip.h>
-# define SOL_UDP IPPROTO_UDP
-# endif /* __NetBSD__ / __FreeBSD__ */
-
-#ifdef ANDROID_CHANGES
-#include "NetdClient.h"
-#endif
-
-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));
-#ifdef ENABLE_FRAG
-static int frag_handler(struct ph1handle *,
- vchar_t *, struct sockaddr *, struct sockaddr *);
-#endif
-
-/*
- * isakmp packet handler
- */
-int
-isakmp_handler(so_isakmp)
- int so_isakmp;
-{
- struct isakmp isakmp;
- union {
- 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;
- vchar_t *buf = NULL, *tmpbuf = NULL;
- int error = -1, res;
-
- /* 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) {
- if (errno == EINTR)
- continue;
- plog(LLV_ERROR, LOCATION, NULL,
- "failed to receive isakmp packet: %s\n",
- strerror (errno));
- goto end;
- }
-
- /* keep-alive packet - ignore */
- if (len == 1 && (x.buf[0]&0xff) == 0xff) {
- /* 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,
- "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 */
- memcpy ((char *)&isakmp, x.buf + extralen, sizeof (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));
- /* dummy receive */
- if ((len = recvfrom(so_isakmp, (char *)&isakmp, sizeof(isakmp),
- 0, (struct sockaddr *)&remote, &remote_len)) < 0) {
- plog(LLV_ERROR, LOCATION, NULL,
- "failed to receive isakmp packet: %s\n",
- strerror (errno));
- }
- goto end;
- }
-
- /* reject it if the size is tooooo big. */
- if (ntohl(isakmp.len) > 0xffff) {
- plog(LLV_ERROR, LOCATION, NULL,
- "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,
- "failed to receive isakmp packet: %s\n",
- strerror (errno));
- }
- goto end;
- }
-
- /* read real message */
- if ((tmpbuf = vmalloc(ntohl(isakmp.len) + extralen)) == NULL) {
- plog(LLV_ERROR, LOCATION, NULL,
- "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,
- "failed to receive isakmp packet: %s\n",
- strerror (errno));
- }
- goto end;
- }
-
- while ((len = recvfromto(so_isakmp, (char *)tmpbuf->v, tmpbuf->l,
- 0, (struct sockaddr *)&remote, &remote_len,
- (struct sockaddr *)&local, &local_len)) < 0) {
- if (errno == EINTR)
- continue;
- plog(LLV_ERROR, LOCATION, NULL,
- "failed to receive isakmp packet: %s\n",
- strerror (errno));
- goto end;
- }
-
- if ((buf = vmalloc(len - extralen)) == NULL) {
- plog(LLV_ERROR, LOCATION, NULL,
- "failed to allocate reading buffer (%u Bytes)\n",
- (len - extralen));
- goto end;
- }
-
- memcpy (buf->v, tmpbuf->v + extralen, buf->l);
-
- len -= extralen;
-
- if (len != buf->l) {
- plog(LLV_ERROR, LOCATION, (struct sockaddr *)&remote,
- "received invalid length (%d != %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);
-
- /* avoid packets with malicious port/address */
- if (extract_port((struct sockaddr *)&remote) == 0) {
- plog(LLV_ERROR, LOCATION, (struct sockaddr *)&remote,
- "src port == 0 (valid as UDP but not with IKE)\n");
- goto end;
- }
-
- /* XXX: check sender whether to be allowed or not to accept */
-
- /* XXX: I don't know how to check isakmp half connection attack. */
-
- /* simply reply if the packet was processed. */
- res=check_recvdpkt((struct sockaddr *)&remote,(struct sockaddr *)&local, buf);
- if (res) {
- plog(LLV_NOTIFY, LOCATION, NULL,
- "the packet is retransmitted by %s (%d).\n",
- saddr2str((struct sockaddr *)&remote), res);
- error = 0;
- goto end;
- }
-
- /* isakmp main routine */
- if (isakmp_main(buf, (struct sockaddr *)&remote,
- (struct sockaddr *)&local) != 0) goto end;
-
- error = 0;
-
-end:
- if (tmpbuf != NULL)
- vfree(tmpbuf);
- if (buf != NULL)
- vfree(buf);
-
- return(error);
-}
-
-/*
- * main processing to handle isakmp payload
- */
-static int
-isakmp_main(msg, remote, local)
- vchar_t *msg;
- struct sockaddr *remote, *local;
-{
- struct isakmp *isakmp = (struct isakmp *)msg->v;
- isakmp_index *index = (isakmp_index *)isakmp;
- u_int32_t msgid = isakmp->msgid;
- struct ph1handle *iph1;
-
-#ifdef HAVE_PRINT_ISAKMP_C
- isakmp_printpacket(msg, remote, local, 0);
-#endif
-
- /* the initiator's cookie must not be zero */
- if (memcmp(&isakmp->i_ck, r_ck0, sizeof(cookie_t)) == 0) {
- plog(LLV_ERROR, LOCATION, remote,
- "malformed cookie received.\n");
- return -1;
- }
-
- /* Check the Major and Minor Version fields. */
- /*
- * XXX Is is right to check version here ?
- * 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,
- "invalid minor version %d.\n",
- ISAKMP_GETMINORV(isakmp->v));
- return -1;
- }
-#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;
- }
-
- /* 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;
- }
- }
-
- iph1 = getph1byindex(index);
- if (iph1 != NULL) {
- /* validity check */
- if (memcmp(&isakmp->r_ck, r_ck0, sizeof(cookie_t)) == 0 &&
- iph1->side == INITIATOR) {
- plog(LLV_DEBUG, LOCATION, remote,
- "malformed cookie received or "
- "the initiator's cookies collide.\n");
- return -1;
- }
-
-#ifdef ENABLE_NATT
- /* Floating ports for NAT-T */
- if (NATT_AVAILABLE(iph1) &&
- ! (iph1->natt_flags & NAT_PORTS_CHANGED) &&
- ((cmpsaddrstrict(iph1->remote, remote) != 0) ||
- (cmpsaddrstrict(iph1->local, local) != 0)))
- {
- /* prevent memory leak */
- racoon_free(iph1->remote);
- racoon_free(iph1->local);
- iph1->remote = NULL;
- iph1->local = NULL;
-
- /* copy-in new addresses */
- iph1->remote = dupsaddr(remote);
- if (iph1->remote == NULL) {
- plog(LLV_ERROR, LOCATION, iph1->remote,
- "phase1 failed: dupsaddr failed.\n");
- remph1(iph1);
- delph1(iph1);
- return -1;
- }
- iph1->local = dupsaddr(local);
- if (iph1->local == NULL) {
- plog(LLV_ERROR, LOCATION, iph1->remote,
- "phase1 failed: dupsaddr failed.\n");
- remph1(iph1);
- delph1(iph1);
- return -1;
- }
-
- /* set the flag to prevent further port floating
- (FIXME: should we allow it? E.g. when the NAT gw
- is rebooted?) */
- iph1->natt_flags |= NAT_PORTS_CHANGED | NAT_ADD_NON_ESP_MARKER;
-
- /* print some neat info */
- plog (LLV_INFO, LOCATION, NULL,
- "NAT-T: ports changed to: %s\n",
- saddr2str_fromto ("%s<->%s", iph1->remote, iph1->local));
-
- natt_keepalive_add_ph1 (iph1);
- }
-#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));
- STRDUP_FATAL(saddr_db);
- STRDUP_FATAL(saddr_act);
-
- plog(LLV_WARNING, LOCATION, remote,
- "remote address mismatched. db=%s, act=%s\n",
- saddr_db, saddr_act);
-
- racoon_free(saddr_db);
- racoon_free(saddr_act);
- }
-
- /*
- * don't check of exchange type here because other type will be
- * with same index, for example, informational exchange.
- */
-
- /* XXX more acceptable check */
- }
-
- 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) {
- 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) {
- 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) {
- 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;
-
- /* 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;
-#ifdef ENABLE_STATS
- struct timeval start, end;
-#endif
-
- /* 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) {
- 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) {
-
-#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
-
- /* save created date. */
- (void)time(&iph1->created);
-
- /* add to the schedule to expire, and seve back pointer. */
- iph1->sce = sched_new(iph1->approval->lifetime,
- isakmp_ph1expire_stub, iph1);
-#ifdef ENABLE_HYBRID
- if (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 */
- iph1->rmconf->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 */
- /* don't anything if local test mode. */
- if (!f_local
- && iph1->rmconf->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,except if
- * ISAKMP mode config was requested. In the later
- * case it is done when we receive the configuration.
- */
- if ((iph1->status == PHASE1ST_ESTABLISHED) &&
- !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;
- }
- }
- }
-
- 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)
- 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);
-
- /* 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;
- }
-
-#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)
- struct remoteconf *rmconf;
- struct sockaddr *remote, *local;
-{
- struct ph1handle *iph1;
-#ifdef ENABLE_STATS
- struct timeval start, end;
-#endif
-
- /* get new entry to isakmp status table. */
- iph1 = newph1();
- if (iph1 == NULL)
- return -1;
-
- iph1->status = PHASE1ST_START;
- iph1->rmconf = rmconf;
- iph1->side = INITIATOR;
- iph1->version = ISAKMP_VERSION_NUMBER;
- 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) {
- 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 */
- if (copy_ph1addresses(iph1, rmconf, remote, local) < 0) {
- delph1(iph1);
- return -1;
- }
-
- (void)insph1(iph1);
-
- /* start phase 1 exchange */
- iph1->etype = rmconf->etypes->type;
-
- plog(LLV_DEBUG, LOCATION, NULL, "===\n");
- {
- char *a;
-
- a = racoon_strdup(saddr2str(iph1->local));
- STRDUP_FATAL(a);
-
- plog(LLV_INFO, LOCATION, NULL,
- "initiate new phase 1 negotiation: %s<=>%s\n",
- a, saddr2str(iph1->remote));
- racoon_free(a);
- }
- plog(LLV_INFO, LOCATION, NULL,
- "begin %s mode.\n",
- s_isakmp_etype(iph1->etype));
-
-#ifdef ENABLE_STATS
- 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);
-
- 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
-
- return 0;
-}
-
-/* new negotiation of phase 1 for responder */
-static int
-isakmp_ph1begin_r(vchar_t *msg, struct sockaddr *remote,
- struct sockaddr *local, u_int8_t etype)
-{
- struct isakmp *isakmp = (struct isakmp *)msg->v;
- struct remoteconf *rmconf;
- struct ph1handle *iph1;
- struct etypes *etypeok;
-#ifdef ENABLE_STATS
- struct timeval start, end;
-#endif
-
- /* look for my configuration */
- rmconf = getrmconf(remote);
- if (rmconf == NULL) {
- plog(LLV_ERROR, LOCATION, remote,
- "couldn't find "
- "configuration.\n");
- return -1;
- }
-
- /* check to be acceptable exchange type */
- etypeok = check_etypeok(rmconf, etype);
- if (etypeok == NULL) {
- plog(LLV_ERROR, LOCATION, remote,
- "not acceptable %s mode\n", s_isakmp_etype(etype));
- return -1;
- }
-
- /* get new entry to isakmp status table. */
- iph1 = newph1();
- 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;
- iph1->flags = 0;
- iph1->side = RESPONDER;
- iph1->etype = etypeok->type;
- iph1->version = isakmp->v;
- iph1->msgid = 0;
-#ifdef HAVE_GSSAPI
- iph1->gssapi_state = NULL;
-#endif
-#ifdef ENABLE_HYBRID
- if ((iph1->mode_cfg = isakmp_cfg_mkstate()) == NULL) {
- 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) {
- delph1(iph1);
- return -1;
- }
- (void)insph1(iph1);
-
- plog(LLV_DEBUG, LOCATION, NULL, "===\n");
- {
- char *a;
-
- a = racoon_strdup(saddr2str(iph1->local));
- STRDUP_FATAL(a);
-
- plog(LLV_INFO, LOCATION, NULL,
- "respond new phase 1 negotiation: %s<=>%s\n",
- a, saddr2str(iph1->remote));
- racoon_free(a);
- }
- plog(LLV_INFO, LOCATION, NULL,
- "begin %s mode.\n", s_isakmp_etype(etype));
-
-#ifdef ENABLE_STATS
- gettimeofday(&iph1->start, NULL);
- 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
-
- return 0;
-
-#else /* ENABLE_FRAG */
-
- /* 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 */
-
-}
-
-/* new negotiation of phase 2 for initiator */
-static int
-isakmp_ph2begin_i(iph1, iph2)
- struct ph1handle *iph1;
- struct ph2handle *iph2;
-{
-#ifdef ENABLE_HYBRID
- if (xauth_check(iph1) != 0) {
- plog(LLV_ERROR, LOCATION, NULL,
- "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");
- {
- char *a;
- a = racoon_strdup(saddr2str(iph2->src));
- STRDUP_FATAL(a);
-
- plog(LLV_INFO, LOCATION, NULL,
- "initiate new phase 2 negotiation: %s<=>%s\n",
- a, saddr2str(iph2->dst));
- racoon_free(a);
- }
-
-#ifdef ENABLE_STATS
- gettimeofday(&iph2->start, NULL);
-#endif
- /* found isakmp-sa */
- bindph12(iph1, iph2);
- iph2->status = PHASE2ST_STATUS2;
-
- if ((ph2exchange[etypesw2(ISAKMP_ETYPE_QUICK)]
- [iph2->side]
- [iph2->status])(iph2, NULL) < 0) {
- unbindph12(iph2);
- /* release ipsecsa handler due to internal error. */
- remph2(iph2);
- return -1;
- }
- return 0;
-}
-
-/* new negotiation of phase 2 for responder */
-static int
-isakmp_ph2begin_r(iph1, msg)
- struct ph1handle *iph1;
- vchar_t *msg;
-{
- struct isakmp *isakmp = (struct isakmp *)msg->v;
- struct ph2handle *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");
- return -1;
- }
-#endif
-
- iph2 = newph2();
- if (iph2 == NULL) {
- plog(LLV_ERROR, LOCATION, NULL,
- "failed to allocate phase2 entry.\n");
- return -1;
- }
-
- iph2->ph1 = iph1;
- iph2->side = RESPONDER;
- iph2->status = PHASE2ST_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);
- return -1;
- }
- iph2->dst = dupsaddr(iph1->remote); /* XXX should be considered */
- if (iph2->dst == NULL) {
- delph2(iph2);
- return -1;
- }
- iph2->src = dupsaddr(iph1->local); /* XXX should be considered */
- if (iph2->src == NULL) {
- delph2(iph2);
- return -1;
- }
-#if (!defined(ENABLE_NATT)) || (defined(BROKEN_NATT))
- if (set_port(iph2->dst, 0) == NULL ||
- set_port(iph2->src, 0) == NULL) {
- plog(LLV_ERROR, LOCATION, NULL,
- "invalid family: %d\n", iph2->dst->sa_family);
- delph2(iph2);
- return -1;
- }
-#endif
-
- /* add new entry to isakmp status table */
- insph2(iph2);
- bindph12(iph1, iph2);
-
- plog(LLV_DEBUG, LOCATION, NULL, "===\n");
- {
- char *a;
-
- a = racoon_strdup(saddr2str(iph2->src));
- STRDUP_FATAL(a);
-
- plog(LLV_INFO, LOCATION, NULL,
- "respond new phase 2 negotiation: %s<=>%s\n",
- a, saddr2str(iph2->dst));
- racoon_free(a);
- }
-
-#ifdef ENABLE_STATS
- 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;
- }
-
- /* 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));
-#endif
-
- return 0;
-}
-
-/*
- * parse ISAKMP payloads, without ISAKMP base header.
- */
-vchar_t *
-isakmp_parsewoh(np0, gen, len)
- int np0;
- struct isakmp_gen *gen;
- int len;
-{
- u_char np = np0 & 0xff;
- int tlen, plen;
- vchar_t *result;
- struct isakmp_parse_t *p, *ep;
-
- plog(LLV_DEBUG, LOCATION, NULL, "begin.\n");
-
- /*
- * 5 is a magic number, but any value larger than 2 should be fine
- * as we do vrealloc() in the following loop.
- */
- result = vmalloc(sizeof(struct isakmp_parse_t) * 5);
- if (result == NULL) {
- plog(LLV_ERROR, LOCATION, NULL,
- "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));
-
- tlen = len;
-
- /* parse through general headers */
- 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");
- vfree(result);
- return NULL;
- }
-
- plog(LLV_DEBUG, LOCATION, NULL,
- "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");
- vfree(result);
- return NULL;
- }
- p->ptr = gen;
- p++;
- if (ep <= p) {
- int off;
-
- off = p - (struct isakmp_parse_t *)result->v;
- result = vrealloc(result, result->l * 2);
- if (result == NULL) {
- plog(LLV_DEBUG, LOCATION, NULL,
- "failed to realloc buffer.\n");
- vfree(result);
- return NULL;
- }
- ep = (struct isakmp_parse_t *)
- (result->v + result->l - sizeof(*ep));
- p = (struct isakmp_parse_t *)result->v;
- p += off;
- }
-
- np = gen->np;
- plen = ntohs(gen->len);
- gen = (struct isakmp_gen *)((caddr_t)gen + plen);
- tlen -= plen;
- }
- p->type = ISAKMP_NPTYPE_NONE;
- p->len = 0;
- p->ptr = NULL;
-
- plog(LLV_DEBUG, LOCATION, NULL, "succeed.\n");
-
- return result;
-}
-
-/*
- * parse ISAKMP payloads, including ISAKMP base header.
- */
-vchar_t *
-isakmp_parse(buf)
- vchar_t *buf;
-{
- struct isakmp *isakmp = (struct isakmp *)buf->v;
- struct isakmp_gen *gen;
- int tlen;
- vchar_t *result;
- u_char np;
-
- np = isakmp->np;
- gen = (struct isakmp_gen *)(buf->v + sizeof(*isakmp));
- tlen = buf->l - sizeof(struct isakmp);
- result = isakmp_parsewoh(np, gen, tlen);
-
- return result;
-}
-
-/* %%% */
-int
-isakmp_init()
-{
- /* initialize a isakmp status table */
- initph1tree();
- initph2tree();
- initctdtree();
- init_recvdpkt();
-
- if (isakmp_open() < 0)
- goto err;
-
- return(0);
-
-err:
- isakmp_close();
- return(-1);
-}
-
-/*
- * make strings containing i_cookie + r_cookie + msgid
- */
-const char *
-isakmp_pindex(index, msgid)
- const isakmp_index *index;
- const u_int32_t msgid;
-{
- static char buf[64];
- const u_char *p;
- int i, j;
-
- memset(buf, 0, sizeof(buf));
-
- /* copy index */
- p = (const u_char *)index;
- for (j = 0, i = 0; i < sizeof(isakmp_index); i++) {
- snprintf((char *)&buf[j], sizeof(buf) - j, "%02x", p[i]);
- j += 2;
- switch (i) {
- case 7:
- buf[j++] = ':';
- }
- }
-
- if (msgid == 0)
- return buf;
-
- /* copy msgid */
- snprintf((char *)&buf[j], sizeof(buf) - j, ":%08x", ntohs(msgid));
-
- return buf;
-}
-
-/* open ISAKMP sockets. */
-int
-isakmp_open()
-{
- const int yes = 1;
- int ifnum = 0, encap_ifnum = 0;
-#ifdef INET6
- int pktinfo;
-#endif
- struct myaddrs *p;
-
- for (p = lcconf->myaddrs; p; p = p->next) {
- if (!p->addr)
- continue;
-
- /* warn if wildcard address - should we forbid this? */
- switch (p->addr->sa_family) {
- case AF_INET:
- if (((struct sockaddr_in *)p->addr)->sin_addr.s_addr == 0)
- plog(LLV_WARNING, LOCATION, NULL,
- "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,
- "listening to wildcard address, "
- "broadcast IKE packet may kill you\n");
- break;
-#endif
- default:
- plog(LLV_ERROR, LOCATION, NULL,
- "unsupported address family %d\n",
- lcconf->default_af);
- goto err_and_next;
- }
-
-#ifdef INET6
- if (p->addr->sa_family == AF_INET6 &&
- IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)
- p->addr)->sin6_addr))
- {
- plog(LLV_DEBUG, LOCATION, NULL,
- "Ignoring multicast address %s\n",
- saddr2str(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,
- "socket (%s)\n", strerror(errno));
- goto err_and_next;
- }
-#ifdef ANDROID_CHANGES
- protectFromVpn(p->sock);
-#endif
-
- if (fcntl(p->sock, F_SETFL, O_NONBLOCK) == -1)
- plog(LLV_WARNING, LOCATION, NULL,
- "failed to put socket in non-blocking mode\n");
-
- /* receive my interface address on inbound packets. */
- switch (p->addr->sa_family) {
- case AF_INET:
- 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,
- "setsockopt IP_RECVDSTADDR (%s)\n",
- strerror(errno));
- goto err_and_next;
- }
- break;
-#ifdef 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
- if (setsockopt(p->sock, IPPROTO_IPV6, pktinfo,
- (const void *)&yes, sizeof(yes)) < 0)
- {
- plog(LLV_ERROR, LOCATION, NULL,
- "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 &&
- setsockopt(p->sock, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
- (void *)&yes, sizeof(yes)) < 0) {
- plog(LLV_ERROR, LOCATION, NULL,
- "setsockopt IPV6_USE_MIN_MTU (%s)\n",
- strerror(errno));
- return -1;
- }
-#endif
-
- if (setsockopt_bypass(p->sock, p->addr->sa_family) < 0)
- goto err_and_next;
-
- if (bind(p->sock, p->addr, sysdep_sa_len(p->addr)) < 0) {
- plog(LLV_ERROR, LOCATION, p->addr,
- "failed to bind to address %s (%s).\n",
- saddr2str(p->addr), strerror(errno));
- close(p->sock);
- goto err_and_next;
- }
-
- ifnum++;
-
- plog(LLV_INFO, LOCATION, NULL,
- "%s used as isakmp port (fd=%d)\n",
- saddr2str(p->addr), p->sock);
-
-#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
- continue;
-
- err_and_next:
- racoon_free(p->addr);
- p->addr = NULL;
- if (! lcconf->autograbaddr && lcconf->strict_address)
- return -1;
- continue;
- }
-
- if (!ifnum) {
- plog(LLV_ERROR, LOCATION, NULL,
- "no address could be bound.\n");
- return -1;
- }
-
-#ifdef ENABLE_NATT
- if (natt_enabled_in_rmconf() && !encap_ifnum) {
- plog(LLV_WARNING, LOCATION, NULL,
- "NAT-T is enabled in at least one remote{} section,\n");
- plog(LLV_WARNING, LOCATION, NULL,
- "but no 'isakmp_natt' address was specified!\n");
- }
-#endif
-
- return 0;
-}
-
-void
-isakmp_close()
-{
-#ifndef ANDROID_PATCHED
- struct myaddrs *p, *next;
-
- for (p = lcconf->myaddrs; p; p = next) {
- next = p->next;
-
- if (!p->addr) {
- racoon_free(p);
- continue;
- }
- close(p->sock);
- racoon_free(p->addr);
- racoon_free(p);
- }
-
- lcconf->myaddrs = NULL;
-#endif
-}
-
-int
-isakmp_send(iph1, sbuf)
- struct ph1handle *iph1;
- vchar_t *sbuf;
-{
- int len = 0;
- int s;
- vchar_t *vbuf = NULL, swap;
-
-#ifdef ENABLE_NATT
- size_t extralen = NON_ESP_MARKER_USE(iph1) ? NON_ESP_MARKER_LEN : 0;
-
- /* Check if NON_ESP_MARKER_LEN is already there (happens when resending packets)
- */
- if(extralen == NON_ESP_MARKER_LEN &&
- *(u_int32_t *)sbuf->v == 0)
- extralen = 0;
-
-#ifdef ENABLE_FRAG
- /*
- * Do not add the non ESP marker for a packet that will
- * be fragmented. The non ESP marker should appear in
- * all fragment's packets, but not in the fragmented packet
- */
- if (iph1->frag && sbuf->l > ISAKMP_FRAG_MAXLEN)
- extralen = 0;
-#endif
- if (extralen)
- plog (LLV_DEBUG, LOCATION, NULL, "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,
- "vbuf allocation failed\n");
- return -1;
- }
- *(u_int32_t *)vbuf->v = 0;
- memcpy (vbuf->v + extralen, sbuf->v, sbuf->l);
- /* ensures that the modified buffer will be sent back to the caller, so
- * add_recvdpkt() will add the correct buffer
- */
- swap = *sbuf;
- *sbuf = *vbuf;
- *vbuf = swap;
- vfree(vbuf);
- }
-#endif
-
- /* select the socket to be sent */
- s = getsockmyaddr(iph1->local);
- if (s == -1){
- return -1;
- }
-
- plog (LLV_DEBUG, LOCATION, NULL, "%zu bytes %s\n", sbuf->l,
- saddr2str_fromto("from %s to %s", iph1->local, iph1->remote));
-
-#ifdef ENABLE_FRAG
- if (iph1->frag && sbuf->l > ISAKMP_FRAG_MAXLEN) {
- if (isakmp_sendfrags(iph1, sbuf) == -1) {
- plog(LLV_ERROR, LOCATION, NULL,
- "isakmp_sendfrags failed\n");
- return -1;
- }
- } else
-#endif
- {
- 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");
- return -1;
- }
- }
-
- return 0;
-}
-
-/* called from scheduler */
-void
-isakmp_ph1resend_stub(p)
- void *p;
-{
- struct ph1handle *iph1;
-
- iph1=(struct ph1handle *)p;
- if(isakmp_ph1resend(iph1) < 0){
- if(iph1->scr != NULL){
- /* Should not happen...
- */
- sched_kill(iph1->scr);
- iph1->scr=NULL;
- }
-
- remph1(iph1);
- delph1(iph1);
- }
-}
-
-int
-isakmp_ph1resend(iph1)
- struct ph1handle *iph1;
-{
- /* Note: NEVER do the rem/del here, it will be done by the caller or by the _stub function
- */
- if (iph1->retry_counter <= 0) {
- plog(LLV_ERROR, LOCATION, NULL,
- "phase1 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);
-
- return -1;
- }
-
- if (isakmp_send(iph1, iph1->sendbuf) < 0){
- plog(LLV_ERROR, LOCATION, NULL,
- "phase1 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;
- }
-
- plog(LLV_DEBUG, LOCATION, NULL,
- "resend phase1 packet %s\n",
- isakmp_pindex(&iph1->index, iph1->msgid));
-
- iph1->retry_counter--;
-
- iph1->scr = sched_new(iph1->rmconf->retry_interval,
- isakmp_ph1resend_stub, iph1);
-
- return 0;
-}
-
-/* called from scheduler */
-void
-isakmp_ph2resend_stub(p)
- void *p;
-{
- struct ph2handle *iph2;
-
- iph2=(struct ph2handle *)p;
-
- if(isakmp_ph2resend(iph2) < 0){
- unbindph12(iph2);
- remph2(iph2);
- delph2(iph2);
- }
-}
-
-int
-isakmp_ph2resend(iph2)
- struct ph2handle *iph2;
-{
- /* Note: NEVER do the unbind/rem/del here, it will be done by the caller or by the _stub function
- */
- if (iph2->ph1->status == PHASE1ST_EXPIRED){
- plog(LLV_ERROR, LOCATION, NULL,
- "phase2 negotiation failed due to phase1 expired. %s\n",
- isakmp_pindex(&iph2->ph1->index, iph2->msgid));
- return -1;
- }
-
- if (iph2->retry_counter <= 0) {
- plog(LLV_ERROR, LOCATION, NULL,
- "phase2 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);
- unbindph12(iph2);
- return -1;
- }
-
- if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0){
- plog(LLV_ERROR, LOCATION, NULL,
- "phase2 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;
- }
-
- plog(LLV_DEBUG, LOCATION, NULL,
- "resend phase2 packet %s\n",
- isakmp_pindex(&iph2->ph1->index, iph2->msgid));
-
- iph2->retry_counter--;
-
- iph2->scr = sched_new(iph2->ph1->rmconf->retry_interval,
- isakmp_ph2resend_stub, iph2);
-
- return 0;
-}
-
-/* called from scheduler */
-void
-isakmp_ph1expire_stub(p)
- void *p;
-{
-
- isakmp_ph1expire((struct ph1handle *)p);
-}
-
-void
-isakmp_ph1expire(iph1)
- struct ph1handle *iph1;
-{
- char *src, *dst;
-
- SCHED_KILL(iph1->sce);
-
- if(iph1->status != PHASE1ST_EXPIRED){
- src = racoon_strdup(saddr2str(iph1->local));
- dst = racoon_strdup(saddr2str(iph1->remote));
- STRDUP_FATAL(src);
- STRDUP_FATAL(dst);
-
- plog(LLV_INFO, LOCATION, NULL,
- "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;
- }
-
- /*
- * the phase1 deletion is postponed until there is no phase2.
- */
- if (LIST_FIRST(&iph1->ph2tree) != NULL) {
- iph1->sce = sched_new(1, isakmp_ph1expire_stub, iph1);
- return;
- }
-
- iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1);
-}
-
-/* called from scheduler */
-void
-isakmp_ph1delete_stub(p)
- void *p;
-{
-
- isakmp_ph1delete((struct ph1handle *)p);
-}
-
-void
-isakmp_ph1delete(iph1)
- struct ph1handle *iph1;
-{
- char *src, *dst;
-
- SCHED_KILL(iph1->sce);
-
- if (LIST_FIRST(&iph1->ph2tree) != NULL) {
- iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1);
- return;
- }
-
- /* don't re-negosiation when the phase 1 SA expires. */
-
- src = racoon_strdup(saddr2str(iph1->local));
- dst = racoon_strdup(saddr2str(iph1->remote));
- STRDUP_FATAL(src);
- STRDUP_FATAL(dst);
-
- plog(LLV_INFO, LOCATION, NULL,
- "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);
-
- return;
-}
-
-/* called from scheduler.
- * this function will call only isakmp_ph2delete().
- * phase 2 handler remain forever if kernel doesn't cry a expire of phase 2 SA
- * by something cause. That's why this function is called after phase 2 SA
- * expires in the userland.
- */
-void
-isakmp_ph2expire_stub(p)
- void *p;
-{
-
- isakmp_ph2expire((struct ph2handle *)p);
-}
-
-void
-isakmp_ph2expire(iph2)
- struct ph2handle *iph2;
-{
- char *src, *dst;
-
- SCHED_KILL(iph2->sce);
-
- src = racoon_strdup(saddrwop2str(iph2->src));
- dst = racoon_strdup(saddrwop2str(iph2->dst));
- STRDUP_FATAL(src);
- STRDUP_FATAL(dst);
-
- plog(LLV_INFO, LOCATION, NULL,
- "phase2 sa expired %s-%s\n", src, dst);
- racoon_free(src);
- racoon_free(dst);
-
- iph2->status = PHASE2ST_EXPIRED;
-
- iph2->sce = sched_new(1, isakmp_ph2delete_stub, iph2);
-
- return;
-}
-
-/* called from scheduler */
-void
-isakmp_ph2delete_stub(p)
- void *p;
-{
-
- isakmp_ph2delete((struct ph2handle *)p);
-}
-
-void
-isakmp_ph2delete(iph2)
- struct ph2handle *iph2;
-{
- char *src, *dst;
-
- SCHED_KILL(iph2->sce);
-
- src = racoon_strdup(saddrwop2str(iph2->src));
- dst = racoon_strdup(saddrwop2str(iph2->dst));
- STRDUP_FATAL(src);
- STRDUP_FATAL(dst);
-
- plog(LLV_INFO, LOCATION, NULL,
- "phase2 sa deleted %s-%s\n", src, dst);
- racoon_free(src);
- racoon_free(dst);
-
- unbindph12(iph2);
- remph2(iph2);
- delph2(iph2);
-
- return;
-}
-
-/* %%%
- * Interface between PF_KEYv2 and ISAKMP
- */
-/*
- * receive ACQUIRE from kernel, and begin either phase1 or phase2.
- * if phase1 has been finished, begin phase2.
- */
-int
-isakmp_post_acquire(iph2)
- struct ph2handle *iph2;
-{
- struct remoteconf *rmconf;
- struct ph1handle *iph1 = NULL;
-
- plog(LLV_DEBUG, LOCATION, NULL, "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));
- 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));
- return 0;
- }
-
- /*
- * Search isakmp status table by address and port
- * If NAT-T is in use, consider null ports as a
- * wildcard and use IKE ports instead.
- */
-#ifdef ENABLE_NATT
- if (!extract_port(iph2->src) && !extract_port(iph2->dst)) {
- if ((iph1 = getph1byaddrwop(iph2->src, iph2->dst)) != NULL) {
- set_port(iph2->src, extract_port(iph1->local));
- set_port(iph2->dst, extract_port(iph1->remote));
- }
- } else {
- iph1 = getph1byaddr(iph2->src, iph2->dst, 0);
- }
-#else
- iph1 = getph1byaddr(iph2->src, iph2->dst, 0);
-#endif
-
- /* no ISAKMP-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) {
- SCHED_KILL(sc);
- return -1;
- }
-
- return 0;
- /*NOTREACHED*/
- }
-
- /* found ISAKMP-SA, but on negotiation. */
- if (iph1->status != PHASE1ST_ESTABLISHED) {
- 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");
- 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))
- return -1;
-
- return 0;
-}
-
-/*
- * receive GETSPI from kernel.
- */
-int
-isakmp_post_getspi(iph2)
- struct ph2handle *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;
- }
-
-#ifdef ENABLE_STATS
- gettimeofday(&start, NULL);
-#endif
- if ((ph2exchange[etypesw2(ISAKMP_ETYPE_QUICK)]
- [iph2->side]
- [iph2->status])(iph2, NULL) != 0)
- 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));
-#endif
-
- return 0;
-}
-
-/* called by scheduler */
-void
-isakmp_chkph1there_stub(p)
- void *p;
-{
- isakmp_chkph1there((struct ph2handle *)p);
-}
-
-void
-isakmp_chkph1there(iph2)
- struct ph2handle *iph2;
-{
- struct ph1handle *iph1;
-
- iph2->retry_checkph1--;
- if (iph2->retry_checkph1 < 0) {
- plog(LLV_ERROR, LOCATION, iph2->dst,
- "phase2 negotiation failed "
- "due to time up waiting for phase1. %s\n",
- sadbsecas2str(iph2->dst, iph2->src,
- iph2->satype, 0, 0));
- plog(LLV_INFO, LOCATION, NULL,
- "delete phase 2 handler.\n");
-
- /* send acquire to kernel as error */
- pk_sendeacquire(iph2);
-
- unbindph12(iph2);
- remph2(iph2);
- delph2(iph2);
-
- return;
- }
-
- /*
- * Search isakmp status table by address and port
- * If NAT-T is in use, consider null ports as a
- * wildcard and use IKE ports instead.
- */
-#ifdef ENABLE_NATT
- if (!extract_port(iph2->src) && !extract_port(iph2->dst)) {
- plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: extract_port.\n");
- if( (iph1 = getph1byaddrwop(iph2->src, iph2->dst)) != NULL){
- plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: found a ph1 wop.\n");
- }
- } else {
- plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: searching byaddr.\n");
- iph1 = getph1byaddr(iph2->src, iph2->dst, 0);
- if(iph1 != NULL)
- plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: found byaddr.\n");
- }
-#else
- iph1 = getph1byaddr(iph2->src, iph2->dst, 0);
-#endif
-
- /* XXX Even if ph1 as responder is there, should we not start
- * phase 2 negotiation ? */
- if (iph1 != NULL
- && iph1->status == PHASE1ST_ESTABLISHED) {
- /* 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));
- 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));
-
- /* begin quick mode */
- (void)isakmp_ph2begin_i(iph1, iph2);
- return;
- }
-
- plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: no established ph1 handler found\n");
-
- /* no isakmp-sa found */
- sched_new(1, isakmp_chkph1there_stub, iph2);
-
- return;
-}
-
-/* copy variable data into ALLOCATED buffer. */
-caddr_t
-isakmp_set_attr_v(buf, type, val, len)
- caddr_t buf;
- int type;
- caddr_t val;
- int len;
-{
- struct isakmp_data *data;
-
- data = (struct isakmp_data *)buf;
- data->type = htons((u_int16_t)type | ISAKMP_GEN_TLV);
- data->lorv = htons((u_int16_t)len);
- memcpy(data + 1, val, len);
-
- return buf + sizeof(*data) + len;
-}
-
-/* copy fixed length data into ALLOCATED buffer. */
-caddr_t
-isakmp_set_attr_l(buf, type, val)
- caddr_t buf;
- int type;
- u_int32_t val;
-{
- struct isakmp_data *data;
-
- data = (struct isakmp_data *)buf;
- data->type = htons((u_int16_t)type | ISAKMP_GEN_TV);
- data->lorv = htons((u_int16_t)val);
-
- return buf + sizeof(*data);
-}
-
-/* add a variable data attribute to the buffer by reallocating it. */
-vchar_t *
-isakmp_add_attr_v(buf0, type, val, len)
- vchar_t *buf0;
- int type;
- caddr_t val;
- int len;
-{
- vchar_t *buf = NULL;
- struct isakmp_data *data;
- int tlen;
- int oldlen = 0;
-
- tlen = sizeof(*data) + len;
-
- if (buf0) {
- oldlen = buf0->l;
- buf = vrealloc(buf0, oldlen + tlen);
- } else
- buf = vmalloc(tlen);
- if (!buf) {
- plog(LLV_ERROR, LOCATION, NULL,
- "failed to get a attribute buffer.\n");
- return NULL;
- }
-
- data = (struct isakmp_data *)(buf->v + oldlen);
- data->type = htons((u_int16_t)type | ISAKMP_GEN_TLV);
- data->lorv = htons((u_int16_t)len);
- memcpy(data + 1, val, len);
-
- return buf;
-}
-
-/* add a fixed data attribute to the buffer by reallocating it. */
-vchar_t *
-isakmp_add_attr_l(buf0, type, val)
- vchar_t *buf0;
- int type;
- u_int32_t val;
-{
- vchar_t *buf = NULL;
- struct isakmp_data *data;
- int tlen;
- int oldlen = 0;
-
- tlen = sizeof(*data);
-
- if (buf0) {
- oldlen = buf0->l;
- buf = vrealloc(buf0, oldlen + tlen);
- } else
- buf = vmalloc(tlen);
- if (!buf) {
- plog(LLV_ERROR, LOCATION, NULL,
- "failed to get a attribute buffer.\n");
- return NULL;
- }
-
- data = (struct isakmp_data *)(buf->v + oldlen);
- data->type = htons((u_int16_t)type | ISAKMP_GEN_TV);
- data->lorv = htons((u_int16_t)val);
-
- return buf;
-}
-
-/*
- * calculate cookie and set.
- */
-int
-isakmp_newcookie(place, remote, local)
- caddr_t place;
- struct sockaddr *remote;
- struct sockaddr *local;
-{
- vchar_t *buf = NULL, *buf2 = NULL;
- char *p;
- int blen;
- int alen;
- caddr_t sa1, sa2;
- time_t t;
- int error = -1;
- u_short port;
-
-
- if (remote->sa_family != local->sa_family) {
- plog(LLV_ERROR, LOCATION, NULL,
- "address family mismatch, remote:%d local:%d\n",
- remote->sa_family, local->sa_family);
- goto end;
- }
- switch (remote->sa_family) {
- case AF_INET:
- alen = sizeof(struct in_addr);
- sa1 = (caddr_t)&((struct sockaddr_in *)remote)->sin_addr;
- sa2 = (caddr_t)&((struct sockaddr_in *)local)->sin_addr;
- break;
-#ifdef INET6
- case AF_INET6:
- alen = sizeof(struct in6_addr);
- sa1 = (caddr_t)&((struct sockaddr_in6 *)remote)->sin6_addr;
- sa2 = (caddr_t)&((struct sockaddr_in6 *)local)->sin6_addr;
- break;
-#endif
- default:
- plog(LLV_ERROR, LOCATION, NULL,
- "invalid family: %d\n", remote->sa_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,
- "failed to get a cookie.\n");
- goto end;
- }
- p = buf->v;
-
- /* copy my address */
- memcpy(p, sa1, alen);
- p += alen;
- port = ((struct sockaddr_in *)remote)->sin_port;
- memcpy(p, &port, sizeof(u_short));
- p += sizeof(u_short);
-
- /* copy target address */
- memcpy(p, sa2, alen);
- p += alen;
- port = ((struct sockaddr_in *)local)->sin_port;
- memcpy(p, &port, sizeof(u_short));
- p += sizeof(u_short);
-
- /* copy time */
- t = time(0);
- memcpy(p, (caddr_t)&t, sizeof(t));
- p += sizeof(t);
-
- /* copy random value */
- buf2 = eay_set_random(lcconf->secret_size);
- if (buf2 == NULL)
- goto end;
- memcpy(p, buf2->v, lcconf->secret_size);
- p += lcconf->secret_size;
- vfree(buf2);
-
- buf2 = eay_sha1_one(buf);
- memcpy(place, buf2->v, sizeof(cookie_t));
-
- sa1 = val2str(place, sizeof (cookie_t));
- plog(LLV_DEBUG, LOCATION, NULL, "new cookie:\n%s\n", sa1);
- racoon_free(sa1);
-
- error = 0;
-end:
- if (buf != NULL)
- vfree(buf);
- if (buf2 != NULL)
- vfree(buf2);
- return error;
-}
-
-/*
- * save partner's(payload) data into phhandle.
- */
-int
-isakmp_p2ph(buf, gen)
- vchar_t **buf;
- struct isakmp_gen *gen;
-{
- /* XXX to be checked in each functions for logging. */
- if (*buf) {
- plog(LLV_WARNING, LOCATION, NULL,
- "ignore this payload, same payload type exist.\n");
- return -1;
- }
-
- *buf = vmalloc(ntohs(gen->len) - sizeof(*gen));
- if (*buf == NULL) {
- plog(LLV_ERROR, LOCATION, NULL,
- "failed to get buffer.\n");
- return -1;
- }
- memcpy((*buf)->v, gen + 1, (*buf)->l);
-
- return 0;
-}
-
-u_int32_t
-isakmp_newmsgid2(iph1)
- struct ph1handle *iph1;
-{
- u_int32_t msgid2;
-
- do {
- msgid2 = eay_random();
- } while (getph2bymsgid(iph1, msgid2));
-
- return msgid2;
-}
-
-/*
- * set values into allocated buffer of isakmp header for phase 1
- */
-static caddr_t
-set_isakmp_header(vbuf, iph1, nptype, etype, flags, msgid)
- vchar_t *vbuf;
- struct ph1handle *iph1;
- int nptype;
- u_int8_t etype;
- u_int8_t flags;
- u_int32_t msgid;
-{
- struct isakmp *isakmp;
-
- if (vbuf->l < sizeof(*isakmp))
- return NULL;
-
- isakmp = (struct isakmp *)vbuf->v;
-
- memcpy(&isakmp->i_ck, &iph1->index.i_ck, sizeof(cookie_t));
- memcpy(&isakmp->r_ck, &iph1->index.r_ck, sizeof(cookie_t));
- isakmp->np = nptype;
- isakmp->v = iph1->version;
- isakmp->etype = etype;
- isakmp->flags = flags;
- isakmp->msgid = msgid;
- isakmp->len = htonl(vbuf->l);
-
- return vbuf->v + sizeof(*isakmp);
-}
-
-/*
- * set values into allocated buffer of isakmp header for phase 1
- */
-caddr_t
-set_isakmp_header1(vbuf, iph1, nptype)
- vchar_t *vbuf;
- struct ph1handle *iph1;
- int nptype;
-{
- return set_isakmp_header (vbuf, iph1, nptype, iph1->etype, iph1->flags, iph1->msgid);
-}
-
-/*
- * set values into allocated buffer of isakmp header for phase 2
- */
-caddr_t
-set_isakmp_header2(vbuf, iph2, nptype)
- vchar_t *vbuf;
- struct ph2handle *iph2;
- int nptype;
-{
- return set_isakmp_header (vbuf, iph2->ph1, nptype, ISAKMP_ETYPE_QUICK, iph2->flags, iph2->msgid);
-}
-
-/*
- * set values into allocated buffer of isakmp payload.
- */
-caddr_t
-set_isakmp_payload(buf, src, nptype)
- caddr_t buf;
- vchar_t *src;
- int nptype;
-{
- struct isakmp_gen *gen;
- caddr_t p = buf;
-
- plog(LLV_DEBUG, LOCATION, NULL, "add payload of len %zu, next type %d\n",
- src->l, nptype);
-
- gen = (struct isakmp_gen *)p;
- gen->np = nptype;
- gen->len = htons(sizeof(*gen) + src->l);
- p += sizeof(*gen);
- memcpy(p, src->v, src->l);
- p += src->l;
-
- 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 *));
-
-char *getname __P((const u_char *));
-#ifdef INET6
-char *getname6 __P((const u_char *));
-#endif
-int safeputchar __P((int));
-
-/*
- * Return a name for the IP address pointed to by ap. This address
- * is assumed to be in network byte order.
- */
-char *
-getname(ap)
- const u_char *ap;
-{
- struct sockaddr_in addr;
- 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),
- ntop_buf, sizeof(ntop_buf), NULL, 0,
- NI_NUMERICHOST | niflags))
- strlcpy(ntop_buf, "?", sizeof(ntop_buf));
-
- return ntop_buf;
-}
-
-#ifdef INET6
-/*
- * Return a name for the IP6 address pointed to by ap. This address
- * is assumed to be in network byte order.
- */
-char *
-getname6(ap)
- const u_char *ap;
-{
- struct sockaddr_in6 addr;
- static char ntop_buf[NI_MAXHOST];
-
- memset(&addr, 0, sizeof(addr));
- 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,
- ntop_buf, sizeof(ntop_buf), NULL, 0,
- NI_NUMERICHOST | niflags))
- strlcpy(ntop_buf, "?", sizeof(ntop_buf));
-
- return ntop_buf;
-}
-#endif /* INET6 */
-
-int
-safeputchar(c)
- int c;
-{
- unsigned char ch;
-
- ch = (unsigned char)(c & 0xff);
- if (c < 0x80 && isprint(c))
- return printf("%c", c & 0xff);
- else
- return printf("\\%03o", c & 0xff);
-}
-
-void
-isakmp_printpacket(msg, from, my, decoded)
- vchar_t *msg;
- struct sockaddr *from;
- struct sockaddr *my;
- int decoded;
-{
-#ifdef YIPS_DEBUG
- struct timeval tv;
- int s;
- char hostbuf[NI_MAXHOST];
- char portbuf[NI_MAXSERV];
- struct isakmp *isakmp;
- vchar_t *buf;
-#endif
-
- if (loglevel < LLV_DEBUG)
- return;
-
-#ifdef YIPS_DEBUG
- plog(LLV_DEBUG, LOCATION, NULL, "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),
- portbuf, sizeof(portbuf),
- NI_NUMERICHOST | NI_NUMERICSERV | niflags)) {
- strlcpy(hostbuf, "?", sizeof(hostbuf));
- strlcpy(portbuf, "?", sizeof(portbuf));
- }
- printf("%s:%s", hostbuf, portbuf);
- } else
- printf("?");
- printf(" -> ");
- if (my) {
- if (getnameinfo(my, sysdep_sa_len(my), hostbuf, sizeof(hostbuf),
- portbuf, sizeof(portbuf),
- NI_NUMERICHOST | NI_NUMERICSERV | niflags)) {
- strlcpy(hostbuf, "?", sizeof(hostbuf));
- strlcpy(portbuf, "?", sizeof(portbuf));
- }
- printf("%s:%s", hostbuf, portbuf);
- } else
- printf("?");
- printf(": ");
-
- buf = vdup(msg);
- if (!buf) {
- printf("(malloc fail)\n");
- return;
- }
- if (decoded) {
- isakmp = (struct isakmp *)buf->v;
- if (isakmp->flags & ISAKMP_FLAG_E) {
-#if 0
- int pad;
- pad = *(u_char *)(buf->v + buf->l - 1);
- if (buf->l < pad && 2 < vflag)
- printf("(wrong padding)");
-#endif
- isakmp->flags &= ~ISAKMP_FLAG_E;
- }
- }
-
- snapend = buf->v + buf->l;
- isakmp_print(buf->v, buf->l, NULL);
- vfree(buf);
- printf("\n");
- fflush(stdout);
-
- return;
-#endif
-}
-#endif /*HAVE_PRINT_ISAKMP_C*/
-
-int
-copy_ph1addresses(iph1, rmconf, remote, local)
- struct ph1handle *iph1;
- struct remoteconf *rmconf;
- struct sockaddr *remote, *local;
-{
- u_int16_t port;
-
- /* address portion must be grabbed from real remote address "remote" */
- iph1->remote = dupsaddr(remote);
- if (iph1->remote == NULL)
- return -1;
-
- /*
- * if remote has no port # (in case of initiator - from ACQUIRE msg)
- * - if remote.conf specifies port #, use that
- * - if remote.conf does not, use 500
- * if remote has port # (in case of responder - from recvfrom(2))
- * respect content of "remote".
- */
- if (extract_port(iph1->remote) == 0) {
- port = extract_port(rmconf->remote);
- if (port == 0)
- port = PORT_ISAKMP;
- set_port(iph1->remote, port);
- }
-
- if (local == NULL)
- iph1->local = getlocaladdr(iph1->remote);
- else
- iph1->local = dupsaddr(local);
- if (iph1->local == NULL)
- return -1;
-
- if (extract_port(iph1->local) == 0)
- set_port(iph1->local, PORT_ISAKMP);
-
-#ifdef ENABLE_NATT
- if (extract_port(iph1->local) == lcconf->port_isakmp_natt) {
- plog(LLV_DEBUG, LOCATION, NULL, "Marking ports as changed\n");
- iph1->natt_flags |= NAT_ADD_NON_ESP_MARKER;
- }
-#endif
-
- 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;
-{
- char *src, *dst;
-
- src = racoon_strdup(saddr2str(iph1->local));
- dst = racoon_strdup(saddr2str(iph1->remote));
- STRDUP_FATAL(src);
- STRDUP_FATAL(dst);
-
- plog(LLV_INFO, LOCATION, NULL,
- "ISAKMP-SA established %s-%s spi:%s\n",
- src, dst,
- 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);
- }
-
- racoon_free(src);
- racoon_free(dst);
-
- return;
-}
-
-struct payload_list *
-isakmp_plist_append (struct payload_list *plist, vchar_t *payload, int payload_type)
-{
- if (! plist) {
- plist = racoon_malloc (sizeof (struct payload_list));
- plist->prev = NULL;
- }
- else {
- plist->next = racoon_malloc (sizeof (struct payload_list));
- plist->next->prev = plist;
- plist = plist->next;
- }
-
- plist->next = NULL;
- plist->payload = payload;
- plist->payload_type = payload_type;
-
- return plist;
-}
-
-vchar_t *
-isakmp_plist_set_all (struct payload_list **plist, struct ph1handle *iph1)
-{
- struct payload_list *ptr = *plist, *first;
- size_t tlen = sizeof (struct isakmp), n = 0;
- vchar_t *buf = NULL;
- char *p;
-
- /* Seek to the first item. */
- while (ptr->prev) ptr = ptr->prev;
- first = ptr;
-
- /* Compute the whole length. */
- while (ptr) {
- tlen += ptr->payload->l + sizeof (struct isakmp_gen);
- ptr = ptr->next;
- }
-
- buf = vmalloc(tlen);
- if (buf == NULL) {
- plog(LLV_ERROR, LOCATION, NULL,
- "failed to get buffer to send.\n");
- goto end;
- }
-
- ptr = first;
-
- p = set_isakmp_header1(buf, iph1, ptr->payload_type);
- if (p == NULL)
- goto end;
-
- while (ptr)
- {
- p = set_isakmp_payload (p, ptr->payload, ptr->next ? ptr->next->payload_type : ISAKMP_NPTYPE_NONE);
- first = ptr;
- ptr = ptr->next;
- racoon_free (first);
- /* ptr->prev = NULL; first = NULL; ... omitted. */
- n++;
- }
-
- *plist = NULL;
-
- return buf;
-end:
- if (buf != NULL)
- vfree(buf);
- return NULL;
-}
-
-#ifdef ENABLE_FRAG
-int
-frag_handler(iph1, msg, remote, local)
- struct ph1handle *iph1;
- vchar_t *msg;
- struct sockaddr *remote;
- struct sockaddr *local;
-{
- vchar_t *newmsg;
-
- if (isakmp_frag_extract(iph1, msg) == 1) {
- if ((newmsg = isakmp_frag_reassembly(iph1)) == NULL) {
- plog(LLV_ERROR, LOCATION, remote,
- "Packet reassembly failed\n");
- return -1;
- }
- 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, PORT_MAX, "%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;
- }
-
- /* 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, PORT_MAX, "%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;
- }
-
- if (script_env_append(&envp, &envc,
- "REMOTE_PORT", portstr) != 0) {
- plog(LLV_ERROR, LOCATION, NULL,
- "Cannot set REMOTEL_PORT\n");
- goto out;
- }
- }
-
- 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;
-
- if (value == NULL) {
- value = "";
- }
-
- envitem = racoon_malloc(strlen(name) + 1 + strlen(value) + 1);
- if (envitem == NULL) {
- plog(LLV_ERROR, LOCATION, NULL,
- "Cannot allocate memory: %s\n", strerror(errno));
- return -1;
- }
- sprintf(envitem, "%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;
-
-}
-
-void
-purge_remote(iph1)
- struct ph1handle *iph1;
-{
- vchar_t *buf = NULL;
- struct sadb_msg *msg, *next, *end;
- struct sadb_sa *sa;
- struct sockaddr *src, *dst;
- caddr_t mhp[SADB_EXT_MAX + 1];
- u_int proto_id;
- struct ph2handle *iph2;
- struct ph1handle *new_iph1;
-
- plog(LLV_INFO, LOCATION, NULL,
- "purging ISAKMP-SA spi=%s.\n",
- isakmp_pindex(&(iph1->index), iph1->msgid));
-
- /* Mark as expired. */
- iph1->status = PHASE1ST_EXPIRED;
-
- /* Check if we have another, still valid, phase1 SA. */
- new_iph1 = getph1byaddr(iph1->local, iph1->remote, 1);
-
- /*
- * Delete all orphaned or binded to the deleting ph1handle phase2 SAs.
- * Keep all others phase2 SAs.
- */
- buf = pfkey_dump_sadb(SADB_SATYPE_UNSPEC);
- if (buf == NULL) {
- plog(LLV_DEBUG, LOCATION, NULL,
- "pfkey_dump_sadb returned nothing.\n");
- return;
- }
-
- msg = (struct sadb_msg *)buf->v;
- end = (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));
- if (msg->sadb_msg_type != SADB_DUMP) {
- msg = next;
- continue;
- }
-
- if (pfkey_align(msg, mhp) || pfkey_check(mhp)) {
- plog(LLV_ERROR, LOCATION, NULL,
- "pfkey_check (%s)\n", ipsec_strerror());
- msg = next;
- continue;
- }
-
- sa = (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]);
-
- if (sa->sadb_sa_state != SADB_SASTATE_LARVAL &&
- sa->sadb_sa_state != SADB_SASTATE_MATURE &&
- sa->sadb_sa_state != SADB_SASTATE_DYING) {
- msg = next;
- continue;
- }
-
- /*
- * check in/outbound SAs.
- * Select only SAs where src == local and dst == remote (outgoing)
- * or src == remote and dst == local (incoming).
- */
- if ((CMPSADDR(iph1->local, src) || CMPSADDR(iph1->remote, dst)) &&
- (CMPSADDR(iph1->local, dst) || CMPSADDR(iph1->remote, src))) {
- msg = next;
- continue;
- }
-
- proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype);
- iph2 = 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,
- "Unknown IPsec-SA spi=%u, hmmmm?\n",
- ntohl(sa->sadb_sa_spi));
- }else{
-
- /*
- * If we have a new ph1, do not purge IPsec-SAs binded
- * to a different ISAKMP-SA
- */
- if (iph2->ph1 != NULL && iph2->ph1 != iph1){
- msg = next;
- continue;
- }
-
- /* If the ph2handle is established, do not purge IPsec-SA */
- if (iph2->status == PHASE2ST_ESTABLISHED ||
- iph2->status == PHASE2ST_EXPIRED) {
-
- plog(LLV_INFO, LOCATION, NULL,
- "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));
- msg = next;
- continue;
- }
- }
- }
-
-
- pfkey_send_delete(lcconf->sock_pfkey,
- msg->sadb_msg_satype,
- IPSEC_MODE_ANY,
- src, dst, sa->sadb_sa_spi);
-
- /* delete a relative phase 2 handle. */
- if (iph2 != NULL) {
- delete_spd(iph2, 0);
- unbindph12(iph2);
- remph2(iph2);
- delph2(iph2);
- }
-
- plog(LLV_INFO, LOCATION, NULL,
- "purged IPsec-SA spi=%u.\n",
- ntohl(sa->sadb_sa_spi));
-
- msg = next;
- }
-
- if (buf)
- vfree(buf);
-
- /* Mark the phase1 handler as EXPIRED */
- plog(LLV_INFO, LOCATION, NULL,
- "purged ISAKMP-SA spi=%s.\n",
- isakmp_pindex(&(iph1->index), iph1->msgid));
-
- SCHED_KILL(iph1->sce);
-
- iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1);
-}
-
-void
-delete_spd(iph2, created)
- struct ph2handle *iph2;
- u_int64_t created;
-{
- struct policyindex spidx;
- struct sockaddr_storage addr;
- u_int8_t pref;
- struct sockaddr *src;
- struct sockaddr *dst;
- int error;
- int idi2type = 0;/* switch whether copy IDs into id[src,dst]. */
-
- if (iph2 == NULL)
- return;
-
- /* Delete the SPD entry if we generated it
- */
- if (! iph2->generated_spidx )
- return;
-
- src = iph2->src;
- dst = iph2->dst;
-
- plog(LLV_INFO, LOCATION, NULL,
- "generated policy, deleting it.\n");
-
- memset(&spidx, 0, sizeof(spidx));
- iph2->spidx_gen = (caddr_t )&spidx;
-
- /* make inbound policy */
- iph2->src = dst;
- iph2->dst = src;
- spidx.dir = IPSEC_DIR_INBOUND;
- spidx.ul_proto = 0;
-
- /*
- * Note: code from get_proposal_r
- */
-
-#define _XIDT(d) ((struct ipsecdoi_id_b *)(d)->v)->type
-
- /*
- * make destination address in spidx from either ID payload
- * or phase 1 address into a address in spidx.
- */
- if (iph2->id != NULL
- && (_XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR
- || _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR
- || _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);
- if (error)
- goto purge;
-
-#ifdef INET6
- /*
- * get scopeid from the SA address.
- * note that the phase 1 source address is used as
- * a destination address to search for a inbound
- * policy entry because rcoon is responder.
- */
- if (_XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR) {
- if ((error =
- setscopeid((struct sockaddr *)&spidx.dst,
- iph2->src)) != 0)
- goto purge;
- }
-#endif
-
- if (_XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR
- || _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR)
- idi2type = _XIDT(iph2->id);
-
- } else {
-
- plog(LLV_DEBUG, LOCATION, NULL,
- "get a destination address of SP index "
- "from phase1 address "
- "due to no ID payloads found "
- "OR because ID type is not address.\n");
-
- /*
- * copy the SOURCE address of IKE into the
- * 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) {
- case AF_INET:
- spidx.prefd =
- sizeof(struct in_addr) << 3;
- break;
-#ifdef INET6
- case AF_INET6:
- spidx.prefd =
- sizeof(struct in6_addr) << 3;
- break;
-#endif
- default:
- spidx.prefd = 0;
- break;
- }
- }
-
- /* make source address in spidx */
- if (iph2->id_p != NULL
- && (_XIDT(iph2->id_p) == IPSECDOI_ID_IPV4_ADDR
- || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR
- || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV4_ADDR_SUBNET
- || _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);
- if (error)
- goto purge;
-
-#ifdef INET6
- /*
- * get scopeid from the SA address.
- * for more detail, see above of this function.
- */
- if (_XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR) {
- error =
- setscopeid((struct sockaddr *)&spidx.src,
- iph2->dst);
- if (error)
- goto purge;
- }
-#endif
-
- /* 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) {
- iph2->src_id =
- dupsaddr((struct sockaddr *)&spidx.dst);
- if (iph2->src_id == NULL) {
- plog(LLV_ERROR, LOCATION, NULL,
- "allocation failed\n");
- goto purge;
- }
- iph2->dst_id =
- dupsaddr((struct sockaddr *)&spidx.src);
- if (iph2->dst_id == NULL) {
- plog(LLV_ERROR, LOCATION, NULL,
- "allocation failed\n");
- goto purge;
- }
- }
-
- } else {
- plog(LLV_DEBUG, LOCATION, NULL,
- "get a source address of SP index "
- "from phase1 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) {
- case AF_INET:
- spidx.prefs =
- sizeof(struct in_addr) << 3;
- break;
-#ifdef INET6
- case AF_INET6:
- spidx.prefs =
- sizeof(struct in6_addr) << 3;
- break;
-#endif
- default:
- spidx.prefs = 0;
- break;
- }
- }
-
-#undef _XIDT
-
- plog(LLV_DEBUG, LOCATION, NULL,
- "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,
- "get dst address from ID payload "
- "%s prefixlen=%u ul_proto=%u\n",
- saddr2str((struct sockaddr *)&spidx.dst),
- spidx.prefd, 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;
-
-#undef _XIDT
-
- /* Check if the generated SPD has the same timestamp as the SA.
- * If timestamps are different, this means that the SPD entry has been
- * refreshed by another SA, and should NOT be deleted with the current SA.
- */
- if( created ){
- struct secpolicy *p;
-
- p = getsp(&spidx);
- if(p != NULL){
- /* just do no test if p is NULL, because this probably just means
- * that the policy has already be deleted for some reason.
- */
- if(p->spidx.created != created)
- goto purge;
- }
- }
-
- /* End of code from get_proposal_r
- */
-
- if (pk_sendspddelete(iph2) < 0) {
- plog(LLV_ERROR, LOCATION, NULL,
- "pfkey spddelete(inbound) failed.\n");
- }else{
- plog(LLV_DEBUG, LOCATION, NULL,
- "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;
- if (pk_sendspddelete(iph2) < 0) {
- plog(LLV_ERROR, LOCATION, NULL,
- "pfkey spddelete(forward) failed.\n");
- }else{
- plog(LLV_DEBUG, LOCATION, NULL,
- "pfkey spddelete(forward) sent.\n");
- }
- }
-#endif
-
- /* 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;
-
- if (pk_sendspddelete(iph2) < 0) {
- plog(LLV_ERROR, LOCATION, NULL,
- "pfkey spddelete(outbound) failed.\n");
- }else{
- plog(LLV_DEBUG, LOCATION, NULL,
- "pfkey spddelete(outbound) sent.\n");
- }
-purge:
- iph2->spidx_gen=NULL;
-}
-
-
-#ifdef INET6
-u_int32_t
-setscopeid(sp_addr0, sa_addr0)
- struct sockaddr *sp_addr0, *sa_addr0;
-{
- struct sockaddr_in6 *sp_addr, *sa_addr;
-
- sp_addr = (struct sockaddr_in6 *)sp_addr0;
- sa_addr = (struct sockaddr_in6 *)sa_addr0;
-
- if (!IN6_IS_ADDR_LINKLOCAL(&sp_addr->sin6_addr)
- && !IN6_IS_ADDR_SITELOCAL(&sp_addr->sin6_addr)
- && !IN6_IS_ADDR_MULTICAST(&sp_addr->sin6_addr))
- return 0;
-
- /* this check should not be here ? */
- if (sa_addr->sin6_family != AF_INET6) {
- plog(LLV_ERROR, LOCATION, NULL,
- "can't get scope ID: family mismatch\n");
- return -1;
- }
-
- if (!IN6_IS_ADDR_LINKLOCAL(&sa_addr->sin6_addr)) {
- plog(LLV_ERROR, LOCATION, NULL,
- "scope ID is not supported except of lladdr.\n");
- return -1;
- }
-
- sp_addr->sin6_scope_id = sa_addr->sin6_scope_id;
-
- return 0;
-}
-#endif