]> git.saurik.com Git - apple/ipsec.git/blame - ipsec-tools/racoon/handler.c
ipsec-34.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / handler.c
CommitLineData
52b7d2ce
A
1/* $Id: handler.c,v 1.13.4.4 2005/07/14 12:00:36 vanhu Exp $ */
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 "config.h"
33
34#include <sys/types.h>
35#include <sys/param.h>
36#include <sys/socket.h>
37
38#include <stdlib.h>
39#include <stdio.h>
40#include <string.h>
41#include <time.h>
42#include <errno.h>
43
44#include "var.h"
45#include "misc.h"
46#include "vmbuf.h"
47#include "plog.h"
48#include "sockmisc.h"
49#include "debug.h"
50
51#include "schedule.h"
52#include "grabmyaddr.h"
53#include "algorithm.h"
54#include "crypto_openssl.h"
55#include "policy.h"
56#include "proposal.h"
57#include "isakmp_var.h"
58#include "evt.h"
59#include "isakmp.h"
60#ifdef ENABLE_HYBRID
61#include "isakmp_xauth.h"
62#include "isakmp_cfg.h"
63#endif
64#include "isakmp_inf.h"
65#include "oakley.h"
66#include "remoteconf.h"
67#include "localconf.h"
68#include "handler.h"
69#include "gcmalloc.h"
70#include "nattraversal.h"
71
72#ifdef HAVE_GSSAPI
73#include "gssapi.h"
74#endif
75
76static LIST_HEAD(_ph1tree_, ph1handle) ph1tree;
77static LIST_HEAD(_ph2tree_, ph2handle) ph2tree;
78static LIST_HEAD(_ctdtree_, contacted) ctdtree;
79static LIST_HEAD(_rcptree_, recvdpkt) rcptree;
80
81static void del_recvdpkt __P((struct recvdpkt *));
82static void rem_recvdpkt __P((struct recvdpkt *));
83static void sweep_recvdpkt __P((void *));
84
85/*
86 * functions about management of the isakmp status table
87 */
88/* %%% management phase 1 handler */
89/*
90 * search for isakmpsa handler with isakmp index.
91 */
92
93extern caddr_t val2str(const char *, size_t);
94
95struct ph1handle *
96getph1byindex(index)
97 isakmp_index *index;
98{
99 struct ph1handle *p;
100
101 LIST_FOREACH(p, &ph1tree, chain) {
102 if (p->status == PHASE1ST_EXPIRED)
103 continue;
104 if (memcmp(&p->index, index, sizeof(*index)) == 0)
105 return p;
106 }
107
108 return NULL;
109}
110
111/*
112 * search for isakmp handler by i_ck in index.
113 */
114struct ph1handle *
115getph1byindex0(index)
116 isakmp_index *index;
117{
118 struct ph1handle *p;
119
120 LIST_FOREACH(p, &ph1tree, chain) {
121 if (p->status == PHASE1ST_EXPIRED)
122 continue;
123 if (memcmp(&p->index, index, sizeof(cookie_t)) == 0)
124 return p;
125 }
126
127 return NULL;
128}
129
130/*
131 * search for isakmpsa handler by source and remote address.
132 * don't use port number to search because this function search
133 * with phase 2's destinaion.
134 */
135struct ph1handle *
136getph1byaddr(local, remote)
137 struct sockaddr *local, *remote;
138{
139 struct ph1handle *p;
140
141 LIST_FOREACH(p, &ph1tree, chain) {
142 if (p->status == PHASE1ST_EXPIRED)
143 continue;
144 if (CMPSADDR(local, p->local) == 0
145 && CMPSADDR(remote, p->remote) == 0)
146 return p;
147 }
148
149 return NULL;
150}
151
152struct ph1handle *
153getph1byaddrwop(local, remote)
154 struct sockaddr *local, *remote;
155{
156 struct ph1handle *p;
157
158 LIST_FOREACH(p, &ph1tree, chain) {
159 if (p->status == PHASE1ST_EXPIRED)
160 continue;
161 if (cmpsaddrwop(local, p->local) == 0
162 && cmpsaddrwop(remote, p->remote) == 0)
163 return p;
164 }
165
166 return NULL;
167}
168
169/*
170 * search for isakmpsa handler by remote address.
171 * don't use port number to search because this function search
172 * with phase 2's destinaion.
173 */
174struct ph1handle *
175getph1bydstaddrwop(remote)
176 struct sockaddr *remote;
177{
178 struct ph1handle *p;
179
180 LIST_FOREACH(p, &ph1tree, chain) {
181 if (p->status == PHASE1ST_EXPIRED)
182 continue;
183 if (cmpsaddrwop(remote, p->remote) == 0)
184 return p;
185 }
186
187 return NULL;
188}
189
190/*
191 * dump isakmp-sa
192 */
193vchar_t *
194dumpph1()
195{
196 struct ph1handle *iph1;
197 struct ph1dump *pd;
198 int cnt = 0;
199 vchar_t *buf;
200
201 /* get length of buffer */
202 LIST_FOREACH(iph1, &ph1tree, chain)
203 cnt++;
204
205 buf = vmalloc(cnt * sizeof(struct ph1dump));
206 if (buf == NULL) {
207 plog(LLV_ERROR, LOCATION, NULL,
208 "failed to get buffer\n");
209 return NULL;
210 }
211 pd = (struct ph1dump *)buf->v;
212
213 LIST_FOREACH(iph1, &ph1tree, chain) {
214 memcpy(&pd->index, &iph1->index, sizeof(iph1->index));
215 pd->status = iph1->status;
216 pd->side = iph1->side;
217 memcpy(&pd->remote, iph1->remote, sysdep_sa_len(iph1->remote));
218 memcpy(&pd->local, iph1->local, sysdep_sa_len(iph1->local));
219 pd->version = iph1->version;
220 pd->etype = iph1->etype;
221 pd->created = iph1->created;
222 pd->ph2cnt = iph1->ph2cnt;
223 pd++;
224 }
225
226 return buf;
227}
228
229/*
230 * create new isakmp Phase 1 status record to handle isakmp in Phase1
231 */
232struct ph1handle *
233newph1()
234{
235 struct ph1handle *iph1;
236
237 /* create new iph1 */
238 iph1 = racoon_calloc(1, sizeof(*iph1));
239 if (iph1 == NULL)
240 return NULL;
241
242 iph1->status = PHASE1ST_SPAWN;
243
244#ifdef ENABLE_DPD
245 iph1->dpd_support = 0;
246 iph1->dpd_lastack = 0;
247 iph1->dpd_seq = 0;
248 iph1->dpd_fails = 0;
249 iph1->dpd_r_u = NULL;
250#endif
251
252 return iph1;
253}
254
255/*
256 * delete new isakmp Phase 1 status record to handle isakmp in Phase1
257 */
258void
259delph1(iph1)
260 struct ph1handle *iph1;
261{
262 /* SA down shell script hook */
263 if (iph1 != NULL)
264 script_hook(iph1, SCRIPT_PHASE1_DOWN);
265
266 EVT_PUSH(iph1->local, iph1->remote, EVTT_PHASE1_DOWN, NULL);
267
268#ifdef ENABLE_NATT
269#ifndef __APPLE__
270 if (iph1->natt_flags & NAT_KA_QUEUED)
271 natt_keepalive_remove (iph1->local, iph1->remote);
272#endif /* __APPLE__ */
273 if (iph1->natt_options) {
274 racoon_free(iph1->natt_options);
275 iph1->natt_options = NULL;
276 }
277#endif
278
279#ifdef ENABLE_DPD
280 if (iph1->dpd_r_u != NULL)
281 SCHED_KILL(iph1->dpd_r_u);
282#endif
283
284 if (iph1->remote) {
285 racoon_free(iph1->remote);
286 iph1->remote = NULL;
287 }
288 if (iph1->local) {
289 racoon_free(iph1->local);
290 iph1->local = NULL;
291 }
292
293 if (iph1->approval) {
294 delisakmpsa(iph1->approval);
295 iph1->approval = NULL;
296 }
297
298#ifdef ENABLE_HYBRID
299 if (iph1->mode_cfg)
300 isakmp_cfg_rmstate(iph1);
301#endif
302
303 VPTRINIT(iph1->authstr);
304
305 sched_scrub_param(iph1);
306 iph1->sce = NULL;
307 iph1->scr = NULL;
308
309 VPTRINIT(iph1->sendbuf);
310
311 VPTRINIT(iph1->dhpriv);
312 VPTRINIT(iph1->dhpub);
313 VPTRINIT(iph1->dhpub_p);
314 VPTRINIT(iph1->dhgxy);
315 VPTRINIT(iph1->nonce);
316 VPTRINIT(iph1->nonce_p);
317 VPTRINIT(iph1->skeyid);
318 VPTRINIT(iph1->skeyid_d);
319 VPTRINIT(iph1->skeyid_a);
320 VPTRINIT(iph1->skeyid_e);
321 VPTRINIT(iph1->key);
322 VPTRINIT(iph1->hash);
323 VPTRINIT(iph1->sig);
324 VPTRINIT(iph1->sig_p);
325 oakley_delcert(iph1->cert);
326 iph1->cert = NULL;
327 oakley_delcert(iph1->cert_p);
328 iph1->cert_p = NULL;
329 oakley_delcert(iph1->crl_p);
330 iph1->crl_p = NULL;
331 oakley_delcert(iph1->cr_p);
332 iph1->cr_p = NULL;
333 VPTRINIT(iph1->id);
334 VPTRINIT(iph1->id_p);
335
336 if (iph1->ivm) {
337 oakley_delivm(iph1->ivm);
338 iph1->ivm = NULL;
339 }
340
341 VPTRINIT(iph1->sa);
342 VPTRINIT(iph1->sa_ret);
343
344#ifdef HAVE_GSSAPI
345 VPTRINIT(iph1->gi_i);
346 VPTRINIT(iph1->gi_r);
347
348 gssapi_free_state(iph1);
349#endif
350
351 racoon_free(iph1);
352}
353
354/*
355 * create new isakmp Phase 1 status record to handle isakmp in Phase1
356 */
357int
358insph1(iph1)
359 struct ph1handle *iph1;
360{
361 /* validity check */
362 if (iph1->remote == NULL) {
363 plog(LLV_ERROR, LOCATION, NULL,
364 "invalid isakmp SA handler. no remote address.\n");
365 return -1;
366 }
367 LIST_INSERT_HEAD(&ph1tree, iph1, chain);
368
369 return 0;
370}
371
372void
373remph1(iph1)
374 struct ph1handle *iph1;
375{
376 LIST_REMOVE(iph1, chain);
377}
378
379/*
380 * flush isakmp-sa
381 */
382void
383flushph1()
384{
385 struct ph1handle *p, *next;
386
387 for (p = LIST_FIRST(&ph1tree); p; p = next) {
388 next = LIST_NEXT(p, chain);
389
390 /* send delete information */
391 if (p->status == PHASE1ST_ESTABLISHED)
392 isakmp_info_send_d1(p);
393
394 remph1(p);
395 delph1(p);
396 }
397}
398
399void
400initph1tree()
401{
402 LIST_INIT(&ph1tree);
403}
404
405/* %%% management phase 2 handler */
406/*
407 * search ph2handle with policy id.
408 */
409struct ph2handle *
410getph2byspid(spid)
411 u_int32_t spid;
412{
413 struct ph2handle *p;
414
415 LIST_FOREACH(p, &ph2tree, chain) {
416 /*
417 * there are ph2handle independent on policy
418 * such like informational exchange.
419 */
420 if (p->spid == spid)
421 return p;
422 }
423
424 return NULL;
425}
426
427/*
428 * search ph2handle with sequence number.
429 */
430struct ph2handle *
431getph2byseq(seq)
432 u_int32_t seq;
433{
434 struct ph2handle *p;
435
436 LIST_FOREACH(p, &ph2tree, chain) {
437 if (p->seq == seq)
438 return p;
439 }
440
441 return NULL;
442}
443
444/*
445 * search ph2handle with message id.
446 */
447struct ph2handle *
448getph2bymsgid(iph1, msgid)
449 struct ph1handle *iph1;
450 u_int32_t msgid;
451{
452 struct ph2handle *p;
453
454 LIST_FOREACH(p, &ph2tree, chain) {
455 if (p->msgid == msgid)
456 return p;
457 }
458
459 return NULL;
460}
461
462struct ph2handle *
463getph2byid(src, dst, spid)
464 struct sockaddr *src, *dst;
465 u_int32_t spid;
466{
467 struct ph2handle *p;
468
469 LIST_FOREACH(p, &ph2tree, chain) {
470 if (spid == p->spid &&
471 CMPSADDR(src, p->src) == 0 &&
472 CMPSADDR(dst, p->dst) == 0)
473 return p;
474 }
475
476 return NULL;
477}
478
479struct ph2handle *
480getph2bysaddr(src, dst)
481 struct sockaddr *src, *dst;
482{
483 struct ph2handle *p;
484
485 LIST_FOREACH(p, &ph2tree, chain) {
486 if (cmpsaddrstrict(src, p->src) == 0 &&
487 cmpsaddrstrict(dst, p->dst) == 0)
488 return p;
489 }
490
491 return NULL;
492}
493
494/*
495 * call by pk_recvexpire().
496 */
497struct ph2handle *
498getph2bysaidx(src, dst, proto_id, spi)
499 struct sockaddr *src, *dst;
500 u_int proto_id;
501 u_int32_t spi;
502{
503 struct ph2handle *iph2;
504 struct saproto *pr;
505
506 LIST_FOREACH(iph2, &ph2tree, chain) {
507 if (iph2->proposal == NULL && iph2->approval == NULL)
508 continue;
509 if (iph2->approval != NULL) {
510 for (pr = iph2->approval->head; pr != NULL;
511 pr = pr->next) {
512 if (proto_id != pr->proto_id)
513 break;
514 if (spi == pr->spi || spi == pr->spi_p)
515 return iph2;
516 }
517 } else if (iph2->proposal != NULL) {
518 for (pr = iph2->proposal->head; pr != NULL;
519 pr = pr->next) {
520 if (proto_id != pr->proto_id)
521 break;
522 if (spi == pr->spi)
523 return iph2;
524 }
525 }
526 }
527
528 return NULL;
529}
530
531/*
532 * create new isakmp Phase 2 status record to handle isakmp in Phase2
533 */
534struct ph2handle *
535newph2()
536{
537 struct ph2handle *iph2 = NULL;
538
539 /* create new iph2 */
540 iph2 = racoon_calloc(1, sizeof(*iph2));
541 if (iph2 == NULL)
542 return NULL;
543
544 iph2->status = PHASE1ST_SPAWN;
545
546 return iph2;
547}
548
549/*
550 * initialize ph2handle
551 * NOTE: don't initialize src/dst.
552 * SPI in the proposal is cleared.
553 */
554void
555initph2(iph2)
556 struct ph2handle *iph2;
557{
558 sched_scrub_param(iph2);
559 iph2->sce = NULL;
560 iph2->scr = NULL;
561
562 VPTRINIT(iph2->sendbuf);
563 VPTRINIT(iph2->msg1);
564
565 /* clear spi, keep variables in the proposal */
566 if (iph2->proposal) {
567 struct saproto *pr;
568 for (pr = iph2->proposal->head; pr != NULL; pr = pr->next)
569 pr->spi = 0;
570 }
571
572 /* clear approval */
573 if (iph2->approval) {
574 flushsaprop(iph2->approval);
575 iph2->approval = NULL;
576 }
577
578 /* clear the generated policy */
579 if (iph2->spidx_gen) {
580 delsp_bothdir((struct policyindex *)iph2->spidx_gen);
581 racoon_free(iph2->spidx_gen);
582 iph2->spidx_gen = NULL;
583 }
584
585 if (iph2->pfsgrp) {
586 oakley_dhgrp_free(iph2->pfsgrp);
587 iph2->pfsgrp = NULL;
588 }
589
590 VPTRINIT(iph2->dhpriv);
591 VPTRINIT(iph2->dhpub);
592 VPTRINIT(iph2->dhpub_p);
593 VPTRINIT(iph2->dhgxy);
594 VPTRINIT(iph2->id);
595 VPTRINIT(iph2->id_p);
596 VPTRINIT(iph2->nonce);
597 VPTRINIT(iph2->nonce_p);
598 VPTRINIT(iph2->sa);
599 VPTRINIT(iph2->sa_ret);
600
601 if (iph2->ivm) {
602 oakley_delivm(iph2->ivm);
603 iph2->ivm = NULL;
604 }
605}
606
607/*
608 * delete new isakmp Phase 2 status record to handle isakmp in Phase2
609 */
610void
611delph2(iph2)
612 struct ph2handle *iph2;
613{
614 initph2(iph2);
615
616 if (iph2->src) {
617 racoon_free(iph2->src);
618 iph2->src = NULL;
619 }
620 if (iph2->dst) {
621 racoon_free(iph2->dst);
622 iph2->dst = NULL;
623 }
624 if (iph2->src_id) {
625 racoon_free(iph2->src_id);
626 iph2->src_id = NULL;
627 }
628 if (iph2->dst_id) {
629 racoon_free(iph2->dst_id);
630 iph2->dst_id = NULL;
631 }
632
633 if (iph2->proposal) {
634 flushsaprop(iph2->proposal);
635 iph2->proposal = NULL;
636 }
637
638 racoon_free(iph2);
639}
640
641/*
642 * create new isakmp Phase 2 status record to handle isakmp in Phase2
643 */
644int
645insph2(iph2)
646 struct ph2handle *iph2;
647{
648 LIST_INSERT_HEAD(&ph2tree, iph2, chain);
649
650 return 0;
651}
652
653void
654remph2(iph2)
655 struct ph2handle *iph2;
656{
657 LIST_REMOVE(iph2, chain);
658}
659
660void
661initph2tree()
662{
663 LIST_INIT(&ph2tree);
664}
665
666void
667flushph2()
668{
669 struct ph2handle *p, *next;
670
671 for (p = LIST_FIRST(&ph2tree); p; p = next) {
672 next = LIST_NEXT(p, chain);
673
674 /* send delete information */
675 if (p->status == PHASE2ST_ESTABLISHED)
676 isakmp_info_send_d2(p);
677
678 delete_spd(p);
679 unbindph12(p);
680 remph2(p);
681 delph2(p);
682 }
683}
684
685/*
686 * Delete all Phase 2 handlers for this src/dst/proto. This
687 * is used during INITIAL-CONTACT processing (so no need to
688 * send a message to the peer).
689 */
690void
691deleteallph2(src, dst, proto_id)
692 struct sockaddr *src, *dst;
693 u_int proto_id;
694{
695 struct ph2handle *iph2, *next;
696 struct saproto *pr;
697
698 for (iph2 = LIST_FIRST(&ph2tree); iph2 != NULL; iph2 = next) {
699 next = LIST_NEXT(iph2, chain);
700 if (iph2->proposal == NULL && iph2->approval == NULL)
701 continue;
702 if (iph2->approval != NULL) {
703 for (pr = iph2->approval->head; pr != NULL;
704 pr = pr->next) {
705 if (proto_id == pr->proto_id)
706 goto zap_it;
707 }
708 } else if (iph2->proposal != NULL) {
709 for (pr = iph2->proposal->head; pr != NULL;
710 pr = pr->next) {
711 if (proto_id == pr->proto_id)
712 goto zap_it;
713 }
714 }
715 continue;
716 zap_it:
717 unbindph12(iph2);
718 remph2(iph2);
719 delph2(iph2);
720 }
721}
722
723/* %%% */
724void
725bindph12(iph1, iph2)
726 struct ph1handle *iph1;
727 struct ph2handle *iph2;
728{
729 iph2->ph1 = iph1;
730 LIST_INSERT_HEAD(&iph1->ph2tree, iph2, ph1bind);
731}
732
733void
734unbindph12(iph2)
735 struct ph2handle *iph2;
736{
737 if (iph2->ph1 != NULL) {
738 iph2->ph1 = NULL;
739 LIST_REMOVE(iph2, ph1bind);
740 }
741}
742
743/* %%% management contacted list */
744/*
745 * search contacted list.
746 */
747struct contacted *
748getcontacted(remote)
749 struct sockaddr *remote;
750{
751 struct contacted *p;
752
753 LIST_FOREACH(p, &ctdtree, chain) {
754 if (cmpsaddrstrict(remote, p->remote) == 0)
755 return p;
756 }
757
758 return NULL;
759}
760
761/*
762 * create new isakmp Phase 2 status record to handle isakmp in Phase2
763 */
764int
765inscontacted(remote)
766 struct sockaddr *remote;
767{
768 struct contacted *new;
769
770 /* create new iph2 */
771 new = racoon_calloc(1, sizeof(*new));
772 if (new == NULL)
773 return -1;
774
775 new->remote = dupsaddr(remote);
776
777 LIST_INSERT_HEAD(&ctdtree, new, chain);
778
779 return 0;
780}
781
782
783void
784clear_contacted()
785{
786 struct contacted *c, *next;
787
788 for (c = LIST_FIRST(&ctdtree); c; c = next) {
789 next = LIST_NEXT(c, chain);
790 LIST_REMOVE(c, chain);
791 racoon_free(c->remote);
792 racoon_free(c);
793 }
794}
795
796void
797initctdtree()
798{
799 LIST_INIT(&ctdtree);
800}
801
802/*
803 * check the response has been sent to the peer. when not, simply reply
804 * the buffered packet to the peer.
805 * OUT:
806 * 0: the packet is received at the first time.
807 * 1: the packet was processed before.
808 * 2: the packet was processed before, but the address mismatches.
809 * -1: error happened.
810 */
811int
812check_recvdpkt(remote, local, rbuf)
813 struct sockaddr *remote, *local;
814 vchar_t *rbuf;
815{
816 vchar_t *hash;
817 struct recvdpkt *r;
818 time_t t;
819 int len, s;
820
821 /* set current time */
822 t = time(NULL);
823
824 hash = eay_md5_one(rbuf);
825 if (!hash) {
826 plog(LLV_ERROR, LOCATION, NULL,
827 "failed to allocate buffer.\n");
828 return -1;
829 }
830
831 LIST_FOREACH(r, &rcptree, chain) {
832 if (memcmp(hash->v, r->hash->v, r->hash->l) == 0)
833 break;
834 }
835 vfree(hash);
836
837 /* this is the first time to receive the packet */
838 if (r == NULL)
839 return 0;
840
841 /*
842 * the packet was processed before, but the remote address mismatches.
843 */
844 if (cmpsaddrstrict(remote, r->remote) != 0)
845 return 2;
846
847 /*
848 * it should not check the local address because the packet
849 * may arrive at other interface.
850 */
851
852 /* check the previous time to send */
853 if (t - r->time_send < 1) {
854 plog(LLV_WARNING, LOCATION, NULL,
855 "the packet retransmitted in a short time from %s\n",
856 saddr2str(remote));
857 /*XXX should it be error ? */
858 }
859
860 /* select the socket to be sent */
861 s = getsockmyaddr(r->local);
862 if (s == -1)
863 return -1;
864
865 /* resend the packet if needed */
866 len = sendfromto(s, r->sendbuf->v, r->sendbuf->l,
867 r->local, r->remote, lcconf->count_persend);
868 if (len == -1) {
869 plog(LLV_ERROR, LOCATION, NULL, "sendfromto failed\n");
870 return -1;
871 }
872
873 /* check the retry counter */
874 r->retry_counter--;
875 if (r->retry_counter <= 0) {
876 rem_recvdpkt(r);
877 del_recvdpkt(r);
878 plog(LLV_DEBUG, LOCATION, NULL,
879 "deleted the retransmission packet to %s.\n",
880 saddr2str(remote));
881 } else
882 r->time_send = t;
883
884 return 1;
885}
886
887/*
888 * adding a hash of received packet into the received list.
889 */
890int
891add_recvdpkt(remote, local, sbuf, rbuf)
892 struct sockaddr *remote, *local;
893 vchar_t *sbuf, *rbuf;
894{
895 struct recvdpkt *new = NULL;
896
897 if (lcconf->retry_counter == 0) {
898 /* no need to add it */
899 return 0;
900 }
901
902 new = racoon_calloc(1, sizeof(*new));
903 if (!new) {
904 plog(LLV_ERROR, LOCATION, NULL,
905 "failed to allocate buffer.\n");
906 return -1;
907 }
908
909 new->hash = eay_md5_one(rbuf);
910 if (!new->hash) {
911 plog(LLV_ERROR, LOCATION, NULL,
912 "failed to allocate buffer.\n");
913 del_recvdpkt(new);
914 return -1;
915 }
916 new->remote = dupsaddr(remote);
917 if (new->remote == NULL) {
918 plog(LLV_ERROR, LOCATION, NULL,
919 "failed to allocate buffer.\n");
920 del_recvdpkt(new);
921 return -1;
922 }
923 new->local = dupsaddr(local);
924 if (new->local == NULL) {
925 plog(LLV_ERROR, LOCATION, NULL,
926 "failed to allocate buffer.\n");
927 del_recvdpkt(new);
928 return -1;
929 }
930 new->sendbuf = vdup(sbuf);
931 if (new->sendbuf == NULL) {
932 plog(LLV_ERROR, LOCATION, NULL,
933 "failed to allocate buffer.\n");
934 del_recvdpkt(new);
935 return -1;
936 }
937
938 new->retry_counter = lcconf->retry_counter;
939 new->time_send = 0;
940 new->created = time(NULL);
941
942 LIST_INSERT_HEAD(&rcptree, new, chain);
943
944 return 0;
945}
946
947void
948del_recvdpkt(r)
949 struct recvdpkt *r;
950{
951 if (r->remote)
952 racoon_free(r->remote);
953 if (r->local)
954 racoon_free(r->local);
955 if (r->hash)
956 vfree(r->hash);
957 if (r->sendbuf)
958 vfree(r->sendbuf);
959 racoon_free(r);
960}
961
962void
963rem_recvdpkt(r)
964 struct recvdpkt *r;
965{
966 LIST_REMOVE(r, chain);
967}
968
969void
970sweep_recvdpkt(dummy)
971 void *dummy;
972{
973 struct recvdpkt *r, *next;
974 time_t t, lt;
975
976 /* set current time */
977 t = time(NULL);
978
979 /* set the lifetime of the retransmission */
980 lt = lcconf->retry_counter * lcconf->retry_interval;
981
982 for (r = LIST_FIRST(&rcptree); r; r = next) {
983 next = LIST_NEXT(r, chain);
984
985 if (t - r->created > lt) {
986 rem_recvdpkt(r);
987 del_recvdpkt(r);
988 }
989 }
990
991 sched_new(lt, sweep_recvdpkt, NULL);
992}
993
994void
995clear_recvdpkt()
996{
997 struct recvdpkt *r, *next;
998
999 for (r = LIST_FIRST(&rcptree); r; r = next) {
1000 next = LIST_NEXT(r, chain);
1001 rem_recvdpkt(r);
1002 del_recvdpkt(r);
1003 }
1004}
1005
1006void
1007init_recvdpkt()
1008{
1009 time_t lt = lcconf->retry_counter * lcconf->retry_interval;
1010
1011 LIST_INIT(&rcptree);
1012
1013 sched_new(lt, sweep_recvdpkt, NULL);
1014}
1015
1016#ifdef ENABLE_HYBRID
1017/*
1018 * Returns 0 if the address was obtained by ISAKMP mode config, 1 otherwise
1019 * This should be in isakmp_cfg.c but ph1tree being private, it must be there
1020 */
1021int
1022exclude_cfg_addr(addr)
1023 const struct sockaddr *addr;
1024{
1025 struct ph1handle *p;
1026 struct sockaddr_in *sin;
1027
1028 LIST_FOREACH(p, &ph1tree, chain) {
1029 if ((p->mode_cfg != NULL) &&
1030 (p->mode_cfg->flags & ISAKMP_CFG_GOT_ADDR4) &&
1031 (addr->sa_family == AF_INET)) {
1032 sin = (struct sockaddr_in *)addr;
1033 if (sin->sin_addr.s_addr == p->mode_cfg->addr4.s_addr)
1034 return 0;
1035 }
1036 }
1037
1038 return 1;
1039}
1040#endif