1/* $NetBSD: isakmp_frag.c,v 1.4 2006/09/09 16:22:09 manu Exp $ */ 2 3/* Id: isakmp_frag.c,v 1.4 2004/11/13 17:31:36 manubsd Exp */ 4 5/* 6 * Copyright (C) 2004 Emmanuel Dreyfus 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the project nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#include "config.h" 35 36#include <sys/types.h> 37#include <sys/param.h> 38#include <sys/socket.h> 39#include <sys/queue.h> 40 41#include <netinet/in.h> 42#include <arpa/inet.h> 43 44#ifdef HAVE_OPENSSL 45#include <openssl/md5.h> 46#endif 47 48#include <stdlib.h> 49#include <stdio.h> 50#include <fcntl.h> 51#include <string.h> 52#include <errno.h> 53#if TIME_WITH_SYS_TIME 54# include <sys/time.h> 55# include <time.h> 56#else 57# if HAVE_SYS_TIME_H 58# include <sys/time.h> 59# else 60# include <time.h> 61# endif 62#endif 63#include <netdb.h> 64#ifdef HAVE_UNISTD_H 65#include <unistd.h> 66#endif 67#include <ctype.h> 68 69#include "var.h" 70#include "misc.h" 71#include "vmbuf.h" 72#include "plog.h" 73#include "sockmisc.h" 74#include "schedule.h" 75#include "debug.h" 76 77#include "isakmp_var.h" 78#include "isakmp.h" 79#include "handler.h" 80#include "isakmp_frag.h" 81#include "strnames.h" 82#include "nattraversal.h" 83#include "grabmyaddr.h" 84#include "localconf.h" 85#include "crypto_openssl.h" 86 87int 88isakmp_sendfrags(iph1, buf) 89 phase1_handle_t *iph1; 90 vchar_t *buf; 91{ 92 struct isakmp *hdr; 93 struct isakmp_frag *fraghdr; 94 caddr_t data; 95 caddr_t sdata; 96 size_t datalen; 97 size_t max_datalen; 98 size_t fraglen; 99 vchar_t *frag; 100 unsigned int fragnum = 0; 101 size_t len; 102 int etype; 103#ifdef ENABLE_NATT 104 size_t extralen = NON_ESP_MARKER_USE(iph1)? NON_ESP_MARKER_LEN : 0; 105#else 106 size_t extralen = 0; 107#endif 108 int s; 109 vchar_t *vbuf; 110 111 112 /* select the socket to be sent */ 113 s = getsockmyaddr((struct sockaddr *)iph1->local); 114 if (s == -1){ 115 return -1; 116 } 117 118 /* 119 * Catch the exchange type for later: the fragments and the 120 * fragmented packet must have the same exchange type. 121 */ 122 hdr = (struct isakmp *)buf->v; 123 etype = hdr->etype; 124 125 /* 126 * We want to send a a packet smaller than ISAKMP_FRAG_MAXLEN 127 * First compute the maximum data length that will fit in it 128 */ 129 max_datalen = ISAKMP_FRAG_MAXLEN - 130 (sizeof(*hdr) + sizeof(*fraghdr)); 131 132 sdata = buf->v; 133 len = buf->l; 134 135 while (len > 0) { 136 fragnum++; 137 138 if (len > max_datalen) 139 datalen = max_datalen; 140 else 141 datalen = len; 142 143 fraglen = sizeof(*hdr) + sizeof(*fraghdr) + datalen; 144 145 if ((frag = vmalloc(fraglen)) == NULL) { 146 plog(ASL_LEVEL_ERR, 147 "Cannot allocate memory\n"); 148 return -1; 149 } 150 151 set_isakmp_header1(frag, iph1, ISAKMP_NPTYPE_FRAG); 152 hdr = (struct isakmp *)frag->v; 153 hdr->etype = etype; 154 155 fraghdr = (struct isakmp_frag *)(hdr + 1); 156 fraghdr->unknown0 = 0; 157 fraghdr->len = htons(fraglen - sizeof(*hdr)); 158 fraghdr->unknown1 = htons(1); 159 fraghdr->index = fragnum; 160 if (len == datalen) 161 fraghdr->flags = ISAKMP_FRAG_LAST; 162 else 163 fraghdr->flags = 0; 164 165 data = (caddr_t)(fraghdr + 1); 166 memcpy(data, sdata, datalen); 167 168#ifdef ENABLE_NATT 169 /* If NAT-T port floating is in use, 4 zero bytes (non-ESP marker) 170 must added just before the packet itself. For this we must 171 allocate a new buffer and release it at the end. */ 172 if (extralen) { 173 if ((vbuf = vmalloc(frag->l + extralen)) == NULL) { 174 plog(ASL_LEVEL_ERR, 175 "%s: vbuf allocation failed\n", __FUNCTION__); 176 vfree(frag); 177 return -1; 178 } 179 *ALIGNED_CAST(u_int32_t *)vbuf->v = 0; // non-esp marker 180 memcpy(vbuf->v + extralen, frag->v, frag->l); 181 vfree(frag); 182 frag = vbuf; 183 } 184#endif 185 186 if (sendfromto(s, frag->v, frag->l, 187 iph1->local, iph1->remote, lcconf->count_persend) == -1) { 188 plog(ASL_LEVEL_ERR, "%s: sendfromto failed\n", __FUNCTION__); 189 vfree(frag); 190 return -1; 191 } 192 193 vfree(frag); 194 195 len -= datalen; 196 sdata += datalen; 197 } 198 199 plog(ASL_LEVEL_DEBUG, 200 "%s: processed %d fragments\n", __FUNCTION__, fragnum); 201 202 return fragnum; 203} 204 205unsigned int 206vendorid_frag_cap(gen) 207 struct isakmp_gen *gen; 208{ 209 int *hp; 210 int hashlen_bytes = eay_md5_hashlen() >> 3; 211 212 hp = ALIGNED_CAST(int *)(gen + 1); 213 214 return ntohl(hp[hashlen_bytes / sizeof(*hp)]); 215} 216 217int 218isakmp_frag_extract(iph1, msg) 219 phase1_handle_t *iph1; 220 vchar_t *msg; 221{ 222 struct isakmp *isakmp; 223 struct isakmp_frag *frag; 224 struct isakmp_frag_item *item; 225 vchar_t *buf; 226 int last_frag = 0; 227 char *data; 228 int i; 229 230 if (msg->l < sizeof(*isakmp) + sizeof(*frag)) { 231 plog(ASL_LEVEL_ERR, "Message too short\n"); 232 return -1; 233 } 234 235 isakmp = (struct isakmp *)msg->v; 236 frag = (struct isakmp_frag *)(isakmp + 1); 237 238 /* 239 * frag->len is the frag payload data plus the frag payload header, 240 * whose size is sizeof(*frag) 241 */ 242 if (msg->l < sizeof(*isakmp) + ntohs(frag->len) || 243 ntohs(frag->len) < sizeof(*frag) + 1) { 244 plog(ASL_LEVEL_ERR, "Fragment too short\n"); 245 return -1; 246 } 247 248 if (ntohs(frag->len) < sizeof(*frag)) { 249 plog(ASL_LEVEL_ERR, 250 "invalid Frag, frag-len %d\n", 251 ntohs(frag->len)); 252 return -1; 253 } 254 255 if ((buf = vmalloc(ntohs(frag->len) - sizeof(*frag))) == NULL) { 256 plog(ASL_LEVEL_ERR, "Cannot allocate memory\n"); 257 return -1; 258 } 259 260 if ((item = racoon_malloc(sizeof(*item))) == NULL) { 261 plog(ASL_LEVEL_ERR, "Cannot allocate memory\n"); 262 vfree(buf); 263 return -1; 264 } 265 bzero(item, sizeof(*item)); 266 267 data = (char *)(frag + 1); 268 memcpy(buf->v, data, buf->l); 269 270 item->frag_num = frag->index; 271 item->frag_last = (frag->flags & ISAKMP_FRAG_LAST); 272 item->frag_next = NULL; 273 item->frag_packet = buf; 274 item->frag_id = ntohs(frag->unknown1); 275 276 plog(ASL_LEVEL_DEBUG, 277 "%s: received fragment #%d frag ID=%d last frag=%d\n", 278 __FUNCTION__, item->frag_num, item->frag_id, item->frag_last); 279 280 /* Insert if new and find the last frag num if present */ 281 struct isakmp_frag_item *current; 282 283 last_frag = (item->frag_last ? item->frag_num : 0); 284 current = iph1->frag_chain; 285 while (current) { 286 if (current->frag_num == item->frag_num) { // duplicate? 287 vfree(item->frag_packet); 288 racoon_free(item); 289 return 0; // already have it 290 } 291 if (current->frag_last) 292 last_frag = current->frag_num; 293 current = current->frag_next; 294 } 295 /* no dup - insert it */ 296 item->frag_next = iph1->frag_chain; 297 iph1->frag_chain = item; 298 299 /* Check if the chain is complete */ 300 if (last_frag == 0) 301 return 0; /* if last_frag not found - chain is not complete */ 302 for (i = 1; i <= last_frag; i++) { 303 current = iph1->frag_chain; 304 while (current) { 305 if (current->frag_num == i) 306 break; 307 current = current->frag_next; 308 }; 309 if (!current) 310 return 0; /* chain not complete */ 311 } 312 313 plog(ASL_LEVEL_DEBUG, 314 "%s: processed fragment %d\n", __FUNCTION__, frag->index); 315 return 1; /* chain is complete */ 316} 317 318vchar_t * 319isakmp_frag_reassembly(iph1) 320 phase1_handle_t *iph1; 321{ 322 struct isakmp_frag_item *item; 323 size_t len = 0; 324 vchar_t *buf = NULL; 325 int frag_count = 0, frag_max = 0; 326 int i; 327 char *data; 328 329 if ((item = iph1->frag_chain) == NULL) { 330 plog(ASL_LEVEL_ERR, "No fragment to reassemble\n"); 331 goto out; 332 } 333 334 do { 335 frag_count++; 336 if (item->frag_num > frag_max && item->frag_last) { 337 frag_max = item->frag_num; 338 } 339 len += item->frag_packet->l; 340 item = item->frag_next; 341 } while (item != NULL); 342 343 if ((buf = vmalloc(len)) == NULL) { 344 plog(ASL_LEVEL_ERR, "Cannot allocate memory\n"); 345 goto out; 346 } 347 data = buf->v; 348 349 for (i = 1; i <= frag_max; i++) { 350 item = iph1->frag_chain; 351 do { 352 if (item->frag_num == i) 353 break; 354 item = item->frag_next; 355 } while (item != NULL); 356 357 if (item == NULL) { 358 plog(ASL_LEVEL_ERR, 359 "Missing fragment #%d\n", i); 360 vfree(buf); 361 buf = NULL; 362 return buf; 363 } 364 memcpy(data, item->frag_packet->v, item->frag_packet->l); 365 data += item->frag_packet->l; 366 } 367 368 plog(ASL_LEVEL_DEBUG, 369 "%s: processed %d fragments\n", __FUNCTION__, frag_count); 370 371out: 372 item = iph1->frag_chain; 373 374 while (item != NULL) { 375 struct isakmp_frag_item *next_item; 376 377 next_item = item->frag_next; 378 379 vfree(item->frag_packet); 380 racoon_free(item); 381 382 item = next_item; 383 } 384 385 iph1->frag_chain = NULL; 386 387 //plogdump(ASL_LEVEL_DEBUG, buf->v, buf->l, "re-assembled fragements:\n"); 388 return buf; 389} 390 391vchar_t * 392isakmp_frag_addcap(buf, cap) 393 vchar_t *buf; 394 int cap; 395{ 396 int val, *capp; 397 size_t len; 398 int hashlen_bytes = eay_md5_hashlen() >> 3; 399 400 /* If the capability has not been added, add room now */ 401 len = buf->l; 402 if (len == hashlen_bytes) { 403 if ((buf = vrealloc(buf, len + sizeof(cap))) == NULL) { 404 plog(ASL_LEVEL_ERR, 405 "Cannot allocate memory\n"); 406 return NULL; 407 } 408 val = 0; 409 memcpy(buf->v + len, &val, sizeof(val)); // Wcast_lign fix - copy instead of assign for unaligned move 410 } 411 capp = (int *)(void*)(buf->v + hashlen_bytes); // Wcast_lign fix - copy instead of assign for unaligned move 412 memcpy(&val, capp, sizeof(val)); 413 val |= htonl(cap); 414 memcpy(capp, &val, sizeof(val)); 415 416 return buf; 417} 418 419int 420sendfragsfromto(s, buf, local, remote, count_persend, frag_flags) 421 int s; 422 vchar_t *buf; 423 struct sockaddr_storage *local; 424 struct sockaddr_storage *remote; 425 int count_persend; 426 u_int32_t frag_flags; 427{ 428 struct isakmp *main_hdr; 429 struct isakmp *hdr; 430 struct isakmp_frag *fraghdr; 431 caddr_t data; 432 caddr_t sdata; 433 size_t datalen; 434 size_t max_datalen; 435 size_t fraglen; 436 vchar_t *frag; 437 unsigned int fragnum = 0; 438 size_t len; 439#ifdef ENABLE_NATT 440 size_t extralen = (frag_flags & FRAG_PUT_NON_ESP_MARKER)? NON_ESP_MARKER_LEN : 0; 441#else 442 size_t extralen = 0; 443#endif 444 445 /* 446 * fragmented packet must have the same exchange type (amongst other fields in the header). 447 */ 448 main_hdr = (struct isakmp *)buf->v; 449 450 /* 451 * We want to send a a packet smaller than ISAKMP_FRAG_MAXLEN 452 * First compute the maximum data length that will fit in it 453 */ 454 max_datalen = ISAKMP_FRAG_MAXLEN - 455 (sizeof(*main_hdr) + sizeof(*fraghdr)); 456 457 sdata = buf->v; 458 len = buf->l; 459 460 while (len > 0) { 461 fragnum++; 462 463 if (len > max_datalen) 464 datalen = max_datalen; 465 else 466 datalen = len; 467 468 fraglen = sizeof(*hdr) + sizeof(*fraghdr) + datalen; 469 470 if ((frag = vmalloc(fraglen)) == NULL) { 471 plog(ASL_LEVEL_ERR, 472 "Cannot allocate memory\n"); 473 return -1; 474 } 475 476 hdr = (struct isakmp *)frag->v; 477 bcopy(main_hdr, hdr, sizeof(*hdr)); 478 hdr->len = htonl(frag->l); 479 hdr->np = ISAKMP_NPTYPE_FRAG; 480 481 fraghdr = (struct isakmp_frag *)(hdr + 1); 482 fraghdr->unknown0 = 0; 483 fraghdr->len = htons(fraglen - sizeof(*hdr)); 484 fraghdr->unknown1 = htons(1); 485 fraghdr->index = fragnum; 486 if (len == datalen) 487 fraghdr->flags = ISAKMP_FRAG_LAST; 488 else 489 fraghdr->flags = 0; 490 491 data = (caddr_t)(fraghdr + 1); 492 memcpy(data, sdata, datalen); 493 494#ifdef ENABLE_NATT 495 /* If NAT-T port floating is in use, 4 zero bytes (non-ESP marker) 496 must added just before the packet itself. For this we must 497 allocate a new buffer and release it at the end. */ 498 if (extralen) { 499 vchar_t *vbuf; 500 501 if ((vbuf = vmalloc(frag->l + extralen)) == NULL) { 502 plog(ASL_LEVEL_ERR, 503 "%s: vbuf allocation failed\n", __FUNCTION__); 504 vfree(frag); 505 return -1; 506 } 507 *ALIGNED_CAST(u_int32_t *)vbuf->v = 0; // non-esp marker 508 memcpy(vbuf->v + extralen, frag->v, frag->l); 509 vfree(frag); 510 frag = vbuf; 511 } 512#endif 513 514 if (sendfromto(s, frag->v, frag->l, local, remote, count_persend) == -1) { 515 plog(ASL_LEVEL_ERR, "sendfromto failed\n"); 516 vfree(frag); 517 return -1; 518 } 519 520 vfree(frag); 521 522 len -= datalen; 523 sdata += datalen; 524 } 525 526 plog(ASL_LEVEL_DEBUG, 527 "%s: processed %d fragments\n", __FUNCTION__, fragnum); 528 529 return fragnum; 530} 531