File: | src/sbin/isakmpd/sa.c |
Warning: | line 820, column 9 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: sa.c,v 1.124 2017/12/05 20:31:45 jca Exp $ */ | |||
2 | /* $EOM: sa.c,v 1.112 2000/12/12 00:22:52 niklas Exp $ */ | |||
3 | ||||
4 | /* | |||
5 | * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. | |||
6 | * Copyright (c) 1999, 2001 Angelos D. Keromytis. All rights reserved. | |||
7 | * Copyright (c) 2003, 2004 Håkan Olsson. 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 | * | |||
18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||
19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |||
22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |||
23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |||
27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
28 | */ | |||
29 | ||||
30 | /* | |||
31 | * This code was written under funding by Ericsson Radio Systems. | |||
32 | */ | |||
33 | ||||
34 | #include <sys/types.h> | |||
35 | #include <sys/un.h> | |||
36 | ||||
37 | #include <stdlib.h> | |||
38 | #include <string.h> | |||
39 | #include <netdb.h> | |||
40 | ||||
41 | #include <regex.h> | |||
42 | #include <keynote.h> | |||
43 | ||||
44 | #include "attribute.h" | |||
45 | #include "conf.h" | |||
46 | #include "connection.h" | |||
47 | #include "cookie.h" | |||
48 | #include "doi.h" | |||
49 | #include "dpd.h" | |||
50 | #include "exchange.h" | |||
51 | #include "isakmp.h" | |||
52 | #include "log.h" | |||
53 | #include "message.h" | |||
54 | #include "monitor.h" | |||
55 | #include "sa.h" | |||
56 | #include "timer.h" | |||
57 | #include "transport.h" | |||
58 | #include "util.h" | |||
59 | #include "cert.h" | |||
60 | #include "policy.h" | |||
61 | #include "key.h" | |||
62 | #include "ipsec.h" | |||
63 | #include "ipsec_num.h" | |||
64 | ||||
65 | /* Initial number of bits from the cookies used as hash. */ | |||
66 | #define INITIAL_BUCKET_BITS6 6 | |||
67 | ||||
68 | /* | |||
69 | * Don't try to use more bits than this as a hash. | |||
70 | * We only XOR 16 bits so going above that means changing the code below | |||
71 | * too. | |||
72 | */ | |||
73 | #define MAX_BUCKET_BITS16 16 | |||
74 | ||||
75 | #if 0 | |||
76 | static void sa_resize(void); | |||
77 | #endif | |||
78 | static void sa_soft_expire(void *); | |||
79 | static void sa_hard_expire(void *); | |||
80 | ||||
81 | static int _net_addrcmp(struct sockaddr *, struct sockaddr *); | |||
82 | ||||
83 | static LIST_HEAD(sa_list, sa)struct sa_list { struct sa *lh_first; } *sa_tab; | |||
84 | ||||
85 | /* Works both as a maximum index and a mask. */ | |||
86 | static int bucket_mask; | |||
87 | ||||
88 | void | |||
89 | sa_init(void) | |||
90 | { | |||
91 | int i; | |||
92 | ||||
93 | bucket_mask = (1 << INITIAL_BUCKET_BITS6) - 1; | |||
94 | sa_tab = calloc(bucket_mask + 1, sizeof(struct sa_list)); | |||
95 | if (!sa_tab) | |||
96 | log_fatal("sa_init: malloc (%lu) failed", | |||
97 | (bucket_mask + 1) * (unsigned long)sizeof(struct sa_list)); | |||
98 | for (i = 0; i <= bucket_mask; i++) | |||
99 | LIST_INIT(&sa_tab[i])do { ((&sa_tab[i])->lh_first) = ((void *)0); } while ( 0); | |||
100 | } | |||
101 | ||||
102 | #if 0 | |||
103 | /* XXX We don't yet resize. */ | |||
104 | static void | |||
105 | sa_resize(void) | |||
106 | { | |||
107 | int new_mask = (bucket_mask + 1) * 2 - 1; | |||
108 | int i; | |||
109 | struct sa_list *new_tab; | |||
110 | ||||
111 | new_tab = reallocarray(sa_tab, new_mask + 1, sizeof(struct sa_list)); | |||
112 | if (!new_tab) | |||
113 | return; | |||
114 | sa_tab = new_tab; | |||
115 | for (i = bucket_mask + 1; i <= new_mask; i++) | |||
116 | LIST_INIT(&sa_tab[i])do { ((&sa_tab[i])->lh_first) = ((void *)0); } while ( 0); | |||
117 | bucket_mask = new_mask; | |||
118 | ||||
119 | /* XXX Rehash existing entries. */ | |||
120 | } | |||
121 | #endif | |||
122 | ||||
123 | /* Lookup an SA with the help from a user-supplied checking function. */ | |||
124 | struct sa * | |||
125 | sa_find(int (*check) (struct sa*, void *), void *arg) | |||
126 | { | |||
127 | int i; | |||
128 | struct sa *sa; | |||
129 | ||||
130 | for (i = 0; i <= bucket_mask; i++) | |||
131 | for (sa = LIST_FIRST(&sa_tab[i])((&sa_tab[i])->lh_first); sa; sa = LIST_NEXT(sa, link)((sa)->link.le_next)) | |||
132 | if (check(sa, arg)) { | |||
133 | LOG_DBG((LOG_SA, 90, "sa_find: return SA %p",log_debug (LOG_SA, 90, "sa_find: return SA %p", sa) | |||
134 | sa))log_debug (LOG_SA, 90, "sa_find: return SA %p", sa); | |||
135 | return sa; | |||
136 | } | |||
137 | LOG_DBG((LOG_SA, 90, "sa_find: no SA matched query"))log_debug (LOG_SA, 90, "sa_find: no SA matched query"); | |||
138 | return 0; | |||
139 | } | |||
140 | ||||
141 | /* Check if SA is an ISAKMP SA with an initiator cookie equal to ICOOKIE. */ | |||
142 | static int | |||
143 | sa_check_icookie(struct sa *sa, void *icookie) | |||
144 | { | |||
145 | return sa->phase == 1 && | |||
146 | memcmp(sa->cookies, icookie, ISAKMP_HDR_ICOOKIE_LEN8) == 0; | |||
147 | } | |||
148 | ||||
149 | /* Lookup an ISAKMP SA out of just the initiator cookie. */ | |||
150 | struct sa * | |||
151 | sa_lookup_from_icookie(u_int8_t *cookie) | |||
152 | { | |||
153 | return sa_find(sa_check_icookie, cookie); | |||
154 | } | |||
155 | ||||
156 | struct name_phase_arg { | |||
157 | char *name; | |||
158 | u_int8_t phase; | |||
159 | }; | |||
160 | ||||
161 | /* Check if SA has the name and phase given by V_ARG. */ | |||
162 | static int | |||
163 | sa_check_name_phase(struct sa *sa, void *v_arg) | |||
164 | { | |||
165 | struct name_phase_arg *arg = v_arg; | |||
166 | ||||
167 | return sa->name && strcasecmp(sa->name, arg->name) == 0 && | |||
168 | sa->phase == arg->phase && !(sa->flags & SA_FLAG_REPLACED0x08); | |||
169 | } | |||
170 | ||||
171 | /* Lookup an SA by name, case-independent, and phase. */ | |||
172 | struct sa * | |||
173 | sa_lookup_by_name(char *name, int phase) | |||
174 | { | |||
175 | struct name_phase_arg arg; | |||
176 | ||||
177 | arg.name = name; | |||
178 | arg.phase = phase; | |||
179 | return sa_find(sa_check_name_phase, &arg); | |||
180 | } | |||
181 | ||||
182 | struct addr_arg { | |||
183 | struct sockaddr *addr; | |||
184 | socklen_t len; | |||
185 | int phase; | |||
186 | int flags; | |||
187 | }; | |||
188 | ||||
189 | /* | |||
190 | * This function has been removed from libc and put here as this | |||
191 | * file is the only user for it. | |||
192 | */ | |||
193 | static int | |||
194 | _net_addrcmp(struct sockaddr *sa1, struct sockaddr *sa2) | |||
195 | { | |||
196 | ||||
197 | if (sa1->sa_len != sa2->sa_len) | |||
198 | return (sa1->sa_len < sa2->sa_len) ? -1 : 1; | |||
199 | if (sa1->sa_family != sa2->sa_family) | |||
200 | return (sa1->sa_family < sa2->sa_family) ? -1 : 1; | |||
201 | ||||
202 | switch(sa1->sa_family) { | |||
203 | case AF_INET2: | |||
204 | return (memcmp(&((struct sockaddr_in *)sa1)->sin_addr, | |||
205 | &((struct sockaddr_in *)sa2)->sin_addr, | |||
206 | sizeof(struct in_addr))); | |||
207 | case AF_INET624: | |||
208 | if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != | |||
209 | ((struct sockaddr_in6 *)sa2)->sin6_scope_id) | |||
210 | return (((struct sockaddr_in6 *)sa1)->sin6_scope_id < | |||
211 | ((struct sockaddr_in6 *)sa2)->sin6_scope_id) | |||
212 | ? -1 : 1; | |||
213 | return memcmp(&((struct sockaddr_in6 *)sa1)->sin6_addr, | |||
214 | &((struct sockaddr_in6 *)sa2)->sin6_addr, | |||
215 | sizeof(struct in6_addr)); | |||
216 | case AF_LOCAL1: | |||
217 | return (strcmp(((struct sockaddr_un *)sa1)->sun_path, | |||
218 | ((struct sockaddr_un *)sa2)->sun_path)); | |||
219 | default: | |||
220 | return -1; | |||
221 | } | |||
222 | } | |||
223 | ||||
224 | /* | |||
225 | * Check if SA is ready and has a peer with an address equal the one given | |||
226 | * by V_ADDR. Furthermore if we are searching for a specific phase, check | |||
227 | * that too. | |||
228 | */ | |||
229 | static int | |||
230 | sa_check_peer(struct sa *sa, void *v_addr) | |||
231 | { | |||
232 | struct addr_arg *addr = v_addr; | |||
233 | struct sockaddr *dst; | |||
234 | ||||
235 | if (!sa->transport || (sa->flags & SA_FLAG_READY0x01) == 0 || | |||
236 | (addr->phase && addr->phase != sa->phase)) | |||
237 | return 0; | |||
238 | ||||
239 | sa->transport->vtbl->get_dst(sa->transport, &dst); | |||
240 | if (_net_addrcmp(dst, addr->addr) != 0) | |||
241 | return 0; | |||
242 | ||||
243 | /* same family, length and address, check port if inet/inet6 */ | |||
244 | switch (dst->sa_family) { | |||
245 | case AF_INET2: | |||
246 | return ((struct sockaddr_in *)dst)->sin_port == ((struct sockaddr_in *)addr->addr)->sin_port; | |||
247 | case AF_INET624: | |||
248 | return ((struct sockaddr_in6 *)dst)->sin6_port == ((struct sockaddr_in6 *)addr->addr)->sin6_port; | |||
249 | } | |||
250 | ||||
251 | return 1; | |||
252 | } | |||
253 | ||||
254 | struct dst_isakmpspi_arg { | |||
255 | struct sockaddr *dst; | |||
256 | u_int8_t *spi; /* must be ISAKMP_SPI_SIZE octets */ | |||
257 | }; | |||
258 | ||||
259 | /* | |||
260 | * Check if SA matches what we are asking for through V_ARG. It has to | |||
261 | * be a finished phase 1 (ISAKMP) SA. | |||
262 | */ | |||
263 | static int | |||
264 | isakmp_sa_check(struct sa *sa, void *v_arg) | |||
265 | { | |||
266 | struct dst_isakmpspi_arg *arg = v_arg; | |||
267 | struct sockaddr *dst, *src; | |||
268 | ||||
269 | if (sa->phase != 1 || !(sa->flags & SA_FLAG_READY0x01)) | |||
270 | return 0; | |||
271 | ||||
272 | /* verify address is either src or dst for this sa */ | |||
273 | sa->transport->vtbl->get_dst(sa->transport, &dst); | |||
274 | sa->transport->vtbl->get_src(sa->transport, &src); | |||
275 | if (memcmp(src, arg->dst, SA_LEN(src)((src)->sa_len)) && | |||
276 | memcmp(dst, arg->dst, SA_LEN(dst)((dst)->sa_len))) | |||
277 | return 0; | |||
278 | ||||
279 | /* match icookie+rcookie against spi */ | |||
280 | if (memcmp(sa->cookies, arg->spi, ISAKMP_HDR_COOKIES_LEN(8 + 8)) == 0) | |||
281 | return 1; | |||
282 | ||||
283 | return 0; | |||
284 | } | |||
285 | ||||
286 | /* | |||
287 | * Find an ISAKMP SA with a "name" of DST & SPI. | |||
288 | */ | |||
289 | struct sa * | |||
290 | sa_lookup_isakmp_sa(struct sockaddr *dst, u_int8_t *spi) | |||
291 | { | |||
292 | struct dst_isakmpspi_arg arg; | |||
293 | ||||
294 | arg.dst = dst; | |||
295 | arg.spi = spi; | |||
296 | ||||
297 | return sa_find(isakmp_sa_check, &arg); | |||
298 | } | |||
299 | ||||
300 | /* Lookup a ready SA by the peer's address. */ | |||
301 | struct sa * | |||
302 | sa_lookup_by_peer(struct sockaddr *dst, socklen_t dstlen, int phase) | |||
303 | { | |||
304 | struct addr_arg arg; | |||
305 | ||||
306 | arg.addr = dst; | |||
307 | arg.len = dstlen; | |||
308 | arg.phase = phase; | |||
309 | ||||
310 | return sa_find(sa_check_peer, &arg); | |||
311 | } | |||
312 | ||||
313 | /* Lookup a ready ISAKMP SA given its peer address. */ | |||
314 | struct sa * | |||
315 | sa_isakmp_lookup_by_peer(struct sockaddr *dst, socklen_t dstlen) | |||
316 | { | |||
317 | struct addr_arg arg; | |||
318 | ||||
319 | arg.addr = dst; | |||
320 | arg.len = dstlen; | |||
321 | arg.phase = 1; | |||
322 | ||||
323 | return sa_find(sa_check_peer, &arg); | |||
324 | } | |||
325 | ||||
326 | int | |||
327 | sa_enter(struct sa *sa) | |||
328 | { | |||
329 | u_int16_t bucket = 0; | |||
330 | int i; | |||
331 | u_int8_t *cp; | |||
332 | ||||
333 | /* XXX We might resize if we are crossing a certain threshold */ | |||
334 | ||||
335 | for (i = 0; i < ISAKMP_HDR_COOKIES_LEN(8 + 8); i += 2) { | |||
336 | cp = sa->cookies + i; | |||
337 | /* Doing it this way avoids alignment problems. */ | |||
338 | bucket ^= cp[0] | cp[1] << 8; | |||
339 | } | |||
340 | for (i = 0; i < ISAKMP_HDR_MESSAGE_ID_LEN4; i += 2) { | |||
341 | cp = sa->message_id + i; | |||
342 | /* Doing it this way avoids alignment problems. */ | |||
343 | bucket ^= cp[0] | cp[1] << 8; | |||
344 | } | |||
345 | bucket &= bucket_mask; | |||
346 | LIST_INSERT_HEAD(&sa_tab[bucket], sa, link)do { if (((sa)->link.le_next = (&sa_tab[bucket])->lh_first ) != ((void *)0)) (&sa_tab[bucket])->lh_first->link .le_prev = &(sa)->link.le_next; (&sa_tab[bucket])-> lh_first = (sa); (sa)->link.le_prev = &(&sa_tab[bucket ])->lh_first; } while (0); | |||
347 | sa_reference(sa); | |||
348 | LOG_DBG((LOG_SA, 70, "sa_enter: SA %p added to SA list", sa))log_debug (LOG_SA, 70, "sa_enter: SA %p added to SA list", sa ); | |||
349 | return 1; | |||
350 | } | |||
351 | ||||
352 | /* | |||
353 | * Lookup the SA given by the header fields MSG. PHASE2 is false when | |||
354 | * looking for phase 1 SAa and true otherwise. | |||
355 | */ | |||
356 | struct sa * | |||
357 | sa_lookup_by_header(u_int8_t *msg, int phase2) | |||
358 | { | |||
359 | return sa_lookup(msg + ISAKMP_HDR_COOKIES_OFF0, | |||
360 | phase2 ? msg + ISAKMP_HDR_MESSAGE_ID_OFF20 : 0); | |||
361 | } | |||
362 | ||||
363 | /* | |||
364 | * Lookup the SA given by the COOKIES and possibly the MESSAGE_ID unless | |||
365 | * a null pointer, meaning we are looking for phase 1 SAs. | |||
366 | */ | |||
367 | struct sa * | |||
368 | sa_lookup(u_int8_t *cookies, u_int8_t *message_id) | |||
369 | { | |||
370 | u_int16_t bucket = 0; | |||
371 | int i; | |||
372 | struct sa *sa; | |||
373 | u_int8_t *cp; | |||
374 | ||||
375 | /* | |||
376 | * We use the cookies to get bits to use as an index into sa_tab, as at | |||
377 | * least one (our cookie) is a good hash, xoring all the bits, 16 at a | |||
378 | * time, and then masking, should do. Doing it this way means we can | |||
379 | * validate cookies very fast thus delimiting the effects of "Denial of | |||
380 | * service"-attacks using packet flooding. | |||
381 | */ | |||
382 | for (i = 0; i < ISAKMP_HDR_COOKIES_LEN(8 + 8); i += 2) { | |||
383 | cp = cookies + i; | |||
384 | /* Doing it this way avoids alignment problems. */ | |||
385 | bucket ^= cp[0] | cp[1] << 8; | |||
386 | } | |||
387 | if (message_id) | |||
388 | for (i = 0; i < ISAKMP_HDR_MESSAGE_ID_LEN4; i += 2) { | |||
389 | cp = message_id + i; | |||
390 | /* Doing it this way avoids alignment problems. */ | |||
391 | bucket ^= cp[0] | cp[1] << 8; | |||
392 | } | |||
393 | bucket &= bucket_mask; | |||
394 | for (sa = LIST_FIRST(&sa_tab[bucket])((&sa_tab[bucket])->lh_first); | |||
395 | sa && (memcmp(cookies, sa->cookies, ISAKMP_HDR_COOKIES_LEN(8 + 8)) != 0 || | |||
396 | (message_id && memcmp(message_id, sa->message_id, | |||
397 | ISAKMP_HDR_MESSAGE_ID_LEN4) != 0) || | |||
398 | (!message_id && !zero_test(sa->message_id, ISAKMP_HDR_MESSAGE_ID_LEN4))); | |||
399 | sa = LIST_NEXT(sa, link)((sa)->link.le_next)) | |||
400 | ; | |||
401 | ||||
402 | return sa; | |||
403 | } | |||
404 | ||||
405 | /* Create an SA. */ | |||
406 | int | |||
407 | sa_create(struct exchange *exchange, struct transport *t) | |||
408 | { | |||
409 | struct sa *sa; | |||
410 | ||||
411 | /* | |||
412 | * We want the SA zeroed for sa_free to be able to find out what fields | |||
413 | * have been filled-in. | |||
414 | */ | |||
415 | sa = calloc(1, sizeof *sa); | |||
416 | if (!sa) { | |||
417 | log_error("sa_create: calloc (1, %lu) failed", | |||
418 | (unsigned long)sizeof *sa); | |||
419 | return -1; | |||
420 | } | |||
421 | sa->transport = t; | |||
422 | if (t) | |||
423 | transport_reference(t); | |||
424 | sa->phase = exchange->phase; | |||
425 | memcpy(sa->cookies, exchange->cookies, ISAKMP_HDR_COOKIES_LEN(8 + 8)); | |||
426 | memcpy(sa->message_id, exchange->message_id, | |||
427 | ISAKMP_HDR_MESSAGE_ID_LEN4); | |||
428 | sa->doi = exchange->doi; | |||
429 | sa->policy_id = -1; | |||
430 | ||||
431 | if (sa->doi->sa_size) { | |||
432 | /* | |||
433 | * Allocate the DOI-specific structure and initialize it to | |||
434 | * zeroes. | |||
435 | */ | |||
436 | sa->data = calloc(1, sa->doi->sa_size); | |||
437 | if (!sa->data) { | |||
438 | log_error("sa_create: calloc (1, %lu) failed", | |||
439 | (unsigned long)sa->doi->sa_size); | |||
440 | free(sa); | |||
441 | return -1; | |||
442 | } | |||
443 | } | |||
444 | TAILQ_INIT(&sa->protos)do { (&sa->protos)->tqh_first = ((void *)0); (& sa->protos)->tqh_last = &(&sa->protos)->tqh_first ; } while (0); | |||
445 | ||||
446 | sa_enter(sa); | |||
447 | TAILQ_INSERT_TAIL(&exchange->sa_list, sa, next)do { (sa)->next.tqe_next = ((void *)0); (sa)->next.tqe_prev = (&exchange->sa_list)->tqh_last; *(&exchange-> sa_list)->tqh_last = (sa); (&exchange->sa_list)-> tqh_last = &(sa)->next.tqe_next; } while (0); | |||
448 | sa_reference(sa); | |||
449 | ||||
450 | LOG_DBG((LOG_SA, 60,log_debug (LOG_SA, 60, "sa_create: sa %p phase %d added to exchange %p (%s)" , sa, sa->phase, exchange, exchange->name ? exchange-> name : "<unnamed>") | |||
451 | "sa_create: sa %p phase %d added to exchange %p (%s)", sa,log_debug (LOG_SA, 60, "sa_create: sa %p phase %d added to exchange %p (%s)" , sa, sa->phase, exchange, exchange->name ? exchange-> name : "<unnamed>") | |||
452 | sa->phase, exchange,log_debug (LOG_SA, 60, "sa_create: sa %p phase %d added to exchange %p (%s)" , sa, sa->phase, exchange, exchange->name ? exchange-> name : "<unnamed>") | |||
453 | exchange->name ? exchange->name : "<unnamed>"))log_debug (LOG_SA, 60, "sa_create: sa %p phase %d added to exchange %p (%s)" , sa, sa->phase, exchange, exchange->name ? exchange-> name : "<unnamed>"); | |||
454 | return 0; | |||
455 | } | |||
456 | ||||
457 | /* | |||
458 | * Dump the internal state of SA to the report channel, with HEADER | |||
459 | * prepended to each line. | |||
460 | */ | |||
461 | void | |||
462 | sa_dump(int cls, int level, char *header, struct sa *sa) | |||
463 | { | |||
464 | struct proto *proto; | |||
465 | char spi_header[80]; | |||
466 | int i; | |||
467 | ||||
468 | LOG_DBG((cls, level, "%s: %p %s phase %d doi %d flags 0x%x", header,log_debug (cls, level, "%s: %p %s phase %d doi %d flags 0x%x" , header, sa, sa->name ? sa->name : "<unnamed>", sa ->phase, sa->doi->id, sa->flags) | |||
469 | sa, sa->name ? sa->name : "<unnamed>", sa->phase, sa->doi->id,log_debug (cls, level, "%s: %p %s phase %d doi %d flags 0x%x" , header, sa, sa->name ? sa->name : "<unnamed>", sa ->phase, sa->doi->id, sa->flags) | |||
470 | sa->flags))log_debug (cls, level, "%s: %p %s phase %d doi %d flags 0x%x" , header, sa, sa->name ? sa->name : "<unnamed>", sa ->phase, sa->doi->id, sa->flags); | |||
471 | LOG_DBG((cls, level, "%s: icookie %08x%08x rcookie %08x%08x", header,log_debug (cls, level, "%s: icookie %08x%08x rcookie %08x%08x" , header, decode_32(sa->cookies), decode_32(sa->cookies + 4), decode_32(sa->cookies + 8), decode_32(sa->cookies + 12)) | |||
472 | decode_32(sa->cookies), decode_32(sa->cookies + 4),log_debug (cls, level, "%s: icookie %08x%08x rcookie %08x%08x" , header, decode_32(sa->cookies), decode_32(sa->cookies + 4), decode_32(sa->cookies + 8), decode_32(sa->cookies + 12)) | |||
473 | decode_32(sa->cookies + 8), decode_32(sa->cookies + 12)))log_debug (cls, level, "%s: icookie %08x%08x rcookie %08x%08x" , header, decode_32(sa->cookies), decode_32(sa->cookies + 4), decode_32(sa->cookies + 8), decode_32(sa->cookies + 12)); | |||
474 | LOG_DBG((cls, level, "%s: msgid %08x refcnt %d", header,log_debug (cls, level, "%s: msgid %08x refcnt %d", header, decode_32 (sa->message_id), sa->refcnt) | |||
475 | decode_32(sa->message_id), sa->refcnt))log_debug (cls, level, "%s: msgid %08x refcnt %d", header, decode_32 (sa->message_id), sa->refcnt); | |||
476 | LOG_DBG((cls, level, "%s: life secs %llu kb %llu", header, sa->seconds,log_debug (cls, level, "%s: life secs %llu kb %llu", header, sa ->seconds, sa->kilobytes) | |||
477 | sa->kilobytes))log_debug (cls, level, "%s: life secs %llu kb %llu", header, sa ->seconds, sa->kilobytes); | |||
478 | for (proto = TAILQ_FIRST(&sa->protos)((&sa->protos)->tqh_first); proto; | |||
479 | proto = TAILQ_NEXT(proto, link)((proto)->link.tqe_next)) { | |||
480 | LOG_DBG((cls, level, "%s: suite %d proto %d", header,log_debug (cls, level, "%s: suite %d proto %d", header, proto ->no, proto->proto) | |||
481 | proto->no, proto->proto))log_debug (cls, level, "%s: suite %d proto %d", header, proto ->no, proto->proto); | |||
482 | LOG_DBG((cls, level,log_debug (cls, level, "%s: spi_sz[0] %d spi[0] %p spi_sz[1] %d spi[1] %p" , header, proto->spi_sz[0], proto->spi[0], proto->spi_sz [1], proto->spi[1]) | |||
483 | "%s: spi_sz[0] %d spi[0] %p spi_sz[1] %d spi[1] %p",log_debug (cls, level, "%s: spi_sz[0] %d spi[0] %p spi_sz[1] %d spi[1] %p" , header, proto->spi_sz[0], proto->spi[0], proto->spi_sz [1], proto->spi[1]) | |||
484 | header, proto->spi_sz[0], proto->spi[0], proto->spi_sz[1],log_debug (cls, level, "%s: spi_sz[0] %d spi[0] %p spi_sz[1] %d spi[1] %p" , header, proto->spi_sz[0], proto->spi[0], proto->spi_sz [1], proto->spi[1]) | |||
485 | proto->spi[1]))log_debug (cls, level, "%s: spi_sz[0] %d spi[0] %p spi_sz[1] %d spi[1] %p" , header, proto->spi_sz[0], proto->spi[0], proto->spi_sz [1], proto->spi[1]); | |||
486 | LOG_DBG((cls, level, "%s: %s, %s", header,log_debug (cls, level, "%s: %s, %s", header, !sa->doi ? "<nodoi>" : sa->doi->decode_ids("initiator id: %s, responder id: %s" , sa->id_i, sa->id_i_len, sa->id_r, sa->id_r_len, 0), !sa->transport ? "<no transport>" : sa->transport ->vtbl->decode_ids(sa->transport)) | |||
487 | !sa->doi ? "<nodoi>" :log_debug (cls, level, "%s: %s, %s", header, !sa->doi ? "<nodoi>" : sa->doi->decode_ids("initiator id: %s, responder id: %s" , sa->id_i, sa->id_i_len, sa->id_r, sa->id_r_len, 0), !sa->transport ? "<no transport>" : sa->transport ->vtbl->decode_ids(sa->transport)) | |||
488 | sa->doi->decode_ids("initiator id: %s, responder id: %s",log_debug (cls, level, "%s: %s, %s", header, !sa->doi ? "<nodoi>" : sa->doi->decode_ids("initiator id: %s, responder id: %s" , sa->id_i, sa->id_i_len, sa->id_r, sa->id_r_len, 0), !sa->transport ? "<no transport>" : sa->transport ->vtbl->decode_ids(sa->transport)) | |||
489 | sa->id_i, sa->id_i_len,log_debug (cls, level, "%s: %s, %s", header, !sa->doi ? "<nodoi>" : sa->doi->decode_ids("initiator id: %s, responder id: %s" , sa->id_i, sa->id_i_len, sa->id_r, sa->id_r_len, 0), !sa->transport ? "<no transport>" : sa->transport ->vtbl->decode_ids(sa->transport)) | |||
490 | sa->id_r, sa->id_r_len, 0),log_debug (cls, level, "%s: %s, %s", header, !sa->doi ? "<nodoi>" : sa->doi->decode_ids("initiator id: %s, responder id: %s" , sa->id_i, sa->id_i_len, sa->id_r, sa->id_r_len, 0), !sa->transport ? "<no transport>" : sa->transport ->vtbl->decode_ids(sa->transport)) | |||
491 | !sa->transport ? "<no transport>" :log_debug (cls, level, "%s: %s, %s", header, !sa->doi ? "<nodoi>" : sa->doi->decode_ids("initiator id: %s, responder id: %s" , sa->id_i, sa->id_i_len, sa->id_r, sa->id_r_len, 0), !sa->transport ? "<no transport>" : sa->transport ->vtbl->decode_ids(sa->transport)) | |||
492 | sa->transport->vtbl->decode_ids(sa->transport)))log_debug (cls, level, "%s: %s, %s", header, !sa->doi ? "<nodoi>" : sa->doi->decode_ids("initiator id: %s, responder id: %s" , sa->id_i, sa->id_i_len, sa->id_r, sa->id_r_len, 0), !sa->transport ? "<no transport>" : sa->transport ->vtbl->decode_ids(sa->transport)); | |||
493 | for (i = 0; i < 2; i++) | |||
494 | if (proto->spi[i]) { | |||
495 | snprintf(spi_header, sizeof spi_header, | |||
496 | "%s: spi[%d]", header, i); | |||
497 | LOG_DBG_BUF((cls, level, spi_header,log_debug_buf (cls, level, spi_header, proto->spi[i], proto ->spi_sz[i]) | |||
498 | proto->spi[i], proto->spi_sz[i]))log_debug_buf (cls, level, spi_header, proto->spi[i], proto ->spi_sz[i]); | |||
499 | } | |||
500 | } | |||
501 | } | |||
502 | ||||
503 | /* | |||
504 | * Display the SA's two SPI values. | |||
505 | */ | |||
506 | static void | |||
507 | report_spi(FILE *fd, const u_int8_t *buf, size_t sz, int spi) | |||
508 | { | |||
509 | #define SBUFSZ(2 * 32 + 9) (2 * 32 + 9) | |||
510 | char s[SBUFSZ(2 * 32 + 9)]; | |||
511 | size_t i, j; | |||
512 | ||||
513 | for (i = j = 0; i < sz;) { | |||
514 | snprintf(s + j, sizeof s - j, "%02x", buf[i++]); | |||
515 | j += strlen(s + j); | |||
516 | if (i % 4 == 0) { | |||
517 | if (i % 32 == 0) { | |||
518 | s[j] = '\0'; | |||
519 | fprintf(fd, "%s", s); | |||
520 | j = 0; | |||
521 | } else | |||
522 | s[j++] = ' '; | |||
523 | } | |||
524 | } | |||
525 | ||||
526 | if (j) { | |||
527 | s[j] = '\0'; | |||
528 | fprintf(fd, "SPI %d: %s\n", spi, s); | |||
529 | } | |||
530 | } | |||
531 | ||||
532 | /* | |||
533 | * Display the transform names to file. | |||
534 | * Structure is taken from pf_key_v2.c, pf_key_v2_set_spi. | |||
535 | * Transform names are taken from /usr/src/sys/crypto/xform.c. | |||
536 | */ | |||
537 | static void | |||
538 | report_proto(FILE *fd, struct proto *proto) | |||
539 | { | |||
540 | struct ipsec_proto *iproto; | |||
541 | int keylen, hashlen; | |||
542 | ||||
543 | switch (proto->proto) { | |||
544 | case IPSEC_PROTO_IPSEC_ESP3: | |||
545 | keylen = ipsec_esp_enckeylength(proto); | |||
546 | hashlen = ipsec_esp_authkeylength(proto); | |||
547 | fprintf(fd, "Transform: IPsec ESP\n"); | |||
548 | fprintf(fd, "Encryption key length: %d\n", keylen); | |||
549 | fprintf(fd, "Authentication key length: %d\n", hashlen); | |||
550 | ||||
551 | fprintf(fd, "Encryption algorithm: "); | |||
552 | switch (proto->id) { | |||
553 | case IPSEC_ESP_3DES3: | |||
554 | fprintf(fd, "3DES\n"); | |||
555 | break; | |||
556 | ||||
557 | case IPSEC_ESP_AES12: | |||
558 | fprintf(fd, "AES (CBC)\n"); | |||
559 | break; | |||
560 | ||||
561 | case IPSEC_ESP_AES_CTR13: | |||
562 | fprintf(fd, "AES (CTR)\n"); | |||
563 | break; | |||
564 | ||||
565 | case IPSEC_ESP_AES_GCM_1620: | |||
566 | fprintf(fd, "AES (GCM)\n"); | |||
567 | break; | |||
568 | ||||
569 | case IPSEC_ESP_AES_GMAC23: | |||
570 | fprintf(fd, "AES (GMAC)\n"); | |||
571 | break; | |||
572 | ||||
573 | case IPSEC_ESP_CAST6: | |||
574 | fprintf(fd, "Cast-128\n"); | |||
575 | break; | |||
576 | ||||
577 | case IPSEC_ESP_BLOWFISH7: | |||
578 | fprintf(fd, "Blowfish\n"); | |||
579 | break; | |||
580 | ||||
581 | default: | |||
582 | fprintf(fd, "unknown (%d)\n", proto->id); | |||
583 | } | |||
584 | ||||
585 | fprintf(fd, "Authentication algorithm: "); | |||
586 | ||||
587 | if (!proto->data) { | |||
588 | fprintf(fd, "none\n"); | |||
589 | break; | |||
590 | } | |||
591 | iproto = proto->data; | |||
592 | ||||
593 | switch (iproto->auth) { | |||
594 | case IPSEC_AUTH_HMAC_MD51: | |||
595 | fprintf(fd, "HMAC-MD5\n"); | |||
596 | break; | |||
597 | ||||
598 | case IPSEC_AUTH_HMAC_SHA2: | |||
599 | fprintf(fd, "HMAC-SHA1\n"); | |||
600 | break; | |||
601 | ||||
602 | case IPSEC_AUTH_HMAC_RIPEMD8: | |||
603 | fprintf(fd, "HMAC-RIPEMD-160\n"); | |||
604 | break; | |||
605 | ||||
606 | case IPSEC_AUTH_HMAC_SHA2_2565: | |||
607 | fprintf(fd, "HMAC-SHA2-256\n"); | |||
608 | break; | |||
609 | ||||
610 | case IPSEC_AUTH_HMAC_SHA2_3846: | |||
611 | fprintf(fd, "HMAC-SHA2-384\n"); | |||
612 | break; | |||
613 | ||||
614 | case IPSEC_AUTH_HMAC_SHA2_5127: | |||
615 | fprintf(fd, "HMAC-SHA2-512\n"); | |||
616 | break; | |||
617 | ||||
618 | case IPSEC_AUTH_DES_MAC3: | |||
619 | case IPSEC_AUTH_KPDK4: | |||
620 | /* XXX We should be supporting KPDK */ | |||
621 | fprintf(fd, "unknown (%d)", iproto->auth); | |||
622 | break; | |||
623 | ||||
624 | default: | |||
625 | fprintf(fd, "none\n"); | |||
626 | } | |||
627 | break; | |||
628 | ||||
629 | case IPSEC_PROTO_IPSEC_AH2: | |||
630 | hashlen = ipsec_ah_keylength(proto); | |||
631 | fprintf(fd, "Transform: IPsec AH\n"); | |||
632 | fprintf(fd, "Encryption not used.\n"); | |||
633 | fprintf(fd, "Authentication key length: %d\n", hashlen); | |||
634 | ||||
635 | fprintf(fd, "Authentication algorithm: "); | |||
636 | switch (proto->id) { | |||
637 | case IPSEC_AH_MD52: | |||
638 | fprintf(fd, "HMAC-MD5\n"); | |||
639 | break; | |||
640 | ||||
641 | case IPSEC_AH_SHA3: | |||
642 | fprintf(fd, "HMAC-SHA1\n"); | |||
643 | break; | |||
644 | ||||
645 | case IPSEC_AH_RIPEMD8: | |||
646 | fprintf(fd, "HMAC-RIPEMD-160\n"); | |||
647 | break; | |||
648 | ||||
649 | case IPSEC_AH_SHA2_2565: | |||
650 | fprintf(fd, "HMAC-SHA2-256\n"); | |||
651 | break; | |||
652 | ||||
653 | case IPSEC_AH_SHA2_3846: | |||
654 | fprintf(fd, "HMAC-SHA2-384\n"); | |||
655 | break; | |||
656 | ||||
657 | case IPSEC_AH_SHA2_5127: | |||
658 | fprintf(fd, "HMAC-SHA2-512\n"); | |||
659 | break; | |||
660 | ||||
661 | default: | |||
662 | fprintf(fd, "unknown (%d)", proto->id); | |||
663 | } | |||
664 | break; | |||
665 | ||||
666 | default: | |||
667 | fprintf(fd, "report_proto: invalid proto %d\n", proto->proto); | |||
668 | } | |||
669 | } | |||
670 | ||||
671 | /* | |||
672 | * Display SA lifetimes. | |||
673 | */ | |||
674 | static void | |||
675 | report_lifetimes(FILE *fd, struct sa *sa) | |||
676 | { | |||
677 | long timeout; | |||
678 | ||||
679 | if (sa->seconds) | |||
680 | fprintf(fd, "Lifetime: %llu seconds\n", sa->seconds); | |||
681 | ||||
682 | if (sa->soft_death) { | |||
683 | timeout = get_timeout(&sa->soft_death->expiration); | |||
684 | if (timeout < 0) | |||
685 | fprintf(fd, "<no soft timeout>\n"); | |||
686 | else | |||
687 | fprintf(fd, "Soft timeout in %ld seconds\n", timeout); | |||
688 | } | |||
689 | ||||
690 | if (sa->death) { | |||
691 | timeout = get_timeout(&sa->death->expiration); | |||
692 | if (timeout < 0) | |||
693 | fprintf(fd, "No hard timeout>\n"); | |||
694 | else | |||
695 | fprintf(fd, "Hard timeout in %ld seconds\n", timeout); | |||
696 | } | |||
697 | ||||
698 | if (sa->kilobytes) | |||
699 | fprintf(fd, "Lifetime: %llu kilobytes\n", sa->kilobytes); | |||
700 | } | |||
701 | ||||
702 | /* | |||
703 | * Print phase 1 specific information. | |||
704 | */ | |||
705 | static void | |||
706 | report_phase1(FILE *fd, struct sa *sa) | |||
707 | { | |||
708 | /* Cookies. */ | |||
709 | fprintf(fd, "icookie %08x%08x rcookie %08x%08x\n", | |||
710 | decode_32(sa->cookies), decode_32(sa->cookies + 4), | |||
711 | decode_32(sa->cookies + 8), decode_32(sa->cookies + 12)); | |||
712 | } | |||
713 | ||||
714 | /* | |||
715 | * Print phase 2 specific information. | |||
716 | */ | |||
717 | static void | |||
718 | report_phase2(FILE *fd, struct sa *sa) | |||
719 | { | |||
720 | struct proto *proto; | |||
721 | int i; | |||
722 | ||||
723 | /* Transform information. */ | |||
724 | for (proto = TAILQ_FIRST(&sa->protos)((&sa->protos)->tqh_first); proto; | |||
725 | proto = TAILQ_NEXT(proto, link)((proto)->link.tqe_next)) { | |||
726 | ||||
727 | /* SPI values. */ | |||
728 | for (i = 0; i < 2; i++) | |||
729 | if (proto->spi[i]) | |||
730 | report_spi(fd, proto->spi[i], | |||
731 | proto->spi_sz[i], i); | |||
732 | else | |||
733 | fprintf(fd, "SPI %d not defined.\n", i); | |||
734 | ||||
735 | /* Proto values. */ | |||
736 | report_proto(fd, proto); | |||
737 | } | |||
738 | } | |||
739 | ||||
740 | /* Report all the SAs to the report channel. */ | |||
741 | void | |||
742 | sa_report(void) | |||
743 | { | |||
744 | struct sa *sa; | |||
745 | int i; | |||
746 | ||||
747 | for (i = 0; i <= bucket_mask; i++) | |||
748 | for (sa = LIST_FIRST(&sa_tab[i])((&sa_tab[i])->lh_first); sa; sa = LIST_NEXT(sa, link)((sa)->link.le_next)) | |||
749 | sa_dump(LOG_REPORT-2, 0, "sa_report", sa); | |||
750 | } | |||
751 | ||||
752 | /* | |||
753 | * Print an SA's connection details to file SA_FILE. | |||
754 | */ | |||
755 | static void | |||
756 | sa_dump_all(FILE *fd, struct sa *sa) | |||
757 | { | |||
758 | /* SA name and phase. */ | |||
759 | fprintf(fd, "SA name: %s", sa->name ? sa->name : "<unnamed>"); | |||
760 | fprintf(fd, " (Phase %d%s)\n", sa->phase, sa->phase == 1 ? | |||
761 | (sa->initiator ? "/Initiator" : "/Responder") : ""); | |||
762 | ||||
763 | /* Source and destination IPs. */ | |||
764 | fprintf(fd, "%s", sa->transport == NULL((void *)0) ? "<no transport>" : | |||
765 | sa->transport->vtbl->decode_ids(sa->transport)); | |||
766 | fprintf(fd, "\n"); | |||
767 | ||||
768 | /* Lifetimes */ | |||
769 | report_lifetimes(fd, sa); | |||
770 | ||||
771 | fprintf(fd, "Flags 0x%08x\n", sa->flags); | |||
772 | ||||
773 | if (sa->phase == 1) | |||
774 | report_phase1(fd, sa); | |||
775 | else if (sa->phase == 2) | |||
776 | report_phase2(fd, sa); | |||
777 | else { | |||
778 | /* Should not happen, but... */ | |||
779 | fprintf(fd, "<unknown phase>\n"); | |||
780 | } | |||
781 | ||||
782 | /* SA separator. */ | |||
783 | fprintf(fd, "\n"); | |||
784 | } | |||
785 | ||||
786 | /* Report info of all SAs to file 'fd'. */ | |||
787 | void | |||
788 | sa_report_all(FILE *fd) | |||
789 | { | |||
790 | struct sa *sa; | |||
791 | int i; | |||
792 | ||||
793 | for (i = 0; i <= bucket_mask; i++) | |||
794 | for (sa = LIST_FIRST(&sa_tab[i])((&sa_tab[i])->lh_first); sa; sa = LIST_NEXT(sa, link)((sa)->link.le_next)) | |||
795 | sa_dump_all(fd, sa); | |||
796 | } | |||
797 | ||||
798 | /* Free the protocol structure pointed to by PROTO. */ | |||
799 | void | |||
800 | proto_free(struct proto *proto) | |||
801 | { | |||
802 | struct proto_attr *pa; | |||
803 | struct sa *sa = proto->sa; | |||
804 | int i; | |||
805 | ||||
806 | for (i = 0; i < 2; i++) | |||
| ||||
807 | if (proto->spi[i]) { | |||
808 | if (sa->doi->delete_spi) | |||
809 | sa->doi->delete_spi(sa, proto, i); | |||
810 | free(proto->spi[i]); | |||
811 | } | |||
812 | TAILQ_REMOVE(&sa->protos, proto, link)do { if (((proto)->link.tqe_next) != ((void *)0)) (proto)-> link.tqe_next->link.tqe_prev = (proto)->link.tqe_prev; else (&sa->protos)->tqh_last = (proto)->link.tqe_prev ; *(proto)->link.tqe_prev = (proto)->link.tqe_next; ; ; } while (0); | |||
813 | if (proto->data) { | |||
814 | if (sa->doi && sa->doi->free_proto_data) | |||
815 | sa->doi->free_proto_data(proto->data); | |||
816 | free(proto->data); | |||
817 | } | |||
818 | if (proto->xf_cnt) | |||
819 | while ((pa = TAILQ_FIRST(&proto->xfs)((&proto->xfs)->tqh_first)) != NULL((void *)0)) { | |||
820 | free(pa->attrs); | |||
| ||||
821 | TAILQ_REMOVE(&proto->xfs, pa, next)do { if (((pa)->next.tqe_next) != ((void *)0)) (pa)->next .tqe_next->next.tqe_prev = (pa)->next.tqe_prev; else (& proto->xfs)->tqh_last = (pa)->next.tqe_prev; *(pa)-> next.tqe_prev = (pa)->next.tqe_next; ; ; } while (0); | |||
822 | free(pa); | |||
823 | } | |||
824 | ||||
825 | LOG_DBG((LOG_SA, 90, "proto_free: freeing %p", proto))log_debug (LOG_SA, 90, "proto_free: freeing %p", proto); | |||
826 | free(proto); | |||
827 | } | |||
828 | ||||
829 | /* Release all resources this SA is using. */ | |||
830 | void | |||
831 | sa_free(struct sa *sa) | |||
832 | { | |||
833 | if (sa->death) { | |||
834 | timer_remove_event(sa->death); | |||
835 | sa->death = 0; | |||
836 | sa->refcnt--; | |||
837 | } | |||
838 | if (sa->soft_death) { | |||
839 | timer_remove_event(sa->soft_death); | |||
840 | sa->soft_death = 0; | |||
841 | sa->refcnt--; | |||
842 | } | |||
843 | if (sa->dpd_event) { | |||
844 | timer_remove_event(sa->dpd_event); | |||
845 | sa->dpd_event = 0; | |||
846 | } | |||
847 | sa_remove(sa); | |||
848 | } | |||
849 | ||||
850 | /* Remove the SA from the hash table of live SAs. */ | |||
851 | void | |||
852 | sa_remove(struct sa *sa) | |||
853 | { | |||
854 | LIST_REMOVE(sa, link)do { if ((sa)->link.le_next != ((void *)0)) (sa)->link. le_next->link.le_prev = (sa)->link.le_prev; *(sa)->link .le_prev = (sa)->link.le_next; ; ; } while (0); | |||
855 | LOG_DBG((LOG_SA, 70, "sa_remove: SA %p removed from SA list", sa))log_debug (LOG_SA, 70, "sa_remove: SA %p removed from SA list" , sa); | |||
856 | sa_release(sa); | |||
857 | } | |||
858 | ||||
859 | /* Raise the reference count of SA. */ | |||
860 | void | |||
861 | sa_reference(struct sa *sa) | |||
862 | { | |||
863 | sa->refcnt++; | |||
864 | LOG_DBG((LOG_SA, 80, "sa_reference: SA %p now has %d references",log_debug (LOG_SA, 80, "sa_reference: SA %p now has %d references" , sa, sa->refcnt) | |||
865 | sa, sa->refcnt))log_debug (LOG_SA, 80, "sa_reference: SA %p now has %d references" , sa, sa->refcnt); | |||
866 | } | |||
867 | ||||
868 | /* Release a reference to SA. */ | |||
869 | void | |||
870 | sa_release(struct sa *sa) | |||
871 | { | |||
872 | struct cert_handler *handler; | |||
873 | struct proto *proto; | |||
874 | ||||
875 | LOG_DBG((LOG_SA, 80, "sa_release: SA %p had %d references",log_debug (LOG_SA, 80, "sa_release: SA %p had %d references", sa, sa->refcnt) | |||
876 | sa, sa->refcnt))log_debug (LOG_SA, 80, "sa_release: SA %p had %d references", sa, sa->refcnt); | |||
877 | ||||
878 | if (--sa->refcnt) | |||
879 | return; | |||
880 | ||||
881 | LOG_DBG((LOG_SA, 60, "sa_release: freeing SA %p", sa))log_debug (LOG_SA, 60, "sa_release: freeing SA %p", sa); | |||
882 | ||||
883 | while ((proto = TAILQ_FIRST(&sa->protos)((&sa->protos)->tqh_first)) != 0) | |||
884 | proto_free(proto); | |||
885 | if (sa->data) { | |||
886 | if (sa->doi && sa->doi->free_sa_data) | |||
887 | sa->doi->free_sa_data(sa->data); | |||
888 | free(sa->data); | |||
889 | } | |||
890 | free(sa->id_i); | |||
891 | free(sa->id_r); | |||
892 | if (sa->recv_cert) { | |||
893 | handler = cert_get(sa->recv_certtype); | |||
894 | if (handler) | |||
895 | handler->cert_free(sa->recv_cert); | |||
896 | } | |||
897 | if (sa->sent_cert) { | |||
898 | handler = cert_get(sa->sent_certtype); | |||
899 | if (handler) | |||
900 | handler->cert_free(sa->sent_cert); | |||
901 | } | |||
902 | if (sa->recv_key) | |||
903 | key_free(sa->recv_keytype, ISAKMP_KEYTYPE_PUBLIC0, | |||
904 | sa->recv_key); | |||
905 | free(sa->keynote_key); /* This is just a string */ | |||
906 | if (sa->policy_id != -1) | |||
907 | kn_close(sa->policy_id); | |||
908 | free(sa->name); | |||
909 | free(sa->keystate); | |||
910 | if (sa->nat_t_keepalive) | |||
911 | timer_remove_event(sa->nat_t_keepalive); | |||
912 | if (sa->dpd_event) | |||
913 | timer_remove_event(sa->dpd_event); | |||
914 | if (sa->transport) | |||
915 | transport_release(sa->transport); | |||
916 | free(sa->tag); | |||
917 | free(sa); | |||
918 | } | |||
919 | ||||
920 | /* | |||
921 | * Rehash the ISAKMP SA this MSG is negotiating with the responder cookie | |||
922 | * filled in. | |||
923 | */ | |||
924 | void | |||
925 | sa_isakmp_upgrade(struct message *msg) | |||
926 | { | |||
927 | struct sa *sa = TAILQ_FIRST(&msg->exchange->sa_list)((&msg->exchange->sa_list)->tqh_first); | |||
928 | ||||
929 | sa_remove(sa); | |||
930 | GET_ISAKMP_HDR_RCOOKIE(msg->iov[0].iov_base,field_get_raw (isakmp_hdr_fld + 1, msg->iov[0].iov_base, sa ->cookies + 8) | |||
931 | sa->cookies + ISAKMP_HDR_ICOOKIE_LEN)field_get_raw (isakmp_hdr_fld + 1, msg->iov[0].iov_base, sa ->cookies + 8); | |||
932 | ||||
933 | /* | |||
934 | * We don't install a transport in the initiator case as we don't know | |||
935 | * what local address will be chosen. Do it now instead. | |||
936 | */ | |||
937 | sa->transport = msg->transport; | |||
938 | transport_reference(sa->transport); | |||
939 | sa_enter(sa); | |||
940 | } | |||
941 | ||||
942 | #define ATTRS_SIZE(17 + 1) (IKE_ATTR_BLOCK_SIZE17 + 1) /* XXX Should be dynamic. */ | |||
943 | ||||
944 | struct attr_validation_state { | |||
945 | u_int8_t *attrp[ATTRS_SIZE(17 + 1)]; | |||
946 | u_int8_t checked[ATTRS_SIZE(17 + 1)]; | |||
947 | u_int16_t len[ATTRS_SIZE(17 + 1)]; | |||
948 | int phase; /* IKE (1) or IPSEC (2) attrs? */ | |||
949 | int mode; /* 0 = 'load', 1 = check */ | |||
950 | }; | |||
951 | ||||
952 | /* Validate an attribute. Return 0 on match. */ | |||
953 | static int | |||
954 | sa_validate_xf_attrs(u_int16_t type, u_int8_t *value, u_int16_t len, | |||
955 | void *arg) | |||
956 | { | |||
957 | int val0, val1; | |||
958 | ||||
959 | struct attr_validation_state *avs = | |||
960 | (struct attr_validation_state *)arg; | |||
961 | ||||
962 | LOG_DBG((LOG_SA, 95, "sa_validate_xf_attrs: phase %d mode %d type %d "log_debug (LOG_SA, 95, "sa_validate_xf_attrs: phase %d mode %d type %d " "len %d", avs->phase, avs->mode, type, len) | |||
963 | "len %d", avs->phase, avs->mode, type, len))log_debug (LOG_SA, 95, "sa_validate_xf_attrs: phase %d mode %d type %d " "len %d", avs->phase, avs->mode, type, len); | |||
964 | ||||
965 | /* Make sure the phase and type are valid. */ | |||
966 | if (avs->phase == 1) { | |||
967 | if (type < IKE_ATTR_ENCRYPTION_ALGORITHM1 || | |||
968 | type > IKE_ATTR_BLOCK_SIZE17) | |||
969 | return 1; | |||
970 | } else if (avs->phase == 2) { | |||
971 | if (type < IPSEC_ATTR_SA_LIFE_TYPE1 || | |||
972 | type > IPSEC_ATTR_ECN_TUNNEL10) | |||
973 | return 1; | |||
974 | } else | |||
975 | return 1; | |||
976 | ||||
977 | if (avs->mode == 0) { /* Load attrs. */ | |||
978 | avs->attrp[type] = value; | |||
979 | avs->len[type] = len; | |||
980 | return 0; | |||
981 | } | |||
982 | /* Checking for a missing attribute is an immediate failure. */ | |||
983 | if (!avs->attrp[type]) | |||
984 | return 1; | |||
985 | ||||
986 | /* Match the loaded attribute against this one, mark it as checked. */ | |||
987 | avs->checked[type]++; | |||
988 | switch (len) { | |||
989 | case 2: | |||
990 | val0 = (int)decode_16(value); | |||
991 | break; | |||
992 | case 4: | |||
993 | val0 = (int)decode_32(value); | |||
994 | break; | |||
995 | default: | |||
996 | return 1; | |||
997 | } | |||
998 | switch (avs->len[type]) { | |||
999 | case 2: | |||
1000 | val1 = (int)decode_16(avs->attrp[type]); | |||
1001 | break; | |||
1002 | case 4: | |||
1003 | val1 = (int)decode_32(avs->attrp[type]); | |||
1004 | break; | |||
1005 | default: | |||
1006 | return 1; | |||
1007 | } | |||
1008 | /* Return 0 when the values are equal. */ | |||
1009 | return (val0 != val1); | |||
1010 | } | |||
1011 | ||||
1012 | /* | |||
1013 | * This function is used to validate the returned proposal (protection suite) | |||
1014 | * we get from the responder against a proposal we sent. Only run as initiator. | |||
1015 | * We return 0 if a match is found (in any transform of this proposal), 1 | |||
1016 | * otherwise. Also see note in sa_add_transform() below. | |||
1017 | */ | |||
1018 | static int | |||
1019 | sa_validate_proto_xf(struct proto *match, struct payload *xf, int phase) | |||
1020 | { | |||
1021 | struct attr_validation_state *avs; | |||
1022 | struct proto_attr *pa; | |||
1023 | int found = 0; | |||
1024 | size_t i; | |||
1025 | u_int8_t xf_id; | |||
1026 | ||||
1027 | if (!match->xf_cnt) | |||
1028 | return 0; | |||
1029 | ||||
1030 | if (match->proto != GET_ISAKMP_PROP_PROTO(xf->context->p)field_get_num (isakmp_prop_fld + 1, xf->context->p)) { | |||
1031 | LOG_DBG((LOG_SA, 70, "sa_validate_proto_xf: proto %p (#%d) "log_debug (LOG_SA, 70, "sa_validate_proto_xf: proto %p (#%d) " "protocol mismatch", match, match->no) | |||
1032 | "protocol mismatch", match, match->no))log_debug (LOG_SA, 70, "sa_validate_proto_xf: proto %p (#%d) " "protocol mismatch", match, match->no); | |||
1033 | return 1; | |||
1034 | } | |||
1035 | avs = calloc(1, sizeof *avs); | |||
1036 | if (!avs) { | |||
1037 | log_error("sa_validate_proto_xf: calloc (1, %lu)", | |||
1038 | (unsigned long)sizeof *avs); | |||
1039 | return 1; | |||
1040 | } | |||
1041 | avs->phase = phase; | |||
1042 | ||||
1043 | /* Load the "proposal candidate" attribute set. */ | |||
1044 | (void)attribute_map(xf->p + ISAKMP_TRANSFORM_SA_ATTRS_OFF8, | |||
1045 | GET_ISAKMP_GEN_LENGTH(xf->p)field_get_num (isakmp_gen_fld + 2, xf->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF8, | |||
1046 | sa_validate_xf_attrs, avs); | |||
1047 | xf_id = GET_ISAKMP_TRANSFORM_ID(xf->p)field_get_num (isakmp_transform_fld + 1, xf->p); | |||
1048 | ||||
1049 | /* Check against the transforms we suggested. */ | |||
1050 | avs->mode++; | |||
1051 | for (pa = TAILQ_FIRST(&match->xfs)((&match->xfs)->tqh_first); pa && !found; | |||
1052 | pa = TAILQ_NEXT(pa, next)((pa)->next.tqe_next)) { | |||
1053 | if (xf_id != GET_ISAKMP_TRANSFORM_ID(pa->attrs)field_get_num (isakmp_transform_fld + 1, pa->attrs)) | |||
1054 | continue; | |||
1055 | ||||
1056 | bzero(avs->checked, sizeof avs->checked); | |||
1057 | if (attribute_map(pa->attrs + ISAKMP_TRANSFORM_SA_ATTRS_OFF8, | |||
1058 | pa->len - ISAKMP_TRANSFORM_SA_ATTRS_OFF8, | |||
1059 | sa_validate_xf_attrs, avs) == 0) | |||
1060 | found++; | |||
1061 | ||||
1062 | LOG_DBG((LOG_SA, 80, "sa_validate_proto_xf: attr_map "log_debug (LOG_SA, 80, "sa_validate_proto_xf: attr_map " "xf %p proto %p pa %p found %d" , xf, match, pa, found) | |||
1063 | "xf %p proto %p pa %p found %d", xf, match, pa, found))log_debug (LOG_SA, 80, "sa_validate_proto_xf: attr_map " "xf %p proto %p pa %p found %d" , xf, match, pa, found); | |||
1064 | ||||
1065 | if (!found) | |||
1066 | continue; | |||
1067 | ||||
1068 | /* | |||
1069 | * Require all attributes present and checked. XXX perhaps | |||
1070 | * not? | |||
1071 | */ | |||
1072 | for (i = 0; i < sizeof avs->checked; i++) | |||
1073 | if (avs->attrp[i] && !avs->checked[i]) | |||
1074 | found = 0; | |||
1075 | ||||
1076 | LOG_DBG((LOG_SA, 80, "sa_validate_proto_xf: req_attr "log_debug (LOG_SA, 80, "sa_validate_proto_xf: req_attr " "xf %p proto %p pa %p found %d" , xf, match, pa, found) | |||
1077 | "xf %p proto %p pa %p found %d", xf, match, pa, found))log_debug (LOG_SA, 80, "sa_validate_proto_xf: req_attr " "xf %p proto %p pa %p found %d" , xf, match, pa, found); | |||
1078 | } | |||
1079 | free(avs); | |||
1080 | return found ? 0 : 1; | |||
1081 | } | |||
1082 | ||||
1083 | /* | |||
1084 | * Register the chosen transform XF into SA. As a side effect set PROTOP | |||
1085 | * to point at the corresponding proto structure. INITIATOR is true if we | |||
1086 | * are the initiator. | |||
1087 | */ | |||
1088 | int | |||
1089 | sa_add_transform(struct sa *sa, struct payload *xf, int initiator, | |||
1090 | struct proto **protop) | |||
1091 | { | |||
1092 | struct proto *proto; | |||
1093 | struct payload *prop = xf->context; | |||
1094 | ||||
1095 | *protop = 0; | |||
1096 | if (!initiator) { | |||
1097 | proto = calloc(1, sizeof *proto); | |||
1098 | if (!proto) | |||
1099 | log_error("sa_add_transform: calloc (1, %lu) failed", | |||
1100 | (unsigned long)sizeof *proto); | |||
1101 | } else { | |||
1102 | /* | |||
1103 | * RFC 2408, section 4.2 states the responder SHOULD use the | |||
1104 | * proposal number from the initiator (i.e us), in it's | |||
1105 | * selected proposal to make this lookup easier. Most vendors | |||
1106 | * follow this. One noted exception is the CiscoPIX (and | |||
1107 | * perhaps other Cisco products). | |||
1108 | * | |||
1109 | * We start by matching on the proposal number, as before. | |||
1110 | */ | |||
1111 | for (proto = TAILQ_FIRST(&sa->protos)((&sa->protos)->tqh_first); | |||
1112 | proto && proto->no != GET_ISAKMP_PROP_NO(prop->p)field_get_num (isakmp_prop_fld + 0, prop->p); | |||
1113 | proto = TAILQ_NEXT(proto, link)((proto)->link.tqe_next)) | |||
1114 | ; | |||
1115 | /* | |||
1116 | * If we did not find a match, search through all proposals | |||
1117 | * and xforms. | |||
1118 | */ | |||
1119 | if (!proto || sa_validate_proto_xf(proto, xf, sa->phase) != 0) | |||
1120 | for (proto = TAILQ_FIRST(&sa->protos)((&sa->protos)->tqh_first); | |||
1121 | proto && sa_validate_proto_xf(proto, xf, sa->phase) != 0; | |||
1122 | proto = TAILQ_NEXT(proto, link)((proto)->link.tqe_next)) | |||
1123 | ; | |||
1124 | } | |||
1125 | if (!proto) | |||
1126 | return -1; | |||
1127 | *protop = proto; | |||
1128 | ||||
1129 | /* Allocate DOI-specific part. */ | |||
1130 | if (!initiator) { | |||
1131 | proto->data = calloc(1, sa->doi->proto_size); | |||
1132 | if (!proto->data) { | |||
1133 | log_error("sa_add_transform: calloc (1, %lu) failed", | |||
1134 | (unsigned long)sa->doi->proto_size); | |||
1135 | goto cleanup; | |||
1136 | } | |||
1137 | } | |||
1138 | proto->no = GET_ISAKMP_PROP_NO(prop->p)field_get_num (isakmp_prop_fld + 0, prop->p); | |||
1139 | proto->proto = GET_ISAKMP_PROP_PROTO(prop->p)field_get_num (isakmp_prop_fld + 1, prop->p); | |||
1140 | proto->spi_sz[0] = GET_ISAKMP_PROP_SPI_SZ(prop->p)field_get_num (isakmp_prop_fld + 2, prop->p); | |||
1141 | if (proto->spi_sz[0]) { | |||
1142 | proto->spi[0] = malloc(proto->spi_sz[0]); | |||
1143 | if (!proto->spi[0]) | |||
1144 | goto cleanup; | |||
1145 | memcpy(proto->spi[0], prop->p + ISAKMP_PROP_SPI_OFF8, | |||
1146 | proto->spi_sz[0]); | |||
1147 | } | |||
1148 | proto->chosen = xf; | |||
1149 | proto->sa = sa; | |||
1150 | proto->id = GET_ISAKMP_TRANSFORM_ID(xf->p)field_get_num (isakmp_transform_fld + 1, xf->p); | |||
1151 | if (!initiator) | |||
1152 | TAILQ_INSERT_TAIL(&sa->protos, proto, link)do { (proto)->link.tqe_next = ((void *)0); (proto)->link .tqe_prev = (&sa->protos)->tqh_last; *(&sa-> protos)->tqh_last = (proto); (&sa->protos)->tqh_last = &(proto)->link.tqe_next; } while (0); | |||
1153 | ||||
1154 | /* Let the DOI get at proto for initializing its own data. */ | |||
1155 | if (sa->doi->proto_init) | |||
1156 | sa->doi->proto_init(proto, 0); | |||
1157 | ||||
1158 | LOG_DBG((LOG_SA, 80,log_debug (LOG_SA, 80, "sa_add_transform: " "proto %p no %d proto %d chosen %p sa %p id %d" , proto, proto->no, proto->proto, proto->chosen, proto ->sa, proto->id) | |||
1159 | "sa_add_transform: "log_debug (LOG_SA, 80, "sa_add_transform: " "proto %p no %d proto %d chosen %p sa %p id %d" , proto, proto->no, proto->proto, proto->chosen, proto ->sa, proto->id) | |||
1160 | "proto %p no %d proto %d chosen %p sa %p id %d",log_debug (LOG_SA, 80, "sa_add_transform: " "proto %p no %d proto %d chosen %p sa %p id %d" , proto, proto->no, proto->proto, proto->chosen, proto ->sa, proto->id) | |||
1161 | proto, proto->no, proto->proto, proto->chosen, proto->sa,log_debug (LOG_SA, 80, "sa_add_transform: " "proto %p no %d proto %d chosen %p sa %p id %d" , proto, proto->no, proto->proto, proto->chosen, proto ->sa, proto->id) | |||
1162 | proto->id))log_debug (LOG_SA, 80, "sa_add_transform: " "proto %p no %d proto %d chosen %p sa %p id %d" , proto, proto->no, proto->proto, proto->chosen, proto ->sa, proto->id); | |||
1163 | ||||
1164 | return 0; | |||
1165 | ||||
1166 | cleanup: | |||
1167 | if (!initiator) { | |||
1168 | free(proto->data); | |||
1169 | free(proto); | |||
1170 | } | |||
1171 | *protop = 0; | |||
1172 | return -1; | |||
1173 | } | |||
1174 | ||||
1175 | /* Delete an SA. Tell the peer if NOTIFY is set. */ | |||
1176 | void | |||
1177 | sa_delete(struct sa *sa, int notify) | |||
1178 | { | |||
1179 | if (notify) | |||
1180 | message_send_delete(sa); | |||
1181 | sa_free(sa); | |||
1182 | } | |||
1183 | ||||
1184 | ||||
1185 | /* Teardown all SAs. */ | |||
1186 | void | |||
1187 | sa_teardown_all(void) | |||
1188 | { | |||
1189 | int i; | |||
1190 | struct sa *sa, *next = 0; | |||
1191 | ||||
1192 | LOG_DBG((LOG_SA, 70, "sa_teardown_all:"))log_debug (LOG_SA, 70, "sa_teardown_all:"); | |||
1193 | /* Get Phase 2 SAs. */ | |||
1194 | for (i = 0; i <= bucket_mask; i++) | |||
1195 | for (sa = LIST_FIRST(&sa_tab[i])((&sa_tab[i])->lh_first); sa; sa = next) { | |||
1196 | next = LIST_NEXT(sa, link)((sa)->link.le_next); | |||
1197 | if (sa->phase == 2) { | |||
1198 | /* | |||
1199 | * Teardown the phase 2 SAs by name, similar | |||
1200 | * to ui_teardown. | |||
1201 | */ | |||
1202 | LOG_DBG((LOG_SA, 70,log_debug (LOG_SA, 70, "sa_teardown_all: tearing down SA %s", sa->name ? sa->name : "<unnamed>") | |||
1203 | "sa_teardown_all: tearing down SA %s",log_debug (LOG_SA, 70, "sa_teardown_all: tearing down SA %s", sa->name ? sa->name : "<unnamed>") | |||
1204 | sa->name ? sa->name : "<unnamed>"))log_debug (LOG_SA, 70, "sa_teardown_all: tearing down SA %s", sa->name ? sa->name : "<unnamed>"); | |||
1205 | if (sa->name) | |||
1206 | connection_teardown(sa->name); | |||
1207 | sa_delete(sa, 1); | |||
1208 | } | |||
1209 | } | |||
1210 | } | |||
1211 | ||||
1212 | /* | |||
1213 | * This function will get called when we are closing in on the death time of SA | |||
1214 | */ | |||
1215 | static void | |||
1216 | sa_soft_expire(void *v_sa) | |||
1217 | { | |||
1218 | struct sa *sa = v_sa; | |||
1219 | ||||
1220 | sa->soft_death = 0; | |||
1221 | sa_release(sa); | |||
1222 | ||||
1223 | if ((sa->flags & (SA_FLAG_STAYALIVE0x02 | SA_FLAG_REPLACED0x08)) == | |||
1224 | SA_FLAG_STAYALIVE0x02) | |||
1225 | exchange_establish(sa->name, 0, 0, 1); | |||
1226 | else | |||
1227 | /* | |||
1228 | * Start to watch the use of this SA, so a renegotiation can | |||
1229 | * happen as soon as it is shown to be alive. | |||
1230 | */ | |||
1231 | sa->flags |= SA_FLAG_FADING0x10; | |||
1232 | } | |||
1233 | ||||
1234 | /* SA has passed its best before date. */ | |||
1235 | static void | |||
1236 | sa_hard_expire(void *v_sa) | |||
1237 | { | |||
1238 | struct sa *sa = v_sa; | |||
1239 | ||||
1240 | sa->death = 0; | |||
1241 | sa_release(sa); | |||
1242 | ||||
1243 | if ((sa->flags & (SA_FLAG_STAYALIVE0x02 | SA_FLAG_REPLACED0x08)) == | |||
1244 | SA_FLAG_STAYALIVE0x02) | |||
1245 | exchange_establish(sa->name, 0, 0, 1); | |||
1246 | ||||
1247 | sa_delete(sa, 1); | |||
1248 | } | |||
1249 | ||||
1250 | void | |||
1251 | sa_reinit(void) | |||
1252 | { | |||
1253 | struct sa *sa; | |||
1254 | char *tag; | |||
1255 | int i; | |||
1256 | ||||
1257 | /* For now; only do this if we have the proper tag configured. */ | |||
1258 | tag = conf_get_str("General", "Renegotiate-on-HUP"); | |||
1259 | if (!tag) | |||
1260 | return; | |||
1261 | ||||
1262 | LOG_DBG((LOG_SA, 30, "sa_reinit: renegotiating active connections"))log_debug (LOG_SA, 30, "sa_reinit: renegotiating active connections" ); | |||
1263 | ||||
1264 | /* | |||
1265 | * Get phase 2 SAs. Soft expire those without active exchanges. Do | |||
1266 | * not touch a phase 2 SA where the soft expiration is not set, ie. | |||
1267 | * the SA is not yet established. | |||
1268 | */ | |||
1269 | for (i = 0; i <= bucket_mask; i++) | |||
1270 | for (sa = LIST_FIRST(&sa_tab[i])((&sa_tab[i])->lh_first); sa; sa = LIST_NEXT(sa, link)((sa)->link.le_next)) | |||
1271 | if (sa->phase == 2) | |||
1272 | if (exchange_lookup_by_name(sa->name, | |||
1273 | sa->phase) == 0 && sa->soft_death) { | |||
1274 | timer_remove_event(sa->soft_death); | |||
1275 | sa_soft_expire(sa); | |||
1276 | } | |||
1277 | } | |||
1278 | ||||
1279 | /* | |||
1280 | * Get an SA attribute's flag value out of textual description. | |||
1281 | */ | |||
1282 | int | |||
1283 | sa_flag(char *attr) | |||
1284 | { | |||
1285 | static struct sa_flag_map { | |||
1286 | char *name; | |||
1287 | int flag; | |||
1288 | } sa_flag_map[] = { | |||
1289 | { | |||
1290 | "active-only", SA_FLAG_ACTIVE_ONLY0x20 | |||
1291 | }, | |||
1292 | ||||
1293 | /* | |||
1294 | * Below this point are flags that are internal to the | |||
1295 | * implementation. | |||
1296 | */ | |||
1297 | { | |||
1298 | "__ondemand", SA_FLAG_ONDEMAND0x04 | |||
1299 | }, | |||
1300 | { | |||
1301 | "ikecfg", SA_FLAG_IKECFG0x40 | |||
1302 | }, | |||
1303 | }; | |||
1304 | size_t i; | |||
1305 | ||||
1306 | for (i = 0; i < sizeof sa_flag_map / sizeof sa_flag_map[0]; i++) | |||
1307 | if (strcasecmp(attr, sa_flag_map[i].name) == 0) | |||
1308 | return sa_flag_map[i].flag; | |||
1309 | log_print("sa_flag: attribute \"%s\" unknown", attr); | |||
1310 | return 0; | |||
1311 | } | |||
1312 | ||||
1313 | /* Mark SA as replaced. */ | |||
1314 | void | |||
1315 | sa_mark_replaced(struct sa *sa) | |||
1316 | { | |||
1317 | LOG_DBG((LOG_SA, 60, "sa_mark_replaced: SA %p (%s) marked as replaced",log_debug (LOG_SA, 60, "sa_mark_replaced: SA %p (%s) marked as replaced" , sa, sa->name ? sa->name : "unnamed") | |||
1318 | sa, sa->name ? sa->name : "unnamed"))log_debug (LOG_SA, 60, "sa_mark_replaced: SA %p (%s) marked as replaced" , sa, sa->name ? sa->name : "unnamed"); | |||
1319 | if (sa->dpd_event) { | |||
1320 | timer_remove_event(sa->dpd_event); | |||
1321 | sa->dpd_event = 0; | |||
1322 | } | |||
1323 | sa->flags |= SA_FLAG_REPLACED0x08; | |||
1324 | } | |||
1325 | ||||
1326 | /* Replace SA */ | |||
1327 | void | |||
1328 | sa_replace(struct sa *sa, struct sa *new_sa) | |||
1329 | { | |||
1330 | LOG_DBG((LOG_SA, 60, "sa_replace: SA %p (%s) is replaced by SA %p (%s)",log_debug (LOG_SA, 60, "sa_replace: SA %p (%s) is replaced by SA %p (%s)" , sa, sa->name ? sa->name : "unnamed", new_sa, new_sa-> name ? new_sa->name : "unnamed") | |||
1331 | sa, sa->name ? sa->name : "unnamed",log_debug (LOG_SA, 60, "sa_replace: SA %p (%s) is replaced by SA %p (%s)" , sa, sa->name ? sa->name : "unnamed", new_sa, new_sa-> name ? new_sa->name : "unnamed") | |||
1332 | new_sa, new_sa->name ? new_sa->name : "unnamed"))log_debug (LOG_SA, 60, "sa_replace: SA %p (%s) is replaced by SA %p (%s)" , sa, sa->name ? sa->name : "unnamed", new_sa, new_sa-> name ? new_sa->name : "unnamed"); | |||
1333 | sa_mark_replaced(sa); | |||
1334 | if (new_sa->flags & SA_FLAG_REPLACED0x08) { | |||
1335 | /* enable the dpd */ | |||
1336 | if ((new_sa->flags & SA_FLAG_DPD0x80) == SA_FLAG_DPD0x80) | |||
1337 | dpd_start(new_sa); | |||
1338 | new_sa->flags &= ~SA_FLAG_REPLACED0x08; | |||
1339 | } | |||
1340 | } | |||
1341 | ||||
1342 | /* | |||
1343 | * Setup expiration timers for SA. This is used for ISAKMP SAs, but also | |||
1344 | * possible to use for application SAs if the application does not deal | |||
1345 | * with expirations itself. An example is the Linux FreeS/WAN KLIPS IPsec | |||
1346 | * stack. | |||
1347 | */ | |||
1348 | int | |||
1349 | sa_setup_expirations(struct sa *sa) | |||
1350 | { | |||
1351 | struct timespec expiration; | |||
1352 | u_int64_t seconds = sa->seconds; | |||
1353 | ||||
1354 | /* | |||
1355 | * Set the soft timeout to a random percentage between 85 & 95 of | |||
1356 | * the negotiated lifetime to break strictly synchronized | |||
1357 | * renegotiations. This works better when the randomization is on the | |||
1358 | * order of processing plus network-roundtrip times, or larger. | |||
1359 | * I.e. it depends on configuration and negotiated lifetimes. | |||
1360 | * It is not good to do the decrease on the hard timeout, because then | |||
1361 | * we may drop our SA before our peer. | |||
1362 | * XXX Better scheme to come? | |||
1363 | */ | |||
1364 | if (!sa->soft_death) { | |||
1365 | clock_gettime(CLOCK_MONOTONIC3, &expiration); | |||
1366 | /* | |||
1367 | * XXX This should probably be configuration controlled | |||
1368 | * somehow. | |||
1369 | */ | |||
1370 | seconds = sa->seconds * (850 + arc4random_uniform(100)) / 1000; | |||
1371 | LOG_DBG((LOG_TIMER, 95,log_debug (LOG_TIMER, 95, "sa_setup_expirations: SA %p soft timeout in %llu seconds" , sa, seconds) | |||
1372 | "sa_setup_expirations: SA %p soft timeout in %llu seconds",log_debug (LOG_TIMER, 95, "sa_setup_expirations: SA %p soft timeout in %llu seconds" , sa, seconds) | |||
1373 | sa, seconds))log_debug (LOG_TIMER, 95, "sa_setup_expirations: SA %p soft timeout in %llu seconds" , sa, seconds); | |||
1374 | expiration.tv_sec += seconds; | |||
1375 | sa->soft_death = timer_add_event("sa_soft_expire", | |||
1376 | sa_soft_expire, sa, &expiration); | |||
1377 | if (!sa->soft_death) { | |||
1378 | /* If we don't give up we might start leaking... */ | |||
1379 | sa_delete(sa, 1); | |||
1380 | return -1; | |||
1381 | } | |||
1382 | sa_reference(sa); | |||
1383 | } | |||
1384 | if (!sa->death) { | |||
1385 | clock_gettime(CLOCK_MONOTONIC3, &expiration); | |||
1386 | LOG_DBG((LOG_TIMER, 95,log_debug (LOG_TIMER, 95, "sa_setup_expirations: SA %p hard timeout in %llu seconds" , sa, sa->seconds) | |||
1387 | "sa_setup_expirations: SA %p hard timeout in %llu seconds",log_debug (LOG_TIMER, 95, "sa_setup_expirations: SA %p hard timeout in %llu seconds" , sa, sa->seconds) | |||
1388 | sa, sa->seconds))log_debug (LOG_TIMER, 95, "sa_setup_expirations: SA %p hard timeout in %llu seconds" , sa, sa->seconds); | |||
1389 | expiration.tv_sec += sa->seconds; | |||
1390 | sa->death = timer_add_event("sa_hard_expire", sa_hard_expire, | |||
1391 | sa, &expiration); | |||
1392 | if (!sa->death) { | |||
1393 | /* If we don't give up we might start leaking... */ | |||
1394 | sa_delete(sa, 1); | |||
1395 | return -1; | |||
1396 | } | |||
1397 | sa_reference(sa); | |||
1398 | } | |||
1399 | return 0; | |||
1400 | } |