Commit | Line | Data |
---|---|---|
ac2f15b3 | 1 | /* $KAME: handler.c,v 1.57 2002/01/21 08:45:54 sakane Exp $ */ |
7ba0088d A |
2 | |
3 | /* | |
4 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. | |
5 | * All rights reserved. | |
6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. Neither the name of the project nor the names of its contributors | |
16 | * may be used to endorse or promote products derived from this software | |
17 | * without specific prior written permission. | |
18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND | |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE | |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
29 | * SUCH DAMAGE. | |
30 | */ | |
31 | ||
32 | #include <sys/types.h> | |
33 | #include <sys/param.h> | |
34 | #include <sys/socket.h> | |
35 | ||
36 | #include <stdlib.h> | |
37 | #include <stdio.h> | |
38 | #include <string.h> | |
39 | #include <time.h> | |
40 | #include <errno.h> | |
41 | ||
42 | #include "var.h" | |
43 | #include "misc.h" | |
44 | #include "vmbuf.h" | |
45 | #include "plog.h" | |
46 | #include "sockmisc.h" | |
47 | #include "debug.h" | |
48 | ||
49 | #include "schedule.h" | |
50 | #include "grabmyaddr.h" | |
51 | #include "algorithm.h" | |
52 | #include "crypto_openssl.h" | |
53 | #include "policy.h" | |
54 | #include "proposal.h" | |
55 | #include "isakmp_var.h" | |
56 | #include "isakmp.h" | |
57 | #include "isakmp_inf.h" | |
58 | #include "oakley.h" | |
59 | #include "remoteconf.h" | |
60 | #include "localconf.h" | |
61 | #include "handler.h" | |
62 | #include "gcmalloc.h" | |
63 | ||
64 | #ifdef HAVE_GSSAPI | |
65 | #include "gssapi.h" | |
66 | #endif | |
67 | ||
68 | static LIST_HEAD(_ph1tree_, ph1handle) ph1tree; | |
69 | static LIST_HEAD(_ph2tree_, ph2handle) ph2tree; | |
70 | static LIST_HEAD(_ctdtree_, contacted) ctdtree; | |
71 | static LIST_HEAD(_rcptree_, recvdpkt) rcptree; | |
72 | ||
73 | static void del_recvdpkt __P((struct recvdpkt *)); | |
74 | static void rem_recvdpkt __P((struct recvdpkt *)); | |
75 | static void sweep_recvdpkt __P((void *)); | |
76 | ||
77 | /* | |
78 | * functions about management of the isakmp status table | |
79 | */ | |
80 | /* %%% management phase 1 handler */ | |
81 | /* | |
82 | * search for isakmpsa handler with isakmp index. | |
83 | */ | |
84 | ||
85 | extern caddr_t val2str(const char *, size_t); | |
86 | ||
87 | struct ph1handle * | |
88 | getph1byindex(index) | |
89 | isakmp_index *index; | |
90 | { | |
91 | struct ph1handle *p; | |
92 | ||
93 | LIST_FOREACH(p, &ph1tree, chain) { | |
94 | if (p->status == PHASE1ST_EXPIRED) | |
95 | continue; | |
96 | if (memcmp(&p->index, index, sizeof(*index)) == 0) | |
97 | return p; | |
98 | } | |
99 | ||
100 | return NULL; | |
101 | } | |
102 | ||
103 | /* | |
104 | * search for isakmp handler by i_ck in index. | |
105 | */ | |
106 | struct ph1handle * | |
107 | getph1byindex0(index) | |
108 | isakmp_index *index; | |
109 | { | |
110 | struct ph1handle *p; | |
111 | ||
112 | LIST_FOREACH(p, &ph1tree, chain) { | |
113 | if (p->status == PHASE1ST_EXPIRED) | |
114 | continue; | |
115 | if (memcmp(&p->index, index, sizeof(cookie_t)) == 0) | |
116 | return p; | |
117 | } | |
118 | ||
119 | return NULL; | |
120 | } | |
121 | ||
122 | /* | |
123 | * search for isakmpsa handler by remote address. | |
124 | * don't use port number to search because this function search | |
125 | * with phase 2's destinaion. | |
126 | */ | |
127 | struct ph1handle * | |
128 | getph1byaddr(local, remote) | |
129 | struct sockaddr *local, *remote; | |
130 | { | |
131 | struct ph1handle *p; | |
132 | ||
133 | LIST_FOREACH(p, &ph1tree, chain) { | |
134 | if (p->status == PHASE1ST_EXPIRED) | |
135 | continue; | |
136 | if (cmpsaddrwop(local, p->local) == 0 | |
137 | && cmpsaddrwop(remote, p->remote) == 0) | |
138 | return p; | |
139 | } | |
140 | ||
141 | return NULL; | |
142 | } | |
143 | ||
144 | /* | |
145 | * dump isakmp-sa | |
146 | */ | |
147 | vchar_t * | |
148 | dumpph1() | |
149 | { | |
150 | struct ph1handle *iph1; | |
151 | struct ph1dump *pd; | |
152 | int cnt = 0; | |
153 | vchar_t *buf; | |
154 | ||
155 | /* get length of buffer */ | |
156 | LIST_FOREACH(iph1, &ph1tree, chain) | |
157 | cnt++; | |
158 | ||
159 | buf = vmalloc(cnt * sizeof(struct ph1dump)); | |
160 | if (buf == NULL) { | |
161 | plog(LLV_ERROR, LOCATION, NULL, | |
162 | "failed to get buffer\n"); | |
163 | return NULL; | |
164 | } | |
165 | pd = (struct ph1dump *)buf->v; | |
166 | ||
167 | LIST_FOREACH(iph1, &ph1tree, chain) { | |
168 | memcpy(&pd->index, &iph1->index, sizeof(iph1->index)); | |
169 | pd->status = iph1->status; | |
170 | pd->side = iph1->side; | |
171 | memcpy(&pd->remote, iph1->remote, iph1->remote->sa_len); | |
172 | memcpy(&pd->local, iph1->local, iph1->local->sa_len); | |
173 | pd->version = iph1->version; | |
174 | pd->etype = iph1->etype; | |
175 | pd->created = iph1->created; | |
176 | pd->ph2cnt = iph1->ph2cnt; | |
177 | pd++; | |
178 | } | |
179 | ||
180 | return buf; | |
181 | } | |
182 | ||
183 | /* | |
184 | * create new isakmp Phase 1 status record to handle isakmp in Phase1 | |
185 | */ | |
186 | struct ph1handle * | |
187 | newph1() | |
188 | { | |
189 | struct ph1handle *iph1; | |
190 | ||
191 | /* create new iph1 */ | |
192 | iph1 = racoon_calloc(1, sizeof(*iph1)); | |
193 | if (iph1 == NULL) | |
194 | return NULL; | |
195 | ||
196 | iph1->status = PHASE1ST_SPAWN; | |
197 | ||
198 | return iph1; | |
199 | } | |
200 | ||
201 | /* | |
202 | * delete new isakmp Phase 1 status record to handle isakmp in Phase1 | |
203 | */ | |
204 | void | |
205 | delph1(iph1) | |
206 | struct ph1handle *iph1; | |
207 | { | |
208 | if (iph1->remote) { | |
209 | racoon_free(iph1->remote); | |
210 | iph1->remote = NULL; | |
211 | } | |
212 | if (iph1->local) { | |
213 | racoon_free(iph1->local); | |
214 | iph1->local = NULL; | |
215 | } | |
216 | ||
217 | VPTRINIT(iph1->authstr); | |
218 | ||
219 | sched_scrub_param(iph1); | |
220 | iph1->sce = NULL; | |
221 | iph1->scr = NULL; | |
222 | ||
223 | VPTRINIT(iph1->sendbuf); | |
224 | ||
225 | VPTRINIT(iph1->dhpriv); | |
226 | VPTRINIT(iph1->dhpub); | |
227 | VPTRINIT(iph1->dhpub_p); | |
228 | VPTRINIT(iph1->dhgxy); | |
229 | VPTRINIT(iph1->nonce); | |
230 | VPTRINIT(iph1->nonce_p); | |
231 | VPTRINIT(iph1->skeyid); | |
232 | VPTRINIT(iph1->skeyid_d); | |
233 | VPTRINIT(iph1->skeyid_a); | |
234 | VPTRINIT(iph1->skeyid_e); | |
235 | VPTRINIT(iph1->key); | |
236 | VPTRINIT(iph1->hash); | |
237 | VPTRINIT(iph1->sig); | |
238 | VPTRINIT(iph1->sig_p); | |
239 | oakley_delcert(iph1->cert); | |
240 | iph1->cert = NULL; | |
241 | oakley_delcert(iph1->cert_p); | |
242 | iph1->cert_p = NULL; | |
243 | oakley_delcert(iph1->crl_p); | |
244 | iph1->crl_p = NULL; | |
245 | oakley_delcert(iph1->cr_p); | |
246 | iph1->cr_p = NULL; | |
247 | VPTRINIT(iph1->id); | |
248 | VPTRINIT(iph1->id_p); | |
249 | ||
250 | if (iph1->ivm) { | |
251 | oakley_delivm(iph1->ivm); | |
252 | iph1->ivm = NULL; | |
253 | } | |
254 | ||
255 | VPTRINIT(iph1->sa); | |
256 | VPTRINIT(iph1->sa_ret); | |
257 | ||
258 | #ifdef HAVE_GSSAPI | |
259 | VPTRINIT(iph1->gi_i); | |
260 | VPTRINIT(iph1->gi_r); | |
261 | ||
262 | gssapi_free_state(iph1); | |
263 | #endif | |
264 | ||
ac2f15b3 A |
265 | #ifdef IKE_NAT_T |
266 | VPTRINIT(iph1->local_natd); | |
267 | VPTRINIT(iph1->remote_natd); | |
268 | #endif | |
269 | ||
7ba0088d A |
270 | racoon_free(iph1); |
271 | } | |
272 | ||
273 | /* | |
274 | * create new isakmp Phase 1 status record to handle isakmp in Phase1 | |
275 | */ | |
276 | int | |
277 | insph1(iph1) | |
278 | struct ph1handle *iph1; | |
279 | { | |
280 | /* validity check */ | |
281 | if (iph1->remote == NULL) { | |
282 | plog(LLV_ERROR, LOCATION, NULL, | |
283 | "invalid isakmp SA handler. no remote address.\n"); | |
284 | return -1; | |
285 | } | |
286 | LIST_INSERT_HEAD(&ph1tree, iph1, chain); | |
287 | ||
288 | return 0; | |
289 | } | |
290 | ||
291 | void | |
292 | remph1(iph1) | |
293 | struct ph1handle *iph1; | |
294 | { | |
295 | LIST_REMOVE(iph1, chain); | |
296 | } | |
297 | ||
298 | /* | |
299 | * flush isakmp-sa | |
300 | */ | |
301 | void | |
302 | flushph1() | |
303 | { | |
304 | struct ph1handle *p, *next; | |
305 | ||
306 | for (p = LIST_FIRST(&ph1tree); p; p = next) { | |
307 | next = LIST_NEXT(p, chain); | |
308 | ||
309 | /* send delete information */ | |
310 | if (p->status == PHASE1ST_ESTABLISHED) | |
311 | isakmp_info_send_d1(p); | |
312 | ||
313 | remph1(p); | |
314 | delph1(p); | |
315 | } | |
316 | } | |
317 | ||
318 | void | |
319 | initph1tree() | |
320 | { | |
321 | LIST_INIT(&ph1tree); | |
322 | } | |
323 | ||
324 | /* %%% management phase 2 handler */ | |
325 | /* | |
326 | * search ph2handle with policy id. | |
327 | */ | |
328 | struct ph2handle * | |
329 | getph2byspid(spid) | |
330 | u_int32_t spid; | |
331 | { | |
332 | struct ph2handle *p; | |
333 | ||
334 | LIST_FOREACH(p, &ph2tree, chain) { | |
335 | /* | |
336 | * there are ph2handle independent on policy | |
337 | * such like informational exchange. | |
338 | */ | |
339 | if (p->spid == spid) | |
340 | return p; | |
341 | } | |
342 | ||
343 | return NULL; | |
344 | } | |
345 | ||
346 | /* | |
347 | * search ph2handle with sequence number. | |
348 | */ | |
349 | struct ph2handle * | |
350 | getph2byseq(seq) | |
351 | u_int32_t seq; | |
352 | { | |
353 | struct ph2handle *p; | |
354 | ||
355 | LIST_FOREACH(p, &ph2tree, chain) { | |
356 | if (p->seq == seq) | |
357 | return p; | |
358 | } | |
359 | ||
360 | return NULL; | |
361 | } | |
362 | ||
363 | /* | |
364 | * search ph2handle with message id. | |
365 | */ | |
366 | struct ph2handle * | |
367 | getph2bymsgid(iph1, msgid) | |
368 | struct ph1handle *iph1; | |
369 | u_int32_t msgid; | |
370 | { | |
371 | struct ph2handle *p; | |
372 | ||
373 | LIST_FOREACH(p, &ph2tree, chain) { | |
374 | if (p->msgid == msgid) | |
375 | return p; | |
376 | } | |
377 | ||
378 | return NULL; | |
379 | } | |
380 | ||
381 | /* | |
382 | * call by pk_recvexpire(). | |
383 | */ | |
384 | struct ph2handle * | |
385 | getph2bysaidx(src, dst, proto_id, spi) | |
386 | struct sockaddr *src, *dst; | |
387 | u_int proto_id; | |
388 | u_int32_t spi; | |
389 | { | |
390 | struct ph2handle *iph2; | |
391 | struct saproto *pr; | |
392 | ||
393 | LIST_FOREACH(iph2, &ph2tree, chain) { | |
394 | if (iph2->proposal == NULL && iph2->approval == NULL) | |
395 | continue; | |
396 | if (iph2->approval != NULL) { | |
397 | for (pr = iph2->approval->head; pr != NULL; | |
398 | pr = pr->next) { | |
399 | if (proto_id != pr->proto_id) | |
400 | break; | |
401 | if (spi == pr->spi || spi == pr->spi_p) | |
402 | return iph2; | |
403 | } | |
404 | } else if (iph2->proposal != NULL) { | |
405 | for (pr = iph2->proposal->head; pr != NULL; | |
406 | pr = pr->next) { | |
407 | if (proto_id != pr->proto_id) | |
408 | break; | |
409 | if (spi == pr->spi) | |
410 | return iph2; | |
411 | } | |
412 | } | |
413 | } | |
414 | ||
415 | return NULL; | |
416 | } | |
417 | ||
418 | /* | |
419 | * create new isakmp Phase 2 status record to handle isakmp in Phase2 | |
420 | */ | |
421 | struct ph2handle * | |
422 | newph2() | |
423 | { | |
424 | struct ph2handle *iph2 = NULL; | |
425 | ||
426 | /* create new iph2 */ | |
427 | iph2 = racoon_calloc(1, sizeof(*iph2)); | |
428 | if (iph2 == NULL) | |
429 | return NULL; | |
430 | ||
431 | iph2->status = PHASE1ST_SPAWN; | |
432 | ||
433 | return iph2; | |
434 | } | |
435 | ||
436 | /* | |
437 | * initialize ph2handle | |
438 | * NOTE: don't initialize src/dst. | |
439 | * SPI in the proposal is cleared. | |
440 | */ | |
441 | void | |
442 | initph2(iph2) | |
443 | struct ph2handle *iph2; | |
444 | { | |
445 | sched_scrub_param(iph2); | |
446 | iph2->sce = NULL; | |
447 | iph2->scr = NULL; | |
448 | ||
449 | VPTRINIT(iph2->sendbuf); | |
450 | VPTRINIT(iph2->msg1); | |
451 | ||
452 | /* clear spi, keep variables in the proposal */ | |
453 | if (iph2->proposal) { | |
454 | struct saproto *pr; | |
455 | for (pr = iph2->proposal->head; pr != NULL; pr = pr->next) | |
456 | pr->spi = 0; | |
457 | } | |
458 | ||
459 | /* clear approval */ | |
460 | if (iph2->approval) { | |
461 | flushsaprop(iph2->approval); | |
462 | iph2->approval = NULL; | |
463 | } | |
464 | ||
465 | /* clear the generated policy */ | |
466 | if (iph2->spidx_gen) { | |
467 | delsp_bothdir((struct policyindex *)iph2->spidx_gen); | |
468 | racoon_free(iph2->spidx_gen); | |
469 | iph2->spidx_gen = NULL; | |
470 | } | |
471 | ||
472 | if (iph2->pfsgrp) { | |
473 | oakley_dhgrp_free(iph2->pfsgrp); | |
474 | iph2->pfsgrp = NULL; | |
475 | } | |
476 | ||
477 | VPTRINIT(iph2->dhpriv); | |
478 | VPTRINIT(iph2->dhpub); | |
479 | VPTRINIT(iph2->dhpub_p); | |
480 | VPTRINIT(iph2->dhgxy); | |
481 | VPTRINIT(iph2->id); | |
482 | VPTRINIT(iph2->id_p); | |
483 | VPTRINIT(iph2->nonce); | |
484 | VPTRINIT(iph2->nonce_p); | |
485 | VPTRINIT(iph2->sa); | |
486 | VPTRINIT(iph2->sa_ret); | |
487 | ||
488 | if (iph2->ivm) { | |
489 | oakley_delivm(iph2->ivm); | |
490 | iph2->ivm = NULL; | |
491 | } | |
492 | } | |
493 | ||
494 | /* | |
495 | * delete new isakmp Phase 2 status record to handle isakmp in Phase2 | |
496 | */ | |
497 | void | |
498 | delph2(iph2) | |
499 | struct ph2handle *iph2; | |
500 | { | |
501 | initph2(iph2); | |
502 | ||
503 | if (iph2->src) { | |
504 | racoon_free(iph2->src); | |
505 | iph2->src = NULL; | |
506 | } | |
507 | if (iph2->dst) { | |
508 | racoon_free(iph2->dst); | |
509 | iph2->dst = NULL; | |
510 | } | |
511 | if (iph2->src_id) { | |
512 | racoon_free(iph2->src_id); | |
513 | iph2->src_id = NULL; | |
514 | } | |
515 | if (iph2->dst_id) { | |
516 | racoon_free(iph2->dst_id); | |
517 | iph2->dst_id = NULL; | |
518 | } | |
519 | ||
520 | if (iph2->proposal) { | |
521 | flushsaprop(iph2->proposal); | |
522 | iph2->proposal = NULL; | |
523 | } | |
524 | ||
525 | racoon_free(iph2); | |
526 | } | |
527 | ||
528 | /* | |
529 | * create new isakmp Phase 2 status record to handle isakmp in Phase2 | |
530 | */ | |
531 | int | |
532 | insph2(iph2) | |
533 | struct ph2handle *iph2; | |
534 | { | |
535 | LIST_INSERT_HEAD(&ph2tree, iph2, chain); | |
536 | ||
537 | return 0; | |
538 | } | |
539 | ||
540 | void | |
541 | remph2(iph2) | |
542 | struct ph2handle *iph2; | |
543 | { | |
544 | LIST_REMOVE(iph2, chain); | |
545 | } | |
546 | ||
547 | void | |
548 | initph2tree() | |
549 | { | |
550 | LIST_INIT(&ph2tree); | |
551 | } | |
552 | ||
553 | void | |
554 | flushph2() | |
555 | { | |
556 | struct ph2handle *p, *next; | |
557 | ||
558 | for (p = LIST_FIRST(&ph2tree); p; p = next) { | |
559 | next = LIST_NEXT(p, chain); | |
560 | ||
561 | /* send delete information */ | |
562 | if (p->status == PHASE2ST_ESTABLISHED) | |
563 | isakmp_info_send_d2(p); | |
564 | ||
565 | unbindph12(p); | |
566 | remph2(p); | |
567 | delph2(p); | |
568 | } | |
569 | } | |
570 | ||
571 | /* | |
572 | * Delete all Phase 2 handlers for this src/dst/proto. This | |
573 | * is used during INITIAL-CONTACT processing (so no need to | |
574 | * send a message to the peer). | |
575 | */ | |
576 | void | |
577 | deleteallph2(src, dst, proto_id) | |
578 | struct sockaddr *src, *dst; | |
579 | u_int proto_id; | |
580 | { | |
581 | struct ph2handle *iph2, *next; | |
582 | struct saproto *pr; | |
583 | ||
584 | for (iph2 = LIST_FIRST(&ph2tree); iph2 != NULL; iph2 = next) { | |
585 | next = LIST_NEXT(iph2, chain); | |
586 | if (iph2->proposal == NULL && iph2->approval == NULL) | |
587 | continue; | |
588 | if (iph2->approval != NULL) { | |
589 | for (pr = iph2->approval->head; pr != NULL; | |
590 | pr = pr->next) { | |
591 | if (proto_id == pr->proto_id) | |
592 | goto zap_it; | |
593 | } | |
594 | } else if (iph2->proposal != NULL) { | |
595 | for (pr = iph2->proposal->head; pr != NULL; | |
596 | pr = pr->next) { | |
597 | if (proto_id == pr->proto_id) | |
598 | goto zap_it; | |
599 | } | |
600 | } | |
601 | continue; | |
602 | zap_it: | |
603 | unbindph12(iph2); | |
604 | remph2(iph2); | |
605 | delph2(iph2); | |
606 | } | |
607 | } | |
608 | ||
609 | /* %%% */ | |
610 | void | |
611 | bindph12(iph1, iph2) | |
612 | struct ph1handle *iph1; | |
613 | struct ph2handle *iph2; | |
614 | { | |
615 | iph2->ph1 = iph1; | |
616 | LIST_INSERT_HEAD(&iph1->ph2tree, iph2, ph1bind); | |
617 | } | |
618 | ||
619 | void | |
620 | unbindph12(iph2) | |
621 | struct ph2handle *iph2; | |
622 | { | |
623 | if (iph2->ph1 != NULL) { | |
624 | iph2->ph1 = NULL; | |
625 | LIST_REMOVE(iph2, ph1bind); | |
626 | } | |
627 | } | |
628 | ||
629 | /* %%% management contacted list */ | |
630 | /* | |
631 | * search contacted list. | |
632 | */ | |
633 | struct contacted * | |
634 | getcontacted(remote) | |
635 | struct sockaddr *remote; | |
636 | { | |
637 | struct contacted *p; | |
638 | ||
639 | LIST_FOREACH(p, &ctdtree, chain) { | |
640 | if (cmpsaddrstrict(remote, p->remote) == 0) | |
641 | return p; | |
642 | } | |
643 | ||
644 | return NULL; | |
645 | } | |
646 | ||
647 | /* | |
648 | * create new isakmp Phase 2 status record to handle isakmp in Phase2 | |
649 | */ | |
650 | int | |
651 | inscontacted(remote) | |
652 | struct sockaddr *remote; | |
653 | { | |
654 | struct contacted *new; | |
655 | ||
656 | /* create new iph2 */ | |
657 | new = racoon_calloc(1, sizeof(*new)); | |
658 | if (new == NULL) | |
659 | return -1; | |
660 | ||
661 | new->remote = dupsaddr(remote); | |
662 | ||
663 | LIST_INSERT_HEAD(&ctdtree, new, chain); | |
664 | ||
665 | return 0; | |
666 | } | |
667 | ||
668 | void | |
669 | initctdtree() | |
670 | { | |
671 | LIST_INIT(&ctdtree); | |
672 | } | |
673 | ||
674 | /* | |
675 | * check the response has been sent to the peer. when not, simply reply | |
676 | * the buffered packet to the peer. | |
677 | * OUT: | |
678 | * 0: the packet is received at the first time. | |
679 | * 1: the packet was processed before. | |
680 | * 2: the packet was processed before, but the address mismatches. | |
681 | * -1: error happened. | |
682 | */ | |
683 | int | |
684 | check_recvdpkt(remote, local, rbuf) | |
685 | struct sockaddr *remote, *local; | |
686 | vchar_t *rbuf; | |
687 | { | |
688 | vchar_t *hash; | |
689 | struct recvdpkt *r; | |
690 | time_t t; | |
691 | int len, s; | |
692 | ||
693 | /* set current time */ | |
694 | t = time(NULL); | |
695 | ||
696 | hash = eay_md5_one(rbuf); | |
697 | if (!hash) { | |
698 | plog(LLV_ERROR, LOCATION, NULL, | |
699 | "failed to allocate buffer.\n"); | |
700 | return -1; | |
701 | } | |
702 | ||
703 | LIST_FOREACH(r, &rcptree, chain) { | |
704 | if (memcmp(hash->v, r->hash->v, r->hash->l) == 0) | |
705 | break; | |
706 | } | |
707 | vfree(hash); | |
708 | ||
709 | /* this is the first time to receive the packet */ | |
710 | if (r == NULL) | |
711 | return 0; | |
712 | ||
713 | /* | |
714 | * the packet was processed before, but the remote address mismatches. | |
715 | */ | |
716 | if (cmpsaddrstrict(remote, r->remote) != 0) | |
717 | return 2; | |
718 | ||
719 | /* | |
720 | * it should not check the local address because the packet | |
721 | * may arrive at other interface. | |
722 | */ | |
723 | ||
724 | /* check the previous time to send */ | |
725 | if (t - r->time_send < 1) { | |
726 | plog(LLV_WARNING, LOCATION, NULL, | |
727 | "the packet retransmitted in a short time from %s\n", | |
728 | saddr2str(remote)); | |
729 | /*XXX should it be error ? */ | |
730 | } | |
731 | ||
732 | /* select the socket to be sent */ | |
733 | s = getsockmyaddr(r->local); | |
734 | if (s == -1) | |
735 | return -1; | |
736 | ||
737 | /* resend the packet if needed */ | |
738 | len = sendfromto(s, r->sendbuf->v, r->sendbuf->l, | |
739 | r->local, r->remote, lcconf->count_persend); | |
740 | if (len == -1) { | |
741 | plog(LLV_ERROR, LOCATION, NULL, "sendfromto failed\n"); | |
742 | return -1; | |
743 | } | |
744 | ||
745 | /* check the retry counter */ | |
746 | r->retry_counter--; | |
747 | if (r->retry_counter <= 0) { | |
748 | rem_recvdpkt(r); | |
749 | del_recvdpkt(r); | |
750 | plog(LLV_DEBUG, LOCATION, NULL, | |
751 | "deleted the retransmission packet to %s.\n", | |
752 | saddr2str(remote)); | |
753 | } else | |
754 | r->time_send = t; | |
755 | ||
756 | return 1; | |
757 | } | |
758 | ||
759 | /* | |
760 | * adding a hash of received packet into the received list. | |
761 | */ | |
762 | int | |
763 | add_recvdpkt(remote, local, sbuf, rbuf) | |
764 | struct sockaddr *remote, *local; | |
765 | vchar_t *sbuf, *rbuf; | |
766 | { | |
767 | struct recvdpkt *new = NULL; | |
768 | ||
769 | if (lcconf->retry_counter == 0) { | |
770 | /* no need to add it */ | |
771 | return 0; | |
772 | } | |
773 | ||
774 | new = racoon_calloc(1, sizeof(*new)); | |
775 | if (!new) { | |
776 | plog(LLV_ERROR, LOCATION, NULL, | |
777 | "failed to allocate buffer.\n"); | |
778 | return -1; | |
779 | } | |
780 | ||
781 | new->hash = eay_md5_one(rbuf); | |
782 | if (!new->hash) { | |
783 | plog(LLV_ERROR, LOCATION, NULL, | |
784 | "failed to allocate buffer.\n"); | |
785 | del_recvdpkt(new); | |
786 | return -1; | |
787 | } | |
788 | new->remote = dupsaddr(remote); | |
789 | if (new->remote == NULL) { | |
790 | plog(LLV_ERROR, LOCATION, NULL, | |
791 | "failed to allocate buffer.\n"); | |
792 | del_recvdpkt(new); | |
793 | return -1; | |
794 | } | |
795 | new->local = dupsaddr(local); | |
796 | if (new->local == NULL) { | |
797 | plog(LLV_ERROR, LOCATION, NULL, | |
798 | "failed to allocate buffer.\n"); | |
799 | del_recvdpkt(new); | |
800 | return -1; | |
801 | } | |
802 | new->sendbuf = vdup(sbuf); | |
803 | if (new->sendbuf == NULL) { | |
804 | plog(LLV_ERROR, LOCATION, NULL, | |
805 | "failed to allocate buffer.\n"); | |
806 | del_recvdpkt(new); | |
807 | return -1; | |
808 | } | |
809 | ||
810 | new->retry_counter = lcconf->retry_counter; | |
811 | new->time_send = 0; | |
812 | new->created = time(NULL); | |
813 | ||
814 | LIST_INSERT_HEAD(&rcptree, new, chain); | |
815 | ||
816 | return 0; | |
817 | } | |
818 | ||
819 | void | |
820 | del_recvdpkt(r) | |
821 | struct recvdpkt *r; | |
822 | { | |
823 | if (r->remote) | |
824 | racoon_free(r->remote); | |
825 | if (r->local) | |
826 | racoon_free(r->local); | |
827 | if (r->hash) | |
828 | vfree(r->hash); | |
829 | if (r->sendbuf) | |
830 | vfree(r->sendbuf); | |
831 | racoon_free(r); | |
832 | } | |
833 | ||
834 | void | |
835 | rem_recvdpkt(r) | |
836 | struct recvdpkt *r; | |
837 | { | |
838 | LIST_REMOVE(r, chain); | |
839 | } | |
840 | ||
841 | void | |
842 | sweep_recvdpkt(dummy) | |
843 | void *dummy; | |
844 | { | |
845 | struct recvdpkt *r, *next; | |
846 | time_t t, lt; | |
847 | ||
848 | /* set current time */ | |
849 | t = time(NULL); | |
850 | ||
851 | /* set the lifetime of the retransmission */ | |
852 | lt = lcconf->retry_counter * lcconf->retry_interval; | |
853 | ||
854 | for (r = LIST_FIRST(&rcptree); r; r = next) { | |
855 | next = LIST_NEXT(r, chain); | |
856 | ||
857 | if (t - r->created > lt) { | |
858 | rem_recvdpkt(r); | |
859 | del_recvdpkt(r); | |
860 | } | |
861 | } | |
862 | ||
863 | sched_new(lt, sweep_recvdpkt, NULL); | |
864 | } | |
865 | ||
866 | void | |
867 | init_recvdpkt() | |
868 | { | |
869 | time_t lt = lcconf->retry_counter * lcconf->retry_interval; | |
870 | ||
871 | LIST_INIT(&rcptree); | |
872 | ||
873 | sched_new(lt, sweep_recvdpkt, NULL); | |
874 | } |