1 | /* $NetBSD: isakmp_inf.c,v 1.47.2.3 2013/04/12 09:53:52 tteras Exp $ */ |
---|
2 | |
---|
3 | /* Id: isakmp_inf.c,v 1.44 2006/05/06 20:45:52 manubsd Exp */ |
---|
4 | |
---|
5 | /* |
---|
6 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
---|
7 | * All rights reserved. |
---|
8 | * |
---|
9 | * Redistribution and use in source and binary forms, with or without |
---|
10 | * modification, are permitted provided that the following conditions |
---|
11 | * are met: |
---|
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. |
---|
20 | * |
---|
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 |
---|
31 | * SUCH DAMAGE. |
---|
32 | */ |
---|
33 | |
---|
34 | #include "config.h" |
---|
35 | |
---|
36 | #include <sys/types.h> |
---|
37 | #include <sys/param.h> |
---|
38 | #include <sys/socket.h> |
---|
39 | |
---|
40 | #include <net/pfkeyv2.h> |
---|
41 | #include <netinet/in.h> |
---|
42 | #include <sys/queue.h> |
---|
43 | #include PATH_IPSEC_H |
---|
44 | |
---|
45 | #include <stdlib.h> |
---|
46 | #include <stdio.h> |
---|
47 | #include <string.h> |
---|
48 | #include <errno.h> |
---|
49 | #if TIME_WITH_SYS_TIME |
---|
50 | # include <sys/time.h> |
---|
51 | # include <time.h> |
---|
52 | #else |
---|
53 | # if HAVE_SYS_TIME_H |
---|
54 | # include <sys/time.h> |
---|
55 | # else |
---|
56 | # include <time.h> |
---|
57 | # endif |
---|
58 | #endif |
---|
59 | #ifdef ENABLE_HYBRID |
---|
60 | #include <resolv.h> |
---|
61 | #endif |
---|
62 | |
---|
63 | #include "libpfkey.h" |
---|
64 | |
---|
65 | #include "var.h" |
---|
66 | #include "vmbuf.h" |
---|
67 | #include "schedule.h" |
---|
68 | #include "str2val.h" |
---|
69 | #include "misc.h" |
---|
70 | #include "plog.h" |
---|
71 | #include "debug.h" |
---|
72 | |
---|
73 | #include "localconf.h" |
---|
74 | #include "remoteconf.h" |
---|
75 | #include "sockmisc.h" |
---|
76 | #include "handler.h" |
---|
77 | #include "policy.h" |
---|
78 | #include "proposal.h" |
---|
79 | #include "isakmp_var.h" |
---|
80 | #include "evt.h" |
---|
81 | #include "isakmp.h" |
---|
82 | #ifdef ENABLE_HYBRID |
---|
83 | #include "isakmp_xauth.h" |
---|
84 | #include "isakmp_unity.h" |
---|
85 | #include "isakmp_cfg.h" |
---|
86 | #endif |
---|
87 | #include "isakmp_inf.h" |
---|
88 | #include "oakley.h" |
---|
89 | #include "ipsec_doi.h" |
---|
90 | #include "crypto_openssl.h" |
---|
91 | #include "pfkey.h" |
---|
92 | #include "policy.h" |
---|
93 | #include "algorithm.h" |
---|
94 | #include "proposal.h" |
---|
95 | #include "admin.h" |
---|
96 | #include "strnames.h" |
---|
97 | #ifdef ENABLE_NATT |
---|
98 | #include "nattraversal.h" |
---|
99 | #endif |
---|
100 | |
---|
101 | /* information exchange */ |
---|
102 | static int isakmp_info_recv_n (struct ph1handle *, struct isakmp_pl_n *, u_int32_t, int); |
---|
103 | static int isakmp_info_recv_d (struct ph1handle *, struct isakmp_pl_d *, u_int32_t, int); |
---|
104 | |
---|
105 | #ifdef ENABLE_DPD |
---|
106 | static int isakmp_info_recv_r_u __P((struct ph1handle *, |
---|
107 | struct isakmp_pl_ru *, u_int32_t)); |
---|
108 | static int isakmp_info_recv_r_u_ack __P((struct ph1handle *, |
---|
109 | struct isakmp_pl_ru *, u_int32_t)); |
---|
110 | static void isakmp_info_send_r_u __P((struct sched *)); |
---|
111 | #endif |
---|
112 | |
---|
113 | static void purge_isakmp_spi __P((int, isakmp_index *, size_t)); |
---|
114 | |
---|
115 | /* %%% |
---|
116 | * Information Exchange |
---|
117 | */ |
---|
118 | /* |
---|
119 | * receive Information |
---|
120 | */ |
---|
121 | int |
---|
122 | isakmp_info_recv(iph1, msg0) |
---|
123 | struct ph1handle *iph1; |
---|
124 | vchar_t *msg0; |
---|
125 | { |
---|
126 | vchar_t *msg = NULL; |
---|
127 | vchar_t *pbuf = NULL; |
---|
128 | u_int32_t msgid = 0; |
---|
129 | int error = -1; |
---|
130 | struct isakmp *isakmp; |
---|
131 | struct isakmp_gen *gen; |
---|
132 | struct isakmp_parse_t *pa, *pap; |
---|
133 | void *p; |
---|
134 | vchar_t *hash, *payload; |
---|
135 | struct isakmp_gen *nd; |
---|
136 | u_int8_t np; |
---|
137 | int encrypted; |
---|
138 | |
---|
139 | plog(LLV_DEBUG, LOCATION, NULL, "receive Information.\n"); |
---|
140 | |
---|
141 | encrypted = ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E); |
---|
142 | msgid = ((struct isakmp *)msg0->v)->msgid; |
---|
143 | |
---|
144 | /* Use new IV to decrypt Informational message. */ |
---|
145 | if (encrypted) { |
---|
146 | struct isakmp_ivm *ivm; |
---|
147 | |
---|
148 | if (iph1->ivm == NULL) { |
---|
149 | plog(LLV_ERROR, LOCATION, NULL, "iph1->ivm == NULL\n"); |
---|
150 | return -1; |
---|
151 | } |
---|
152 | |
---|
153 | /* compute IV */ |
---|
154 | ivm = oakley_newiv2(iph1, ((struct isakmp *)msg0->v)->msgid); |
---|
155 | if (ivm == NULL) |
---|
156 | return -1; |
---|
157 | |
---|
158 | msg = oakley_do_decrypt(iph1, msg0, ivm->iv, ivm->ive); |
---|
159 | oakley_delivm(ivm); |
---|
160 | if (msg == NULL) |
---|
161 | return -1; |
---|
162 | |
---|
163 | } else |
---|
164 | msg = vdup(msg0); |
---|
165 | |
---|
166 | /* Safety check */ |
---|
167 | if (msg->l < sizeof(*isakmp) + sizeof(*gen)) { |
---|
168 | plog(LLV_ERROR, LOCATION, NULL, |
---|
169 | "ignore information because the " |
---|
170 | "message is way too short - %zu byte(s).\n", |
---|
171 | msg->l); |
---|
172 | goto end; |
---|
173 | } |
---|
174 | |
---|
175 | isakmp = (struct isakmp *)msg->v; |
---|
176 | gen = (struct isakmp_gen *)((caddr_t)isakmp + sizeof(struct isakmp)); |
---|
177 | np = gen->np; |
---|
178 | |
---|
179 | if (encrypted) { |
---|
180 | if (isakmp->np != ISAKMP_NPTYPE_HASH) { |
---|
181 | plog(LLV_ERROR, LOCATION, NULL, |
---|
182 | "ignore information because the " |
---|
183 | "message has no hash payload.\n"); |
---|
184 | goto end; |
---|
185 | } |
---|
186 | |
---|
187 | if (iph1->status != PHASE1ST_ESTABLISHED && |
---|
188 | iph1->status != PHASE1ST_DYING) { |
---|
189 | plog(LLV_ERROR, LOCATION, NULL, |
---|
190 | "ignore information because ISAKMP-SA " |
---|
191 | "has not been established yet.\n"); |
---|
192 | goto end; |
---|
193 | } |
---|
194 | |
---|
195 | /* Safety check */ |
---|
196 | if (msg->l < sizeof(*isakmp) + ntohs(gen->len) + sizeof(*nd)) { |
---|
197 | plog(LLV_ERROR, LOCATION, NULL, |
---|
198 | "ignore information because the " |
---|
199 | "message is too short - %zu byte(s).\n", |
---|
200 | msg->l); |
---|
201 | goto end; |
---|
202 | } |
---|
203 | |
---|
204 | p = (caddr_t) gen + sizeof(struct isakmp_gen); |
---|
205 | nd = (struct isakmp_gen *) ((caddr_t) gen + ntohs(gen->len)); |
---|
206 | |
---|
207 | /* nd length check */ |
---|
208 | if (ntohs(nd->len) > msg->l - (sizeof(struct isakmp) + |
---|
209 | ntohs(gen->len))) { |
---|
210 | plog(LLV_ERROR, LOCATION, NULL, |
---|
211 | "too long payload length (broken message?)\n"); |
---|
212 | goto end; |
---|
213 | } |
---|
214 | |
---|
215 | if (ntohs(nd->len) < sizeof(*nd)) { |
---|
216 | plog(LLV_ERROR, LOCATION, NULL, |
---|
217 | "too short payload length (broken message?)\n"); |
---|
218 | goto end; |
---|
219 | } |
---|
220 | |
---|
221 | payload = vmalloc(ntohs(nd->len)); |
---|
222 | if (payload == NULL) { |
---|
223 | plog(LLV_ERROR, LOCATION, NULL, |
---|
224 | "cannot allocate memory\n"); |
---|
225 | goto end; |
---|
226 | } |
---|
227 | |
---|
228 | memcpy(payload->v, (caddr_t) nd, ntohs(nd->len)); |
---|
229 | |
---|
230 | /* compute HASH */ |
---|
231 | hash = oakley_compute_hash1(iph1, isakmp->msgid, payload); |
---|
232 | if (hash == NULL) { |
---|
233 | plog(LLV_ERROR, LOCATION, NULL, |
---|
234 | "cannot compute hash\n"); |
---|
235 | |
---|
236 | vfree(payload); |
---|
237 | goto end; |
---|
238 | } |
---|
239 | |
---|
240 | if (ntohs(gen->len) - sizeof(struct isakmp_gen) != hash->l) { |
---|
241 | plog(LLV_ERROR, LOCATION, NULL, |
---|
242 | "ignore information due to hash length mismatch\n"); |
---|
243 | |
---|
244 | vfree(hash); |
---|
245 | vfree(payload); |
---|
246 | goto end; |
---|
247 | } |
---|
248 | |
---|
249 | if (memcmp(p, hash->v, hash->l) != 0) { |
---|
250 | plog(LLV_ERROR, LOCATION, NULL, |
---|
251 | "ignore information due to hash mismatch\n"); |
---|
252 | |
---|
253 | vfree(hash); |
---|
254 | vfree(payload); |
---|
255 | goto end; |
---|
256 | } |
---|
257 | |
---|
258 | plog(LLV_DEBUG, LOCATION, NULL, "hash validated.\n"); |
---|
259 | |
---|
260 | vfree(hash); |
---|
261 | vfree(payload); |
---|
262 | } else { |
---|
263 | /* make sure the packet was encrypted after the beginning of phase 1. */ |
---|
264 | switch (iph1->etype) { |
---|
265 | case ISAKMP_ETYPE_AGG: |
---|
266 | case ISAKMP_ETYPE_BASE: |
---|
267 | case ISAKMP_ETYPE_IDENT: |
---|
268 | if ((iph1->side == INITIATOR && iph1->status < PHASE1ST_MSG3SENT) |
---|
269 | || (iph1->side == RESPONDER && iph1->status < PHASE1ST_MSG2SENT)) { |
---|
270 | break; |
---|
271 | } |
---|
272 | /*FALLTHRU*/ |
---|
273 | default: |
---|
274 | plog(LLV_ERROR, LOCATION, iph1->remote, |
---|
275 | "%s message must be encrypted\n", |
---|
276 | s_isakmp_nptype(np)); |
---|
277 | error = 0; |
---|
278 | goto end; |
---|
279 | } |
---|
280 | } |
---|
281 | |
---|
282 | if (!(pbuf = isakmp_parse(msg))) { |
---|
283 | error = -1; |
---|
284 | goto end; |
---|
285 | } |
---|
286 | |
---|
287 | error = 0; |
---|
288 | for (pa = (struct isakmp_parse_t *)pbuf->v; pa->type; pa++) { |
---|
289 | switch (pa->type) { |
---|
290 | case ISAKMP_NPTYPE_HASH: |
---|
291 | /* Handled above */ |
---|
292 | break; |
---|
293 | case ISAKMP_NPTYPE_N: |
---|
294 | error = isakmp_info_recv_n(iph1, |
---|
295 | (struct isakmp_pl_n *)pa->ptr, |
---|
296 | msgid, encrypted); |
---|
297 | break; |
---|
298 | case ISAKMP_NPTYPE_D: |
---|
299 | error = isakmp_info_recv_d(iph1, |
---|
300 | (struct isakmp_pl_d *)pa->ptr, |
---|
301 | msgid, encrypted); |
---|
302 | break; |
---|
303 | case ISAKMP_NPTYPE_NONCE: |
---|
304 | /* XXX to be 6.4.2 ike-01.txt */ |
---|
305 | /* XXX IV is to be synchronized. */ |
---|
306 | plog(LLV_ERROR, LOCATION, iph1->remote, |
---|
307 | "ignore Acknowledged Informational\n"); |
---|
308 | break; |
---|
309 | default: |
---|
310 | /* don't send information, see isakmp_ident_r1() */ |
---|
311 | error = 0; |
---|
312 | plog(LLV_ERROR, LOCATION, iph1->remote, |
---|
313 | "reject the packet, " |
---|
314 | "received unexpected payload type %s.\n", |
---|
315 | s_isakmp_nptype(gen->np)); |
---|
316 | } |
---|
317 | if (error < 0) |
---|
318 | break; |
---|
319 | } |
---|
320 | end: |
---|
321 | if (msg != NULL) |
---|
322 | vfree(msg); |
---|
323 | if (pbuf != NULL) |
---|
324 | vfree(pbuf); |
---|
325 | return error; |
---|
326 | } |
---|
327 | |
---|
328 | |
---|
329 | /* |
---|
330 | * log unhandled / unallowed Notification payload |
---|
331 | */ |
---|
332 | int |
---|
333 | isakmp_log_notify(iph1, notify, exchange) |
---|
334 | struct ph1handle *iph1; |
---|
335 | struct isakmp_pl_n *notify; |
---|
336 | const char *exchange; |
---|
337 | { |
---|
338 | u_int type; |
---|
339 | char *nraw, *ndata, *nhex; |
---|
340 | size_t l; |
---|
341 | |
---|
342 | type = ntohs(notify->type); |
---|
343 | if (ntohs(notify->h.len) < sizeof(*notify) + notify->spi_size) { |
---|
344 | plog(LLV_ERROR, LOCATION, iph1->remote, |
---|
345 | "invalid spi_size in %s notification in %s.\n", |
---|
346 | s_isakmp_notify_msg(type), exchange); |
---|
347 | return -1; |
---|
348 | } |
---|
349 | |
---|
350 | plog(LLV_ERROR, LOCATION, iph1->remote, |
---|
351 | "notification %s received in %s.\n", |
---|
352 | s_isakmp_notify_msg(type), exchange); |
---|
353 | |
---|
354 | nraw = ((char*) notify) + sizeof(*notify) + notify->spi_size; |
---|
355 | l = ntohs(notify->h.len) - sizeof(*notify) - notify->spi_size; |
---|
356 | if (l > 0) { |
---|
357 | if (type >= ISAKMP_NTYPE_MINERROR && |
---|
358 | type <= ISAKMP_NTYPE_MAXERROR) { |
---|
359 | ndata = binsanitize(nraw, l); |
---|
360 | if (ndata != NULL) { |
---|
361 | plog(LLV_ERROR, LOCATION, iph1->remote, |
---|
362 | "error message: '%s'.\n", |
---|
363 | ndata); |
---|
364 | racoon_free(ndata); |
---|
365 | } else { |
---|
366 | plog(LLV_ERROR, LOCATION, iph1->remote, |
---|
367 | "Cannot allocate memory\n"); |
---|
368 | } |
---|
369 | } else { |
---|
370 | nhex = val2str(nraw, l); |
---|
371 | if (nhex != NULL) { |
---|
372 | plog(LLV_ERROR, LOCATION, iph1->remote, |
---|
373 | "notification payload: %s.\n", |
---|
374 | nhex); |
---|
375 | racoon_free(nhex); |
---|
376 | } else { |
---|
377 | plog(LLV_ERROR, LOCATION, iph1->remote, |
---|
378 | "Cannot allocate memory\n"); |
---|
379 | } |
---|
380 | } |
---|
381 | } |
---|
382 | |
---|
383 | return 0; |
---|
384 | } |
---|
385 | |
---|
386 | |
---|
387 | /* |
---|
388 | * handling of Notification payload |
---|
389 | */ |
---|
390 | static int |
---|
391 | isakmp_info_recv_n(iph1, notify, msgid, encrypted) |
---|
392 | struct ph1handle *iph1; |
---|
393 | struct isakmp_pl_n *notify; |
---|
394 | u_int32_t msgid; |
---|
395 | int encrypted; |
---|
396 | { |
---|
397 | u_int type; |
---|
398 | |
---|
399 | type = ntohs(notify->type); |
---|
400 | switch (type) { |
---|
401 | case ISAKMP_NTYPE_CONNECTED: |
---|
402 | case ISAKMP_NTYPE_RESPONDER_LIFETIME: |
---|
403 | case ISAKMP_NTYPE_REPLAY_STATUS: |
---|
404 | #ifdef ENABLE_HYBRID |
---|
405 | case ISAKMP_NTYPE_UNITY_HEARTBEAT: |
---|
406 | #endif |
---|
407 | /* do something */ |
---|
408 | break; |
---|
409 | case ISAKMP_NTYPE_INITIAL_CONTACT: |
---|
410 | if (encrypted) |
---|
411 | return isakmp_info_recv_initialcontact(iph1, NULL); |
---|
412 | break; |
---|
413 | #ifdef ENABLE_DPD |
---|
414 | case ISAKMP_NTYPE_R_U_THERE: |
---|
415 | if (encrypted) |
---|
416 | return isakmp_info_recv_r_u(iph1, |
---|
417 | (struct isakmp_pl_ru *)notify, msgid); |
---|
418 | break; |
---|
419 | case ISAKMP_NTYPE_R_U_THERE_ACK: |
---|
420 | if (encrypted) |
---|
421 | return isakmp_info_recv_r_u_ack(iph1, |
---|
422 | (struct isakmp_pl_ru *)notify, msgid); |
---|
423 | break; |
---|
424 | #endif |
---|
425 | } |
---|
426 | |
---|
427 | /* If we receive a error notification we should delete the related |
---|
428 | * phase1 / phase2 handle, and send an event to racoonctl. |
---|
429 | * However, since phase1 error notifications are not encrypted and |
---|
430 | * can not be authenticated, it would allow a DoS attack possibility |
---|
431 | * to handle them. |
---|
432 | * Phase2 error notifications should be encrypted, so we could handle |
---|
433 | * those, but it needs implementing (the old code didn't implement |
---|
434 | * that either). |
---|
435 | * So we are good to just log the messages here. |
---|
436 | */ |
---|
437 | if (encrypted) |
---|
438 | isakmp_log_notify(iph1, notify, "informational exchange"); |
---|
439 | else |
---|
440 | isakmp_log_notify(iph1, notify, "unencrypted informational exchange"); |
---|
441 | |
---|
442 | return 0; |
---|
443 | } |
---|
444 | |
---|
445 | /* |
---|
446 | * handling of Deletion payload |
---|
447 | */ |
---|
448 | static int |
---|
449 | isakmp_info_recv_d(iph1, delete, msgid, encrypted) |
---|
450 | struct ph1handle *iph1; |
---|
451 | struct isakmp_pl_d *delete; |
---|
452 | u_int32_t msgid; |
---|
453 | int encrypted; |
---|
454 | { |
---|
455 | int tlen, num_spi; |
---|
456 | vchar_t *pbuf; |
---|
457 | int protected = 0; |
---|
458 | struct ph1handle *del_ph1; |
---|
459 | struct ph2handle *iph2; |
---|
460 | union { |
---|
461 | u_int32_t spi32; |
---|
462 | u_int16_t spi16[2]; |
---|
463 | } spi; |
---|
464 | |
---|
465 | if (ntohl(delete->doi) != IPSEC_DOI) { |
---|
466 | plog(LLV_ERROR, LOCATION, iph1->remote, |
---|
467 | "delete payload with invalid doi:%d.\n", |
---|
468 | ntohl(delete->doi)); |
---|
469 | #ifdef ENABLE_HYBRID |
---|
470 | /* |
---|
471 | * At deconnexion time, Cisco VPN client does this |
---|
472 | * with a zero DOI. Don't give up in that situation. |
---|
473 | */ |
---|
474 | if (((iph1->mode_cfg->flags & |
---|
475 | ISAKMP_CFG_VENDORID_UNITY) == 0) || (delete->doi != 0)) |
---|
476 | return 0; |
---|
477 | #else |
---|
478 | return 0; |
---|
479 | #endif |
---|
480 | } |
---|
481 | |
---|
482 | num_spi = ntohs(delete->num_spi); |
---|
483 | tlen = ntohs(delete->h.len) - sizeof(struct isakmp_pl_d); |
---|
484 | |
---|
485 | if (tlen != num_spi * delete->spi_size) { |
---|
486 | plog(LLV_ERROR, LOCATION, iph1->remote, |
---|
487 | "deletion payload with invalid length.\n"); |
---|
488 | return 0; |
---|
489 | } |
---|
490 | |
---|
491 | plog(LLV_DEBUG, LOCATION, iph1->remote, |
---|
492 | "delete payload for protocol %s\n", |
---|
493 | s_ipsecdoi_proto(delete->proto_id)); |
---|
494 | |
---|
495 | if((iph1 == NULL || !iph1->rmconf->weak_phase1_check) && !encrypted) { |
---|
496 | plog(LLV_WARNING, LOCATION, iph1->remote, |
---|
497 | "Ignoring unencrypted delete payload " |
---|
498 | "(check the weak_phase1_check option)\n"); |
---|
499 | return 0; |
---|
500 | } |
---|
501 | |
---|
502 | switch (delete->proto_id) { |
---|
503 | case IPSECDOI_PROTO_ISAKMP: |
---|
504 | if (delete->spi_size != sizeof(isakmp_index)) { |
---|
505 | plog(LLV_ERROR, LOCATION, iph1->remote, |
---|
506 | "delete payload with strange spi " |
---|
507 | "size %d(proto_id:%d)\n", |
---|
508 | delete->spi_size, delete->proto_id); |
---|
509 | return 0; |
---|
510 | } |
---|
511 | |
---|
512 | del_ph1=getph1byindex((isakmp_index *)(delete + 1)); |
---|
513 | if(del_ph1 != NULL){ |
---|
514 | |
---|
515 | evt_phase1(iph1, EVT_PHASE1_PEER_DELETED, NULL); |
---|
516 | sched_cancel(&del_ph1->scr); |
---|
517 | |
---|
518 | /* |
---|
519 | * Delete also IPsec-SAs if rekeying is enabled. |
---|
520 | */ |
---|
521 | if (ph1_rekey_enabled(del_ph1)) |
---|
522 | purge_remote(del_ph1); |
---|
523 | else |
---|
524 | isakmp_ph1expire(del_ph1); |
---|
525 | } |
---|
526 | break; |
---|
527 | |
---|
528 | case IPSECDOI_PROTO_IPSEC_AH: |
---|
529 | case IPSECDOI_PROTO_IPSEC_ESP: |
---|
530 | if (delete->spi_size != sizeof(u_int32_t)) { |
---|
531 | plog(LLV_ERROR, LOCATION, iph1->remote, |
---|
532 | "delete payload with strange spi " |
---|
533 | "size %d(proto_id:%d)\n", |
---|
534 | delete->spi_size, delete->proto_id); |
---|
535 | return 0; |
---|
536 | } |
---|
537 | purge_ipsec_spi(iph1->remote, delete->proto_id, |
---|
538 | (u_int32_t *)(delete + 1), num_spi); |
---|
539 | break; |
---|
540 | |
---|
541 | case IPSECDOI_PROTO_IPCOMP: |
---|
542 | /* need to handle both 16bit/32bit SPI */ |
---|
543 | memset(&spi, 0, sizeof(spi)); |
---|
544 | if (delete->spi_size == sizeof(spi.spi16[1])) { |
---|
545 | memcpy(&spi.spi16[1], delete + 1, |
---|
546 | sizeof(spi.spi16[1])); |
---|
547 | } else if (delete->spi_size == sizeof(spi.spi32)) |
---|
548 | memcpy(&spi.spi32, delete + 1, sizeof(spi.spi32)); |
---|
549 | else { |
---|
550 | plog(LLV_ERROR, LOCATION, iph1->remote, |
---|
551 | "delete payload with strange spi " |
---|
552 | "size %d(proto_id:%d)\n", |
---|
553 | delete->spi_size, delete->proto_id); |
---|
554 | return 0; |
---|
555 | } |
---|
556 | purge_ipsec_spi(iph1->remote, delete->proto_id, |
---|
557 | &spi.spi32, num_spi); |
---|
558 | break; |
---|
559 | |
---|
560 | default: |
---|
561 | plog(LLV_ERROR, LOCATION, iph1->remote, |
---|
562 | "deletion message received, " |
---|
563 | "invalid proto_id: %d\n", |
---|
564 | delete->proto_id); |
---|
565 | return 0; |
---|
566 | } |
---|
567 | |
---|
568 | plog(LLV_DEBUG, LOCATION, NULL, "purged SAs.\n"); |
---|
569 | |
---|
570 | return 0; |
---|
571 | } |
---|
572 | |
---|
573 | /* |
---|
574 | * send Delete payload (for ISAKMP SA) in Informational exchange. |
---|
575 | */ |
---|
576 | int |
---|
577 | isakmp_info_send_d1(iph1) |
---|
578 | struct ph1handle *iph1; |
---|
579 | { |
---|
580 | struct isakmp_pl_d *d; |
---|
581 | vchar_t *payload = NULL; |
---|
582 | int tlen; |
---|
583 | int error = 0; |
---|
584 | |
---|
585 | if (iph1->status != PHASE2ST_ESTABLISHED) |
---|
586 | return 0; |
---|
587 | |
---|
588 | /* create delete payload */ |
---|
589 | |
---|
590 | /* send SPIs of inbound SAs. */ |
---|
591 | /* XXX should send outbound SAs's ? */ |
---|
592 | tlen = sizeof(*d) + sizeof(isakmp_index); |
---|
593 | payload = vmalloc(tlen); |
---|
594 | if (payload == NULL) { |
---|
595 | plog(LLV_ERROR, LOCATION, NULL, |
---|
596 | "failed to get buffer for payload.\n"); |
---|
597 | return errno; |
---|
598 | } |
---|
599 | |
---|
600 | d = (struct isakmp_pl_d *)payload->v; |
---|
601 | d->h.np = ISAKMP_NPTYPE_NONE; |
---|
602 | d->h.len = htons(tlen); |
---|
603 | d->doi = htonl(IPSEC_DOI); |
---|
604 | d->proto_id = IPSECDOI_PROTO_ISAKMP; |
---|
605 | d->spi_size = sizeof(isakmp_index); |
---|
606 | d->num_spi = htons(1); |
---|
607 | memcpy(d + 1, &iph1->index, sizeof(isakmp_index)); |
---|
608 | |
---|
609 | error = isakmp_info_send_common(iph1, payload, |
---|
610 | ISAKMP_NPTYPE_D, 0); |
---|
611 | vfree(payload); |
---|
612 | |
---|
613 | return error; |
---|
614 | } |
---|
615 | |
---|
616 | /* |
---|
617 | * send Delete payload (for IPsec SA) in Informational exchange, based on |
---|
618 | * pfkey msg. It sends always single SPI. |
---|
619 | */ |
---|
620 | int |
---|
621 | isakmp_info_send_d2(iph2) |
---|
622 | struct ph2handle *iph2; |
---|
623 | { |
---|
624 | struct ph1handle *iph1; |
---|
625 | struct saproto *pr; |
---|
626 | struct isakmp_pl_d *d; |
---|
627 | vchar_t *payload = NULL; |
---|
628 | int tlen; |
---|
629 | int error = 0; |
---|
630 | u_int8_t *spi; |
---|
631 | |
---|
632 | if (iph2->status != PHASE2ST_ESTABLISHED) |
---|
633 | return 0; |
---|
634 | |
---|
635 | /* |
---|
636 | * don't send delete information if there is no phase 1 handler. |
---|
637 | * It's nonsensical to negotiate phase 1 to send the information. |
---|
638 | */ |
---|
639 | iph1 = getph1byaddr(iph2->src, iph2->dst, 0); |
---|
640 | if (iph1 == NULL){ |
---|
641 | plog(LLV_DEBUG2, LOCATION, NULL, |
---|
642 | "No ph1 handler found, could not send DELETE_SA\n"); |
---|
643 | return 0; |
---|
644 | } |
---|
645 | |
---|
646 | /* create delete payload */ |
---|
647 | for (pr = iph2->approval->head; pr != NULL; pr = pr->next) { |
---|
648 | |
---|
649 | /* send SPIs of inbound SAs. */ |
---|
650 | /* |
---|
651 | * XXX should I send outbound SAs's ? |
---|
652 | * I send inbound SAs's SPI only at the moment because I can't |
---|
653 | * decode any more if peer send encoded packet without aware of |
---|
654 | * deletion of SA. Outbound SAs don't come under the situation. |
---|
655 | */ |
---|
656 | tlen = sizeof(*d) + pr->spisize; |
---|
657 | payload = vmalloc(tlen); |
---|
658 | if (payload == NULL) { |
---|
659 | plog(LLV_ERROR, LOCATION, NULL, |
---|
660 | "failed to get buffer for payload.\n"); |
---|
661 | return errno; |
---|
662 | } |
---|
663 | |
---|
664 | d = (struct isakmp_pl_d *)payload->v; |
---|
665 | d->h.np = ISAKMP_NPTYPE_NONE; |
---|
666 | d->h.len = htons(tlen); |
---|
667 | d->doi = htonl(IPSEC_DOI); |
---|
668 | d->proto_id = pr->proto_id; |
---|
669 | d->spi_size = pr->spisize; |
---|
670 | d->num_spi = htons(1); |
---|
671 | /* |
---|
672 | * XXX SPI bits are left-filled, for use with IPComp. |
---|
673 | * we should be switching to variable-length spi field... |
---|
674 | */ |
---|
675 | spi = (u_int8_t *)&pr->spi; |
---|
676 | spi += sizeof(pr->spi); |
---|
677 | spi -= pr->spisize; |
---|
678 | memcpy(d + 1, spi, pr->spisize); |
---|
679 | |
---|
680 | error = isakmp_info_send_common(iph1, payload, |
---|
681 | ISAKMP_NPTYPE_D, 0); |
---|
682 | vfree(payload); |
---|
683 | } |
---|
684 | |
---|
685 | return error; |
---|
686 | } |
---|
687 | |
---|
688 | /* |
---|
689 | * send Notification payload (for without ISAKMP SA) in Informational exchange |
---|
690 | */ |
---|
691 | int |
---|
692 | isakmp_info_send_nx(isakmp, remote, local, type, data) |
---|
693 | struct isakmp *isakmp; |
---|
694 | struct sockaddr *remote, *local; |
---|
695 | int type; |
---|
696 | vchar_t *data; |
---|
697 | { |
---|
698 | struct ph1handle *iph1 = NULL; |
---|
699 | vchar_t *payload = NULL; |
---|
700 | int tlen; |
---|
701 | int error = -1; |
---|
702 | struct isakmp_pl_n *n; |
---|
703 | int spisiz = 0; /* see below */ |
---|
704 | |
---|
705 | /* add new entry to isakmp status table. */ |
---|
706 | iph1 = newph1(); |
---|
707 | if (iph1 == NULL) |
---|
708 | return -1; |
---|
709 | |
---|
710 | memcpy(&iph1->index.i_ck, &isakmp->i_ck, sizeof(cookie_t)); |
---|
711 | isakmp_newcookie((char *)&iph1->index.r_ck, remote, local); |
---|
712 | iph1->status = PHASE1ST_START; |
---|
713 | iph1->side = INITIATOR; |
---|
714 | iph1->version = isakmp->v; |
---|
715 | iph1->flags = 0; |
---|
716 | iph1->msgid = 0; /* XXX */ |
---|
717 | #ifdef ENABLE_HYBRID |
---|
718 | if ((iph1->mode_cfg = isakmp_cfg_mkstate()) == NULL) |
---|
719 | goto end; |
---|
720 | #endif |
---|
721 | #ifdef ENABLE_FRAG |
---|
722 | iph1->frag = 0; |
---|
723 | iph1->frag_last_index = 0; |
---|
724 | iph1->frag_chain = NULL; |
---|
725 | #endif |
---|
726 | |
---|
727 | /* copy remote address */ |
---|
728 | if (copy_ph1addresses(iph1, NULL, remote, local) < 0) |
---|
729 | goto end; |
---|
730 | |
---|
731 | tlen = sizeof(*n) + spisiz; |
---|
732 | if (data) |
---|
733 | tlen += data->l; |
---|
734 | payload = vmalloc(tlen); |
---|
735 | if (payload == NULL) { |
---|
736 | plog(LLV_ERROR, LOCATION, NULL, |
---|
737 | "failed to get buffer to send.\n"); |
---|
738 | goto end; |
---|
739 | } |
---|
740 | |
---|
741 | n = (struct isakmp_pl_n *)payload->v; |
---|
742 | n->h.np = ISAKMP_NPTYPE_NONE; |
---|
743 | n->h.len = htons(tlen); |
---|
744 | n->doi = htonl(IPSEC_DOI); |
---|
745 | n->proto_id = IPSECDOI_KEY_IKE; |
---|
746 | n->spi_size = spisiz; |
---|
747 | n->type = htons(type); |
---|
748 | if (spisiz) |
---|
749 | memset(n + 1, 0, spisiz); /* XXX spisiz is always 0 */ |
---|
750 | if (data) |
---|
751 | memcpy((caddr_t)(n + 1) + spisiz, data->v, data->l); |
---|
752 | |
---|
753 | error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, 0); |
---|
754 | vfree(payload); |
---|
755 | |
---|
756 | end: |
---|
757 | if (iph1 != NULL) |
---|
758 | delph1(iph1); |
---|
759 | |
---|
760 | return error; |
---|
761 | } |
---|
762 | |
---|
763 | /* |
---|
764 | * send Notification payload (for ISAKMP SA) in Informational exchange |
---|
765 | */ |
---|
766 | int |
---|
767 | isakmp_info_send_n1(iph1, type, data) |
---|
768 | struct ph1handle *iph1; |
---|
769 | int type; |
---|
770 | vchar_t *data; |
---|
771 | { |
---|
772 | vchar_t *payload = NULL; |
---|
773 | int tlen; |
---|
774 | int error = 0; |
---|
775 | struct isakmp_pl_n *n; |
---|
776 | int spisiz; |
---|
777 | |
---|
778 | /* |
---|
779 | * note on SPI size: which description is correct? I have chosen |
---|
780 | * this to be 0. |
---|
781 | * |
---|
782 | * RFC2408 3.1, 2nd paragraph says: ISAKMP SA is identified by |
---|
783 | * Initiator/Responder cookie and SPI has no meaning, SPI size = 0. |
---|
784 | * RFC2408 3.1, first paragraph on page 40: ISAKMP SA is identified |
---|
785 | * by cookie and SPI has no meaning, 0 <= SPI size <= 16. |
---|
786 | * RFC2407 4.6.3.3, INITIAL-CONTACT is required to set to 16. |
---|
787 | */ |
---|
788 | if (type == ISAKMP_NTYPE_INITIAL_CONTACT) |
---|
789 | spisiz = sizeof(isakmp_index); |
---|
790 | else |
---|
791 | spisiz = 0; |
---|
792 | |
---|
793 | tlen = sizeof(*n) + spisiz; |
---|
794 | if (data) |
---|
795 | tlen += data->l; |
---|
796 | payload = vmalloc(tlen); |
---|
797 | if (payload == NULL) { |
---|
798 | plog(LLV_ERROR, LOCATION, NULL, |
---|
799 | "failed to get buffer to send.\n"); |
---|
800 | return errno; |
---|
801 | } |
---|
802 | |
---|
803 | n = (struct isakmp_pl_n *)payload->v; |
---|
804 | n->h.np = ISAKMP_NPTYPE_NONE; |
---|
805 | n->h.len = htons(tlen); |
---|
806 | n->doi = htonl(iph1->rmconf->doitype); |
---|
807 | n->proto_id = IPSECDOI_PROTO_ISAKMP; /* XXX to be configurable ? */ |
---|
808 | n->spi_size = spisiz; |
---|
809 | n->type = htons(type); |
---|
810 | if (spisiz) |
---|
811 | memcpy(n + 1, &iph1->index, sizeof(isakmp_index)); |
---|
812 | if (data) |
---|
813 | memcpy((caddr_t)(n + 1) + spisiz, data->v, data->l); |
---|
814 | |
---|
815 | error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, iph1->flags); |
---|
816 | vfree(payload); |
---|
817 | |
---|
818 | return error; |
---|
819 | } |
---|
820 | |
---|
821 | /* |
---|
822 | * send Notification payload (for IPsec SA) in Informational exchange |
---|
823 | */ |
---|
824 | int |
---|
825 | isakmp_info_send_n2(iph2, type, data) |
---|
826 | struct ph2handle *iph2; |
---|
827 | int type; |
---|
828 | vchar_t *data; |
---|
829 | { |
---|
830 | struct ph1handle *iph1 = iph2->ph1; |
---|
831 | vchar_t *payload = NULL; |
---|
832 | int tlen; |
---|
833 | int error = 0; |
---|
834 | struct isakmp_pl_n *n; |
---|
835 | struct saproto *pr; |
---|
836 | |
---|
837 | if (!iph2->approval) |
---|
838 | return EINVAL; |
---|
839 | |
---|
840 | pr = iph2->approval->head; |
---|
841 | |
---|
842 | /* XXX must be get proper spi */ |
---|
843 | tlen = sizeof(*n) + pr->spisize; |
---|
844 | if (data) |
---|
845 | tlen += data->l; |
---|
846 | payload = vmalloc(tlen); |
---|
847 | if (payload == NULL) { |
---|
848 | plog(LLV_ERROR, LOCATION, NULL, |
---|
849 | "failed to get buffer to send.\n"); |
---|
850 | return errno; |
---|
851 | } |
---|
852 | |
---|
853 | n = (struct isakmp_pl_n *)payload->v; |
---|
854 | n->h.np = ISAKMP_NPTYPE_NONE; |
---|
855 | n->h.len = htons(tlen); |
---|
856 | n->doi = htonl(IPSEC_DOI); /* IPSEC DOI (1) */ |
---|
857 | n->proto_id = pr->proto_id; /* IPSEC AH/ESP/whatever*/ |
---|
858 | n->spi_size = pr->spisize; |
---|
859 | n->type = htons(type); |
---|
860 | *(u_int32_t *)(n + 1) = pr->spi; |
---|
861 | if (data) |
---|
862 | memcpy((caddr_t)(n + 1) + pr->spisize, data->v, data->l); |
---|
863 | |
---|
864 | iph2->flags |= ISAKMP_FLAG_E; /* XXX Should we do FLAG_A ? */ |
---|
865 | error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, iph2->flags); |
---|
866 | vfree(payload); |
---|
867 | |
---|
868 | return error; |
---|
869 | } |
---|
870 | |
---|
871 | /* |
---|
872 | * send Information |
---|
873 | * When ph1->skeyid_a == NULL, send message without encoding. |
---|
874 | */ |
---|
875 | int |
---|
876 | isakmp_info_send_common(iph1, payload, np, flags) |
---|
877 | struct ph1handle *iph1; |
---|
878 | vchar_t *payload; |
---|
879 | u_int32_t np; |
---|
880 | int flags; |
---|
881 | { |
---|
882 | struct ph2handle *iph2 = NULL; |
---|
883 | vchar_t *hash = NULL; |
---|
884 | struct isakmp *isakmp; |
---|
885 | struct isakmp_gen *gen; |
---|
886 | char *p; |
---|
887 | int tlen; |
---|
888 | int error = -1; |
---|
889 | |
---|
890 | /* add new entry to isakmp status table */ |
---|
891 | iph2 = newph2(); |
---|
892 | if (iph2 == NULL) |
---|
893 | goto end; |
---|
894 | |
---|
895 | iph2->dst = dupsaddr(iph1->remote); |
---|
896 | if (iph2->dst == NULL) { |
---|
897 | delph2(iph2); |
---|
898 | goto end; |
---|
899 | } |
---|
900 | iph2->src = dupsaddr(iph1->local); |
---|
901 | if (iph2->src == NULL) { |
---|
902 | delph2(iph2); |
---|
903 | goto end; |
---|
904 | } |
---|
905 | iph2->side = INITIATOR; |
---|
906 | iph2->status = PHASE2ST_START; |
---|
907 | iph2->msgid = isakmp_newmsgid2(iph1); |
---|
908 | |
---|
909 | /* get IV and HASH(1) if skeyid_a was generated. */ |
---|
910 | if (iph1->skeyid_a != NULL) { |
---|
911 | iph2->ivm = oakley_newiv2(iph1, iph2->msgid); |
---|
912 | if (iph2->ivm == NULL) { |
---|
913 | delph2(iph2); |
---|
914 | goto end; |
---|
915 | } |
---|
916 | |
---|
917 | /* generate HASH(1) */ |
---|
918 | hash = oakley_compute_hash1(iph1, iph2->msgid, payload); |
---|
919 | if (hash == NULL) { |
---|
920 | delph2(iph2); |
---|
921 | goto end; |
---|
922 | } |
---|
923 | |
---|
924 | /* initialized total buffer length */ |
---|
925 | tlen = hash->l; |
---|
926 | tlen += sizeof(*gen); |
---|
927 | } else { |
---|
928 | /* IKE-SA is not established */ |
---|
929 | hash = NULL; |
---|
930 | |
---|
931 | /* initialized total buffer length */ |
---|
932 | tlen = 0; |
---|
933 | } |
---|
934 | if ((flags & ISAKMP_FLAG_A) == 0) |
---|
935 | iph2->flags = (hash == NULL ? 0 : ISAKMP_FLAG_E); |
---|
936 | else |
---|
937 | iph2->flags = (hash == NULL ? 0 : ISAKMP_FLAG_A); |
---|
938 | |
---|
939 | insph2(iph2); |
---|
940 | bindph12(iph1, iph2); |
---|
941 | |
---|
942 | tlen += sizeof(*isakmp) + payload->l; |
---|
943 | |
---|
944 | /* create buffer for isakmp payload */ |
---|
945 | iph2->sendbuf = vmalloc(tlen); |
---|
946 | if (iph2->sendbuf == NULL) { |
---|
947 | plog(LLV_ERROR, LOCATION, NULL, |
---|
948 | "failed to get buffer to send.\n"); |
---|
949 | goto err; |
---|
950 | } |
---|
951 | |
---|
952 | /* create isakmp header */ |
---|
953 | isakmp = (struct isakmp *)iph2->sendbuf->v; |
---|
954 | memcpy(&isakmp->i_ck, &iph1->index.i_ck, sizeof(cookie_t)); |
---|
955 | memcpy(&isakmp->r_ck, &iph1->index.r_ck, sizeof(cookie_t)); |
---|
956 | isakmp->np = hash == NULL ? (np & 0xff) : ISAKMP_NPTYPE_HASH; |
---|
957 | isakmp->v = iph1->version; |
---|
958 | isakmp->etype = ISAKMP_ETYPE_INFO; |
---|
959 | isakmp->flags = iph2->flags; |
---|
960 | memcpy(&isakmp->msgid, &iph2->msgid, sizeof(isakmp->msgid)); |
---|
961 | isakmp->len = htonl(tlen); |
---|
962 | p = (char *)(isakmp + 1); |
---|
963 | |
---|
964 | /* create HASH payload */ |
---|
965 | if (hash != NULL) { |
---|
966 | gen = (struct isakmp_gen *)p; |
---|
967 | gen->np = np & 0xff; |
---|
968 | gen->len = htons(sizeof(*gen) + hash->l); |
---|
969 | p += sizeof(*gen); |
---|
970 | memcpy(p, hash->v, hash->l); |
---|
971 | p += hash->l; |
---|
972 | } |
---|
973 | |
---|
974 | /* add payload */ |
---|
975 | memcpy(p, payload->v, payload->l); |
---|
976 | p += payload->l; |
---|
977 | |
---|
978 | #ifdef HAVE_PRINT_ISAKMP_C |
---|
979 | isakmp_printpacket(iph2->sendbuf, iph1->local, iph1->remote, 1); |
---|
980 | #endif |
---|
981 | |
---|
982 | /* encoding */ |
---|
983 | if (ISSET(isakmp->flags, ISAKMP_FLAG_E)) { |
---|
984 | vchar_t *tmp; |
---|
985 | |
---|
986 | tmp = oakley_do_encrypt(iph2->ph1, iph2->sendbuf, iph2->ivm->ive, |
---|
987 | iph2->ivm->iv); |
---|
988 | VPTRINIT(iph2->sendbuf); |
---|
989 | if (tmp == NULL) |
---|
990 | goto err; |
---|
991 | iph2->sendbuf = tmp; |
---|
992 | } |
---|
993 | |
---|
994 | /* HDR*, HASH(1), N */ |
---|
995 | if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0) { |
---|
996 | VPTRINIT(iph2->sendbuf); |
---|
997 | goto err; |
---|
998 | } |
---|
999 | |
---|
1000 | plog(LLV_DEBUG, LOCATION, NULL, |
---|
1001 | "sendto Information %s.\n", s_isakmp_nptype(np)); |
---|
1002 | |
---|
1003 | /* |
---|
1004 | * don't resend notify message because peer can use Acknowledged |
---|
1005 | * Informational if peer requires the reply of the notify message. |
---|
1006 | */ |
---|
1007 | |
---|
1008 | /* XXX If Acknowledged Informational required, don't delete ph2handle */ |
---|
1009 | error = 0; |
---|
1010 | VPTRINIT(iph2->sendbuf); |
---|
1011 | goto err; /* XXX */ |
---|
1012 | |
---|
1013 | end: |
---|
1014 | if (hash) |
---|
1015 | vfree(hash); |
---|
1016 | return error; |
---|
1017 | |
---|
1018 | err: |
---|
1019 | remph2(iph2); |
---|
1020 | delph2(iph2); |
---|
1021 | goto end; |
---|
1022 | } |
---|
1023 | |
---|
1024 | /* |
---|
1025 | * add a notify payload to buffer by reallocating buffer. |
---|
1026 | * If buf == NULL, the function only create a notify payload. |
---|
1027 | * |
---|
1028 | * XXX Which is SPI to be included, inbound or outbound ? |
---|
1029 | */ |
---|
1030 | vchar_t * |
---|
1031 | isakmp_add_pl_n(buf0, np_p, type, pr, data) |
---|
1032 | vchar_t *buf0; |
---|
1033 | u_int8_t **np_p; |
---|
1034 | int type; |
---|
1035 | struct saproto *pr; |
---|
1036 | vchar_t *data; |
---|
1037 | { |
---|
1038 | vchar_t *buf = NULL; |
---|
1039 | struct isakmp_pl_n *n; |
---|
1040 | int tlen; |
---|
1041 | int oldlen = 0; |
---|
1042 | |
---|
1043 | if (*np_p) |
---|
1044 | **np_p = ISAKMP_NPTYPE_N; |
---|
1045 | |
---|
1046 | tlen = sizeof(*n) + pr->spisize; |
---|
1047 | |
---|
1048 | if (data) |
---|
1049 | tlen += data->l; |
---|
1050 | if (buf0) { |
---|
1051 | oldlen = buf0->l; |
---|
1052 | buf = vrealloc(buf0, buf0->l + tlen); |
---|
1053 | } else |
---|
1054 | buf = vmalloc(tlen); |
---|
1055 | if (!buf) { |
---|
1056 | plog(LLV_ERROR, LOCATION, NULL, |
---|
1057 | "failed to get a payload buffer.\n"); |
---|
1058 | return NULL; |
---|
1059 | } |
---|
1060 | |
---|
1061 | n = (struct isakmp_pl_n *)(buf->v + oldlen); |
---|
1062 | n->h.np = ISAKMP_NPTYPE_NONE; |
---|
1063 | n->h.len = htons(tlen); |
---|
1064 | n->doi = htonl(IPSEC_DOI); /* IPSEC DOI (1) */ |
---|
1065 | n->proto_id = pr->proto_id; /* IPSEC AH/ESP/whatever*/ |
---|
1066 | n->spi_size = pr->spisize; |
---|
1067 | n->type = htons(type); |
---|
1068 | *(u_int32_t *)(n + 1) = pr->spi; /* XXX */ |
---|
1069 | if (data) |
---|
1070 | memcpy((caddr_t)(n + 1) + pr->spisize, data->v, data->l); |
---|
1071 | |
---|
1072 | /* save the pointer of next payload type */ |
---|
1073 | *np_p = &n->h.np; |
---|
1074 | |
---|
1075 | return buf; |
---|
1076 | } |
---|
1077 | |
---|
1078 | static void |
---|
1079 | purge_isakmp_spi(proto, spi, n) |
---|
1080 | int proto; |
---|
1081 | isakmp_index *spi; /*network byteorder*/ |
---|
1082 | size_t n; |
---|
1083 | { |
---|
1084 | struct ph1handle *iph1; |
---|
1085 | size_t i; |
---|
1086 | |
---|
1087 | for (i = 0; i < n; i++) { |
---|
1088 | iph1 = getph1byindex(&spi[i]); |
---|
1089 | if (!iph1) |
---|
1090 | continue; |
---|
1091 | |
---|
1092 | plog(LLV_INFO, LOCATION, NULL, |
---|
1093 | "purged ISAKMP-SA proto_id=%s spi=%s.\n", |
---|
1094 | s_ipsecdoi_proto(proto), |
---|
1095 | isakmp_pindex(&spi[i], 0)); |
---|
1096 | |
---|
1097 | iph1->status = PHASE1ST_EXPIRED; |
---|
1098 | isakmp_ph1delete(iph1); |
---|
1099 | } |
---|
1100 | } |
---|
1101 | |
---|
1102 | |
---|
1103 | |
---|
1104 | void |
---|
1105 | purge_ipsec_spi(dst0, proto, spi, n) |
---|
1106 | struct sockaddr *dst0; |
---|
1107 | int proto; |
---|
1108 | u_int32_t *spi; /*network byteorder*/ |
---|
1109 | size_t n; |
---|
1110 | { |
---|
1111 | vchar_t *buf = NULL; |
---|
1112 | struct sadb_msg *msg, *next, *end; |
---|
1113 | struct sadb_sa *sa; |
---|
1114 | struct sadb_lifetime *lt; |
---|
1115 | struct sockaddr *src, *dst; |
---|
1116 | struct ph2handle *iph2; |
---|
1117 | u_int64_t created; |
---|
1118 | size_t i; |
---|
1119 | caddr_t mhp[SADB_EXT_MAX + 1]; |
---|
1120 | unsigned num_purged = 0; |
---|
1121 | |
---|
1122 | plog(LLV_DEBUG2, LOCATION, NULL, |
---|
1123 | "purge_ipsec_spi:\n"); |
---|
1124 | plog(LLV_DEBUG2, LOCATION, NULL, "dst0: %s\n", saddr2str(dst0)); |
---|
1125 | plog(LLV_DEBUG2, LOCATION, NULL, "SPI: %08X\n", ntohl(spi[0])); |
---|
1126 | |
---|
1127 | buf = pfkey_dump_sadb(ipsecdoi2pfkey_proto(proto)); |
---|
1128 | if (buf == NULL) { |
---|
1129 | plog(LLV_DEBUG, LOCATION, NULL, |
---|
1130 | "pfkey_dump_sadb returned nothing.\n"); |
---|
1131 | return; |
---|
1132 | } |
---|
1133 | |
---|
1134 | msg = (struct sadb_msg *)buf->v; |
---|
1135 | end = (struct sadb_msg *)(buf->v + buf->l); |
---|
1136 | |
---|
1137 | while (msg < end) { |
---|
1138 | if ((msg->sadb_msg_len << 3) < sizeof(*msg)) |
---|
1139 | break; |
---|
1140 | next = (struct sadb_msg *)((caddr_t)msg + (msg->sadb_msg_len << 3)); |
---|
1141 | if (msg->sadb_msg_type != SADB_DUMP) { |
---|
1142 | msg = next; |
---|
1143 | continue; |
---|
1144 | } |
---|
1145 | |
---|
1146 | if (pfkey_align(msg, mhp) || pfkey_check(mhp)) { |
---|
1147 | plog(LLV_ERROR, LOCATION, NULL, |
---|
1148 | "pfkey_check (%s)\n", ipsec_strerror()); |
---|
1149 | msg = next; |
---|
1150 | continue; |
---|
1151 | } |
---|
1152 | |
---|
1153 | sa = (struct sadb_sa *)(mhp[SADB_EXT_SA]); |
---|
1154 | if (!sa |
---|
1155 | || !mhp[SADB_EXT_ADDRESS_SRC] |
---|
1156 | || !mhp[SADB_EXT_ADDRESS_DST]) { |
---|
1157 | msg = next; |
---|
1158 | continue; |
---|
1159 | } |
---|
1160 | pk_fixup_sa_addresses(mhp); |
---|
1161 | src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); |
---|
1162 | dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); |
---|
1163 | lt = (struct sadb_lifetime*)mhp[SADB_EXT_LIFETIME_HARD]; |
---|
1164 | if(lt != NULL) |
---|
1165 | created = lt->sadb_lifetime_addtime; |
---|
1166 | else |
---|
1167 | created = 0; |
---|
1168 | |
---|
1169 | if (sa->sadb_sa_state != SADB_SASTATE_MATURE |
---|
1170 | && sa->sadb_sa_state != SADB_SASTATE_DYING) { |
---|
1171 | msg = next; |
---|
1172 | continue; |
---|
1173 | } |
---|
1174 | |
---|
1175 | plog(LLV_DEBUG2, LOCATION, NULL, "src: %s\n", saddr2str(src)); |
---|
1176 | plog(LLV_DEBUG2, LOCATION, NULL, "dst: %s\n", saddr2str(dst)); |
---|
1177 | plog(LLV_DEBUG2, LOCATION, NULL, "spi: %u\n", ntohl(sa->sadb_sa_spi)); |
---|
1178 | |
---|
1179 | /* XXX n^2 algorithm, inefficient */ |
---|
1180 | |
---|
1181 | /* don't delete inbound SAs at the moment */ |
---|
1182 | /* XXX should we remove SAs with opposite direction as well? */ |
---|
1183 | if (cmpsaddr(dst0, dst) != CMPSADDR_MATCH) { |
---|
1184 | msg = next; |
---|
1185 | continue; |
---|
1186 | } |
---|
1187 | |
---|
1188 | for (i = 0; i < n; i++) { |
---|
1189 | plog(LLV_DEBUG, LOCATION, NULL, |
---|
1190 | "check spi(packet)=%u spi(db)=%u.\n", |
---|
1191 | ntohl(spi[i]), ntohl(sa->sadb_sa_spi)); |
---|
1192 | if (spi[i] != sa->sadb_sa_spi) |
---|
1193 | continue; |
---|
1194 | |
---|
1195 | pfkey_send_delete(lcconf->sock_pfkey, |
---|
1196 | msg->sadb_msg_satype, |
---|
1197 | IPSEC_MODE_ANY, |
---|
1198 | src, dst, sa->sadb_sa_spi); |
---|
1199 | |
---|
1200 | /* |
---|
1201 | * delete a relative phase 2 handler. |
---|
1202 | * continue to process if no relative phase 2 handler |
---|
1203 | * exists. |
---|
1204 | */ |
---|
1205 | iph2 = getph2bysaidx(src, dst, proto, spi[i]); |
---|
1206 | if(iph2 != NULL){ |
---|
1207 | delete_spd(iph2, created); |
---|
1208 | remph2(iph2); |
---|
1209 | delph2(iph2); |
---|
1210 | } |
---|
1211 | |
---|
1212 | plog(LLV_INFO, LOCATION, NULL, |
---|
1213 | "purged IPsec-SA proto_id=%s spi=%u.\n", |
---|
1214 | s_ipsecdoi_proto(proto), |
---|
1215 | ntohl(spi[i])); |
---|
1216 | num_purged++; |
---|
1217 | } |
---|
1218 | |
---|
1219 | msg = next; |
---|
1220 | } |
---|
1221 | |
---|
1222 | if (buf) |
---|
1223 | vfree(buf); |
---|
1224 | |
---|
1225 | plog(LLV_DEBUG, LOCATION, NULL, "purged %u SAs.\n", num_purged); |
---|
1226 | } |
---|
1227 | |
---|
1228 | /* |
---|
1229 | * delete all phase2 sa relatived to the destination address |
---|
1230 | * (except the phase2 within which the INITIAL-CONTACT was received). |
---|
1231 | * Don't delete Phase 1 handlers on INITIAL-CONTACT, and don't ignore |
---|
1232 | * an INITIAL-CONTACT if we have contacted the peer. This matches the |
---|
1233 | * Sun IKE behavior, and makes rekeying work much better when the peer |
---|
1234 | * restarts. |
---|
1235 | */ |
---|
1236 | int |
---|
1237 | isakmp_info_recv_initialcontact(iph1, protectedph2) |
---|
1238 | struct ph1handle *iph1; |
---|
1239 | struct ph2handle *protectedph2; |
---|
1240 | { |
---|
1241 | vchar_t *buf = NULL; |
---|
1242 | struct sadb_msg *msg, *next, *end; |
---|
1243 | struct sadb_sa *sa; |
---|
1244 | struct sockaddr *src, *dst; |
---|
1245 | caddr_t mhp[SADB_EXT_MAX + 1]; |
---|
1246 | int proto_id, i; |
---|
1247 | struct ph2handle *iph2; |
---|
1248 | #if 0 |
---|
1249 | char *loc, *rem; |
---|
1250 | #endif |
---|
1251 | |
---|
1252 | plog(LLV_INFO, LOCATION, iph1->remote, "received INITIAL-CONTACT\n"); |
---|
1253 | |
---|
1254 | if (f_local) |
---|
1255 | return 0; |
---|
1256 | |
---|
1257 | #if 0 |
---|
1258 | loc = racoon_strdup(saddrwop2str(iph1->local)); |
---|
1259 | rem = racoon_strdup(saddrwop2str(iph1->remote)); |
---|
1260 | STRDUP_FATAL(loc); |
---|
1261 | STRDUP_FATAL(rem); |
---|
1262 | |
---|
1263 | /* |
---|
1264 | * Purge all IPSEC-SAs for the peer. We can do this |
---|
1265 | * the easy way (using a PF_KEY SADB_DELETE extension) |
---|
1266 | * or we can do it the hard way. |
---|
1267 | */ |
---|
1268 | for (i = 0; i < pfkey_nsatypes; i++) { |
---|
1269 | proto_id = pfkey2ipsecdoi_proto(pfkey_satypes[i].ps_satype); |
---|
1270 | |
---|
1271 | plog(LLV_INFO, LOCATION, NULL, |
---|
1272 | "purging %s SAs for %s -> %s\n", |
---|
1273 | pfkey_satypes[i].ps_name, loc, rem); |
---|
1274 | if (pfkey_send_delete_all(lcconf->sock_pfkey, |
---|
1275 | pfkey_satypes[i].ps_satype, IPSEC_MODE_ANY, |
---|
1276 | iph1->local, iph1->remote) == -1) { |
---|
1277 | plog(LLV_ERROR, LOCATION, NULL, |
---|
1278 | "delete_all %s -> %s failed for %s (%s)\n", |
---|
1279 | loc, rem, |
---|
1280 | pfkey_satypes[i].ps_name, ipsec_strerror()); |
---|
1281 | goto the_hard_way; |
---|
1282 | } |
---|
1283 | |
---|
1284 | deleteallph2(iph1->local, iph1->remote, proto_id); |
---|
1285 | |
---|
1286 | plog(LLV_INFO, LOCATION, NULL, |
---|
1287 | "purging %s SAs for %s -> %s\n", |
---|
1288 | pfkey_satypes[i].ps_name, rem, loc); |
---|
1289 | if (pfkey_send_delete_all(lcconf->sock_pfkey, |
---|
1290 | pfkey_satypes[i].ps_satype, IPSEC_MODE_ANY, |
---|
1291 | iph1->remote, iph1->local) == -1) { |
---|
1292 | plog(LLV_ERROR, LOCATION, NULL, |
---|
1293 | "delete_all %s -> %s failed for %s (%s)\n", |
---|
1294 | rem, loc, |
---|
1295 | pfkey_satypes[i].ps_name, ipsec_strerror()); |
---|
1296 | goto the_hard_way; |
---|
1297 | } |
---|
1298 | |
---|
1299 | deleteallph2(iph1->remote, iph1->local, proto_id); |
---|
1300 | } |
---|
1301 | |
---|
1302 | racoon_free(loc); |
---|
1303 | racoon_free(rem); |
---|
1304 | return 0; |
---|
1305 | |
---|
1306 | the_hard_way: |
---|
1307 | racoon_free(loc); |
---|
1308 | racoon_free(rem); |
---|
1309 | #endif |
---|
1310 | |
---|
1311 | buf = pfkey_dump_sadb(SADB_SATYPE_UNSPEC); |
---|
1312 | if (buf == NULL) { |
---|
1313 | plog(LLV_DEBUG, LOCATION, NULL, |
---|
1314 | "pfkey_dump_sadb returned nothing.\n"); |
---|
1315 | return 0; |
---|
1316 | } |
---|
1317 | |
---|
1318 | msg = (struct sadb_msg *)buf->v; |
---|
1319 | end = (struct sadb_msg *)(buf->v + buf->l); |
---|
1320 | |
---|
1321 | for (; msg < end; msg = next) { |
---|
1322 | if ((msg->sadb_msg_len << 3) < sizeof(*msg)) |
---|
1323 | break; |
---|
1324 | |
---|
1325 | next = (struct sadb_msg *)((caddr_t)msg + (msg->sadb_msg_len << 3)); |
---|
1326 | if (msg->sadb_msg_type != SADB_DUMP) |
---|
1327 | continue; |
---|
1328 | |
---|
1329 | if (pfkey_align(msg, mhp) || pfkey_check(mhp)) { |
---|
1330 | plog(LLV_ERROR, LOCATION, NULL, |
---|
1331 | "pfkey_check (%s)\n", ipsec_strerror()); |
---|
1332 | continue; |
---|
1333 | } |
---|
1334 | |
---|
1335 | if (mhp[SADB_EXT_SA] == NULL |
---|
1336 | || mhp[SADB_EXT_ADDRESS_SRC] == NULL |
---|
1337 | || mhp[SADB_EXT_ADDRESS_DST] == NULL) |
---|
1338 | continue; |
---|
1339 | |
---|
1340 | sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; |
---|
1341 | pk_fixup_sa_addresses(mhp); |
---|
1342 | src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); |
---|
1343 | dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); |
---|
1344 | |
---|
1345 | if (sa->sadb_sa_state != SADB_SASTATE_MATURE |
---|
1346 | && sa->sadb_sa_state != SADB_SASTATE_DYING) |
---|
1347 | continue; |
---|
1348 | |
---|
1349 | /* |
---|
1350 | * RFC2407 4.6.3.3 INITIAL-CONTACT is the message that |
---|
1351 | * announces the sender of the message was rebooted. |
---|
1352 | * it is interpreted to delete all SAs which source address |
---|
1353 | * is the sender of the message. |
---|
1354 | * racoon only deletes SA which is matched both the |
---|
1355 | * source address and the destination accress. |
---|
1356 | */ |
---|
1357 | |
---|
1358 | /* |
---|
1359 | * Check that the IP and port match. But this is not optimal, |
---|
1360 | * since NAT-T can make the peer have multiple different |
---|
1361 | * ports. Correct thing to do is delete all entries with |
---|
1362 | * same identity. -TT |
---|
1363 | */ |
---|
1364 | if ((cmpsaddr(iph1->local, src) != CMPSADDR_MATCH || |
---|
1365 | cmpsaddr(iph1->remote, dst) != CMPSADDR_MATCH) && |
---|
1366 | (cmpsaddr(iph1->local, dst) != CMPSADDR_MATCH || |
---|
1367 | cmpsaddr(iph1->remote, src) != CMPSADDR_MATCH)) |
---|
1368 | continue; |
---|
1369 | |
---|
1370 | /* |
---|
1371 | * Make sure this is an SATYPE that we manage. |
---|
1372 | * This is gross; too bad we couldn't do it the |
---|
1373 | * easy way. |
---|
1374 | */ |
---|
1375 | for (i = 0; i < pfkey_nsatypes; i++) { |
---|
1376 | if (pfkey_satypes[i].ps_satype == |
---|
1377 | msg->sadb_msg_satype) |
---|
1378 | break; |
---|
1379 | } |
---|
1380 | if (i == pfkey_nsatypes) |
---|
1381 | continue; |
---|
1382 | |
---|
1383 | plog(LLV_INFO, LOCATION, NULL, |
---|
1384 | "purging spi=%u.\n", ntohl(sa->sadb_sa_spi)); |
---|
1385 | pfkey_send_delete(lcconf->sock_pfkey, |
---|
1386 | msg->sadb_msg_satype, |
---|
1387 | IPSEC_MODE_ANY, src, dst, sa->sadb_sa_spi); |
---|
1388 | |
---|
1389 | /* |
---|
1390 | * delete a relative phase 2 handler. |
---|
1391 | * continue to process if no relative phase 2 handler |
---|
1392 | * exists. |
---|
1393 | */ |
---|
1394 | proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype); |
---|
1395 | iph2 = getph2bysaidx(src, dst, proto_id, sa->sadb_sa_spi); |
---|
1396 | if (iph2 && iph2 != protectedph2) { |
---|
1397 | delete_spd(iph2, 0); |
---|
1398 | remph2(iph2); |
---|
1399 | delph2(iph2); |
---|
1400 | } |
---|
1401 | } |
---|
1402 | |
---|
1403 | vfree(buf); |
---|
1404 | return 0; |
---|
1405 | } |
---|
1406 | |
---|
1407 | |
---|
1408 | #ifdef ENABLE_DPD |
---|
1409 | static int |
---|
1410 | isakmp_info_recv_r_u (iph1, ru, msgid) |
---|
1411 | struct ph1handle *iph1; |
---|
1412 | struct isakmp_pl_ru *ru; |
---|
1413 | u_int32_t msgid; |
---|
1414 | { |
---|
1415 | struct isakmp_pl_ru *ru_ack; |
---|
1416 | vchar_t *payload = NULL; |
---|
1417 | int tlen; |
---|
1418 | int error = 0; |
---|
1419 | |
---|
1420 | plog(LLV_DEBUG, LOCATION, iph1->remote, |
---|
1421 | "DPD R-U-There received\n"); |
---|
1422 | |
---|
1423 | /* XXX should compare cookies with iph1->index? |
---|
1424 | Or is this already done by calling function? */ |
---|
1425 | tlen = sizeof(*ru_ack); |
---|
1426 | payload = vmalloc(tlen); |
---|
1427 | if (payload == NULL) { |
---|
1428 | plog(LLV_ERROR, LOCATION, NULL, |
---|
1429 | "failed to get buffer to send.\n"); |
---|
1430 | return errno; |
---|
1431 | } |
---|
1432 | |
---|
1433 | ru_ack = (struct isakmp_pl_ru *)payload->v; |
---|
1434 | ru_ack->h.np = ISAKMP_NPTYPE_NONE; |
---|
1435 | ru_ack->h.len = htons(tlen); |
---|
1436 | ru_ack->doi = htonl(IPSEC_DOI); |
---|
1437 | ru_ack->type = htons(ISAKMP_NTYPE_R_U_THERE_ACK); |
---|
1438 | ru_ack->proto_id = IPSECDOI_PROTO_ISAKMP; /* XXX ? */ |
---|
1439 | ru_ack->spi_size = sizeof(isakmp_index); |
---|
1440 | memcpy(ru_ack->i_ck, ru->i_ck, sizeof(cookie_t)); |
---|
1441 | memcpy(ru_ack->r_ck, ru->r_ck, sizeof(cookie_t)); |
---|
1442 | ru_ack->data = ru->data; |
---|
1443 | |
---|
1444 | /* XXX Should we do FLAG_A ? */ |
---|
1445 | error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, |
---|
1446 | ISAKMP_FLAG_E); |
---|
1447 | vfree(payload); |
---|
1448 | |
---|
1449 | plog(LLV_DEBUG, LOCATION, NULL, "received a valid R-U-THERE, ACK sent\n"); |
---|
1450 | |
---|
1451 | /* Should we mark tunnel as active ? */ |
---|
1452 | return error; |
---|
1453 | } |
---|
1454 | |
---|
1455 | static int |
---|
1456 | isakmp_info_recv_r_u_ack (iph1, ru, msgid) |
---|
1457 | struct ph1handle *iph1; |
---|
1458 | struct isakmp_pl_ru *ru; |
---|
1459 | u_int32_t msgid; |
---|
1460 | { |
---|
1461 | u_int32_t seq; |
---|
1462 | |
---|
1463 | plog(LLV_DEBUG, LOCATION, iph1->remote, |
---|
1464 | "DPD R-U-There-Ack received\n"); |
---|
1465 | |
---|
1466 | seq = ntohl(ru->data); |
---|
1467 | if (seq <= iph1->dpd_last_ack || seq > iph1->dpd_seq) { |
---|
1468 | plog(LLV_ERROR, LOCATION, iph1->remote, |
---|
1469 | "Wrong DPD sequence number (%d; last_ack=%d, seq=%d).\n", |
---|
1470 | seq, iph1->dpd_last_ack, iph1->dpd_seq); |
---|
1471 | return 0; |
---|
1472 | } |
---|
1473 | |
---|
1474 | /* accept cookies in original or reversed order */ |
---|
1475 | if ((memcmp(ru->i_ck, iph1->index.i_ck, sizeof(cookie_t)) || |
---|
1476 | memcmp(ru->r_ck, iph1->index.r_ck, sizeof(cookie_t))) && |
---|
1477 | (memcmp(ru->r_ck, iph1->index.i_ck, sizeof(cookie_t)) || |
---|
1478 | memcmp(ru->i_ck, iph1->index.r_ck, sizeof(cookie_t)))) { |
---|
1479 | plog(LLV_ERROR, LOCATION, iph1->remote, |
---|
1480 | "Cookie mismatch in DPD ACK!.\n"); |
---|
1481 | return 0; |
---|
1482 | } |
---|
1483 | |
---|
1484 | iph1->dpd_fails = 0; |
---|
1485 | iph1->dpd_last_ack = seq; |
---|
1486 | sched_cancel(&iph1->dpd_r_u); |
---|
1487 | isakmp_sched_r_u(iph1, 0); |
---|
1488 | |
---|
1489 | plog(LLV_DEBUG, LOCATION, iph1->remote, "received an R-U-THERE-ACK\n"); |
---|
1490 | |
---|
1491 | return 0; |
---|
1492 | } |
---|
1493 | |
---|
1494 | |
---|
1495 | |
---|
1496 | |
---|
1497 | /* |
---|
1498 | * send DPD R-U-THERE payload in Informational exchange. |
---|
1499 | */ |
---|
1500 | static void |
---|
1501 | isakmp_info_send_r_u(sc) |
---|
1502 | struct sched *sc; |
---|
1503 | { |
---|
1504 | struct ph1handle *iph1 = container_of(sc, struct ph1handle, dpd_r_u); |
---|
1505 | |
---|
1506 | /* create R-U-THERE payload */ |
---|
1507 | struct isakmp_pl_ru *ru; |
---|
1508 | vchar_t *payload = NULL; |
---|
1509 | int tlen; |
---|
1510 | int error = 0; |
---|
1511 | |
---|
1512 | plog(LLV_DEBUG, LOCATION, iph1->remote, "DPD monitoring....\n"); |
---|
1513 | |
---|
1514 | if (iph1->status == PHASE1ST_EXPIRED) { |
---|
1515 | /* This can happen after removing tunnels from the |
---|
1516 | * config file and then reloading. |
---|
1517 | * Such iph1 have rmconf=NULL, so return before the if |
---|
1518 | * block below. |
---|
1519 | */ |
---|
1520 | return; |
---|
1521 | } |
---|
1522 | |
---|
1523 | if (iph1->dpd_fails >= iph1->rmconf->dpd_maxfails) { |
---|
1524 | |
---|
1525 | plog(LLV_INFO, LOCATION, iph1->remote, |
---|
1526 | "DPD: remote (ISAKMP-SA spi=%s) seems to be dead.\n", |
---|
1527 | isakmp_pindex(&iph1->index, 0)); |
---|
1528 | |
---|
1529 | script_hook(iph1, SCRIPT_PHASE1_DEAD); |
---|
1530 | evt_phase1(iph1, EVT_PHASE1_DPD_TIMEOUT, NULL); |
---|
1531 | purge_remote(iph1); |
---|
1532 | |
---|
1533 | /* Do not reschedule here: phase1 is deleted, |
---|
1534 | * DPD will be reactivated when a new ph1 will be negociated |
---|
1535 | */ |
---|
1536 | return; |
---|
1537 | } |
---|
1538 | |
---|
1539 | /* TODO: check recent activity to avoid useless sends... */ |
---|
1540 | |
---|
1541 | tlen = sizeof(*ru); |
---|
1542 | payload = vmalloc(tlen); |
---|
1543 | if (payload == NULL) { |
---|
1544 | plog(LLV_ERROR, LOCATION, NULL, |
---|
1545 | "failed to get buffer for payload.\n"); |
---|
1546 | return; |
---|
1547 | } |
---|
1548 | ru = (struct isakmp_pl_ru *)payload->v; |
---|
1549 | ru->h.np = ISAKMP_NPTYPE_NONE; |
---|
1550 | ru->h.len = htons(tlen); |
---|
1551 | ru->doi = htonl(IPSEC_DOI); |
---|
1552 | ru->type = htons(ISAKMP_NTYPE_R_U_THERE); |
---|
1553 | ru->proto_id = IPSECDOI_PROTO_ISAKMP; /* XXX ?*/ |
---|
1554 | ru->spi_size = sizeof(isakmp_index); |
---|
1555 | |
---|
1556 | memcpy(ru->i_ck, iph1->index.i_ck, sizeof(cookie_t)); |
---|
1557 | memcpy(ru->r_ck, iph1->index.r_ck, sizeof(cookie_t)); |
---|
1558 | |
---|
1559 | if (iph1->dpd_seq == 0) { |
---|
1560 | /* generate a random seq which is not too big */ |
---|
1561 | iph1->dpd_seq = iph1->dpd_last_ack = rand() & 0x0fff; |
---|
1562 | } |
---|
1563 | |
---|
1564 | iph1->dpd_seq++; |
---|
1565 | iph1->dpd_fails++; |
---|
1566 | ru->data = htonl(iph1->dpd_seq); |
---|
1567 | |
---|
1568 | error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, 0); |
---|
1569 | vfree(payload); |
---|
1570 | |
---|
1571 | plog(LLV_DEBUG, LOCATION, iph1->remote, |
---|
1572 | "DPD R-U-There sent (%d)\n", error); |
---|
1573 | |
---|
1574 | /* Reschedule the r_u_there with a short delay, |
---|
1575 | * will be deleted/rescheduled if ACK received before */ |
---|
1576 | isakmp_sched_r_u(iph1, 1); |
---|
1577 | |
---|
1578 | plog(LLV_DEBUG, LOCATION, iph1->remote, |
---|
1579 | "rescheduling send_r_u (%d).\n", iph1->rmconf->dpd_retry); |
---|
1580 | } |
---|
1581 | |
---|
1582 | /* Schedule a new R-U-THERE */ |
---|
1583 | int |
---|
1584 | isakmp_sched_r_u(iph1, retry) |
---|
1585 | struct ph1handle *iph1; |
---|
1586 | int retry; |
---|
1587 | { |
---|
1588 | if(iph1 == NULL || |
---|
1589 | iph1->rmconf == NULL) |
---|
1590 | return 1; |
---|
1591 | |
---|
1592 | |
---|
1593 | if(iph1->dpd_support == 0 || |
---|
1594 | iph1->rmconf->dpd_interval == 0) |
---|
1595 | return 0; |
---|
1596 | |
---|
1597 | if(retry) |
---|
1598 | sched_schedule(&iph1->dpd_r_u, iph1->rmconf->dpd_retry, |
---|
1599 | isakmp_info_send_r_u); |
---|
1600 | else |
---|
1601 | sched_schedule(&iph1->dpd_r_u, iph1->rmconf->dpd_interval, |
---|
1602 | isakmp_info_send_r_u); |
---|
1603 | |
---|
1604 | return 0; |
---|
1605 | } |
---|
1606 | #endif |
---|