summaryrefslogtreecommitdiffstats
path: root/ipsec-tools/src/racoon/isakmp_frag.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipsec-tools/src/racoon/isakmp_frag.c')
-rw-r--r--ipsec-tools/src/racoon/isakmp_frag.c356
1 files changed, 356 insertions, 0 deletions
diff --git a/ipsec-tools/src/racoon/isakmp_frag.c b/ipsec-tools/src/racoon/isakmp_frag.c
new file mode 100644
index 00000000..ebba34b4
--- /dev/null
+++ b/ipsec-tools/src/racoon/isakmp_frag.c
@@ -0,0 +1,356 @@
+/* $NetBSD: isakmp_frag.c,v 1.5 2009/04/22 11:24:20 tteras Exp $ */
+
+/* Id: isakmp_frag.c,v 1.4 2004/11/13 17:31:36 manubsd Exp */
+
+/*
+ * Copyright (C) 2004 Emmanuel Dreyfus
+ * 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 <openssl/md5.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.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>
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "sockmisc.h"
+#include "schedule.h"
+#include "debug.h"
+
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "handler.h"
+#include "isakmp_frag.h"
+#include "strnames.h"
+
+int
+isakmp_sendfrags(iph1, buf)
+ struct ph1handle *iph1;
+ vchar_t *buf;
+{
+ struct isakmp *hdr;
+ struct isakmp_frag *fraghdr;
+ caddr_t data;
+ caddr_t sdata;
+ size_t datalen;
+ size_t max_datalen;
+ size_t fraglen;
+ vchar_t *frag;
+ unsigned int trailer;
+ unsigned int fragnum = 0;
+ size_t len;
+ int etype;
+
+ /*
+ * Catch the exchange type for later: the fragments and the
+ * fragmented packet must have the same exchange type.
+ */
+ hdr = (struct isakmp *)buf->v;
+ etype = hdr->etype;
+
+ /*
+ * We want to send a a packet smaller than ISAKMP_FRAG_MAXLEN
+ * First compute the maximum data length that will fit in it
+ */
+ max_datalen = ISAKMP_FRAG_MAXLEN -
+ (sizeof(*hdr) + sizeof(*fraghdr) + sizeof(trailer));
+
+ sdata = buf->v;
+ len = buf->l;
+
+ while (len > 0) {
+ fragnum++;
+
+ if (len > max_datalen)
+ datalen = max_datalen;
+ else
+ datalen = len;
+
+ fraglen = sizeof(*hdr)
+ + sizeof(*fraghdr)
+ + datalen;
+
+ if ((frag = vmalloc(fraglen)) == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "Cannot allocate memory\n");
+ return -1;
+ }
+
+ set_isakmp_header1(frag, iph1, ISAKMP_NPTYPE_FRAG);
+ hdr = (struct isakmp *)frag->v;
+ hdr->etype = etype;
+
+ fraghdr = (struct isakmp_frag *)(hdr + 1);
+ fraghdr->unknown0 = htons(0);
+ fraghdr->len = htons(fraglen - sizeof(*hdr));
+ fraghdr->unknown1 = htons(1);
+ fraghdr->index = fragnum;
+ if (len == datalen)
+ fraghdr->flags = ISAKMP_FRAG_LAST;
+ else
+ fraghdr->flags = 0;
+
+ data = (caddr_t)(fraghdr + 1);
+ memcpy(data, sdata, datalen);
+
+ if (isakmp_send(iph1, frag) < 0) {
+ plog(LLV_ERROR, LOCATION, NULL, "isakmp_send failed\n");
+ return -1;
+ }
+
+ vfree(frag);
+
+ len -= datalen;
+ sdata += datalen;
+ }
+
+ return fragnum;
+}
+
+unsigned int
+vendorid_frag_cap(gen)
+ struct isakmp_gen *gen;
+{
+ int *hp;
+
+ hp = (int *)(gen + 1);
+
+ return ntohl(hp[MD5_DIGEST_LENGTH / sizeof(*hp)]);
+}
+
+int
+isakmp_frag_extract(iph1, msg)
+ struct ph1handle *iph1;
+ vchar_t *msg;
+{
+ struct isakmp *isakmp;
+ struct isakmp_frag *frag;
+ struct isakmp_frag_item *item;
+ vchar_t *buf;
+ size_t len;
+ int last_frag = 0;
+ char *data;
+ int i;
+
+ if (msg->l < sizeof(*isakmp) + sizeof(*frag)) {
+ plog(LLV_ERROR, LOCATION, NULL, "Message too short\n");
+ return -1;
+ }
+
+ isakmp = (struct isakmp *)msg->v;
+ frag = (struct isakmp_frag *)(isakmp + 1);
+
+ /*
+ * frag->len is the frag payload data plus the frag payload header,
+ * whose size is sizeof(*frag)
+ */
+ if (msg->l < sizeof(*isakmp) + ntohs(frag->len) ||
+ ntohs(frag->len) < sizeof(*frag) + 1) {
+ plog(LLV_ERROR, LOCATION, NULL, "Fragment too short\n");
+ return -1;
+ }
+
+ if ((buf = vmalloc(ntohs(frag->len) - sizeof(*frag))) == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
+ return -1;
+ }
+
+ if ((item = racoon_malloc(sizeof(*item))) == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
+ vfree(buf);
+ return -1;
+ }
+
+ data = (char *)(frag + 1);
+ memcpy(buf->v, data, buf->l);
+
+ item->frag_num = frag->index;
+ item->frag_last = (frag->flags & ISAKMP_FRAG_LAST);
+ item->frag_next = NULL;
+ item->frag_packet = buf;
+
+ /* Look for the last frag while inserting the new item in the chain */
+ if (item->frag_last)
+ last_frag = item->frag_num;
+
+ if (iph1->frag_chain == NULL) {
+ iph1->frag_chain = item;
+ } else {
+ struct isakmp_frag_item *current;
+
+ current = iph1->frag_chain;
+ while (current->frag_next) {
+ if (current->frag_last)
+ last_frag = item->frag_num;
+ current = current->frag_next;
+ }
+ current->frag_next = item;
+ }
+
+ /* If we saw the last frag, check if the chain is complete */
+ if (last_frag != 0) {
+ for (i = 1; i <= last_frag; i++) {
+ item = iph1->frag_chain;
+ do {
+ if (item->frag_num == i)
+ break;
+ item = item->frag_next;
+ } while (item != NULL);
+
+ if (item == NULL) /* Not found */
+ break;
+ }
+
+ if (item != NULL) /* It is complete */
+ return 1;
+ }
+
+ return 0;
+}
+
+vchar_t *
+isakmp_frag_reassembly(iph1)
+ struct ph1handle *iph1;
+{
+ struct isakmp_frag_item *item;
+ size_t len = 0;
+ vchar_t *buf = NULL;
+ int frag_count = 0;
+ int i;
+ char *data;
+
+ if ((item = iph1->frag_chain) == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL, "No fragment to reassemble\n");
+ goto out;
+ }
+
+ do {
+ frag_count++;
+ len += item->frag_packet->l;
+ item = item->frag_next;
+ } while (item != NULL);
+
+ if ((buf = vmalloc(len)) == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
+ goto out;
+ }
+ data = buf->v;
+
+ for (i = 1; i <= frag_count; i++) {
+ item = iph1->frag_chain;
+ do {
+ if (item->frag_num == i)
+ break;
+ item = item->frag_next;
+ } while (item != NULL);
+
+ if (item == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "Missing fragment #%d\n", i);
+ vfree(buf);
+ buf = NULL;
+ goto out;
+ }
+ memcpy(data, item->frag_packet->v, item->frag_packet->l);
+ data += item->frag_packet->l;
+ }
+
+out:
+ item = iph1->frag_chain;
+ do {
+ struct isakmp_frag_item *next_item;
+
+ next_item = item->frag_next;
+
+ vfree(item->frag_packet);
+ racoon_free(item);
+
+ item = next_item;
+ } while (item != NULL);
+
+ iph1->frag_chain = NULL;
+
+ return buf;
+}
+
+vchar_t *
+isakmp_frag_addcap(buf, cap)
+ vchar_t *buf;
+ int cap;
+{
+ int *capp;
+ size_t len;
+
+ /* If the capability has not been added, add room now */
+ len = buf->l;
+ if (len == MD5_DIGEST_LENGTH) {
+ if ((buf = vrealloc(buf, len + sizeof(cap))) == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "Cannot allocate memory\n");
+ return NULL;
+ }
+ capp = (int *)(buf->v + len);
+ *capp = htonl(0);
+ }
+
+ capp = (int *)(buf->v + MD5_DIGEST_LENGTH);
+ *capp |= htonl(cap);
+
+ return buf;
+}
+