]>
Commit | Line | Data |
---|---|---|
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 | ||
76 | static LIST_HEAD(_ph1tree_, ph1handle) ph1tree; | |
77 | static LIST_HEAD(_ph2tree_, ph2handle) ph2tree; | |
78 | static LIST_HEAD(_ctdtree_, contacted) ctdtree; | |
79 | static LIST_HEAD(_rcptree_, recvdpkt) rcptree; | |
80 | ||
81 | static void del_recvdpkt __P((struct recvdpkt *)); | |
82 | static void rem_recvdpkt __P((struct recvdpkt *)); | |
83 | static 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 | ||
93 | extern caddr_t val2str(const char *, size_t); | |
94 | ||
95 | struct ph1handle * | |
96 | getph1byindex(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 | */ | |
114 | struct ph1handle * | |
115 | getph1byindex0(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 | */ | |
135 | struct ph1handle * | |
136 | getph1byaddr(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 | ||
152 | struct ph1handle * | |
153 | getph1byaddrwop(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 | */ | |
174 | struct ph1handle * | |
175 | getph1bydstaddrwop(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 | */ | |
193 | vchar_t * | |
194 | dumpph1() | |
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 | */ | |
232 | struct ph1handle * | |
233 | newph1() | |
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 | */ | |
258 | void | |
259 | delph1(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 | */ | |
357 | int | |
358 | insph1(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 | ||
372 | void | |
373 | remph1(iph1) | |
374 | struct ph1handle *iph1; | |
375 | { | |
376 | LIST_REMOVE(iph1, chain); | |
377 | } | |
378 | ||
379 | /* | |
380 | * flush isakmp-sa | |
381 | */ | |
382 | void | |
383 | flushph1() | |
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 | ||
399 | void | |
400 | initph1tree() | |
401 | { | |
402 | LIST_INIT(&ph1tree); | |
403 | } | |
404 | ||
405 | /* %%% management phase 2 handler */ | |
406 | /* | |
407 | * search ph2handle with policy id. | |
408 | */ | |
409 | struct ph2handle * | |
410 | getph2byspid(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 | */ | |
430 | struct ph2handle * | |
431 | getph2byseq(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 | */ | |
447 | struct ph2handle * | |
448 | getph2bymsgid(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 | ||
462 | struct ph2handle * | |
463 | getph2byid(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 | ||
479 | struct ph2handle * | |
480 | getph2bysaddr(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 | */ | |
497 | struct ph2handle * | |
498 | getph2bysaidx(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 | */ | |
534 | struct ph2handle * | |
535 | newph2() | |
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 | */ | |
554 | void | |
555 | initph2(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 | */ | |
610 | void | |
611 | delph2(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 | */ | |
644 | int | |
645 | insph2(iph2) | |
646 | struct ph2handle *iph2; | |
647 | { | |
648 | LIST_INSERT_HEAD(&ph2tree, iph2, chain); | |
649 | ||
650 | return 0; | |
651 | } | |
652 | ||
653 | void | |
654 | remph2(iph2) | |
655 | struct ph2handle *iph2; | |
656 | { | |
657 | LIST_REMOVE(iph2, chain); | |
658 | } | |
659 | ||
660 | void | |
661 | initph2tree() | |
662 | { | |
663 | LIST_INIT(&ph2tree); | |
664 | } | |
665 | ||
666 | void | |
667 | flushph2() | |
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 | */ | |
690 | void | |
691 | deleteallph2(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 | /* %%% */ | |
724 | void | |
725 | bindph12(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 | ||
733 | void | |
734 | unbindph12(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 | */ | |
747 | struct contacted * | |
748 | getcontacted(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 | */ | |
764 | int | |
765 | inscontacted(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 | ||
783 | void | |
784 | clear_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 | ||
796 | void | |
797 | initctdtree() | |
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 | */ | |
811 | int | |
812 | check_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 | */ | |
890 | int | |
891 | add_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 | ||
947 | void | |
948 | del_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 | ||
962 | void | |
963 | rem_recvdpkt(r) | |
964 | struct recvdpkt *r; | |
965 | { | |
966 | LIST_REMOVE(r, chain); | |
967 | } | |
968 | ||
969 | void | |
970 | sweep_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 | ||
994 | void | |
995 | clear_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 | ||
1006 | void | |
1007 | init_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 | */ | |
1021 | int | |
1022 | exclude_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 |