]>
Commit | Line | Data |
---|---|---|
d1e348cf A |
1 | /* $NetBSD: isakmp_inf.c,v 1.14.4.8 2007/08/01 11:52:20 vanhu Exp $ */ |
2 | ||
3 | /* Id: isakmp_inf.c,v 1.44 2006/05/06 20:45:52 manubsd Exp */ | |
52b7d2ce A |
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" | |
65c25746 | 35 | #include "racoon_types.h" |
52b7d2ce A |
36 | |
37 | #include <sys/types.h> | |
38 | #include <sys/param.h> | |
39 | #include <sys/socket.h> | |
40 | ||
65c25746 | 41 | #include <net/pfkeyv2.h> |
52b7d2ce A |
42 | #include <netinet/in.h> |
43 | #include <sys/queue.h> | |
44 | #ifndef HAVE_NETINET6_IPSEC | |
45 | #include <netinet/ipsec.h> | |
46 | #else | |
47 | #include <netinet6/ipsec.h> | |
48 | #endif | |
49 | ||
50 | #include <stdlib.h> | |
51 | #include <stdio.h> | |
52 | #include <string.h> | |
53 | #include <errno.h> | |
54 | #if TIME_WITH_SYS_TIME | |
55 | # include <sys/time.h> | |
56 | # include <time.h> | |
57 | #else | |
58 | # if HAVE_SYS_TIME_H | |
59 | # include <sys/time.h> | |
60 | # else | |
61 | # include <time.h> | |
62 | # endif | |
63 | #endif | |
64 | ||
65 | #include "libpfkey.h" | |
66 | ||
67 | #include "var.h" | |
68 | #include "vmbuf.h" | |
69 | #include "schedule.h" | |
70 | #include "str2val.h" | |
71 | #include "misc.h" | |
72 | #include "plog.h" | |
73 | #include "debug.h" | |
65c25746 A |
74 | #include "fsm.h" |
75 | #include "session.h" | |
76 | #include "ike_session.h" | |
52b7d2ce A |
77 | |
78 | #include "localconf.h" | |
79 | #include "remoteconf.h" | |
80 | #include "sockmisc.h" | |
d1e348cf A |
81 | #include "handler.h" |
82 | #include "policy.h" | |
83 | #include "proposal.h" | |
52b7d2ce | 84 | #include "isakmp_var.h" |
52b7d2ce A |
85 | #include "isakmp.h" |
86 | #ifdef ENABLE_HYBRID | |
87 | #include "isakmp_xauth.h" | |
d1e348cf | 88 | #include "isakmp_unity.h" |
52b7d2ce A |
89 | #include "isakmp_cfg.h" |
90 | #endif | |
91 | #include "isakmp_inf.h" | |
92 | #include "oakley.h" | |
52b7d2ce A |
93 | #include "ipsec_doi.h" |
94 | #include "crypto_openssl.h" | |
95 | #include "pfkey.h" | |
96 | #include "policy.h" | |
97 | #include "algorithm.h" | |
98 | #include "proposal.h" | |
52b7d2ce A |
99 | #include "strnames.h" |
100 | #ifdef ENABLE_NATT | |
101 | #include "nattraversal.h" | |
102 | #endif | |
103 | #include "vpn_control_var.h" | |
104 | #include "vpn_control.h" | |
d1e348cf A |
105 | #include "ike_session.h" |
106 | #include "ipsecSessionTracer.h" | |
107 | #include "ipsecMessageTracer.h" | |
52b7d2ce A |
108 | |
109 | /* information exchange */ | |
65c25746 A |
110 | static int isakmp_info_recv_n (phase1_handle_t *, struct isakmp_pl_n *, u_int32_t, int); |
111 | static int isakmp_info_recv_d (phase1_handle_t *, struct isakmp_pl_d *, u_int32_t, int); | |
52b7d2ce A |
112 | |
113 | #ifdef ENABLE_DPD | |
65c25746 A |
114 | static int isakmp_info_recv_r_u (phase1_handle_t *, struct isakmp_pl_ru *, u_int32_t); |
115 | static int isakmp_info_recv_r_u_ack (phase1_handle_t *, struct isakmp_pl_ru *, u_int32_t); | |
52b7d2ce A |
116 | #endif |
117 | ||
118 | #ifdef ENABLE_VPNCONTROL_PORT | |
65c25746 | 119 | static int isakmp_info_recv_lb (phase1_handle_t *, struct isakmp_pl_lb *lb, int); |
52b7d2ce A |
120 | #endif |
121 | ||
d1e348cf | 122 | static int |
65c25746 | 123 | isakmp_ph1_responder_lifetime (phase1_handle_t *iph1, struct isakmp_pl_resp_lifetime *notify) |
d1e348cf A |
124 | { |
125 | char *spi; | |
126 | ||
127 | if (ntohs(notify->h.len) < sizeof(*notify) + notify->spi_size) { | |
65c25746 | 128 | plog(ASL_LEVEL_ERR, |
d1e348cf A |
129 | "invalid spi_size in notification payload.\n"); |
130 | return -1; | |
131 | } | |
132 | spi = val2str((char *)(notify + 1), notify->spi_size); | |
133 | ||
7ebaebe2 | 134 | plog(ASL_LEVEL_NOTICE, |
d1e348cf A |
135 | "notification message ISAKMP-SA RESPONDER-LIFETIME, " |
136 | "doi=%d proto_id=%d spi=%s(size=%d).\n", | |
137 | ntohl(notify->doi), notify->proto_id, spi, notify->spi_size); | |
138 | ||
139 | /* TODO */ | |
140 | #if 0 | |
141 | struct isakmp_pl_attr *attrpl; | |
142 | int len = ntohs(notify->h.len) - (sizeof(*notify) + notify->spi_size); | |
143 | ||
144 | attrpl = (struct isakmp_pl_attr *)((char *)(notify + 1) + notify->spi_size); | |
145 | while (len > 0) { | |
146 | } | |
147 | #endif | |
148 | ||
149 | racoon_free(spi); | |
150 | return 0; | |
151 | } | |
152 | ||
153 | static int | |
65c25746 | 154 | isakmp_ph2_responder_lifetime (phase2_handle_t *iph2, struct isakmp_pl_resp_lifetime *notify) |
d1e348cf A |
155 | { |
156 | char *spi; | |
157 | ||
158 | if (ntohs(notify->h.len) < sizeof(*notify) + notify->spi_size) { | |
65c25746 | 159 | plog(ASL_LEVEL_ERR, |
d1e348cf A |
160 | "invalid spi_size in notification payload.\n"); |
161 | return -1; | |
162 | } | |
163 | spi = val2str((char *)(notify + 1), notify->spi_size); | |
164 | ||
7ebaebe2 | 165 | plog(ASL_LEVEL_NOTICE, |
d1e348cf A |
166 | "notification message IPSEC-SA RESPONDER-LIFETIME, " |
167 | "doi=%d proto_id=%d spi=%s(size=%d).\n", | |
168 | ntohl(notify->doi), notify->proto_id, spi, notify->spi_size); | |
169 | ||
170 | /* TODO */ | |
171 | ||
172 | racoon_free(spi); | |
173 | return 0; | |
174 | } | |
175 | ||
52b7d2ce A |
176 | /* \f%%% |
177 | * Information Exchange | |
178 | */ | |
179 | /* | |
180 | * receive Information | |
181 | */ | |
182 | int | |
65c25746 | 183 | isakmp_info_recv(phase1_handle_t *iph1, vchar_t *msg0) |
52b7d2ce A |
184 | { |
185 | vchar_t *msg = NULL; | |
d1e348cf A |
186 | vchar_t *pbuf = NULL; |
187 | u_int32_t msgid = 0; | |
52b7d2ce A |
188 | int error = -1; |
189 | struct isakmp *isakmp; | |
190 | struct isakmp_gen *gen; | |
85f41bec | 191 | struct isakmp_parse_t *pa; |
52b7d2ce A |
192 | void *p; |
193 | vchar_t *hash, *payload; | |
194 | struct isakmp_gen *nd; | |
195 | u_int8_t np; | |
196 | int encrypted; | |
e8d9021d | 197 | int flag = 0; |
d06a7ccb | 198 | int disconnect = 0; |
52b7d2ce | 199 | |
7ebaebe2 | 200 | plog(ASL_LEVEL_NOTICE, "receive Information.\n"); |
52b7d2ce A |
201 | |
202 | encrypted = ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E); | |
d1e348cf | 203 | msgid = ((struct isakmp *)msg0->v)->msgid; |
52b7d2ce A |
204 | |
205 | /* Use new IV to decrypt Informational message. */ | |
206 | if (encrypted) { | |
52b7d2ce A |
207 | struct isakmp_ivm *ivm; |
208 | ||
d1e348cf | 209 | if (iph1->ivm == NULL) { |
65c25746 | 210 | plog(ASL_LEVEL_ERR, "iph1->ivm == NULL\n"); |
d1e348cf A |
211 | IPSECSESSIONTRACEREVENT(iph1->parent_session, |
212 | IPSECSESSIONEVENTCODE_IKE_PACKET_RX_FAIL, | |
213 | CONSTSTR("Information message"), | |
214 | CONSTSTR("Failed to process Information Message (no IV)")); | |
215 | return -1; | |
216 | } | |
217 | ||
52b7d2ce A |
218 | /* compute IV */ |
219 | ivm = oakley_newiv2(iph1, ((struct isakmp *)msg0->v)->msgid); | |
d1e348cf | 220 | if (ivm == NULL) { |
65c25746 | 221 | plog(ASL_LEVEL_ERR, |
e8d9021d | 222 | "failed to compute IV\n"); |
d1e348cf A |
223 | IPSECSESSIONTRACEREVENT(iph1->parent_session, |
224 | IPSECSESSIONEVENTCODE_IKE_PACKET_RX_FAIL, | |
225 | CONSTSTR("Information message"), | |
226 | CONSTSTR("Failed to process Information Message (can't compute IV)")); | |
52b7d2ce | 227 | return -1; |
d1e348cf | 228 | } |
52b7d2ce A |
229 | |
230 | msg = oakley_do_decrypt(iph1, msg0, ivm->iv, ivm->ive); | |
231 | oakley_delivm(ivm); | |
d1e348cf | 232 | if (msg == NULL) { |
65c25746 | 233 | plog(ASL_LEVEL_ERR, |
e8d9021d | 234 | "failed to decrypt packet\n"); |
d1e348cf A |
235 | IPSECSESSIONTRACEREVENT(iph1->parent_session, |
236 | IPSECSESSIONEVENTCODE_IKE_PACKET_RX_FAIL, | |
237 | CONSTSTR("Information message"), | |
238 | CONSTSTR("Failed to decrypt Information message")); | |
52b7d2ce | 239 | return -1; |
d1e348cf | 240 | } |
52b7d2ce A |
241 | |
242 | } else | |
243 | msg = vdup(msg0); | |
244 | ||
245 | /* Safety check */ | |
246 | if (msg->l < sizeof(*isakmp) + sizeof(*gen)) { | |
65c25746 | 247 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
248 | "ignore information because the " |
249 | "message is way too short\n"); | |
250 | goto end; | |
251 | } | |
252 | ||
253 | isakmp = (struct isakmp *)msg->v; | |
254 | gen = (struct isakmp_gen *)((caddr_t)isakmp + sizeof(struct isakmp)); | |
255 | np = gen->np; | |
256 | ||
257 | if (encrypted) { | |
258 | if (isakmp->np != ISAKMP_NPTYPE_HASH) { | |
65c25746 | 259 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
260 | "ignore information because the " |
261 | "message has no hash payload.\n"); | |
262 | goto end; | |
263 | } | |
264 | ||
65c25746 | 265 | if (!FSM_STATE_IS_ESTABLISHED(iph1->status) && |
d1e348cf | 266 | (!iph1->approval || !iph1->skeyid_a)) { |
65c25746 | 267 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
268 | "ignore information because ISAKMP-SA " |
269 | "has not been established yet.\n"); | |
270 | goto end; | |
271 | } | |
272 | ||
273 | /* Safety check */ | |
274 | if (msg->l < sizeof(*isakmp) + ntohs(gen->len) + sizeof(*nd)) { | |
65c25746 | 275 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
276 | "ignore information because the " |
277 | "message is too short\n"); | |
278 | goto end; | |
279 | } | |
280 | ||
281 | p = (caddr_t) gen + sizeof(struct isakmp_gen); | |
282 | nd = (struct isakmp_gen *) ((caddr_t) gen + ntohs(gen->len)); | |
283 | ||
284 | /* nd length check */ | |
285 | if (ntohs(nd->len) > msg->l - (sizeof(struct isakmp) + | |
286 | ntohs(gen->len))) { | |
65c25746 | 287 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
288 | "too long payload length (broken message?)\n"); |
289 | goto end; | |
290 | } | |
291 | ||
292 | if (ntohs(nd->len) < sizeof(*nd)) { | |
65c25746 | 293 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
294 | "too short payload length (broken message?)\n"); |
295 | goto end; | |
296 | } | |
297 | ||
298 | payload = vmalloc(ntohs(nd->len)); | |
299 | if (payload == NULL) { | |
65c25746 | 300 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
301 | "cannot allocate memory\n"); |
302 | goto end; | |
303 | } | |
304 | ||
305 | memcpy(payload->v, (caddr_t) nd, ntohs(nd->len)); | |
306 | ||
307 | /* compute HASH */ | |
308 | hash = oakley_compute_hash1(iph1, isakmp->msgid, payload); | |
309 | if (hash == NULL) { | |
65c25746 | 310 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
311 | "cannot compute hash\n"); |
312 | ||
313 | vfree(payload); | |
314 | goto end; | |
315 | } | |
316 | ||
317 | if (ntohs(gen->len) - sizeof(struct isakmp_gen) != hash->l) { | |
65c25746 | 318 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
319 | "ignore information due to hash length mismatch\n"); |
320 | ||
321 | vfree(hash); | |
322 | vfree(payload); | |
323 | goto end; | |
324 | } | |
325 | ||
f255a978 | 326 | if (timingsafe_bcmp(p, hash->v, hash->l) != 0) { |
65c25746 | 327 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
328 | "ignore information due to hash mismatch\n"); |
329 | ||
330 | vfree(hash); | |
331 | vfree(payload); | |
332 | goto end; | |
333 | } | |
334 | ||
65c25746 | 335 | plog(ASL_LEVEL_DEBUG, "hash validated.\n"); |
52b7d2ce A |
336 | |
337 | vfree(hash); | |
338 | vfree(payload); | |
339 | } else { | |
65c25746 | 340 | /* make sure phase 1 was not yet at encrypted state */ |
52b7d2ce A |
341 | switch (iph1->etype) { |
342 | case ISAKMP_ETYPE_AGG: | |
65c25746 A |
343 | // %%%%% should also check for unity/mode cfg - last pkt is encrypted in such cases |
344 | if (!FSM_STATE_IS_ESTABLISHED(iph1->status) && | |
345 | ((iph1->side == INITIATOR && iph1->status == IKEV1_STATE_AGG_I_MSG3SENT) || | |
346 | (iph1->side == RESPONDER && iph1->status == IKEV1_STATE_AGG_R_MSG3RCVD))) { | |
347 | break; | |
348 | } | |
d06a7ccb | 349 | /*FALLTHRU*/ |
52b7d2ce | 350 | case ISAKMP_ETYPE_IDENT: |
65c25746 A |
351 | if (!FSM_STATE_IS_ESTABLISHED(iph1->status) && |
352 | ((iph1->side == INITIATOR && (iph1->status == IKEV1_STATE_IDENT_I_MSG5SENT | |
353 | || iph1->status == IKEV1_STATE_IDENT_I_MSG6RCVD)) || | |
354 | (iph1->side == RESPONDER && (iph1->status == IKEV1_STATE_IDENT_R_MSG5RCVD)))) { | |
52b7d2ce A |
355 | break; |
356 | } | |
357 | /*FALLTHRU*/ | |
358 | default: | |
d06a7ccb A |
359 | if ((np == ISAKMP_NPTYPE_NONE) && |
360 | !FSM_STATE_IS_ESTABLISHED(iph1->status) && | |
361 | (iph1->side == INITIATOR && (iph1->status == IKEV1_STATE_AGG_I_MSG1SENT))) { | |
362 | // proposal rejected by peer, terminate now. | |
363 | disconnect = 1; | |
364 | } | |
365 | ||
65c25746 | 366 | plog(ASL_LEVEL_ERR, |
d06a7ccb A |
367 | "%s message must be encrypted, status 0x%x, side %d\n", |
368 | s_isakmp_nptype(np), iph1->status, iph1->side); | |
d1e348cf | 369 | error = 0; |
52b7d2ce A |
370 | goto end; |
371 | } | |
372 | } | |
373 | ||
d1e348cf | 374 | if (!(pbuf = isakmp_parse(msg))) { |
65c25746 | 375 | plog(ASL_LEVEL_ERR, |
d1e348cf A |
376 | "failed to parse msg"); |
377 | error = -1; | |
378 | goto end; | |
379 | } | |
380 | ||
381 | error = 0; | |
85f41bec | 382 | for (pa = ALIGNED_CAST(struct isakmp_parse_t *)pbuf->v; pa->type; pa++) { // Wcast-align fix (void*) - aligned buffer of aligned (unpacked) structs |
d1e348cf A |
383 | switch (pa->type) { |
384 | case ISAKMP_NPTYPE_HASH: | |
385 | /* Handled above */ | |
386 | break; | |
387 | case ISAKMP_NPTYPE_N: | |
d06a7ccb A |
388 | if ((ntohs(((struct isakmp_pl_n *)pa->ptr)->type) == ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN) && |
389 | !FSM_STATE_IS_ESTABLISHED(iph1->status) && | |
390 | (iph1->side == INITIATOR && (iph1->status == IKEV1_STATE_AGG_I_MSG1SENT))) { | |
391 | // proposal rejected by peer, terminate now. | |
392 | disconnect = 1; | |
393 | plog(ASL_LEVEL_ERR, | |
394 | "%s message with %s notification receveid, status 0x%x, side %d\n", | |
395 | s_isakmp_nptype(np), s_isakmp_notify_msg(ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN), iph1->status, iph1->side); | |
396 | break; | |
397 | } | |
d1e348cf A |
398 | error = isakmp_info_recv_n(iph1, |
399 | (struct isakmp_pl_n *)pa->ptr, | |
400 | msgid, encrypted); | |
401 | break; | |
402 | case ISAKMP_NPTYPE_D: | |
403 | error = isakmp_info_recv_d(iph1, | |
404 | (struct isakmp_pl_d *)pa->ptr, | |
405 | msgid, encrypted); | |
406 | break; | |
407 | case ISAKMP_NPTYPE_NONCE: | |
408 | /* XXX to be 6.4.2 ike-01.txt */ | |
409 | /* XXX IV is to be synchronized. */ | |
65c25746 | 410 | plog(ASL_LEVEL_ERR, |
d1e348cf A |
411 | "ignore Acknowledged Informational\n"); |
412 | break; | |
413 | default: | |
414 | /* don't send information, see isakmp_ident_r1() */ | |
415 | error = 0; | |
65c25746 | 416 | plog(ASL_LEVEL_ERR, |
d1e348cf A |
417 | "reject the packet, " |
418 | "received unexpected payload type %s.\n", | |
419 | s_isakmp_nptype(gen->np)); | |
420 | } | |
421 | if(error < 0) { | |
422 | break; | |
423 | } else { | |
424 | flag |= error; | |
425 | } | |
426 | } | |
427 | IPSECSESSIONTRACEREVENT(iph1->parent_session, | |
428 | IPSECSESSIONEVENTCODE_IKE_PACKET_RX_SUCC, | |
429 | CONSTSTR("Information message"), | |
430 | CONSTSTR(NULL)); | |
431 | ||
432 | end: | |
433 | if (error) { | |
434 | IPSECSESSIONTRACEREVENT(iph1->parent_session, | |
435 | IPSECSESSIONEVENTCODE_IKE_PACKET_RX_FAIL, | |
436 | CONSTSTR("Information message"), | |
437 | CONSTSTR("Failed to process Information Message")); | |
438 | } | |
439 | if (msg != NULL) | |
440 | vfree(msg); | |
441 | if (pbuf != NULL) | |
442 | vfree(pbuf); | |
d06a7ccb A |
443 | if (disconnect) { |
444 | ike_session_t *session = NULL; | |
445 | ||
446 | if (session = iph1->parent_session) { | |
447 | gettimeofday(&session->stop_timestamp, NULL); | |
448 | if (!session->term_reason) { | |
449 | session->term_reason = ike_session_stopped_by_peer; | |
450 | } | |
451 | ike_session_purge_ph1s_by_session(session); | |
452 | } | |
453 | } | |
d1e348cf A |
454 | return error; |
455 | } | |
456 | ||
457 | /* | |
458 | * handling of Notification payload | |
459 | */ | |
460 | static int | |
65c25746 | 461 | isakmp_info_recv_n(phase1_handle_t *iph1, struct isakmp_pl_n *notify, u_int32_t msgid, int encrypted) |
d1e348cf A |
462 | { |
463 | u_int type; | |
d1e348cf A |
464 | vchar_t *ndata; |
465 | char *nraw; | |
466 | size_t l; | |
467 | char *spi; | |
468 | ||
469 | type = ntohs(notify->type); | |
470 | ||
471 | switch (type) { | |
472 | case ISAKMP_NTYPE_CONNECTED: | |
473 | case ISAKMP_NTYPE_REPLAY_STATUS: | |
474 | #ifdef ENABLE_HYBRID | |
475 | case ISAKMP_NTYPE_UNITY_HEARTBEAT: | |
476 | #endif | |
477 | /* do something */ | |
52b7d2ce | 478 | break; |
d1e348cf A |
479 | case ISAKMP_NTYPE_RESPONDER_LIFETIME: |
480 | if (encrypted) { | |
481 | return(isakmp_ph1_responder_lifetime(iph1, | |
482 | (struct isakmp_pl_resp_lifetime *)notify)); | |
483 | } | |
484 | break; | |
485 | case ISAKMP_NTYPE_INITIAL_CONTACT: | |
e8d9021d | 486 | if (encrypted) { |
d1e348cf A |
487 | info_recv_initialcontact(iph1); |
488 | return 0; | |
e8d9021d | 489 | } |
52b7d2ce | 490 | break; |
d1e348cf A |
491 | #ifdef ENABLE_DPD |
492 | case ISAKMP_NTYPE_R_U_THERE: | |
493 | if (encrypted) | |
494 | return isakmp_info_recv_r_u(iph1, | |
495 | (struct isakmp_pl_ru *)notify, msgid); | |
496 | break; | |
497 | case ISAKMP_NTYPE_R_U_THERE_ACK: | |
498 | if (encrypted) | |
499 | return isakmp_info_recv_r_u_ack(iph1, | |
500 | (struct isakmp_pl_ru *)notify, msgid); | |
52b7d2ce | 501 | break; |
d1e348cf A |
502 | #endif |
503 | #ifdef ENABLE_VPNCONTROL_PORT | |
504 | case ISAKMP_NTYPE_LOAD_BALANCE: | |
505 | isakmp_info_recv_lb(iph1, (struct isakmp_pl_lb *)notify, encrypted); | |
506 | break; | |
507 | #endif | |
508 | ||
52b7d2ce | 509 | default: |
d1e348cf A |
510 | { |
511 | /* XXX there is a potential of dos attack. */ | |
512 | if(type >= ISAKMP_NTYPE_MINERROR && | |
513 | type <= ISAKMP_NTYPE_MAXERROR) { | |
514 | if (msgid == 0) { | |
515 | /* don't think this realy deletes ph1 ? */ | |
65c25746 A |
516 | plog(ASL_LEVEL_ERR, |
517 | "Delete Phase 1 handle.\n"); | |
d1e348cf A |
518 | return -1; |
519 | } else { | |
65c25746 A |
520 | if (ike_session_getph2bymsgid(iph1, msgid) == NULL) { |
521 | plog(ASL_LEVEL_ERR, | |
522 | "Fatal %s notify messsage, " | |
523 | "Phase 1 should be deleted.\n", | |
d1e348cf A |
524 | s_isakmp_notify_msg(type)); |
525 | } else { | |
65c25746 A |
526 | plog(ASL_LEVEL_ERR, |
527 | "Fatal %s notify messsage, " | |
528 | "Phase 2 should be deleted.\n", | |
d1e348cf A |
529 | s_isakmp_notify_msg(type)); |
530 | } | |
531 | } | |
532 | } else { | |
65c25746 A |
533 | plog(ASL_LEVEL_ERR, |
534 | "Unhandled notify message %s, " | |
535 | "no Phase 2 handle found.\n", | |
d1e348cf A |
536 | s_isakmp_notify_msg(type)); |
537 | } | |
538 | } | |
539 | break; | |
540 | } | |
541 | ||
542 | /* get spi if specified and allocate */ | |
543 | if(notify->spi_size > 0) { | |
544 | if (ntohs(notify->h.len) < sizeof(*notify) + notify->spi_size) { | |
65c25746 A |
545 | plog(ASL_LEVEL_ERR, |
546 | "Invalid spi_size in notification payload.\n"); | |
d1e348cf A |
547 | return -1; |
548 | } | |
549 | spi = val2str((char *)(notify + 1), notify->spi_size); | |
550 | ||
7ebaebe2 | 551 | plog(ASL_LEVEL_NOTICE, |
65c25746 | 552 | "Notification message %d:%s, " |
d1e348cf A |
553 | "doi=%d proto_id=%d spi=%s(size=%d).\n", |
554 | type, s_isakmp_notify_msg(type), | |
555 | ntohl(notify->doi), notify->proto_id, spi, notify->spi_size); | |
556 | ||
557 | racoon_free(spi); | |
558 | } | |
559 | ||
560 | /* Send the message data to the logs */ | |
561 | if(type >= ISAKMP_NTYPE_MINERROR && | |
562 | type <= ISAKMP_NTYPE_MAXERROR) { | |
563 | l = ntohs(notify->h.len) - sizeof(*notify) - notify->spi_size; | |
564 | if (l > 0) { | |
565 | nraw = (char*)notify; | |
566 | nraw += sizeof(*notify) + notify->spi_size; | |
567 | if ((ndata = vmalloc(l)) != NULL) { | |
568 | memcpy(ndata->v, nraw, ndata->l); | |
65c25746 | 569 | plog(ASL_LEVEL_ERR, |
d1e348cf A |
570 | "Message: '%s'.\n", |
571 | binsanitize(ndata->v, ndata->l)); | |
572 | vfree(ndata); | |
573 | } else { | |
65c25746 | 574 | plog(ASL_LEVEL_ERR, |
d1e348cf A |
575 | "Cannot allocate memory\n"); |
576 | } | |
577 | } | |
578 | } | |
579 | return 0; | |
580 | } | |
581 | ||
e8d9021d | 582 | #ifdef ENABLE_VPNCONTROL_PORT |
65c25746 A |
583 | static void |
584 | isakmp_info_vpncontrol_notify_ike_failed (phase1_handle_t *iph1, int isakmp_info_initiator, int type, vchar_t *data) | |
e8d9021d | 585 | { |
d06a7ccb | 586 | u_int32_t address = iph1_get_remote_v4_address(iph1); |
e8d9021d A |
587 | u_int32_t fail_reason; |
588 | ||
589 | /* notify the API that we have received the delete */ | |
d06a7ccb | 590 | |
e8d9021d A |
591 | if (isakmp_info_initiator == FROM_REMOTE) { |
592 | int premature = oakley_find_status_in_certchain(iph1->cert, CERT_STATUS_PREMATURE); | |
593 | int expired = oakley_find_status_in_certchain(iph1->cert, CERT_STATUS_EXPIRED); | |
594 | ||
595 | if (premature) { | |
596 | fail_reason = VPNCTL_NTYPE_LOCAL_CERT_PREMATURE; | |
65c25746 | 597 | plog(ASL_LEVEL_NOTICE, ">>> Server reports client's certificate is pre-mature\n"); |
e8d9021d A |
598 | } else if (expired) { |
599 | fail_reason = VPNCTL_NTYPE_LOCAL_CERT_EXPIRED; | |
65c25746 | 600 | plog(ASL_LEVEL_NOTICE, ">>> Server reports client's certificate is expired\n"); |
e8d9021d A |
601 | } else { |
602 | fail_reason = type; | |
603 | } | |
604 | vpncontrol_notify_ike_failed(fail_reason, isakmp_info_initiator, address, 0, NULL); | |
605 | return; | |
606 | } else { | |
607 | /* FROM_LOCAL */ | |
608 | if (type == ISAKMP_INTERNAL_ERROR || | |
609 | type <= ISAKMP_NTYPE_UNEQUAL_PAYLOAD_LENGTHS) { | |
610 | int premature = oakley_find_status_in_certchain(iph1->cert_p, CERT_STATUS_PREMATURE); | |
611 | int expired = oakley_find_status_in_certchain(iph1->cert_p, CERT_STATUS_EXPIRED); | |
612 | int subjname = oakley_find_status_in_certchain(iph1->cert_p, CERT_STATUS_INVALID_SUBJNAME); | |
613 | int subjaltname = oakley_find_status_in_certchain(iph1->cert_p, CERT_STATUS_INVALID_SUBJALTNAME); | |
614 | ||
615 | if (premature) { | |
616 | fail_reason = VPNCTL_NTYPE_PEER_CERT_PREMATURE; | |
65c25746 | 617 | plog(ASL_LEVEL_NOTICE, ">>> Server's certificate is pre-mature\n"); |
e8d9021d A |
618 | } else if (expired) { |
619 | fail_reason = VPNCTL_NTYPE_PEER_CERT_EXPIRED; | |
65c25746 | 620 | plog(ASL_LEVEL_NOTICE, ">>> Server's certificate is expired\n"); |
e8d9021d A |
621 | } else if (subjname) { |
622 | fail_reason = VPNCTL_NTYPE_PEER_CERT_INVALID_SUBJNAME; | |
65c25746 | 623 | plog(ASL_LEVEL_NOTICE, ">>> Server's certificate subject name not valid\n"); |
e8d9021d A |
624 | } else if (subjaltname) { |
625 | fail_reason = VPNCTL_NTYPE_PEER_CERT_INVALID_SUBJALTNAME; | |
65c25746 | 626 | plog(ASL_LEVEL_NOTICE, ">>> Server's certificate subject alternate name not valid\n"); |
e8d9021d A |
627 | } else { |
628 | fail_reason = type; | |
629 | } | |
630 | (void)vpncontrol_notify_ike_failed(fail_reason, isakmp_info_initiator, address, | |
631 | (data ? data->l : 0), (u_int8_t *)(data ? data->v : NULL)); | |
632 | return; | |
633 | } | |
634 | } | |
635 | } | |
636 | #endif /* ENABLE_VPNCONTROL_PORT */ | |
637 | ||
d1e348cf A |
638 | /* |
639 | * handling of Deletion payload | |
640 | */ | |
641 | static int | |
65c25746 | 642 | isakmp_info_recv_d(phase1_handle_t *iph1, struct isakmp_pl_d *delete, u_int32_t msgid, int encrypted) |
d1e348cf A |
643 | { |
644 | int tlen, num_spi; | |
65c25746 | 645 | phase1_handle_t *del_ph1; |
d1e348cf A |
646 | union { |
647 | u_int32_t spi32; | |
648 | u_int16_t spi16[2]; | |
649 | } spi; | |
650 | ||
651 | if (ntohl(delete->doi) != IPSEC_DOI) { | |
65c25746 | 652 | plog(ASL_LEVEL_ERR, |
d1e348cf A |
653 | "delete payload with invalid doi:%d.\n", |
654 | ntohl(delete->doi)); | |
655 | #ifdef ENABLE_HYBRID | |
656 | /* | |
657 | * At deconnexion time, Cisco VPN client does this | |
658 | * with a zero DOI. Don't give up in that situation. | |
659 | */ | |
660 | if (((iph1->mode_cfg->flags & | |
661 | ISAKMP_CFG_VENDORID_UNITY) == 0) || (delete->doi != 0)) | |
662 | return 0; | |
663 | #else | |
664 | return 0; | |
665 | #endif | |
666 | } | |
667 | ||
668 | num_spi = ntohs(delete->num_spi); | |
669 | tlen = ntohs(delete->h.len) - sizeof(struct isakmp_pl_d); | |
670 | ||
671 | if (tlen != num_spi * delete->spi_size) { | |
65c25746 | 672 | plog(ASL_LEVEL_ERR, |
d1e348cf A |
673 | "deletion payload with invalid length.\n"); |
674 | return 0; | |
675 | } | |
676 | ||
7ebaebe2 | 677 | plog(ASL_LEVEL_NOTICE, |
d1e348cf A |
678 | "delete payload for protocol %s\n", |
679 | s_ipsecdoi_proto(delete->proto_id)); | |
680 | ||
681 | if(!iph1->rmconf->weak_phase1_check && !encrypted) { | |
65c25746 | 682 | plog(ASL_LEVEL_WARNING, |
d1e348cf A |
683 | "Ignoring unencrypted delete payload " |
684 | "(check the weak_phase1_check option)\n"); | |
685 | return 0; | |
686 | } | |
687 | ||
688 | switch (delete->proto_id) { | |
689 | case IPSECDOI_PROTO_ISAKMP: | |
690 | if (delete->spi_size != sizeof(isakmp_index)) { | |
65c25746 | 691 | plog(ASL_LEVEL_ERR, |
d1e348cf A |
692 | "delete payload with strange spi " |
693 | "size %d(proto_id:%d)\n", | |
694 | delete->spi_size, delete->proto_id); | |
695 | return 0; | |
696 | } | |
697 | ||
65c25746 | 698 | del_ph1 = ike_session_getph1byindex(iph1->parent_session, (isakmp_index *)(delete + 1)); |
d1e348cf A |
699 | if(del_ph1 != NULL){ |
700 | ||
701 | // hack: start a rekey now, if one was pending (only for client). | |
702 | if (del_ph1->sce_rekey && | |
703 | del_ph1->parent_session && | |
704 | del_ph1->parent_session->is_client && | |
d9c572c0 A |
705 | del_ph1->parent_session->established && |
706 | !(del_ph1->rmconf->natt_multiple_user && | |
707 | del_ph1->parent_session->is_l2tpvpn_ipsec)) { | |
fce29cd9 | 708 | isakmp_ph1rekeyexpire(del_ph1, FALSE); |
d1e348cf A |
709 | } |
710 | ||
d1e348cf A |
711 | if (del_ph1->scr) |
712 | SCHED_KILL(del_ph1->scr); | |
713 | ||
714 | /* | |
715 | * Do not delete IPsec SAs when receiving an IKE delete notification. | |
716 | * Just delete the IKE SA. | |
717 | */ | |
718 | #ifdef ENABLE_VPNCONTROL_PORT | |
e8d9021d | 719 | if (del_ph1->started_by_api || (del_ph1->is_rekey && del_ph1->parent_session && del_ph1->parent_session->is_client)) { |
65c25746 | 720 | if (ike_session_islast_ph1(del_ph1)) { |
e8d9021d | 721 | isakmp_info_vpncontrol_notify_ike_failed(del_ph1, FROM_REMOTE, VPNCTL_NTYPE_PH1_DELETE, NULL); |
d1e348cf | 722 | } |
e8d9021d | 723 | } |
d1e348cf | 724 | #endif |
1760d65d A |
725 | if (del_ph1->rmconf->natt_multiple_user && |
726 | del_ph1->parent_session->is_l2tpvpn_ipsec) { | |
7ebaebe2 | 727 | plog(ASL_LEVEL_NOTICE, "Ignoring IKE delete from peer for L2TP server\n"); |
1760d65d A |
728 | break; |
729 | } | |
d1e348cf A |
730 | isakmp_ph1expire(del_ph1); |
731 | } | |
732 | break; | |
733 | ||
734 | case IPSECDOI_PROTO_IPSEC_AH: | |
735 | case IPSECDOI_PROTO_IPSEC_ESP: | |
736 | if (delete->spi_size != sizeof(u_int32_t)) { | |
65c25746 | 737 | plog(ASL_LEVEL_ERR, |
d1e348cf A |
738 | "delete payload with strange spi " |
739 | "size %d(proto_id:%d)\n", | |
740 | delete->spi_size, delete->proto_id); | |
741 | return 0; | |
742 | } | |
1760d65d A |
743 | if (iph1->rmconf->natt_multiple_user && |
744 | iph1->parent_session->is_l2tpvpn_ipsec) { | |
d9c572c0 A |
745 | uint32_t *ph2_spi = ALIGNED_CAST(u_int32_t *)(delete + 1); |
746 | phase2_handle_t *iph2 = ike_session_getph2bysaidx(iph1->local, iph1->remote, delete->proto_id, ph2_spi[0]); | |
747 | ||
748 | if (iph2 != NULL) { | |
749 | iph2->is_defunct = 1; | |
7ebaebe2 | 750 | plog(ASL_LEVEL_NOTICE, "Ignoring SA delete from peer for L2TP server\n"); |
d9c572c0 A |
751 | break; |
752 | } | |
1760d65d | 753 | } |
d1e348cf | 754 | purge_ipsec_spi(iph1->remote, delete->proto_id, |
65c25746 | 755 | ALIGNED_CAST(u_int32_t *)(delete + 1), num_spi, NULL, NULL); // Wcast-align fix (void*) - delete payload is aligned |
52b7d2ce | 756 | break; |
d1e348cf A |
757 | |
758 | case IPSECDOI_PROTO_IPCOMP: | |
759 | /* need to handle both 16bit/32bit SPI */ | |
760 | memset(&spi, 0, sizeof(spi)); | |
761 | if (delete->spi_size == sizeof(spi.spi16[1])) { | |
762 | memcpy(&spi.spi16[1], delete + 1, | |
763 | sizeof(spi.spi16[1])); | |
764 | } else if (delete->spi_size == sizeof(spi.spi32)) | |
765 | memcpy(&spi.spi32, delete + 1, sizeof(spi.spi32)); | |
766 | else { | |
65c25746 | 767 | plog(ASL_LEVEL_ERR, |
d1e348cf A |
768 | "delete payload with strange spi " |
769 | "size %d(proto_id:%d)\n", | |
770 | delete->spi_size, delete->proto_id); | |
771 | return 0; | |
772 | } | |
773 | purge_ipsec_spi(iph1->remote, delete->proto_id, | |
65c25746 | 774 | &spi.spi32, num_spi, NULL, NULL); |
d1e348cf A |
775 | break; |
776 | ||
777 | default: | |
65c25746 | 778 | plog(ASL_LEVEL_ERR, |
d1e348cf A |
779 | "deletion message received, " |
780 | "invalid proto_id: %d\n", | |
781 | delete->proto_id); | |
782 | return 0; | |
52b7d2ce A |
783 | } |
784 | ||
7ebaebe2 | 785 | plog(ASL_LEVEL_NOTICE, "purged SAs.\n"); |
52b7d2ce A |
786 | |
787 | return 0; | |
788 | } | |
789 | ||
790 | /* | |
791 | * send Delete payload (for ISAKMP SA) in Informational exchange. | |
792 | */ | |
793 | int | |
65c25746 | 794 | isakmp_info_send_d1(phase1_handle_t *iph1) |
52b7d2ce A |
795 | { |
796 | struct isakmp_pl_d *d; | |
797 | vchar_t *payload = NULL; | |
798 | int tlen; | |
799 | int error = 0; | |
800 | ||
65c25746 | 801 | if (!FSM_STATE_IS_ESTABLISHED(iph1->status)) |
52b7d2ce A |
802 | return 0; |
803 | ||
804 | /* create delete payload */ | |
805 | ||
806 | /* send SPIs of inbound SAs. */ | |
807 | /* XXX should send outbound SAs's ? */ | |
808 | tlen = sizeof(*d) + sizeof(isakmp_index); | |
809 | payload = vmalloc(tlen); | |
810 | if (payload == NULL) { | |
65c25746 | 811 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
812 | "failed to get buffer for payload.\n"); |
813 | return errno; | |
814 | } | |
815 | ||
816 | d = (struct isakmp_pl_d *)payload->v; | |
817 | d->h.np = ISAKMP_NPTYPE_NONE; | |
818 | d->h.len = htons(tlen); | |
819 | d->doi = htonl(IPSEC_DOI); | |
820 | d->proto_id = IPSECDOI_PROTO_ISAKMP; | |
821 | d->spi_size = sizeof(isakmp_index); | |
822 | d->num_spi = htons(1); | |
823 | memcpy(d + 1, &iph1->index, sizeof(isakmp_index)); | |
824 | ||
825 | error = isakmp_info_send_common(iph1, payload, | |
826 | ISAKMP_NPTYPE_D, 0); | |
827 | vfree(payload); | |
d1e348cf A |
828 | if (error) { |
829 | IPSECSESSIONTRACEREVENT(iph1->parent_session, | |
830 | IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_TX_FAIL, | |
831 | CONSTSTR("Delete ISAKMP-SA"), | |
832 | CONSTSTR("Failed to transmit Delete-ISAKMP-SA message")); | |
833 | } else { | |
834 | IPSECSESSIONTRACEREVENT(iph1->parent_session, | |
835 | IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_TX_SUCC, | |
836 | CONSTSTR("Delete ISAKMP-SA"), | |
837 | CONSTSTR(NULL)); | |
838 | } | |
52b7d2ce A |
839 | |
840 | return error; | |
841 | } | |
842 | ||
843 | /* | |
844 | * send Delete payload (for IPsec SA) in Informational exchange, based on | |
845 | * pfkey msg. It sends always single SPI. | |
846 | */ | |
847 | int | |
65c25746 | 848 | isakmp_info_send_d2(phase2_handle_t *iph2) |
52b7d2ce | 849 | { |
65c25746 | 850 | phase1_handle_t *iph1; |
52b7d2ce A |
851 | struct saproto *pr; |
852 | struct isakmp_pl_d *d; | |
853 | vchar_t *payload = NULL; | |
854 | int tlen; | |
855 | int error = 0; | |
856 | u_int8_t *spi; | |
857 | ||
65c25746 | 858 | if (!FSM_STATE_IS_ESTABLISHED(iph2->status)) |
52b7d2ce | 859 | return 0; |
d9c572c0 | 860 | |
52b7d2ce A |
861 | /* |
862 | * don't send delete information if there is no phase 1 handler. | |
863 | * It's nonsensical to negotiate phase 1 to send the information. | |
864 | */ | |
d1e348cf A |
865 | iph1 = ike_session_get_established_ph1(iph2->parent_session); |
866 | if (!iph1) { | |
65c25746 | 867 | iph1 = ike_session_getph1byaddr(iph2->parent_session, iph2->src, iph2->dst); |
d1e348cf A |
868 | } |
869 | if (iph1 == NULL){ | |
870 | IPSECSESSIONTRACEREVENT(iph2->parent_session, | |
871 | IPSECSESSIONEVENTCODE_IKE_PACKET_TX_FAIL, | |
872 | CONSTSTR("Information message"), | |
873 | CONSTSTR("Failed to transmit Information message")); | |
874 | IPSECSESSIONTRACEREVENT(iph2->parent_session, | |
875 | IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_TX_FAIL, | |
876 | CONSTSTR("Delete IPSEC-SA"), | |
877 | CONSTSTR("Failed to transmit Delete-IPSEC-SA message")); | |
7ebaebe2 | 878 | plog(ASL_LEVEL_NOTICE, |
d1e348cf | 879 | "No ph1 handler found, could not send DELETE_SA\n"); |
52b7d2ce | 880 | return 0; |
d1e348cf | 881 | } |
52b7d2ce A |
882 | |
883 | /* create delete payload */ | |
884 | for (pr = iph2->approval->head; pr != NULL; pr = pr->next) { | |
885 | ||
886 | /* send SPIs of inbound SAs. */ | |
887 | /* | |
888 | * XXX should I send outbound SAs's ? | |
889 | * I send inbound SAs's SPI only at the moment because I can't | |
890 | * decode any more if peer send encoded packet without aware of | |
891 | * deletion of SA. Outbound SAs don't come under the situation. | |
892 | */ | |
893 | tlen = sizeof(*d) + pr->spisize; | |
894 | payload = vmalloc(tlen); | |
895 | if (payload == NULL) { | |
d1e348cf A |
896 | IPSECSESSIONTRACEREVENT(iph2->parent_session, |
897 | IPSECSESSIONEVENTCODE_IKE_PACKET_TX_FAIL, | |
898 | CONSTSTR("Information message"), | |
899 | CONSTSTR("Failed to transmit Information message")); | |
900 | IPSECSESSIONTRACEREVENT(iph2->parent_session, | |
901 | IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_TX_FAIL, | |
902 | CONSTSTR("Delete IPSEC-SA"), | |
903 | CONSTSTR("Failed to transmit Delete-IPSEC-SA message")); | |
65c25746 | 904 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
905 | "failed to get buffer for payload.\n"); |
906 | return errno; | |
907 | } | |
908 | ||
909 | d = (struct isakmp_pl_d *)payload->v; | |
910 | d->h.np = ISAKMP_NPTYPE_NONE; | |
911 | d->h.len = htons(tlen); | |
912 | d->doi = htonl(IPSEC_DOI); | |
913 | d->proto_id = pr->proto_id; | |
914 | d->spi_size = pr->spisize; | |
915 | d->num_spi = htons(1); | |
916 | /* | |
917 | * XXX SPI bits are left-filled, for use with IPComp. | |
918 | * we should be switching to variable-length spi field... | |
919 | */ | |
920 | spi = (u_int8_t *)&pr->spi; | |
921 | spi += sizeof(pr->spi); | |
922 | spi -= pr->spisize; | |
923 | memcpy(d + 1, spi, pr->spisize); | |
924 | ||
925 | error = isakmp_info_send_common(iph1, payload, | |
926 | ISAKMP_NPTYPE_D, 0); | |
927 | vfree(payload); | |
d1e348cf A |
928 | if (error) { |
929 | IPSECSESSIONTRACEREVENT(iph2->parent_session, | |
930 | IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_TX_FAIL, | |
931 | CONSTSTR("Delete IPSEC-SA"), | |
932 | CONSTSTR("Failed to transmit Delete-IPSEC-SA")); | |
933 | } else { | |
934 | IPSECSESSIONTRACEREVENT(iph2->parent_session, | |
935 | IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_TX_SUCC, | |
936 | CONSTSTR("Delete IPSEC-SA"), | |
937 | CONSTSTR(NULL)); | |
938 | } | |
52b7d2ce A |
939 | } |
940 | ||
941 | return error; | |
942 | } | |
943 | ||
944 | /* | |
65c25746 | 945 | * send Notification payload (without ISAKMP SA) in an Informational exchange |
52b7d2ce A |
946 | */ |
947 | int | |
65c25746 A |
948 | isakmp_info_send_nx(struct isakmp *isakmp, struct sockaddr_storage *remote, struct sockaddr_storage *local, |
949 | int type, vchar_t *data) | |
52b7d2ce | 950 | { |
65c25746 | 951 | phase1_handle_t *iph1 = NULL; |
52b7d2ce A |
952 | struct remoteconf *rmconf; |
953 | vchar_t *payload = NULL; | |
954 | int tlen; | |
955 | int error = -1; | |
956 | struct isakmp_pl_n *n; | |
957 | int spisiz = 0; /* see below */ | |
1760d65d | 958 | ike_session_t *sess = ike_session_get_session(local, remote, FALSE, NULL); |
52b7d2ce A |
959 | |
960 | /* search appropreate configuration */ | |
961 | rmconf = getrmconf(remote); | |
962 | if (rmconf == NULL) { | |
d1e348cf A |
963 | IPSECSESSIONTRACEREVENT(sess, |
964 | IPSECSESSIONEVENTCODE_IKE_PACKET_TX_FAIL, | |
965 | CONSTSTR("Information message"), | |
966 | CONSTSTR("Failed to transmit Information message (no remote configuration)")); | |
65c25746 | 967 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
968 | "no configuration found for peer address.\n"); |
969 | goto end; | |
970 | } | |
971 | ||
972 | /* add new entry to isakmp status table. */ | |
65c25746 | 973 | iph1 = ike_session_newph1(ISAKMP_VERSION_NUMBER_IKEV1); |
d1e348cf A |
974 | if (iph1 == NULL) { |
975 | IPSECSESSIONTRACEREVENT(sess, | |
976 | IPSECSESSIONEVENTCODE_IKE_PACKET_TX_FAIL, | |
977 | CONSTSTR("Information message"), | |
65c25746 A |
978 | CONSTSTR("Failed to transmit Information message (no new Phase 1)")); |
979 | plog(ASL_LEVEL_ERR, | |
d1e348cf | 980 | "failed to allocate ph1"); |
52b7d2ce | 981 | return -1; |
d1e348cf | 982 | } |
52b7d2ce A |
983 | |
984 | memcpy(&iph1->index.i_ck, &isakmp->i_ck, sizeof(cookie_t)); | |
985 | isakmp_newcookie((char *)&iph1->index.r_ck, remote, local); | |
65c25746 | 986 | fsm_set_state(&iph1->status, IKEV1_STATE_INFO); |
52b7d2ce | 987 | iph1->rmconf = rmconf; |
65c25746 | 988 | retain_rmconf(iph1->rmconf); |
52b7d2ce A |
989 | iph1->side = INITIATOR; |
990 | iph1->version = isakmp->v; | |
991 | iph1->flags = 0; | |
992 | iph1->msgid = 0; /* XXX */ | |
993 | #ifdef ENABLE_HYBRID | |
d1e348cf A |
994 | if ((iph1->mode_cfg = isakmp_cfg_mkstate()) == NULL) { |
995 | error = -1; | |
996 | goto end; | |
997 | } | |
52b7d2ce A |
998 | #endif |
999 | #ifdef ENABLE_FRAG | |
1000 | iph1->frag = 0; | |
1001 | iph1->frag_chain = NULL; | |
1002 | #endif | |
1003 | ||
1004 | /* copy remote address */ | |
d1e348cf A |
1005 | if (copy_ph1addresses(iph1, rmconf, remote, local) < 0) { |
1006 | IPSECSESSIONTRACEREVENT(sess, | |
1007 | IPSECSESSIONEVENTCODE_IKE_PACKET_TX_FAIL, | |
1008 | CONSTSTR("Information message"), | |
65c25746 A |
1009 | CONSTSTR("Failed to transmit Information Message (can't copy Phase 1 addresses)")); |
1010 | plog(ASL_LEVEL_ERR, | |
d1e348cf A |
1011 | "failed to copy ph1 addresses"); |
1012 | error = -1; | |
47612122 | 1013 | iph1 = NULL; /* deleted in copy_ph1addresses */ |
d1e348cf A |
1014 | goto end; |
1015 | } | |
52b7d2ce A |
1016 | |
1017 | tlen = sizeof(*n) + spisiz; | |
1018 | if (data) | |
1019 | tlen += data->l; | |
1020 | payload = vmalloc(tlen); | |
1021 | if (payload == NULL) { | |
d1e348cf A |
1022 | IPSECSESSIONTRACEREVENT(sess, |
1023 | IPSECSESSIONEVENTCODE_IKE_PACKET_TX_FAIL, | |
1024 | CONSTSTR("Information message"), | |
1025 | CONSTSTR("Failed to transmit Information Message (can't allocate payload)")); | |
65c25746 | 1026 | plog(ASL_LEVEL_ERR, |
52b7d2ce | 1027 | "failed to get buffer to send.\n"); |
d1e348cf | 1028 | error = -1; |
52b7d2ce A |
1029 | goto end; |
1030 | } | |
1031 | ||
1032 | n = (struct isakmp_pl_n *)payload->v; | |
1033 | n->h.np = ISAKMP_NPTYPE_NONE; | |
1034 | n->h.len = htons(tlen); | |
1035 | n->doi = htonl(IPSEC_DOI); | |
1036 | n->proto_id = IPSECDOI_KEY_IKE; | |
1037 | n->spi_size = spisiz; | |
1038 | n->type = htons(type); | |
1039 | if (spisiz) | |
d1e348cf | 1040 | memset(n + 1, 0, spisiz); /* XXX spisiz is always 0 */ |
52b7d2ce A |
1041 | if (data) |
1042 | memcpy((caddr_t)(n + 1) + spisiz, data->v, data->l); | |
1043 | ||
1044 | #ifdef ENABLE_VPNCONTROL_PORT | |
e8d9021d | 1045 | isakmp_info_vpncontrol_notify_ike_failed(iph1, FROM_LOCAL, type, data); |
52b7d2ce | 1046 | #endif |
65c25746 A |
1047 | if (ike_session_link_phase1(sess, iph1)) |
1048 | fatal_error(-1); | |
1049 | ||
52b7d2ce A |
1050 | error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, 0); |
1051 | vfree(payload); | |
d1e348cf A |
1052 | if (error) { |
1053 | IPSECSESSIONTRACEREVENT(sess, | |
1054 | IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_TX_FAIL, | |
1055 | CONSTSTR("Without ISAKMP-SA"), | |
1056 | CONSTSTR("Failed to transmit Without-ISAKMP-SA message")); | |
1057 | } else { | |
1058 | IPSECSESSIONTRACEREVENT(sess, | |
1059 | IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_TX_SUCC, | |
1060 | CONSTSTR("Without ISAKMP-SA"), | |
1061 | CONSTSTR(NULL)); | |
1062 | } | |
1063 | ||
52b7d2ce A |
1064 | end: |
1065 | if (iph1 != NULL) | |
65c25746 | 1066 | ike_session_unlink_phase1(iph1); |
52b7d2ce A |
1067 | |
1068 | return error; | |
1069 | } | |
1070 | ||
1071 | /* | |
65c25746 | 1072 | * send Notification payload (with ISAKMP SA) in an Informational exchange |
52b7d2ce A |
1073 | */ |
1074 | int | |
65c25746 | 1075 | isakmp_info_send_n1(phase1_handle_t *iph1, int type, vchar_t *data) |
52b7d2ce A |
1076 | { |
1077 | vchar_t *payload = NULL; | |
1078 | int tlen; | |
1079 | int error = 0; | |
1080 | struct isakmp_pl_n *n; | |
1081 | int spisiz; | |
1082 | ||
1083 | /* | |
1084 | * note on SPI size: which description is correct? I have chosen | |
1085 | * this to be 0. | |
1086 | * | |
1087 | * RFC2408 3.1, 2nd paragraph says: ISAKMP SA is identified by | |
1088 | * Initiator/Responder cookie and SPI has no meaning, SPI size = 0. | |
1089 | * RFC2408 3.1, first paragraph on page 40: ISAKMP SA is identified | |
1090 | * by cookie and SPI has no meaning, 0 <= SPI size <= 16. | |
1091 | * RFC2407 4.6.3.3, INITIAL-CONTACT is required to set to 16. | |
1092 | */ | |
1093 | if (type == ISAKMP_NTYPE_INITIAL_CONTACT || | |
1094 | type == ISAKMP_NTYPE_LOAD_BALANCE) | |
1095 | spisiz = sizeof(isakmp_index); | |
1096 | else | |
1097 | spisiz = 0; | |
1098 | ||
1099 | tlen = sizeof(*n) + spisiz; | |
1100 | if (data) | |
1101 | tlen += data->l; | |
1102 | payload = vmalloc(tlen); | |
1103 | if (payload == NULL) { | |
d1e348cf A |
1104 | IPSECSESSIONTRACEREVENT(iph1->parent_session, |
1105 | IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_TX_FAIL, | |
1106 | CONSTSTR("ISAKMP-SA"), | |
1107 | CONSTSTR("Failed to transmit ISAKMP-SA message (can't allocate payload)")); | |
65c25746 | 1108 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1109 | "failed to get buffer to send.\n"); |
1110 | return errno; | |
1111 | } | |
1112 | ||
1113 | n = (struct isakmp_pl_n *)payload->v; | |
1114 | n->h.np = ISAKMP_NPTYPE_NONE; | |
1115 | n->h.len = htons(tlen); | |
1116 | n->doi = htonl(iph1->rmconf->doitype); | |
1117 | n->proto_id = IPSECDOI_PROTO_ISAKMP; /* XXX to be configurable ? */ | |
1118 | n->spi_size = spisiz; | |
1119 | n->type = htons(type); | |
1120 | if (spisiz) | |
1121 | memcpy(n + 1, &iph1->index, sizeof(isakmp_index)); | |
1122 | if (data) | |
1123 | memcpy((caddr_t)(n + 1) + spisiz, data->v, data->l); | |
1124 | ||
1125 | #ifdef ENABLE_VPNCONTROL_PORT | |
e8d9021d | 1126 | isakmp_info_vpncontrol_notify_ike_failed(iph1, FROM_LOCAL, type, data); |
52b7d2ce A |
1127 | #endif |
1128 | ||
1129 | error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, iph1->flags); | |
1130 | vfree(payload); | |
d1e348cf A |
1131 | if (error) { |
1132 | IPSECSESSIONTRACEREVENT(iph1->parent_session, | |
1133 | IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_TX_FAIL, | |
1134 | CONSTSTR("ISAKMP-SA"), | |
1135 | CONSTSTR("Can't transmit ISAKMP-SA message")); | |
1136 | } else { | |
1137 | IPSECSESSIONTRACEREVENT(iph1->parent_session, | |
1138 | IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_TX_SUCC, | |
1139 | CONSTSTR("ISAKMP-SA"), | |
1140 | CONSTSTR(NULL)); | |
1141 | } | |
52b7d2ce A |
1142 | |
1143 | return error; | |
1144 | } | |
1145 | ||
1146 | /* | |
65c25746 | 1147 | * send Notification payload (with IPsec SA) in an Informational exchange |
52b7d2ce A |
1148 | */ |
1149 | int | |
65c25746 | 1150 | isakmp_info_send_n2(phase2_handle_t *iph2, int type, vchar_t *data) |
52b7d2ce | 1151 | { |
65c25746 | 1152 | phase1_handle_t *iph1 = iph2->ph1; |
52b7d2ce A |
1153 | vchar_t *payload = NULL; |
1154 | int tlen; | |
1155 | int error = 0; | |
1156 | struct isakmp_pl_n *n; | |
1157 | struct saproto *pr; | |
1158 | ||
1159 | if (!iph2->approval) | |
1160 | return EINVAL; | |
1161 | ||
1162 | pr = iph2->approval->head; | |
1163 | ||
1164 | /* XXX must be get proper spi */ | |
1165 | tlen = sizeof(*n) + pr->spisize; | |
1166 | if (data) | |
1167 | tlen += data->l; | |
1168 | payload = vmalloc(tlen); | |
1169 | if (payload == NULL) { | |
d1e348cf A |
1170 | IPSECSESSIONTRACEREVENT(iph2->parent_session, |
1171 | IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_TX_FAIL, | |
1172 | CONSTSTR("IPSEC-SA"), | |
1173 | CONSTSTR("Failed to transmit IPSEC-SA message (can't allocate payload)")); | |
65c25746 | 1174 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1175 | "failed to get buffer to send.\n"); |
1176 | return errno; | |
1177 | } | |
1178 | ||
1179 | n = (struct isakmp_pl_n *)payload->v; | |
1180 | n->h.np = ISAKMP_NPTYPE_NONE; | |
1181 | n->h.len = htons(tlen); | |
1182 | n->doi = htonl(IPSEC_DOI); /* IPSEC DOI (1) */ | |
1183 | n->proto_id = pr->proto_id; /* IPSEC AH/ESP/whatever*/ | |
1184 | n->spi_size = pr->spisize; | |
1185 | n->type = htons(type); | |
85f41bec | 1186 | memcpy(n + 1, &pr->spi, sizeof(u_int32_t)); // Wcast-align fix - copy instead of assign |
52b7d2ce A |
1187 | if (data) |
1188 | memcpy((caddr_t)(n + 1) + pr->spisize, data->v, data->l); | |
1189 | ||
1190 | iph2->flags |= ISAKMP_FLAG_E; /* XXX Should we do FLAG_A ? */ | |
1191 | error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, iph2->flags); | |
1192 | vfree(payload); | |
d1e348cf A |
1193 | if (error) { |
1194 | IPSECSESSIONTRACEREVENT(iph2->parent_session, | |
1195 | IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_TX_FAIL, | |
1196 | CONSTSTR("IPSEC-SA"), | |
1197 | CONSTSTR("Failed to transmit IPSEC-SA message")); | |
1198 | } else { | |
1199 | IPSECSESSIONTRACEREVENT(iph2->parent_session, | |
1200 | IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_TX_SUCC, | |
1201 | CONSTSTR("IPSEC-SA"), | |
1202 | CONSTSTR(NULL)); | |
1203 | } | |
1204 | ||
52b7d2ce A |
1205 | return error; |
1206 | } | |
1207 | ||
1208 | /* | |
1209 | * send Information | |
1210 | * When ph1->skeyid_a == NULL, send message without encoding. | |
1211 | */ | |
1212 | int | |
65c25746 | 1213 | isakmp_info_send_common(phase1_handle_t *iph1, vchar_t *payload, u_int32_t np, int flags) |
52b7d2ce | 1214 | { |
65c25746 | 1215 | phase2_handle_t *iph2 = NULL; |
52b7d2ce A |
1216 | vchar_t *hash = NULL; |
1217 | struct isakmp *isakmp; | |
1218 | struct isakmp_gen *gen; | |
1219 | char *p; | |
1220 | int tlen; | |
1221 | int error = -1; | |
1222 | ||
1223 | /* add new entry to isakmp status table */ | |
65c25746 | 1224 | iph2 = ike_session_newph2(ISAKMP_VERSION_NUMBER_IKEV1, PHASE2_TYPE_INFO); |
d1e348cf | 1225 | if (iph2 == NULL) { |
65c25746 | 1226 | plog(ASL_LEVEL_ERR, |
d1e348cf | 1227 | "failed to allocate ph2"); |
52b7d2ce | 1228 | goto end; |
d1e348cf | 1229 | } |
52b7d2ce | 1230 | |
65c25746 | 1231 | iph2->dst = dupsaddr(iph1->remote); |
d1e348cf | 1232 | if (iph2->dst == NULL) { |
65c25746 | 1233 | plog(ASL_LEVEL_ERR, |
d1e348cf | 1234 | "failed to duplicate remote address"); |
65c25746 | 1235 | ike_session_delph2(iph2); |
d1e348cf A |
1236 | goto end; |
1237 | } | |
65c25746 | 1238 | iph2->src = dupsaddr(iph1->local); |
d1e348cf | 1239 | if (iph2->src == NULL) { |
65c25746 | 1240 | plog(ASL_LEVEL_ERR, |
d1e348cf | 1241 | "failed to duplicate local address"); |
65c25746 | 1242 | ike_session_delph2(iph2); |
d1e348cf A |
1243 | goto end; |
1244 | } | |
85f41bec | 1245 | switch (iph1->remote->ss_family) { |
52b7d2ce | 1246 | case AF_INET: |
d1e348cf | 1247 | #if (!defined(ENABLE_NATT)) || (defined(BROKEN_NATT)) |
52b7d2ce A |
1248 | ((struct sockaddr_in *)iph2->dst)->sin_port = 0; |
1249 | ((struct sockaddr_in *)iph2->src)->sin_port = 0; | |
1250 | #endif | |
1251 | break; | |
1252 | #ifdef INET6 | |
1253 | case AF_INET6: | |
d1e348cf | 1254 | #if (!defined(ENABLE_NATT)) || (defined(BROKEN_NATT)) |
52b7d2ce A |
1255 | ((struct sockaddr_in6 *)iph2->dst)->sin6_port = 0; |
1256 | ((struct sockaddr_in6 *)iph2->src)->sin6_port = 0; | |
d1e348cf | 1257 | #endif |
52b7d2ce A |
1258 | break; |
1259 | #endif | |
1260 | default: | |
65c25746 | 1261 | plog(ASL_LEVEL_ERR, |
85f41bec | 1262 | "invalid family: %d\n", iph1->remote->ss_family); |
65c25746 | 1263 | ike_session_delph2(iph2); |
52b7d2ce A |
1264 | goto end; |
1265 | } | |
52b7d2ce | 1266 | iph2->side = INITIATOR; |
65c25746 | 1267 | fsm_set_state(&iph2->status, IKEV1_STATE_INFO); |
52b7d2ce A |
1268 | iph2->msgid = isakmp_newmsgid2(iph1); |
1269 | ||
1270 | /* get IV and HASH(1) if skeyid_a was generated. */ | |
1271 | if (iph1->skeyid_a != NULL) { | |
1272 | iph2->ivm = oakley_newiv2(iph1, iph2->msgid); | |
1273 | if (iph2->ivm == NULL) { | |
65c25746 | 1274 | plog(ASL_LEVEL_ERR, |
d1e348cf | 1275 | "failed to generate IV"); |
65c25746 | 1276 | ike_session_delph2(iph2); |
52b7d2ce A |
1277 | goto end; |
1278 | } | |
1279 | ||
1280 | /* generate HASH(1) */ | |
65c25746 | 1281 | hash = oakley_compute_hash1(iph1, iph2->msgid, payload); |
52b7d2ce | 1282 | if (hash == NULL) { |
65c25746 | 1283 | plog(ASL_LEVEL_ERR, |
d1e348cf | 1284 | "failed to generate HASH"); |
65c25746 | 1285 | ike_session_delph2(iph2); |
52b7d2ce A |
1286 | goto end; |
1287 | } | |
1288 | ||
1289 | /* initialized total buffer length */ | |
1290 | tlen = hash->l; | |
1291 | tlen += sizeof(*gen); | |
1292 | } else { | |
1293 | /* IKE-SA is not established */ | |
1294 | hash = NULL; | |
1295 | ||
1296 | /* initialized total buffer length */ | |
1297 | tlen = 0; | |
1298 | } | |
1299 | if ((flags & ISAKMP_FLAG_A) == 0) | |
1300 | iph2->flags = (hash == NULL ? 0 : ISAKMP_FLAG_E); | |
1301 | else | |
1302 | iph2->flags = (hash == NULL ? 0 : ISAKMP_FLAG_A); | |
1303 | ||
65c25746 | 1304 | ike_session_link_ph2_to_ph1(iph1, iph2); |
52b7d2ce A |
1305 | |
1306 | tlen += sizeof(*isakmp) + payload->l; | |
1307 | ||
1308 | /* create buffer for isakmp payload */ | |
1309 | iph2->sendbuf = vmalloc(tlen); | |
1310 | if (iph2->sendbuf == NULL) { | |
65c25746 | 1311 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1312 | "failed to get buffer to send.\n"); |
1313 | goto err; | |
1314 | } | |
1315 | ||
1316 | /* create isakmp header */ | |
1317 | isakmp = (struct isakmp *)iph2->sendbuf->v; | |
1318 | memcpy(&isakmp->i_ck, &iph1->index.i_ck, sizeof(cookie_t)); | |
1319 | memcpy(&isakmp->r_ck, &iph1->index.r_ck, sizeof(cookie_t)); | |
1320 | isakmp->np = hash == NULL ? (np & 0xff) : ISAKMP_NPTYPE_HASH; | |
1321 | isakmp->v = iph1->version; | |
1322 | isakmp->etype = ISAKMP_ETYPE_INFO; | |
1323 | isakmp->flags = iph2->flags; | |
1324 | memcpy(&isakmp->msgid, &iph2->msgid, sizeof(isakmp->msgid)); | |
1325 | isakmp->len = htonl(tlen); | |
1326 | p = (char *)(isakmp + 1); | |
1327 | ||
1328 | /* create HASH payload */ | |
1329 | if (hash != NULL) { | |
1330 | gen = (struct isakmp_gen *)p; | |
1331 | gen->np = np & 0xff; | |
1332 | gen->len = htons(sizeof(*gen) + hash->l); | |
1333 | p += sizeof(*gen); | |
1334 | memcpy(p, hash->v, hash->l); | |
1335 | p += hash->l; | |
1336 | } | |
1337 | ||
1338 | /* add payload */ | |
1339 | memcpy(p, payload->v, payload->l); | |
1340 | p += payload->l; | |
1341 | ||
1342 | #ifdef HAVE_PRINT_ISAKMP_C | |
1343 | isakmp_printpacket(iph2->sendbuf, iph1->local, iph1->remote, 1); | |
1344 | #endif | |
1345 | ||
1346 | /* encoding */ | |
1347 | if (ISSET(isakmp->flags, ISAKMP_FLAG_E)) { | |
1348 | vchar_t *tmp; | |
1349 | ||
1350 | tmp = oakley_do_encrypt(iph2->ph1, iph2->sendbuf, iph2->ivm->ive, | |
1351 | iph2->ivm->iv); | |
1352 | VPTRINIT(iph2->sendbuf); | |
d1e348cf | 1353 | if (tmp == NULL) { |
65c25746 | 1354 | plog(ASL_LEVEL_ERR, |
d1e348cf | 1355 | "failed to encrypt packet"); |
52b7d2ce | 1356 | goto err; |
d1e348cf | 1357 | } |
52b7d2ce A |
1358 | iph2->sendbuf = tmp; |
1359 | } | |
1360 | ||
1361 | /* HDR*, HASH(1), N */ | |
1362 | if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0) { | |
65c25746 | 1363 | plog(ASL_LEVEL_ERR, |
d1e348cf | 1364 | "failed to send packet"); |
52b7d2ce A |
1365 | VPTRINIT(iph2->sendbuf); |
1366 | goto err; | |
1367 | } | |
1368 | ||
7ebaebe2 | 1369 | plog(ASL_LEVEL_NOTICE, |
52b7d2ce A |
1370 | "sendto Information %s.\n", s_isakmp_nptype(np)); |
1371 | ||
1372 | /* | |
1373 | * don't resend notify message because peer can use Acknowledged | |
1374 | * Informational if peer requires the reply of the notify message. | |
1375 | */ | |
1376 | ||
1377 | /* XXX If Acknowledged Informational required, don't delete ph2handle */ | |
1378 | error = 0; | |
1379 | VPTRINIT(iph2->sendbuf); | |
d1e348cf A |
1380 | IPSECSESSIONTRACEREVENT(iph1->parent_session, |
1381 | IPSECSESSIONEVENTCODE_IKE_PACKET_TX_SUCC, | |
1382 | CONSTSTR("Information message"), | |
1383 | CONSTSTR(NULL)); | |
1384 | ||
52b7d2ce A |
1385 | goto err; /* XXX */ |
1386 | ||
1387 | end: | |
d1e348cf A |
1388 | if (error) { |
1389 | IPSECSESSIONTRACEREVENT(iph1->parent_session, | |
1390 | IPSECSESSIONEVENTCODE_IKE_PACKET_TX_FAIL, | |
1391 | CONSTSTR("Information message"), | |
1392 | CONSTSTR("Failed to transmit Information message")); | |
1393 | } | |
52b7d2ce A |
1394 | if (hash) |
1395 | vfree(hash); | |
1396 | return error; | |
1397 | ||
1398 | err: | |
65c25746 | 1399 | ike_session_unlink_phase2(iph2); |
52b7d2ce A |
1400 | goto end; |
1401 | } | |
1402 | ||
1403 | /* | |
1404 | * add a notify payload to buffer by reallocating buffer. | |
1405 | * If buf == NULL, the function only create a notify payload. | |
1406 | * | |
1407 | * XXX Which is SPI to be included, inbound or outbound ? | |
1408 | */ | |
1409 | vchar_t * | |
65c25746 | 1410 | isakmp_add_pl_n(vchar_t *buf0, u_int8_t **np_p, int type, struct saproto *pr, vchar_t *data) |
52b7d2ce A |
1411 | { |
1412 | vchar_t *buf = NULL; | |
1413 | struct isakmp_pl_n *n; | |
1414 | int tlen; | |
1415 | int oldlen = 0; | |
1416 | ||
1417 | if (*np_p) | |
1418 | **np_p = ISAKMP_NPTYPE_N; | |
1419 | ||
1420 | tlen = sizeof(*n) + pr->spisize; | |
1421 | ||
1422 | if (data) | |
1423 | tlen += data->l; | |
1424 | if (buf0) { | |
1425 | oldlen = buf0->l; | |
1426 | buf = vrealloc(buf0, buf0->l + tlen); | |
1427 | } else | |
1428 | buf = vmalloc(tlen); | |
1429 | if (!buf) { | |
65c25746 | 1430 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1431 | "failed to get a payload buffer.\n"); |
1432 | return NULL; | |
1433 | } | |
1434 | ||
1435 | n = (struct isakmp_pl_n *)(buf->v + oldlen); | |
1436 | n->h.np = ISAKMP_NPTYPE_NONE; | |
1437 | n->h.len = htons(tlen); | |
1438 | n->doi = htonl(IPSEC_DOI); /* IPSEC DOI (1) */ | |
1439 | n->proto_id = pr->proto_id; /* IPSEC AH/ESP/whatever*/ | |
1440 | n->spi_size = pr->spisize; | |
1441 | n->type = htons(type); | |
85f41bec | 1442 | memcpy(n + 1, &pr->spi, sizeof(u_int32_t)); // Wcast-align fix - copy instead of assign with cast |
52b7d2ce A |
1443 | if (data) |
1444 | memcpy((caddr_t)(n + 1) + pr->spisize, data->v, data->l); | |
1445 | ||
1446 | /* save the pointer of next payload type */ | |
1447 | *np_p = &n->h.np; | |
1448 | ||
1449 | return buf; | |
1450 | } | |
1451 | ||
d1e348cf A |
1452 | |
1453 | void | |
65c25746 | 1454 | purge_ipsec_spi(struct sockaddr_storage *dst0, int proto, u_int32_t *spi /*network byteorder*/, size_t n, u_int32_t *inbound_spi, size_t *max_inbound_spi) |
52b7d2ce A |
1455 | { |
1456 | vchar_t *buf = NULL; | |
1457 | struct sadb_msg *msg, *next, *end; | |
1458 | struct sadb_sa *sa; | |
d1e348cf | 1459 | struct sadb_lifetime *lt; |
85f41bec | 1460 | struct sockaddr_storage *src, *dst; |
65c25746 | 1461 | phase2_handle_t *iph2; |
d1e348cf | 1462 | u_int64_t created; |
65c25746 | 1463 | size_t i, j = 0; |
52b7d2ce A |
1464 | caddr_t mhp[SADB_EXT_MAX + 1]; |
1465 | ||
1466 | buf = pfkey_dump_sadb(ipsecdoi2pfkey_proto(proto)); | |
1467 | if (buf == NULL) { | |
7ebaebe2 | 1468 | plog(ASL_LEVEL_NOTICE, |
52b7d2ce A |
1469 | "pfkey_dump_sadb returned nothing.\n"); |
1470 | return; | |
1471 | } | |
1472 | ||
85f41bec A |
1473 | msg = ALIGNED_CAST(struct sadb_msg *)buf->v; |
1474 | end = ALIGNED_CAST(struct sadb_msg *)(buf->v + buf->l); | |
52b7d2ce A |
1475 | |
1476 | while (msg < end) { | |
1477 | if ((msg->sadb_msg_len << 3) < sizeof(*msg)) | |
1478 | break; | |
85f41bec | 1479 | next = ALIGNED_CAST(struct sadb_msg *)((caddr_t)msg + (msg->sadb_msg_len << 3)); |
52b7d2ce A |
1480 | if (msg->sadb_msg_type != SADB_DUMP) { |
1481 | msg = next; | |
1482 | continue; | |
1483 | } | |
1484 | ||
1485 | if (pfkey_align(msg, mhp) || pfkey_check(mhp)) { | |
65c25746 | 1486 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1487 | "pfkey_check (%s)\n", ipsec_strerror()); |
1488 | msg = next; | |
1489 | continue; | |
1490 | } | |
1491 | ||
85f41bec | 1492 | sa = ALIGNED_CAST(struct sadb_sa *)(mhp[SADB_EXT_SA]); // Wcast-align fix (void*) - buffer of pointers to aligned structs |
52b7d2ce A |
1493 | if (!sa |
1494 | || !mhp[SADB_EXT_ADDRESS_SRC] | |
1495 | || !mhp[SADB_EXT_ADDRESS_DST]) { | |
1496 | msg = next; | |
1497 | continue; | |
1498 | } | |
85f41bec A |
1499 | src = ALIGNED_CAST(struct sockaddr_storage*)PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); // Wcast-align fix (void*) - buffer of pointers to aligned structs |
1500 | dst = ALIGNED_CAST(struct sockaddr_storage*)PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); | |
1501 | lt = ALIGNED_CAST(struct sadb_lifetime*)mhp[SADB_EXT_LIFETIME_HARD]; | |
d1e348cf A |
1502 | if(lt != NULL) |
1503 | created = lt->sadb_lifetime_addtime; | |
1504 | else | |
1505 | created = 0; | |
52b7d2ce A |
1506 | |
1507 | if (sa->sadb_sa_state != SADB_SASTATE_MATURE | |
1508 | && sa->sadb_sa_state != SADB_SASTATE_DYING) { | |
1509 | msg = next; | |
1510 | continue; | |
1511 | } | |
1512 | ||
1513 | /* XXX n^2 algorithm, inefficient */ | |
1514 | ||
65c25746 | 1515 | /* don't delete inbound SAs at the moment (just save them in inbound_spi) */ |
52b7d2ce | 1516 | /* XXX should we remove SAs with opposite direction as well? */ |
d1e348cf | 1517 | if (CMPSADDR2(dst0, dst)) { |
52b7d2ce A |
1518 | msg = next; |
1519 | continue; | |
1520 | } | |
1521 | ||
1522 | for (i = 0; i < n; i++) { | |
65c25746 A |
1523 | u_int32_t *i_spi; |
1524 | ||
52b7d2ce A |
1525 | if (spi[i] != sa->sadb_sa_spi) |
1526 | continue; | |
1527 | ||
52b7d2ce A |
1528 | /* |
1529 | * delete a relative phase 2 handler. | |
1530 | * continue to process if no relative phase 2 handler | |
1531 | * exists. | |
1532 | */ | |
65c25746 A |
1533 | if (inbound_spi && max_inbound_spi && j < *max_inbound_spi) { |
1534 | i_spi = &inbound_spi[j]; | |
1535 | } else { | |
1536 | i_spi = NULL; | |
1537 | } | |
1538 | iph2 = ike_session_getph2bysaidx2(src, dst, proto, spi[i], i_spi); | |
1539 | ||
1540 | pfkey_send_delete(lcconf->sock_pfkey, | |
1541 | msg->sadb_msg_satype, | |
1542 | IPSEC_MODE_ANY, | |
1543 | src, dst, sa->sadb_sa_spi); | |
1544 | ||
d1e348cf | 1545 | if(iph2 != NULL){ |
52b7d2ce | 1546 | delete_spd(iph2); |
65c25746 A |
1547 | ike_session_unlink_phase2(iph2); |
1548 | if (i_spi) { | |
1549 | j++; | |
1550 | } | |
52b7d2ce A |
1551 | } |
1552 | ||
7ebaebe2 | 1553 | plog(ASL_LEVEL_NOTICE, "Purged IPsec-SA proto_id=%s spi=%u.\n", |
65c25746 A |
1554 | s_ipsecdoi_proto(proto), |
1555 | ntohl(spi[i])); | |
52b7d2ce A |
1556 | } |
1557 | ||
1558 | msg = next; | |
1559 | } | |
1560 | ||
65c25746 A |
1561 | if (max_inbound_spi) { |
1562 | *max_inbound_spi = j; | |
1563 | } | |
1564 | ||
52b7d2ce A |
1565 | if (buf) |
1566 | vfree(buf); | |
1567 | } | |
1568 | ||
1569 | /* | |
1570 | * delete all phase2 sa relatived to the destination address. | |
1571 | * Don't delete Phase 1 handlers on INITIAL-CONTACT, and don't ignore | |
1572 | * an INITIAL-CONTACT if we have contacted the peer. This matches the | |
1573 | * Sun IKE behavior, and makes rekeying work much better when the peer | |
1574 | * restarts. | |
1575 | */ | |
65c25746 A |
1576 | void |
1577 | info_recv_initialcontact(phase1_handle_t *iph1) | |
52b7d2ce A |
1578 | { |
1579 | vchar_t *buf = NULL; | |
1580 | struct sadb_msg *msg, *next, *end; | |
1581 | struct sadb_sa *sa; | |
85f41bec | 1582 | struct sockaddr_storage *src, *dst; |
52b7d2ce A |
1583 | caddr_t mhp[SADB_EXT_MAX + 1]; |
1584 | int proto_id, i; | |
65c25746 | 1585 | phase2_handle_t *iph2; |
52b7d2ce A |
1586 | #if 0 |
1587 | char *loc, *rem; | |
1588 | #endif | |
1589 | ||
1590 | if (f_local) | |
1591 | return; | |
1592 | ||
d1e348cf | 1593 | // TODO: make sure that is_rekey is cleared for this. and session indicates the same |
52b7d2ce | 1594 | #if 0 |
d1e348cf A |
1595 | loc = racoon_strdup(saddrwop2str(iph1->local)); |
1596 | rem = racoon_strdup(saddrwop2str(iph1->remote)); | |
1597 | STRDUP_FATAL(loc); | |
1598 | STRDUP_FATAL(rem); | |
52b7d2ce A |
1599 | |
1600 | /* | |
1601 | * Purge all IPSEC-SAs for the peer. We can do this | |
1602 | * the easy way (using a PF_KEY SADB_DELETE extension) | |
1603 | * or we can do it the hard way. | |
1604 | */ | |
1605 | for (i = 0; i < pfkey_nsatypes; i++) { | |
1606 | proto_id = pfkey2ipsecdoi_proto(pfkey_satypes[i].ps_satype); | |
1607 | ||
7ebaebe2 | 1608 | plog(ASL_LEVEL_NOTICE, |
52b7d2ce A |
1609 | "purging %s SAs for %s -> %s\n", |
1610 | pfkey_satypes[i].ps_name, loc, rem); | |
1611 | if (pfkey_send_delete_all(lcconf->sock_pfkey, | |
1612 | pfkey_satypes[i].ps_satype, IPSEC_MODE_ANY, | |
1613 | iph1->local, iph1->remote) == -1) { | |
65c25746 | 1614 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1615 | "delete_all %s -> %s failed for %s (%s)\n", |
1616 | loc, rem, | |
1617 | pfkey_satypes[i].ps_name, ipsec_strerror()); | |
1618 | goto the_hard_way; | |
1619 | } | |
1620 | ||
65c25746 | 1621 | ike_session_deleteallph2(iph1->local, iph1->remote, proto_id); |
52b7d2ce | 1622 | |
7ebaebe2 | 1623 | plog(ASL_LEVEL_NOTICE, |
52b7d2ce A |
1624 | "purging %s SAs for %s -> %s\n", |
1625 | pfkey_satypes[i].ps_name, rem, loc); | |
1626 | if (pfkey_send_delete_all(lcconf->sock_pfkey, | |
1627 | pfkey_satypes[i].ps_satype, IPSEC_MODE_ANY, | |
1628 | iph1->remote, iph1->local) == -1) { | |
65c25746 | 1629 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1630 | "delete_all %s -> %s failed for %s (%s)\n", |
1631 | rem, loc, | |
1632 | pfkey_satypes[i].ps_name, ipsec_strerror()); | |
1633 | goto the_hard_way; | |
1634 | } | |
1635 | ||
65c25746 | 1636 | ike_session_deleteallph2(iph1->remote, iph1->local, proto_id); |
52b7d2ce A |
1637 | } |
1638 | ||
1639 | racoon_free(loc); | |
1640 | racoon_free(rem); | |
1641 | return; | |
1642 | ||
1643 | the_hard_way: | |
1644 | racoon_free(loc); | |
1645 | racoon_free(rem); | |
1646 | #endif | |
1647 | ||
1648 | buf = pfkey_dump_sadb(SADB_SATYPE_UNSPEC); | |
1649 | if (buf == NULL) { | |
7ebaebe2 | 1650 | plog(ASL_LEVEL_NOTICE, |
52b7d2ce A |
1651 | "pfkey_dump_sadb returned nothing.\n"); |
1652 | return; | |
1653 | } | |
1654 | ||
85f41bec A |
1655 | msg = ALIGNED_CAST(struct sadb_msg *)buf->v; |
1656 | end = ALIGNED_CAST(struct sadb_msg *)(buf->v + buf->l); | |
52b7d2ce A |
1657 | |
1658 | while (msg < end) { | |
1659 | if ((msg->sadb_msg_len << 3) < sizeof(*msg)) | |
1660 | break; | |
85f41bec | 1661 | next = ALIGNED_CAST(struct sadb_msg *)((caddr_t)msg + (msg->sadb_msg_len << 3)); |
52b7d2ce A |
1662 | if (msg->sadb_msg_type != SADB_DUMP) { |
1663 | msg = next; | |
1664 | continue; | |
1665 | } | |
1666 | ||
1667 | if (pfkey_align(msg, mhp) || pfkey_check(mhp)) { | |
65c25746 | 1668 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1669 | "pfkey_check (%s)\n", ipsec_strerror()); |
1670 | msg = next; | |
1671 | continue; | |
1672 | } | |
1673 | ||
1674 | if (mhp[SADB_EXT_SA] == NULL | |
1675 | || mhp[SADB_EXT_ADDRESS_SRC] == NULL | |
1676 | || mhp[SADB_EXT_ADDRESS_DST] == NULL) { | |
1677 | msg = next; | |
1678 | continue; | |
1679 | } | |
85f41bec A |
1680 | sa = ALIGNED_CAST(struct sadb_sa *)mhp[SADB_EXT_SA]; // Wcast-align fix (void*) - buffer of pointers to aligned structs |
1681 | src = ALIGNED_CAST(struct sockaddr_storage *)PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); | |
1682 | dst = ALIGNED_CAST(struct sockaddr_storage *)PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); | |
52b7d2ce A |
1683 | |
1684 | if (sa->sadb_sa_state != SADB_SASTATE_MATURE | |
1685 | && sa->sadb_sa_state != SADB_SASTATE_DYING) { | |
1686 | msg = next; | |
1687 | continue; | |
1688 | } | |
1689 | ||
1690 | /* | |
1691 | * RFC2407 4.6.3.3 INITIAL-CONTACT is the message that | |
1692 | * announces the sender of the message was rebooted. | |
1693 | * it is interpreted to delete all SAs which source address | |
1694 | * is the sender of the message. | |
1695 | * racoon only deletes SA which is matched both the | |
1696 | * source address and the destination accress. | |
1697 | */ | |
1698 | #ifdef ENABLE_NATT | |
1699 | /* | |
1700 | * XXX RFC 3947 says that whe MUST NOT use IP+port to find old SAs | |
1701 | * from this peer ! | |
1702 | */ | |
1703 | if(iph1->natt_flags & NAT_DETECTED){ | |
1704 | if (CMPSADDR(iph1->local, src) == 0 && | |
1705 | CMPSADDR(iph1->remote, dst) == 0) | |
1706 | ; | |
1707 | else if (CMPSADDR(iph1->remote, src) == 0 && | |
1708 | CMPSADDR(iph1->local, dst) == 0) | |
1709 | ; | |
1710 | else { | |
1711 | msg = next; | |
1712 | continue; | |
1713 | } | |
1714 | } else | |
1715 | #endif | |
1716 | /* If there is no NAT-T, we don't have to check addr + port... | |
1717 | * XXX what about a configuration with a remote peers which is not | |
1718 | * NATed, but which NATs some other peers ? | |
1719 | * Here, the INITIAl-CONTACT would also flush all those NATed peers !! | |
1720 | */ | |
1721 | if (cmpsaddrwop(iph1->local, src) == 0 && | |
1722 | cmpsaddrwop(iph1->remote, dst) == 0) | |
1723 | ; | |
1724 | else if (cmpsaddrwop(iph1->remote, src) == 0 && | |
1725 | cmpsaddrwop(iph1->local, dst) == 0) | |
1726 | ; | |
1727 | else { | |
1728 | msg = next; | |
1729 | continue; | |
1730 | } | |
1731 | ||
1732 | /* | |
1733 | * Make sure this is an SATYPE that we manage. | |
1734 | * This is gross; too bad we couldn't do it the | |
1735 | * easy way. | |
1736 | */ | |
1737 | for (i = 0; i < pfkey_nsatypes; i++) { | |
1738 | if (pfkey_satypes[i].ps_satype == | |
1739 | msg->sadb_msg_satype) | |
1740 | break; | |
1741 | } | |
1742 | if (i == pfkey_nsatypes) { | |
1743 | msg = next; | |
1744 | continue; | |
1745 | } | |
1746 | ||
7ebaebe2 | 1747 | plog(ASL_LEVEL_NOTICE, |
52b7d2ce A |
1748 | "purging spi=%u.\n", ntohl(sa->sadb_sa_spi)); |
1749 | pfkey_send_delete(lcconf->sock_pfkey, | |
1750 | msg->sadb_msg_satype, | |
1751 | IPSEC_MODE_ANY, src, dst, sa->sadb_sa_spi); | |
1752 | ||
1753 | /* | |
1754 | * delete a relative phase 2 handler. | |
1755 | * continue to process if no relative phase 2 handler | |
1756 | * exists. | |
1757 | */ | |
1758 | proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype); | |
65c25746 | 1759 | iph2 = ike_session_getph2bysaidx(src, dst, proto_id, sa->sadb_sa_spi); |
52b7d2ce A |
1760 | if (iph2) { |
1761 | delete_spd(iph2); | |
65c25746 | 1762 | ike_session_unlink_phase2(iph2); |
52b7d2ce A |
1763 | } |
1764 | ||
1765 | msg = next; | |
1766 | } | |
1767 | ||
1768 | vfree(buf); | |
1769 | } | |
1770 | ||
52b7d2ce | 1771 | void |
65c25746 | 1772 | isakmp_check_notify(struct isakmp_gen *gen /* points to Notify payload */, phase1_handle_t *iph1) |
52b7d2ce A |
1773 | { |
1774 | struct isakmp_pl_n *notify = (struct isakmp_pl_n *)gen; | |
1775 | ||
7ebaebe2 | 1776 | plog(ASL_LEVEL_NOTICE, |
52b7d2ce A |
1777 | "Notify Message received\n"); |
1778 | ||
1779 | switch (ntohs(notify->type)) { | |
1780 | case ISAKMP_NTYPE_CONNECTED: | |
52b7d2ce | 1781 | case ISAKMP_NTYPE_RESPONDER_LIFETIME: |
52b7d2ce | 1782 | case ISAKMP_NTYPE_REPLAY_STATUS: |
d1e348cf A |
1783 | case ISAKMP_NTYPE_HEARTBEAT: |
1784 | #ifdef ENABLE_HYBRID | |
1785 | case ISAKMP_NTYPE_UNITY_HEARTBEAT: | |
1786 | #endif | |
65c25746 A |
1787 | plog(ASL_LEVEL_WARNING, |
1788 | "Ignore %s notification.\n", | |
d1e348cf | 1789 | s_isakmp_notify_msg(ntohs(notify->type))); |
52b7d2ce A |
1790 | break; |
1791 | case ISAKMP_NTYPE_INITIAL_CONTACT: | |
65c25746 A |
1792 | plog(ASL_LEVEL_WARNING, |
1793 | "Ignore INITIAL-CONTACT notification, " | |
1794 | "because it is only accepted after Phase 1.\n"); | |
52b7d2ce A |
1795 | break; |
1796 | case ISAKMP_NTYPE_LOAD_BALANCE: | |
65c25746 A |
1797 | plog(ASL_LEVEL_WARNING, |
1798 | "Ignore LOAD-BALANCE notification, " | |
1799 | "because it is only accepted after Phase 1.\n"); | |
52b7d2ce | 1800 | break; |
52b7d2ce A |
1801 | default: |
1802 | isakmp_info_send_n1(iph1, ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE, NULL); | |
65c25746 A |
1803 | plog(ASL_LEVEL_ERR, |
1804 | "Received unknown notification type %s.\n", | |
d1e348cf | 1805 | s_isakmp_notify_msg(ntohs(notify->type))); |
52b7d2ce A |
1806 | } |
1807 | ||
1808 | return; | |
1809 | } | |
1810 | ||
d1e348cf | 1811 | void |
65c25746 | 1812 | isakmp_check_ph2_notify(struct isakmp_gen *gen /* points to Notify payload */, phase2_handle_t *iph2) |
d1e348cf A |
1813 | { |
1814 | struct isakmp_pl_n *notify = (struct isakmp_pl_n *)gen; | |
1815 | ||
7ebaebe2 | 1816 | plog(ASL_LEVEL_NOTICE, |
65c25746 | 1817 | "Phase 2 Notify Message received\n"); |
d1e348cf A |
1818 | |
1819 | switch (ntohs(notify->type)) { | |
1820 | case ISAKMP_NTYPE_RESPONDER_LIFETIME: | |
1821 | return((void)isakmp_ph2_responder_lifetime(iph2, | |
1822 | (struct isakmp_pl_resp_lifetime *)notify)); | |
1823 | break; | |
1824 | case ISAKMP_NTYPE_CONNECTED: | |
1825 | case ISAKMP_NTYPE_REPLAY_STATUS: | |
1826 | case ISAKMP_NTYPE_HEARTBEAT: | |
1827 | #ifdef ENABLE_HYBRID | |
1828 | case ISAKMP_NTYPE_UNITY_HEARTBEAT: | |
1829 | #endif | |
65c25746 A |
1830 | plog(ASL_LEVEL_WARNING, |
1831 | "Ignore %s notification.\n", | |
d1e348cf A |
1832 | s_isakmp_notify_msg(ntohs(notify->type))); |
1833 | break; | |
1834 | case ISAKMP_NTYPE_INITIAL_CONTACT: | |
65c25746 A |
1835 | plog(ASL_LEVEL_WARNING, |
1836 | "Ignore INITIAL-CONTACT notification, " | |
1837 | "because it is only accepted after Phase 1.\n"); | |
d1e348cf A |
1838 | break; |
1839 | case ISAKMP_NTYPE_LOAD_BALANCE: | |
65c25746 A |
1840 | plog(ASL_LEVEL_WARNING, |
1841 | "Ignore LOAD-BALANCE notification, " | |
1842 | "because it is only accepted after Phase 1.\n"); | |
d1e348cf A |
1843 | break; |
1844 | default: | |
1845 | isakmp_info_send_n1(iph2->ph1, ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE, NULL); | |
65c25746 A |
1846 | plog(ASL_LEVEL_ERR, |
1847 | "Received unknown notification type %s.\n", | |
d1e348cf A |
1848 | s_isakmp_notify_msg(ntohs(notify->type))); |
1849 | } | |
1850 | ||
1851 | return; | |
1852 | } | |
1853 | ||
52b7d2ce A |
1854 | #ifdef ENABLE_VPNCONTROL_PORT |
1855 | static int | |
65c25746 | 1856 | isakmp_info_recv_lb(phase1_handle_t *iph1, struct isakmp_pl_lb *n, int encrypted) |
52b7d2ce A |
1857 | { |
1858 | ||
1859 | if (iph1->side != INITIATOR) | |
1860 | { | |
7ebaebe2 | 1861 | plog(ASL_LEVEL_NOTICE, |
52b7d2ce A |
1862 | "LOAD-BALANCE notification ignored - we are not the initiator.\n"); |
1863 | return 0; | |
1864 | } | |
52b7d2ce | 1865 | if (!encrypted) { |
7ebaebe2 | 1866 | plog(ASL_LEVEL_NOTICE, |
52b7d2ce A |
1867 | "LOAD-BALANCE notification ignored - not protected.\n"); |
1868 | return 0; | |
1869 | } | |
1870 | if (ntohs(n->h.len) != sizeof(struct isakmp_pl_lb)) { | |
7ebaebe2 A |
1871 | plog(ASL_LEVEL_NOTICE, |
1872 | "isakmp_info_recv_lb Invalid length of payload\n"); | |
52b7d2ce | 1873 | return -1; |
d06a7ccb A |
1874 | } |
1875 | ||
52b7d2ce | 1876 | vpncontrol_notify_ike_failed(ISAKMP_NTYPE_LOAD_BALANCE, FROM_REMOTE, |
d06a7ccb | 1877 | iph1_get_remote_v4_address(iph1), 4, (u_int8_t*)(&(n->address))); |
52b7d2ce | 1878 | |
65c25746 A |
1879 | plog(ASL_LEVEL_NOTICE, |
1880 | "Received LOAD_BALANCE notification.\n"); | |
52b7d2ce | 1881 | |
d1e348cf | 1882 | if (((struct sockaddr_in*)iph1->remote)->sin_addr.s_addr != ntohl(n->address)) { |
7ebaebe2 | 1883 | plog(ASL_LEVEL_NOTICE, |
65c25746 | 1884 | "Deleting old Phase 1 because of LOAD_BALANCE notification - redirect address=%x.\n", |
d1e348cf A |
1885 | ntohl(n->address)); |
1886 | ||
65c25746 | 1887 | if (FSM_STATE_IS_ESTABLISHED(iph1->status)) { |
d1e348cf A |
1888 | isakmp_info_send_d1(iph1); |
1889 | } | |
1890 | isakmp_ph1expire(iph1); | |
1891 | } | |
1892 | ||
52b7d2ce A |
1893 | return 0; |
1894 | } | |
1895 | #endif | |
1896 | ||
1897 | #ifdef ENABLE_DPD | |
1898 | static int | |
65c25746 | 1899 | isakmp_info_recv_r_u (phase1_handle_t *iph1, struct isakmp_pl_ru *ru, u_int32_t msgid) |
52b7d2ce A |
1900 | { |
1901 | struct isakmp_pl_ru *ru_ack; | |
1902 | vchar_t *payload = NULL; | |
1903 | int tlen; | |
1904 | int error = 0; | |
1905 | ||
7ebaebe2 | 1906 | plog(ASL_LEVEL_NOTICE, |
52b7d2ce A |
1907 | "DPD R-U-There received\n"); |
1908 | ||
1909 | /* XXX should compare cookies with iph1->index? | |
1910 | Or is this already done by calling function? */ | |
1911 | tlen = sizeof(*ru_ack); | |
1912 | payload = vmalloc(tlen); | |
1913 | if (payload == NULL) { | |
d1e348cf A |
1914 | IPSECSESSIONTRACEREVENT(iph1->parent_session, |
1915 | IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_TX_FAIL, | |
1916 | CONSTSTR("R-U-THERE? ACK"), | |
1917 | CONSTSTR("Failed to transmit DPD response")); | |
65c25746 | 1918 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1919 | "failed to get buffer to send.\n"); |
1920 | return errno; | |
1921 | } | |
1922 | ||
1923 | ru_ack = (struct isakmp_pl_ru *)payload->v; | |
1924 | ru_ack->h.np = ISAKMP_NPTYPE_NONE; | |
1925 | ru_ack->h.len = htons(tlen); | |
1926 | ru_ack->doi = htonl(IPSEC_DOI); | |
1927 | ru_ack->type = htons(ISAKMP_NTYPE_R_U_THERE_ACK); | |
1928 | ru_ack->proto_id = IPSECDOI_PROTO_ISAKMP; /* XXX ? */ | |
1929 | ru_ack->spi_size = sizeof(isakmp_index); | |
1930 | memcpy(ru_ack->i_ck, ru->i_ck, sizeof(cookie_t)); | |
1931 | memcpy(ru_ack->r_ck, ru->r_ck, sizeof(cookie_t)); | |
1932 | ru_ack->data = ru->data; | |
1933 | ||
1934 | /* XXX Should we do FLAG_A ? */ | |
1935 | error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, | |
1936 | ISAKMP_FLAG_E); | |
1937 | vfree(payload); | |
d1e348cf A |
1938 | if (error) { |
1939 | IPSECSESSIONTRACEREVENT(iph1->parent_session, | |
1940 | IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_TX_FAIL, | |
1941 | CONSTSTR("R-U-THERE? ACK"), | |
1942 | CONSTSTR("Failed to transmit DPD ack")); | |
1943 | } else { | |
1944 | IPSECSESSIONTRACEREVENT(iph1->parent_session, | |
1945 | IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_TX_SUCC, | |
1946 | CONSTSTR("R-U-THERE? ACK"), | |
1947 | CONSTSTR(NULL)); | |
1948 | } | |
52b7d2ce | 1949 | |
7ebaebe2 | 1950 | plog(ASL_LEVEL_NOTICE, "received a valid R-U-THERE, ACK sent\n"); |
52b7d2ce A |
1951 | |
1952 | /* Should we mark tunnel as active ? */ | |
1953 | return error; | |
1954 | } | |
1955 | ||
1956 | static int | |
65c25746 | 1957 | isakmp_info_recv_r_u_ack (phase1_handle_t *iph1, struct isakmp_pl_ru *ru, u_int32_t msgid) |
52b7d2ce A |
1958 | { |
1959 | ||
7ebaebe2 | 1960 | plog(ASL_LEVEL_NOTICE, |
52b7d2ce A |
1961 | "DPD R-U-There-Ack received\n"); |
1962 | ||
1963 | /* XXX Maintain window of acceptable sequence numbers ? | |
1964 | * => ru->data <= iph2->dpd_seq && | |
1965 | * ru->data >= iph2->dpd_seq - iph2->dpd_fails ? */ | |
d1e348cf | 1966 | if (ntohl(ru->data) != iph1->dpd_seq) { |
65c25746 | 1967 | plog(ASL_LEVEL_ERR, |
52b7d2ce | 1968 | "Wrong DPD sequence number (%d, %d expected).\n", |
d1e348cf | 1969 | ntohl(ru->data), iph1->dpd_seq); |
52b7d2ce A |
1970 | return 0; |
1971 | } | |
1972 | ||
1973 | if (memcmp(ru->i_ck, iph1->index.i_ck, sizeof(cookie_t)) || | |
1974 | memcmp(ru->r_ck, iph1->index.r_ck, sizeof(cookie_t))) { | |
65c25746 | 1975 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1976 | "Cookie mismatch in DPD ACK!.\n"); |
1977 | return 0; | |
1978 | } | |
1979 | ||
1980 | iph1->dpd_fails = 0; | |
1981 | ||
d1e348cf A |
1982 | iph1->dpd_seq++; |
1983 | ||
52b7d2ce A |
1984 | /* Useless ??? */ |
1985 | iph1->dpd_lastack = time(NULL); | |
1986 | ||
d1e348cf | 1987 | SCHED_KILL(iph1->dpd_r_u); |
52b7d2ce A |
1988 | |
1989 | isakmp_sched_r_u(iph1, 0); | |
1990 | ||
d1e348cf A |
1991 | if (iph1->side == INITIATOR) { |
1992 | IPSECSESSIONTRACEREVENT(iph1->parent_session, | |
1993 | IPSECSESSIONEVENTCODE_IKEV1_DPD_INIT_RESP, | |
1994 | CONSTSTR("Initiator DPD Response"), | |
1995 | CONSTSTR(NULL)); | |
1996 | } else { | |
1997 | IPSECSESSIONTRACEREVENT(iph1->parent_session, | |
1998 | IPSECSESSIONEVENTCODE_IKEV1_DPD_RESP_RESP, | |
1999 | CONSTSTR("Responder DPD Response"), | |
2000 | CONSTSTR(NULL)); | |
2001 | } | |
7ebaebe2 | 2002 | plog(ASL_LEVEL_NOTICE, "received an R-U-THERE-ACK\n"); |
52b7d2ce | 2003 | |
e8d9021d A |
2004 | #ifdef ENABLE_VPNCONTROL_PORT |
2005 | vpncontrol_notify_peer_resp_ph1(1, iph1); | |
2006 | #endif /* ENABLE_VPNCONTROL_PORT */ | |
2007 | ||
52b7d2ce A |
2008 | return 0; |
2009 | } | |
2010 | ||
2011 | ||
2012 | /* | |
2013 | * send Delete payload (for ISAKMP SA) in Informational exchange. | |
2014 | */ | |
d1e348cf | 2015 | void |
65c25746 | 2016 | isakmp_info_send_r_u(void *arg) |
52b7d2ce | 2017 | { |
65c25746 | 2018 | phase1_handle_t *iph1 = arg; |
52b7d2ce A |
2019 | |
2020 | /* create R-U-THERE payload */ | |
2021 | struct isakmp_pl_ru *ru; | |
2022 | vchar_t *payload = NULL; | |
2023 | int tlen; | |
2024 | int error = 0; | |
2025 | ||
65c25746 | 2026 | if (!FSM_STATE_IS_ESTABLISHED(iph1->status)) { |
7ebaebe2 | 2027 | plog(ASL_LEVEL_NOTICE, "DPD r-u send aborted, invalid Phase 1 status %d....\n", |
d1e348cf A |
2028 | iph1->status); |
2029 | return; | |
2030 | } | |
52b7d2ce A |
2031 | |
2032 | if (iph1->dpd_fails >= iph1->rmconf->dpd_maxfails) { | |
d1e348cf A |
2033 | IPSECSESSIONTRACEREVENT(iph1->parent_session, |
2034 | IPSECSESSIONEVENTCODE_IKEV1_DPD_MAX_RETRANSMIT, | |
2035 | CONSTSTR("DPD maximum retransmits"), | |
2036 | CONSTSTR("maxed-out of DPD requests without receiving an ack")); | |
2037 | ||
d06a7ccb | 2038 | (void)vpncontrol_notify_ike_failed(VPNCTL_NTYPE_PEER_DEAD, FROM_LOCAL, iph1_get_remote_v4_address(iph1), 0, NULL); |
d1e348cf | 2039 | |
52b7d2ce | 2040 | purge_remote(iph1); |
7ebaebe2 | 2041 | plog(ASL_LEVEL_NOTICE, |
52b7d2ce A |
2042 | "DPD: remote seems to be dead\n"); |
2043 | ||
2044 | /* Do not reschedule here: phase1 is deleted, | |
2045 | * DPD will be reactivated when a new ph1 will be negociated | |
2046 | */ | |
2047 | return; | |
2048 | } | |
2049 | ||
52b7d2ce A |
2050 | tlen = sizeof(*ru); |
2051 | payload = vmalloc(tlen); | |
2052 | if (payload == NULL) { | |
d1e348cf A |
2053 | IPSECSESSIONTRACEREVENT(iph1->parent_session, |
2054 | IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_TX_FAIL, | |
2055 | CONSTSTR("R-U-THERE?"), | |
2056 | CONSTSTR("Failed to transmit DPD request")); | |
65c25746 | 2057 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
2058 | "failed to get buffer for payload.\n"); |
2059 | return; | |
2060 | } | |
2061 | ru = (struct isakmp_pl_ru *)payload->v; | |
2062 | ru->h.np = ISAKMP_NPTYPE_NONE; | |
2063 | ru->h.len = htons(tlen); | |
2064 | ru->doi = htonl(IPSEC_DOI); | |
2065 | ru->type = htons(ISAKMP_NTYPE_R_U_THERE); | |
2066 | ru->proto_id = IPSECDOI_PROTO_ISAKMP; /* XXX ?*/ | |
2067 | ru->spi_size = sizeof(isakmp_index); | |
2068 | ||
2069 | memcpy(ru->i_ck, iph1->index.i_ck, sizeof(cookie_t)); | |
2070 | memcpy(ru->r_ck, iph1->index.r_ck, sizeof(cookie_t)); | |
2071 | ||
2072 | if (iph1->dpd_seq == 0){ | |
2073 | /* generate a random seq which is not too big */ | |
2074 | srand(time(NULL)); | |
2075 | iph1->dpd_seq = rand() & 0x0fff; | |
2076 | } | |
2077 | ||
2078 | ru->data = htonl(iph1->dpd_seq); | |
2079 | ||
2080 | error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, 0); | |
2081 | vfree(payload); | |
d1e348cf A |
2082 | if (error) { |
2083 | IPSECSESSIONTRACEREVENT(iph1->parent_session, | |
2084 | IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_TX_FAIL, | |
2085 | CONSTSTR("R-U-THERE?"), | |
2086 | CONSTSTR("Failed to transmit DPD request")); | |
2087 | } else { | |
2088 | IPSECSESSIONTRACEREVENT(iph1->parent_session, | |
2089 | IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_TX_SUCC, | |
2090 | CONSTSTR("R-U-THERE?"), | |
2091 | CONSTSTR(NULL)); | |
2092 | } | |
52b7d2ce | 2093 | |
d1e348cf A |
2094 | if (iph1->side == INITIATOR) { |
2095 | IPSECSESSIONTRACEREVENT(iph1->parent_session, | |
2096 | iph1->dpd_fails? IPSECSESSIONEVENTCODE_IKEV1_DPD_INIT_RETRANSMIT : IPSECSESSIONEVENTCODE_IKEV1_DPD_INIT_REQ, | |
2097 | CONSTSTR("Initiator DPD Request"), | |
2098 | CONSTSTR(NULL)); | |
2099 | } else { | |
2100 | IPSECSESSIONTRACEREVENT(iph1->parent_session, | |
2101 | iph1->dpd_fails? IPSECSESSIONEVENTCODE_IKEV1_DPD_RESP_RETRANSMIT : IPSECSESSIONEVENTCODE_IKEV1_DPD_RESP_REQ, | |
2102 | CONSTSTR("Responder DPD Request"), | |
2103 | CONSTSTR(NULL)); | |
2104 | } | |
7ebaebe2 | 2105 | plog(ASL_LEVEL_NOTICE, |
52b7d2ce A |
2106 | "DPD R-U-There sent (%d)\n", error); |
2107 | ||
2108 | /* will be decreased if ACK received... */ | |
2109 | iph1->dpd_fails++; | |
2110 | ||
52b7d2ce A |
2111 | /* Reschedule the r_u_there with a short delay, |
2112 | * will be deleted/rescheduled if ACK received before */ | |
2113 | isakmp_sched_r_u(iph1, 1); | |
2114 | ||
7ebaebe2 | 2115 | plog(ASL_LEVEL_NOTICE, |
52b7d2ce A |
2116 | "rescheduling send_r_u (%d).\n", iph1->rmconf->dpd_retry); |
2117 | } | |
2118 | ||
d1e348cf A |
2119 | /* |
2120 | * monitor DPD (ALGORITHM_INBOUND_DETECT) Informational exchange. | |
2121 | */ | |
2122 | static void | |
65c25746 | 2123 | isakmp_info_monitor_r_u_algo_inbound_detect (phase1_handle_t *iph1) |
d1e348cf | 2124 | { |
65c25746 | 2125 | if (!FSM_STATE_IS_ESTABLISHED(iph1->status)) { |
7ebaebe2 | 2126 | plog(ASL_LEVEL_NOTICE, "DPD monitoring (for ALGORITHM_INBOUND_DETECT) aborted, invalid Phase 1 status %d....\n", |
d1e348cf A |
2127 | iph1->status); |
2128 | return; | |
2129 | } | |
2130 | ||
7ebaebe2 | 2131 | plog(ASL_LEVEL_NOTICE, "DPD monitoring (for ALGORITHM_INBOUND_DETECT) ....\n"); |
d1e348cf A |
2132 | |
2133 | // check phase1 for ike packets received from peer | |
2134 | if (iph1->peer_sent_ike) { | |
2135 | // yes, reshedule check | |
2136 | iph1->peer_sent_ike = 0; | |
2137 | ||
2138 | /* ike packets received from peer... reschedule dpd */ | |
2139 | isakmp_sched_r_u(iph1, 0); | |
2140 | ||
7ebaebe2 | 2141 | plog(ASL_LEVEL_NOTICE, |
d1e348cf A |
2142 | "ike packets received from peer... reschedule monitor.\n"); |
2143 | ||
2144 | return; | |
2145 | } | |
2146 | ||
2147 | // after ike packets, next we check if any data was received | |
2148 | if (!iph1->parent_session->peer_sent_data_sc_dpd) { | |
2149 | isakmp_info_send_r_u(iph1); | |
2150 | } else { | |
2151 | isakmp_sched_r_u(iph1, 0); | |
2152 | ||
7ebaebe2 | 2153 | plog(ASL_LEVEL_NOTICE, |
d1e348cf A |
2154 | "rescheduling DPD monitoring (for ALGORITHM_INBOUND_DETECT).\n"); |
2155 | } | |
2156 | iph1->parent_session->peer_sent_data_sc_dpd = 0; | |
2157 | } | |
2158 | ||
2159 | /* | |
e8d9021d | 2160 | * monitor DPD (ALGORITHM_BLACKHOLE_DETECT) Informational exchange. |
d1e348cf A |
2161 | */ |
2162 | static void | |
65c25746 | 2163 | isakmp_info_monitor_r_u_algo_blackhole_detect (phase1_handle_t *iph1) |
d1e348cf | 2164 | { |
65c25746 | 2165 | if (!FSM_STATE_IS_ESTABLISHED(iph1->status)) { |
7ebaebe2 | 2166 | plog(ASL_LEVEL_NOTICE, "DPD monitoring (for ALGORITHM_BLACKHOLE_DETECT) aborted, invalid Phase 1 status %d....\n", |
d1e348cf A |
2167 | iph1->status); |
2168 | return; | |
2169 | } | |
2170 | ||
7ebaebe2 | 2171 | plog(ASL_LEVEL_NOTICE, "DPD monitoring (for ALGORITHM_BLACKHOLE_DETECT) ....\n"); |
d1e348cf A |
2172 | |
2173 | // check if data was sent but none was received | |
2174 | if (iph1->parent_session->i_sent_data_sc_dpd && | |
2175 | !iph1->parent_session->peer_sent_data_sc_dpd) { | |
2176 | isakmp_info_send_r_u(iph1); | |
2177 | } else { | |
2178 | isakmp_sched_r_u(iph1, 0); | |
2179 | ||
7ebaebe2 | 2180 | plog(ASL_LEVEL_NOTICE, |
d1e348cf A |
2181 | "rescheduling DPD monitoring (for ALGORITHM_BLACKHOLE_DETECT) i = %d, peer %d.\n", |
2182 | iph1->parent_session->i_sent_data_sc_dpd, | |
2183 | iph1->parent_session->peer_sent_data_sc_dpd); | |
2184 | } | |
2185 | iph1->parent_session->i_sent_data_sc_dpd = 0; | |
2186 | iph1->parent_session->peer_sent_data_sc_dpd = 0; | |
2187 | } | |
2188 | ||
2189 | /* | |
2190 | * monitor DPD Informational exchange. | |
2191 | */ | |
2192 | static void | |
65c25746 | 2193 | isakmp_info_monitor_r_u(void *arg) |
d1e348cf | 2194 | { |
65c25746 | 2195 | phase1_handle_t *iph1 = arg; |
d1e348cf A |
2196 | |
2197 | if (iph1 && iph1->rmconf) { | |
2198 | if (iph1->rmconf->dpd_algo == DPD_ALGO_INBOUND_DETECT) { | |
2199 | isakmp_info_monitor_r_u_algo_inbound_detect(iph1); | |
2200 | } else if (iph1->rmconf->dpd_algo == DPD_ALGO_BLACKHOLE_DETECT) { | |
2201 | isakmp_info_monitor_r_u_algo_blackhole_detect(iph1); | |
2202 | } else { | |
7ebaebe2 | 2203 | plog(ASL_LEVEL_NOTICE, "DPD monitoring aborted, invalid algorithm %d....\n", |
d1e348cf A |
2204 | iph1->rmconf->dpd_algo); |
2205 | } | |
2206 | } | |
2207 | } | |
2208 | ||
52b7d2ce A |
2209 | /* Schedule a new R-U-THERE */ |
2210 | int | |
65c25746 | 2211 | isakmp_sched_r_u(phase1_handle_t *iph1, int retry) |
52b7d2ce A |
2212 | { |
2213 | if(iph1 == NULL || | |
2214 | iph1->rmconf == NULL) | |
2215 | return 1; | |
2216 | ||
2217 | ||
2218 | if(iph1->dpd_support == 0 || | |
2219 | iph1->rmconf->dpd_interval == 0) | |
2220 | return 0; | |
2221 | ||
d1e348cf | 2222 | if(retry) { |
52b7d2ce | 2223 | iph1->dpd_r_u = sched_new(iph1->rmconf->dpd_retry, |
d1e348cf A |
2224 | isakmp_info_send_r_u, iph1); |
2225 | } else { | |
2226 | if (iph1->rmconf->dpd_algo == DPD_ALGO_INBOUND_DETECT || | |
2227 | iph1->rmconf->dpd_algo == DPD_ALGO_BLACKHOLE_DETECT) { | |
2228 | iph1->dpd_r_u = sched_new(iph1->rmconf->dpd_interval, | |
2229 | isakmp_info_monitor_r_u, iph1); | |
2230 | } else { | |
2231 | iph1->dpd_r_u = sched_new(iph1->rmconf->dpd_interval, | |
2232 | isakmp_info_send_r_u, iph1); | |
2233 | } | |
2234 | } | |
52b7d2ce A |
2235 | |
2236 | return 0; | |
2237 | } | |
d1e348cf A |
2238 | |
2239 | /* | |
2240 | * punts dpd for later because of some activity that: | |
2241 | * 1) implicitly does dpd (e.g. phase2 exchanges), or | |
2242 | * 2) indicates liveness (e.g. received ike packets). | |
2243 | */ | |
2244 | void | |
65c25746 | 2245 | isakmp_reschedule_info_monitor_if_pending (phase1_handle_t *iph1, char *reason) |
d1e348cf A |
2246 | { |
2247 | if (!iph1 || | |
65c25746 | 2248 | !FSM_STATE_IS_ESTABLISHED(iph1->status) || |
d1e348cf A |
2249 | !iph1->dpd_support || |
2250 | !iph1->rmconf->dpd_interval || | |
2251 | iph1->rmconf->dpd_algo == DPD_ALGO_DEFAULT) { | |
2252 | return; | |
2253 | } | |
2254 | ||
2255 | if (!iph1->peer_sent_ike) { | |
2256 | SCHED_KILL(iph1->dpd_r_u); | |
2257 | ||
2258 | isakmp_sched_r_u(iph1, 0); | |
2259 | ||
7ebaebe2 | 2260 | plog(ASL_LEVEL_NOTICE, |
d1e348cf A |
2261 | "%s... rescheduling send_r_u.\n", |
2262 | reason); | |
2263 | } | |
2264 | iph1->peer_sent_ike++; | |
2265 | } | |
52b7d2ce | 2266 | #endif |