]>
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"
87 isakmp_sendfrags(iph1
, buf
)
88 struct ph1handle
*iph1
;
92 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(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
) {
146 plog(LLV_ERROR
, LOCATION
, 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
) {
174 plog(LLV_ERROR
, LOCATION
, NULL
,
175 "%s: vbuf allocation failed\n", __FUNCTION__
);
179 *(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(LLV_ERROR
, LOCATION
, NULL
, "%s: sendfromto failed\n", __FUNCTION__
);
199 plog(LLV_DEBUG2
, LOCATION
, NULL
,
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
= (int *)(gen
+ 1);
214 return ntohl(hp
[hashlen_bytes
/ sizeof(*hp
)]);
218 isakmp_frag_extract(iph1
, msg
)
219 struct ph1handle
*iph1
;
222 struct isakmp
*isakmp
;
223 struct isakmp_frag
*frag
;
224 struct isakmp_frag_item
*item
;
231 if (msg
->l
< sizeof(*isakmp
) + sizeof(*frag
)) {
232 plog(LLV_ERROR
, LOCATION
, NULL
, "Message too short\n");
236 isakmp
= (struct isakmp
*)msg
->v
;
237 frag
= (struct isakmp_frag
*)(isakmp
+ 1);
240 * frag->len is the frag payload data plus the frag payload header,
241 * whose size is sizeof(*frag)
243 if (msg
->l
< sizeof(*isakmp
) + ntohs(frag
->len
) ||
244 ntohs(frag
->len
) < sizeof(*frag
) + 1) {
245 plog(LLV_ERROR
, LOCATION
, NULL
, "Fragment too short\n");
249 if (ntohs(frag
->len
) < sizeof(*frag
)) {
250 plog(LLV_ERROR
, LOCATION
, NULL
,
251 "invalid Frag, frag-len %d\n",
256 if ((buf
= vmalloc(ntohs(frag
->len
) - sizeof(*frag
))) == NULL
) {
257 plog(LLV_ERROR
, LOCATION
, NULL
, "Cannot allocate memory\n");
261 if ((item
= racoon_malloc(sizeof(*item
))) == NULL
) {
262 plog(LLV_ERROR
, LOCATION
, NULL
, "Cannot allocate memory\n");
266 bzero(item
, sizeof(*item
));
268 data
= (char *)(frag
+ 1);
269 memcpy(buf
->v
, data
, buf
->l
);
271 item
->frag_num
= frag
->index
;
272 item
->frag_last
= (frag
->flags
& ISAKMP_FRAG_LAST
);
273 item
->frag_next
= NULL
;
274 item
->frag_packet
= buf
;
275 item
->frag_id
= ntohs(frag
->unknown1
);
277 /* Look for the last frag while inserting the new item in the chain */
279 last_frag
= item
->frag_num
;
281 if (iph1
->frag_chain
== NULL
) {
282 iph1
->frag_chain
= item
;
284 struct isakmp_frag_item
*current
;
287 current
= iph1
->frag_chain
;
288 if (!current
->frag_next
&& current
->frag_last
) {
289 last_frag
= current
->frag_num
;
291 while (current
->frag_next
) {
292 if (current
->frag_last
)
293 last_frag
= current
->frag_num
;
294 if (current
->frag_num
== item
->frag_num
) {
297 current
= current
->frag_next
;
301 current
->frag_next
= item
;
310 /* If we saw the last frag, check if the chain is complete */
311 if (last_frag
!= 0) {
312 for (i
= 1; i
<= last_frag
; i
++) {
313 item
= iph1
->frag_chain
;
315 if (item
->frag_num
== i
)
317 item
= item
->frag_next
;
318 } while (item
!= NULL
);
320 if (item
== NULL
) /* Not found */
324 if (item
!= NULL
) /* It is complete */
328 plog(LLV_DEBUG2
, LOCATION
, NULL
,
329 "%s: processed %d fragments\n", __FUNCTION__
, last_frag
);
335 isakmp_frag_reassembly(iph1
)
336 struct ph1handle
*iph1
;
338 struct isakmp_frag_item
*item
;
341 int frag_count
= 0, frag_max
= 0;
345 if ((item
= iph1
->frag_chain
) == NULL
) {
346 plog(LLV_ERROR
, LOCATION
, NULL
, "No fragment to reassemble\n");
352 if (item
->frag_num
> frag_max
&& item
->frag_last
) {
353 frag_max
= item
->frag_num
;
355 len
+= item
->frag_packet
->l
;
356 item
= item
->frag_next
;
357 } while (item
!= NULL
);
359 if ((buf
= vmalloc(len
)) == NULL
) {
360 plog(LLV_ERROR
, LOCATION
, NULL
, "Cannot allocate memory\n");
365 for (i
= 1; i
<= frag_max
; i
++) {
366 item
= iph1
->frag_chain
;
368 if (item
->frag_num
== i
)
370 item
= item
->frag_next
;
371 } while (item
!= NULL
);
374 plog(LLV_ERROR
, LOCATION
, NULL
,
375 "Missing fragment #%d\n", i
);
380 memcpy(data
, item
->frag_packet
->v
, item
->frag_packet
->l
);
381 data
+= item
->frag_packet
->l
;
384 plog(LLV_DEBUG2
, LOCATION
, NULL
,
385 "%s: processed %d fragments\n", __FUNCTION__
, frag_count
);
388 item
= iph1
->frag_chain
;
390 while (item
!= NULL
) {
391 struct isakmp_frag_item
*next_item
;
393 next_item
= item
->frag_next
;
395 vfree(item
->frag_packet
);
401 iph1
->frag_chain
= NULL
;
407 isakmp_frag_addcap(buf
, cap
)
413 int hashlen_bytes
= eay_md5_hashlen() >> 3;
415 /* If the capability has not been added, add room now */
417 if (len
== hashlen_bytes
) {
418 if ((buf
= vrealloc(buf
, len
+ sizeof(cap
))) == NULL
) {
419 plog(LLV_ERROR
, LOCATION
, NULL
,
420 "Cannot allocate memory\n");
423 capp
= (int *)(buf
->v
+ len
);
427 capp
= (int *)(buf
->v
+ hashlen_bytes
);
434 sendfragsfromto(s
, buf
, local
, remote
, count_persend
, frag_flags
)
437 struct sockaddr
*local
;
438 struct sockaddr
*remote
;
440 u_int32_t frag_flags
;
442 struct isakmp
*main_hdr
;
444 struct isakmp_frag
*fraghdr
;
451 unsigned int trailer
;
452 unsigned int fragnum
= 0;
455 size_t extralen
= (frag_flags
& FRAG_PUT_NON_ESP_MARKER
)? NON_ESP_MARKER_LEN
: 0;
461 * fragmented packet must have the same exchange type (amongst other fields in the header).
463 main_hdr
= (struct isakmp
*)buf
->v
;
466 * We want to send a a packet smaller than ISAKMP_FRAG_MAXLEN
467 * First compute the maximum data length that will fit in it
469 max_datalen
= ISAKMP_FRAG_MAXLEN
-
470 (sizeof(*main_hdr
) + sizeof(*fraghdr
));
478 if (len
> max_datalen
)
479 datalen
= max_datalen
;
483 fraglen
= sizeof(*hdr
) + sizeof(*fraghdr
) + datalen
;
485 if ((frag
= vmalloc(fraglen
)) == NULL
) {
486 plog(LLV_ERROR
, LOCATION
, NULL
,
487 "Cannot allocate memory\n");
491 hdr
= (struct isakmp
*)frag
->v
;
492 bcopy(main_hdr
, hdr
, sizeof(*hdr
));
493 hdr
->len
= htonl(frag
->l
);
494 hdr
->np
= ISAKMP_NPTYPE_FRAG
;
496 fraghdr
= (struct isakmp_frag
*)(hdr
+ 1);
497 fraghdr
->unknown0
= 0;
498 fraghdr
->len
= htons(fraglen
- sizeof(*hdr
));
499 fraghdr
->unknown1
= htons(1);
500 fraghdr
->index
= fragnum
;
502 fraghdr
->flags
= ISAKMP_FRAG_LAST
;
506 data
= (caddr_t
)(fraghdr
+ 1);
507 memcpy(data
, sdata
, datalen
);
510 /* If NAT-T port floating is in use, 4 zero bytes (non-ESP marker)
511 must added just before the packet itself. For this we must
512 allocate a new buffer and release it at the end. */
516 if ((vbuf
= vmalloc(frag
->l
+ extralen
)) == NULL
) {
517 plog(LLV_ERROR
, LOCATION
, NULL
,
518 "%s: vbuf allocation failed\n", __FUNCTION__
);
522 *(u_int32_t
*)vbuf
->v
= 0; // non-esp marker
523 memcpy(vbuf
->v
+ extralen
, frag
->v
, frag
->l
);
529 if (sendfromto(s
, frag
->v
, frag
->l
, local
, remote
, count_persend
) == -1) {
530 plog(LLV_ERROR
, LOCATION
, NULL
, "sendfromto failed\n");
541 plog(LLV_DEBUG2
, LOCATION
, NULL
,
542 "%s: processed %d fragments\n", __FUNCTION__
, fragnum
);