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