]>
git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/isakmp_frag.c
1 /* $NetBSD: isakmp_frag.c,v 1.4 2006/09/09 16:22:09 manu Exp $ */
3 /* Id: isakmp_frag.c,v 1.4 2004/11/13 17:31:36 manubsd Exp */
6 * Copyright (C) 2004 Emmanuel Dreyfus
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
36 #include <sys/types.h>
37 #include <sys/param.h>
38 #include <sys/socket.h>
39 #include <sys/queue.h>
41 #include <netinet/in.h>
42 #include <arpa/inet.h>
45 #include <openssl/md5.h>
53 #if TIME_WITH_SYS_TIME
54 # include <sys/time.h>
58 # include <sys/time.h>
77 #include "isakmp_var.h"
80 #include "isakmp_frag.h"
82 #include "nattraversal.h"
83 #include "grabmyaddr.h"
84 #include "localconf.h"
85 #include "crypto_openssl.h"
88 isakmp_sendfrags(iph1
, buf
)
89 phase1_handle_t
*iph1
;
93 struct isakmp_frag
*fraghdr
;
100 unsigned int fragnum
= 0;
104 size_t extralen
= NON_ESP_MARKER_USE(iph1
)? NON_ESP_MARKER_LEN
: 0;
112 /* select the socket to be sent */
113 s
= getsockmyaddr((struct sockaddr
*)iph1
->local
);
119 * Catch the exchange type for later: the fragments and the
120 * fragmented packet must have the same exchange type.
122 hdr
= (struct isakmp
*)buf
->v
;
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
129 max_datalen
= ISAKMP_FRAG_MAXLEN
-
130 (sizeof(*hdr
) + sizeof(*fraghdr
));
138 if (len
> max_datalen
)
139 datalen
= max_datalen
;
143 fraglen
= sizeof(*hdr
) + sizeof(*fraghdr
) + datalen
;
145 if ((frag
= vmalloc(fraglen
)) == NULL
) {
147 "Cannot allocate memory\n");
151 set_isakmp_header1(frag
, iph1
, ISAKMP_NPTYPE_FRAG
);
152 hdr
= (struct isakmp
*)frag
->v
;
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
;
161 fraghdr
->flags
= ISAKMP_FRAG_LAST
;
165 data
= (caddr_t
)(fraghdr
+ 1);
166 memcpy(data
, sdata
, datalen
);
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. */
173 if ((vbuf
= vmalloc(frag
->l
+ extralen
)) == NULL
) {
175 "%s: vbuf allocation failed\n", __FUNCTION__
);
179 *ALIGNED_CAST(u_int32_t
*)vbuf
->v
= 0; // non-esp marker
180 memcpy(vbuf
->v
+ extralen
, frag
->v
, frag
->l
);
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__
);
199 plog(ASL_LEVEL_DEBUG
,
200 "%s: processed %d fragments\n", __FUNCTION__
, fragnum
);
206 vendorid_frag_cap(gen
)
207 struct isakmp_gen
*gen
;
210 int hashlen_bytes
= eay_md5_hashlen() >> 3;
212 hp
= ALIGNED_CAST(int *)(gen
+ 1);
214 return ntohl(hp
[hashlen_bytes
/ sizeof(*hp
)]);
218 isakmp_frag_extract(iph1
, msg
)
219 phase1_handle_t
*iph1
;
222 struct isakmp
*isakmp
;
223 struct isakmp_frag
*frag
;
224 struct isakmp_frag_item
*item
;
230 if (msg
->l
< sizeof(*isakmp
) + sizeof(*frag
)) {
231 plog(ASL_LEVEL_ERR
, "Message too short\n");
235 isakmp
= (struct isakmp
*)msg
->v
;
236 frag
= (struct isakmp_frag
*)(isakmp
+ 1);
239 * frag->len is the frag payload data plus the frag payload header,
240 * whose size is sizeof(*frag)
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");
248 if (ntohs(frag
->len
) < sizeof(*frag
)) {
250 "invalid Frag, frag-len %d\n",
255 if ((buf
= vmalloc(ntohs(frag
->len
) - sizeof(*frag
))) == NULL
) {
256 plog(ASL_LEVEL_ERR
, "Cannot allocate memory\n");
260 if ((item
= racoon_malloc(sizeof(*item
))) == NULL
) {
261 plog(ASL_LEVEL_ERR
, "Cannot allocate memory\n");
265 bzero(item
, sizeof(*item
));
267 data
= (char *)(frag
+ 1);
268 memcpy(buf
->v
, data
, buf
->l
);
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
);
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
);
280 /* Insert if new and find the last frag num if present */
281 struct isakmp_frag_item
*current
;
283 last_frag
= (item
->frag_last
? item
->frag_num
: 0);
284 current
= iph1
->frag_chain
;
286 if (current
->frag_num
== item
->frag_num
) { // duplicate?
287 vfree(item
->frag_packet
);
289 return 0; // already have it
291 if (current
->frag_last
)
292 last_frag
= current
->frag_num
;
293 current
= current
->frag_next
;
295 /* no dup - insert it */
296 item
->frag_next
= iph1
->frag_chain
;
297 iph1
->frag_chain
= item
;
299 /* Check if the chain is complete */
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
;
305 if (current
->frag_num
== i
)
307 current
= current
->frag_next
;
310 return 0; /* chain not complete */
313 plog(ASL_LEVEL_DEBUG
,
314 "%s: processed fragment %d\n", __FUNCTION__
, frag
->index
);
315 return 1; /* chain is complete */
319 isakmp_frag_reassembly(iph1
)
320 phase1_handle_t
*iph1
;
322 struct isakmp_frag_item
*item
;
325 int frag_count
= 0, frag_max
= 0;
329 if ((item
= iph1
->frag_chain
) == NULL
) {
330 plog(ASL_LEVEL_ERR
, "No fragment to reassemble\n");
336 if (item
->frag_num
> frag_max
&& item
->frag_last
) {
337 frag_max
= item
->frag_num
;
339 len
+= item
->frag_packet
->l
;
340 item
= item
->frag_next
;
341 } while (item
!= NULL
);
343 if ((buf
= vmalloc(len
)) == NULL
) {
344 plog(ASL_LEVEL_ERR
, "Cannot allocate memory\n");
349 for (i
= 1; i
<= frag_max
; i
++) {
350 item
= iph1
->frag_chain
;
352 if (item
->frag_num
== i
)
354 item
= item
->frag_next
;
355 } while (item
!= NULL
);
359 "Missing fragment #%d\n", i
);
364 memcpy(data
, item
->frag_packet
->v
, item
->frag_packet
->l
);
365 data
+= item
->frag_packet
->l
;
368 plog(ASL_LEVEL_DEBUG
,
369 "%s: processed %d fragments\n", __FUNCTION__
, frag_count
);
372 item
= iph1
->frag_chain
;
374 while (item
!= NULL
) {
375 struct isakmp_frag_item
*next_item
;
377 next_item
= item
->frag_next
;
379 vfree(item
->frag_packet
);
385 iph1
->frag_chain
= NULL
;
387 //plogdump(ASL_LEVEL_DEBUG, buf->v, buf->l, "re-assembled fragements:\n");
392 isakmp_frag_addcap(buf
, cap
)
398 int hashlen_bytes
= eay_md5_hashlen() >> 3;
400 /* If the capability has not been added, add room now */
402 if (len
== hashlen_bytes
) {
403 if ((buf
= vrealloc(buf
, len
+ sizeof(cap
))) == NULL
) {
405 "Cannot allocate memory\n");
409 memcpy(buf
->v
+ len
, &val
, sizeof(val
)); // Wcast_lign fix - copy instead of assign for unaligned move
411 capp
= (int *)(void*)(buf
->v
+ hashlen_bytes
); // Wcast_lign fix - copy instead of assign for unaligned move
412 memcpy(&val
, capp
, sizeof(val
));
414 memcpy(capp
, &val
, sizeof(val
));
420 sendfragsfromto(s
, buf
, local
, remote
, count_persend
, frag_flags
)
423 struct sockaddr_storage
*local
;
424 struct sockaddr_storage
*remote
;
426 u_int32_t frag_flags
;
428 struct isakmp
*main_hdr
;
430 struct isakmp_frag
*fraghdr
;
437 unsigned int fragnum
= 0;
440 size_t extralen
= (frag_flags
& FRAG_PUT_NON_ESP_MARKER
)? NON_ESP_MARKER_LEN
: 0;
446 * fragmented packet must have the same exchange type (amongst other fields in the header).
448 main_hdr
= (struct isakmp
*)buf
->v
;
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
454 max_datalen
= ISAKMP_FRAG_MAXLEN
-
455 (sizeof(*main_hdr
) + sizeof(*fraghdr
));
463 if (len
> max_datalen
)
464 datalen
= max_datalen
;
468 fraglen
= sizeof(*hdr
) + sizeof(*fraghdr
) + datalen
;
470 if ((frag
= vmalloc(fraglen
)) == NULL
) {
472 "Cannot allocate memory\n");
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
;
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
;
487 fraghdr
->flags
= ISAKMP_FRAG_LAST
;
491 data
= (caddr_t
)(fraghdr
+ 1);
492 memcpy(data
, sdata
, datalen
);
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. */
501 if ((vbuf
= vmalloc(frag
->l
+ extralen
)) == NULL
) {
503 "%s: vbuf allocation failed\n", __FUNCTION__
);
507 *ALIGNED_CAST(u_int32_t
*)vbuf
->v
= 0; // non-esp marker
508 memcpy(vbuf
->v
+ extralen
, frag
->v
, frag
->l
);
514 if (sendfromto(s
, frag
->v
, frag
->l
, local
, remote
, count_persend
) == -1) {
515 plog(ASL_LEVEL_ERR
, "sendfromto failed\n");
526 plog(ASL_LEVEL_DEBUG
,
527 "%s: processed %d fragments\n", __FUNCTION__
, fragnum
);