File: | programs/pluto/pending.c |
Warning: | line 290, column 4 Access to field 'name' results in a dereference of a null pointer (loaded from field 'connection') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* information about connections between hosts and clients | |||
2 | * | |||
3 | * Copyright (C) 1998-2002,2013,2015 D. Hugh Redelmeier <hugh@mimosa.com> | |||
4 | * Copyright (C) 2003-2007 Michael Richardson <mcr@xelerance.com> | |||
5 | * Copyright (C) 2009 Paul Wouters <paul@xelerance.com> | |||
6 | * Copyright (C) 2012 Paul Wouters <paul@libreswan.org> | |||
7 | * Copyright (C) 2012-2018 Paul Wouters <pwouters@redhat.com> | |||
8 | * Copyright (C) 2011 Anthony Tong <atong@TrustedCS.com> | |||
9 | * Copyright (C) 2017-2018 Antony Antony <antony@phenome.org> | |||
10 | * Copyright (C) 2019 Andrew Cagney <cagney@gnu.org> | |||
11 | * | |||
12 | * This program is free software; you can redistribute it and/or modify it | |||
13 | * under the terms of the GNU General Public License as published by the | |||
14 | * Free Software Foundation; either version 2 of the License, or (at your | |||
15 | * option) any later version. See <https://www.gnu.org/licenses/gpl2.txt>. | |||
16 | * | |||
17 | * This program is distributed in the hope that it will be useful, but | |||
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |||
19 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |||
20 | * for more details. | |||
21 | */ | |||
22 | ||||
23 | #include <string.h> | |||
24 | #include <stdio.h> | |||
25 | #include <stddef.h> | |||
26 | #include <stdlib.h> | |||
27 | #include <unistd.h> | |||
28 | #include <netinet/in.h> | |||
29 | #include <sys/socket.h> | |||
30 | #include <sys/stat.h> | |||
31 | #include <netinet/in.h> | |||
32 | #include <arpa/inet.h> | |||
33 | #include <arpa/nameser.h> /* missing from <resolv.h> on old systems */ | |||
34 | #include <errno(*__errno_location ()).h> | |||
35 | ||||
36 | ||||
37 | #include "sysdep.h" | |||
38 | #include "constants.h" | |||
39 | #include "defs.h" | |||
40 | #include "id.h" | |||
41 | #include "x509.h" | |||
42 | #include "certs.h" | |||
43 | #include "connections.h" /* needs id.h */ | |||
44 | #include "pending.h" | |||
45 | #include "log.h" | |||
46 | #include "state.h" | |||
47 | #include "packet.h" | |||
48 | #include "demux.h" | |||
49 | #include "ikev1_quick.h" | |||
50 | #include "timer.h" | |||
51 | #include "pluto_crypt.h" /* for pluto_crypto_req & pluto_crypto_req_cont */ | |||
52 | #include "ikev2.h" | |||
53 | #include "ip_address.h" | |||
54 | #include "hostpair.h" | |||
55 | ||||
56 | /* | |||
57 | * queue an IPsec SA negotiation pending completion of a | |||
58 | * suitable phase 1 (IKE SA) | |||
59 | */ | |||
60 | void add_pending(struct fd *whack_sock, | |||
61 | struct ike_sa *ike, | |||
62 | struct connection *c, | |||
63 | lset_t policy, | |||
64 | unsigned long try, | |||
65 | so_serial_t replacing, | |||
66 | struct xfrm_user_sec_ctx_ike *uctx, | |||
67 | bool_Bool part_of_initiate) | |||
68 | { | |||
69 | struct pending *p, **pp; | |||
70 | ||||
71 | /* look for duplicate pending IPsec SA's, skip add operation */ | |||
72 | pp = host_pair_first_pending(c); | |||
73 | ||||
74 | for (p = pp ? *pp : NULL((void*)0); p != NULL((void*)0); p = p->next) { | |||
75 | if (p->connection == c && p->ike == ike) { | |||
76 | address_buf b; | |||
77 | connection_buf cib; | |||
78 | dbg("Ignored already queued up pending IPsec SA negotiation with %s "PRI_CONNECTION"",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("Ignored already queued up pending IPsec SA negotiation with %s " "\"%s\"%s""", str_address(&c->spd.that.host_addr, & b), (c)->name, str_connection_instance(c, &cib)); } } | |||
79 | str_address(&c->spd.that.host_addr, &b),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("Ignored already queued up pending IPsec SA negotiation with %s " "\"%s\"%s""", str_address(&c->spd.that.host_addr, & b), (c)->name, str_connection_instance(c, &cib)); } } | |||
80 | pri_connection(c, &cib)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("Ignored already queued up pending IPsec SA negotiation with %s " "\"%s\"%s""", str_address(&c->spd.that.host_addr, & b), (c)->name, str_connection_instance(c, &cib)); } }; | |||
81 | return; | |||
82 | } | |||
83 | } | |||
84 | ||||
85 | p = alloc_thing(struct pending, "struct pending")((struct pending*) alloc_bytes(sizeof(struct pending), ("struct pending" ))); | |||
86 | p->whack_sock = dup_any(whack_sock)dup_any_fd((whack_sock), (where_t) { .func = __func__, .basename = "pending.c" , .line = 86}); /*on heap*/ | |||
87 | p->ike = ike; | |||
88 | p->connection = c; | |||
89 | p->policy = policy; | |||
90 | p->try = try; | |||
91 | p->replacing = replacing; | |||
92 | p->pend_time = mononow(); | |||
93 | p->part_of_initiate = part_of_initiate; /* useful */ | |||
94 | p->uctx = NULL((void*)0); | |||
95 | if (uctx != NULL((void*)0)) { | |||
96 | p->uctx = clone_thing(*uctx, "pending security context")((__typeof__(&(*uctx))) clone_bytes((const void *)&(* uctx), sizeof(*uctx), ("pending security context"))); | |||
97 | dbg("pending IPsec SA negotiation with security context %s, %d",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("pending IPsec SA negotiation with security context %s, %d" , p->uctx->sec_ctx_value, p->uctx->ctx.ctx_len); } } | |||
98 | p->uctx->sec_ctx_value,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("pending IPsec SA negotiation with security context %s, %d" , p->uctx->sec_ctx_value, p->uctx->ctx.ctx_len); } } | |||
99 | p->uctx->ctx.ctx_len){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("pending IPsec SA negotiation with security context %s, %d" , p->uctx->sec_ctx_value, p->uctx->ctx.ctx_len); } }; | |||
100 | } | |||
101 | ||||
102 | /* | |||
103 | * If this is part of an initiate then there's already enough | |||
104 | * going on; no need to log this action. | |||
105 | */ | |||
106 | enum stream only = part_of_initiate ? (DBGP(DBG_BASE)(cur_debugging & (((lset_t)1 << (DBG_BASE_IX)))) ? DEBUG_STREAM : NO_STREAM) : ALL_STREAMS; | |||
107 | if (only != NO_STREAM) { | |||
108 | address_buf b; | |||
109 | connection_buf cibb; | |||
110 | struct connection *cb = ike->sa.st_connection; | |||
111 | log_pending(only | RC_COMMENT, p, | |||
112 | "queuing pending IPsec SA negotiating with %s IKE SA #%lu "PRI_CONNECTION"\"%s\"%s""", | |||
113 | ipstr(&c->spd.that.host_addr, &b), | |||
114 | ike->sa.st_serialno, pri_connection(cb, &cibb)(cb)->name, str_connection_instance(cb, &cibb)); | |||
115 | } | |||
116 | host_pair_enqueue_pending(c, p, &p->next); | |||
117 | } | |||
118 | ||||
119 | /* | |||
120 | * Release all the whacks awaiting the completion of this state. This | |||
121 | * is accomplished by closing all the whack socket file descriptors. | |||
122 | * We go to some trouble to tell each whack, but to not tell it twice. | |||
123 | */ | |||
124 | ||||
125 | void release_pending_whacks(struct state *st, err_t story) | |||
126 | { | |||
127 | /* | |||
128 | * Use fstat() to uniquely identify the whack connection - | |||
129 | * multiple sockets to the same whack will have similar | |||
130 | * 'struct stat' values. | |||
131 | * | |||
132 | * If the socket is valid, close it. | |||
133 | */ | |||
134 | if (!fd_p(st->st_whack_sockst_logger->object_whackfd)) { | |||
135 | dbg("%s: state #%lu has no whack fd",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s: state #%lu has no whack fd", __func__, st ->st_serialno); } } | |||
136 | __func__, st->st_serialno){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s: state #%lu has no whack fd", __func__, st ->st_serialno); } }; | |||
137 | return; | |||
138 | } | |||
139 | ||||
140 | /* | |||
141 | * Check for the SA's parent and if that needs to disconnect. | |||
142 | * | |||
143 | * For instance, when the IKE_SA establishes but the first | |||
144 | * CHILD_SA fails with a timeout then this code will be called | |||
145 | * with the CHILD_SA. | |||
146 | * | |||
147 | * XXX: Since this is meant to release pending whacks, should | |||
148 | * this check for, and release the whacks for any pending | |||
149 | * CHILD_SA attached to this ST's IKE SA? | |||
150 | */ | |||
151 | struct ike_sa *ike_with_same_whack = NULL((void*)0); | |||
152 | if (IS_CHILD_SA(st)((st)->st_clonedfrom != 0)) { | |||
153 | struct ike_sa *ike = ike_sa(st, HERE(where_t) { .func = __func__, .basename = "pending.c" , .line = 153}); | |||
154 | if (same_fd(st->st_whack_sockst_logger->object_whackfd, ike->sa.st_whack_sockst_logger->object_whackfd)) { | |||
155 | ike_with_same_whack = ike; | |||
156 | release_any_whack(&ike->sa, HERE(where_t) { .func = __func__, .basename = "pending.c" , .line = 156}, "release pending whacks state's IKE SA"); | |||
157 | } else { | |||
158 | release_any_whack(st, HERE(where_t) { .func = __func__, .basename = "pending.c" , .line = 158}, "releasing isolated child"); | |||
159 | return; | |||
160 | } | |||
161 | } else { | |||
162 | ike_with_same_whack = pexpect_ike_sa(st); | |||
163 | } | |||
164 | pexpect(ike_with_same_whack != NULL)({ _Bool assertion__ = ike_with_same_whack != ((void*)0); if ( !assertion__) { log_pexpect((where_t) { .func = __func__, .basename = "pending.c" , .line = 164}, "%s", "ike_with_same_whack != NULL" ); } assertion__; }); | |||
165 | ||||
166 | /* | |||
167 | * Now go through pending children and close the whack socket | |||
168 | * of any that are going to be assigned this ST as the parent. | |||
169 | * XXX: Is this because the parent is dying so anything | |||
170 | * waiting on it should be deleted. | |||
171 | * | |||
172 | * SAME_FD() is used to identify whack sockets that are | |||
173 | * different to ST - when found a further release message is | |||
174 | * printed. | |||
175 | */ | |||
176 | ||||
177 | struct pending **pp = host_pair_first_pending(st->st_connection); | |||
178 | if (pp == NULL((void*)0)) | |||
179 | return; | |||
180 | for (struct pending *p = *pp; p != NULL((void*)0); p = p->next) { | |||
181 | dbg("%s: IKE SA #%lu "PRI_FD" has pending CHILD SA with socket "PRI_FD,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s: IKE SA #%lu ""fd-fd@%p"" has pending CHILD SA with socket " "fd-fd@%p", __func__, p->ike->sa.st_serialno, (p->ike ->sa.st_logger->object_whackfd), (p->whack_sock)); } } | |||
182 | __func__, p->ike->sa.st_serialno,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s: IKE SA #%lu ""fd-fd@%p"" has pending CHILD SA with socket " "fd-fd@%p", __func__, p->ike->sa.st_serialno, (p->ike ->sa.st_logger->object_whackfd), (p->whack_sock)); } } | |||
183 | pri_fd(p->ike->sa.st_whack_sock),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s: IKE SA #%lu ""fd-fd@%p"" has pending CHILD SA with socket " "fd-fd@%p", __func__, p->ike->sa.st_serialno, (p->ike ->sa.st_logger->object_whackfd), (p->whack_sock)); } } | |||
184 | pri_fd(p->whack_sock)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s: IKE SA #%lu ""fd-fd@%p"" has pending CHILD SA with socket " "fd-fd@%p", __func__, p->ike->sa.st_serialno, (p->ike ->sa.st_logger->object_whackfd), (p->whack_sock)); } }; | |||
185 | if (p->ike == ike_with_same_whack && fd_p(p->whack_sock)) { | |||
186 | if (!same_fd(st->st_whack_sockst_logger->object_whackfd, p->whack_sock)) { | |||
187 | /* XXX: why not the log file? */ | |||
188 | log_pending(WHACK_STREAM|RC_COMMENT, p, | |||
189 | "%s for IKE SA, but releasing whack for pending %s", | |||
190 | story, | |||
191 | /* IPsec SA or CHILD SA */ | |||
192 | enum_enum_name(&sa_type_names, | |||
193 | p->connection->ike_version, | |||
194 | IPSEC_SA)); | |||
195 | } | |||
196 | close_any(&p->whack_sock)close_any_fd((&p->whack_sock), (where_t) { .func = __func__ , .basename = "pending.c" , .line = 196});/*on-heap*/ | |||
197 | } | |||
198 | } | |||
199 | release_any_whack(st, HERE(where_t) { .func = __func__, .basename = "pending.c" , .line = 199}, "releasing child"); | |||
200 | } | |||
201 | ||||
202 | /* | |||
203 | * remove a pending from a linked list. | |||
204 | * | |||
205 | * pp points to the link to the entry. | |||
206 | * *pp will be updated to point to the successor to the original *pp. | |||
207 | * In effect, we advance *pp. | |||
208 | * Note: If you are traversing a linked list and deleting some entries, | |||
209 | * you should not advance pp after calling delete_pending. | |||
210 | */ | |||
211 | static void delete_pending(struct pending **pp) | |||
212 | { | |||
213 | struct pending *p = *pp; | |||
214 | ||||
215 | *pp = p->next; | |||
216 | if (p->connection != NULL((void*)0)) | |||
217 | connection_discard(p->connection); | |||
218 | close_any(&p->whack_sock)close_any_fd((&p->whack_sock), (where_t) { .func = __func__ , .basename = "pending.c" , .line = 218}); /*on-heap*/ | |||
219 | ||||
220 | if (DBGP(DBG_BASE)(cur_debugging & (((lset_t)1 << (DBG_BASE_IX))))) { | |||
221 | if (p->connection == NULL((void*)0)) { | |||
222 | /* ??? when does this happen? */ | |||
223 | DBG_log("removing pending policy for no connection {%p}", p); | |||
224 | } else { | |||
225 | connection_buf cib; | |||
226 | DBG_log("removing pending policy for "PRI_CONNECTION"\"%s\"%s"" {%p}", | |||
227 | pri_connection(p->connection, &cib)(p->connection)->name, str_connection_instance(p->connection , &cib), p); | |||
228 | } | |||
229 | } | |||
230 | ||||
231 | pfreeany(p->uctx){ typeof(p->uctx) *pp_ = &(p->uctx); if (*pp_ != (( void*)0)) { pfree(*pp_); *pp_ = ((void*)0); } }; | |||
232 | pfree(p); | |||
233 | } | |||
234 | ||||
235 | /* | |||
236 | * Look for phase2s that were waiting for a phase 1. | |||
237 | * | |||
238 | * XXX instead of doing this work NOW, we should simply create an event | |||
239 | * in zero future time to unpend the state. | |||
240 | * YYY but, in fact, quick_mode will enqueue a cryptographic operation | |||
241 | * anyway, which will get done "later" anyway, so make it is just fine | |||
242 | * as it is. | |||
243 | * In IKEv2 it called when AUTH is complete, child is established. | |||
244 | * Established child get removed not unpend. | |||
245 | */ | |||
246 | void unpend(struct ike_sa *ike, struct connection *cc) | |||
247 | { | |||
248 | struct pending **pp, *p; | |||
249 | char *what ="unqueuing"; | |||
250 | ||||
251 | if (cc == NULL((void*)0)) { | |||
| ||||
252 | dbg("unpending state #%lu", ike->sa.st_serialno){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("unpending state #%lu", ike->sa.st_serialno ); } }; | |||
253 | } else { | |||
254 | connection_buf cib; | |||
255 | dbg("unpending state #%lu connection "PRI_CONNECTION"",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("unpending state #%lu connection ""\"%s\"%s""" , ike->sa.st_serialno, (cc)->name, str_connection_instance (cc, &cib)); } } | |||
256 | ike->sa.st_serialno, pri_connection(cc, &cib)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("unpending state #%lu connection ""\"%s\"%s""" , ike->sa.st_serialno, (cc)->name, str_connection_instance (cc, &cib)); } }; | |||
257 | } | |||
258 | ||||
259 | for (pp = host_pair_first_pending(ike->sa.st_connection); | |||
260 | (p = *pp) != NULL((void*)0); ) | |||
261 | { | |||
262 | if (p->ike == ike) { | |||
263 | p->pend_time = mononow(); | |||
264 | switch (ike->sa.st_ike_version) { | |||
265 | case IKEv2: | |||
266 | if (cc != p->connection) { | |||
267 | ikev2_initiate_child_sa(p); | |||
268 | } else { | |||
269 | /* | |||
270 | * IKEv2 AUTH negotiation | |||
271 | * include child. nothing to | |||
272 | * upend, like in IKEv1, | |||
273 | * delete it | |||
274 | */ | |||
275 | what = "delete from"; | |||
276 | } | |||
277 | break; | |||
278 | case IKEv1: | |||
279 | quick_outI1(p->whack_sock, &ike->sa, p->connection, | |||
280 | p->policy, | |||
281 | p->try, p->replacing | |||
282 | , p->uctx | |||
283 | ); | |||
284 | break; | |||
285 | default: | |||
286 | bad_case(ike->sa.st_ike_version)libreswan_bad_case("ike->sa.st_ike_version", (ike->sa.st_ike_version ), (where_t) { .func = __func__, .basename = "pending.c" , .line = 286}); | |||
287 | } | |||
288 | address_buf b; | |||
289 | connection_buf cib; | |||
290 | dbg("%s pending %s with %s "PRI_CONNECTION"",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s pending %s with %s ""\"%s\"%s""", what, (ike ->sa.st_ike_version == IKEv2) ? "Child SA" : "Quick Mode", str_address(&p->connection->spd.that.host_addr, & b), (p->connection)->name, str_connection_instance(p-> connection, &cib)); } } | |||
| ||||
291 | what,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s pending %s with %s ""\"%s\"%s""", what, (ike ->sa.st_ike_version == IKEv2) ? "Child SA" : "Quick Mode", str_address(&p->connection->spd.that.host_addr, & b), (p->connection)->name, str_connection_instance(p-> connection, &cib)); } } | |||
292 | (ike->sa.st_ike_version == IKEv2) ? "Child SA" : "Quick Mode",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s pending %s with %s ""\"%s\"%s""", what, (ike ->sa.st_ike_version == IKEv2) ? "Child SA" : "Quick Mode", str_address(&p->connection->spd.that.host_addr, & b), (p->connection)->name, str_connection_instance(p-> connection, &cib)); } } | |||
293 | str_address(&p->connection->spd.that.host_addr, &b),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s pending %s with %s ""\"%s\"%s""", what, (ike ->sa.st_ike_version == IKEv2) ? "Child SA" : "Quick Mode", str_address(&p->connection->spd.that.host_addr, & b), (p->connection)->name, str_connection_instance(p-> connection, &cib)); } } | |||
294 | pri_connection(p->connection, &cib)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s pending %s with %s ""\"%s\"%s""", what, (ike ->sa.st_ike_version == IKEv2) ? "Child SA" : "Quick Mode", str_address(&p->connection->spd.that.host_addr, & b), (p->connection)->name, str_connection_instance(p-> connection, &cib)); } }; | |||
295 | ||||
296 | p->connection = NULL((void*)0); /* ownership transferred */ | |||
297 | delete_pending(pp); /* in effect, advances pp */ | |||
298 | } else { | |||
299 | pp = &p->next; | |||
300 | } | |||
301 | } | |||
302 | } | |||
303 | ||||
304 | struct connection *first_pending(const struct ike_sa *ike, | |||
305 | lset_t *policy, | |||
306 | struct fd **p_whack_sock) | |||
307 | { | |||
308 | struct pending **pp, *p; | |||
309 | ||||
310 | dbg("getting first pending from state #%lu", ike->sa.st_serialno){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("getting first pending from state #%lu", ike-> sa.st_serialno); } }; | |||
311 | ||||
312 | for (pp = host_pair_first_pending(ike->sa.st_connection); | |||
313 | (p = *pp) != NULL((void*)0); pp = &p->next) | |||
314 | { | |||
315 | if (p->ike == ike) { | |||
316 | close_any(p_whack_sock)close_any_fd((p_whack_sock), (where_t) { .func = __func__, .basename = "pending.c" , .line = 316}); /*on-heap*/ | |||
317 | *p_whack_sock = dup_any(p->whack_sock)dup_any_fd((p->whack_sock), (where_t) { .func = __func__, . basename = "pending.c" , .line = 317}); /*on-heap*/ | |||
318 | *policy = p->policy; | |||
319 | return p->connection; | |||
320 | } | |||
321 | } | |||
322 | return NULL((void*)0); | |||
323 | } | |||
324 | ||||
325 | /* | |||
326 | * Look for phase2s that were waiting for a phase 1. If the time that we | |||
327 | * have been pending exceeds a DPD timeout that was set, then we call the | |||
328 | * dpd_timeout() on this state. We hope this kills the pending state. | |||
329 | */ | |||
330 | bool_Bool pending_check_timeout(const struct connection *c) | |||
331 | { | |||
332 | struct pending **pp, *p; | |||
333 | ||||
334 | for (pp = host_pair_first_pending(c); (p = *pp) != NULL((void*)0); ) { | |||
335 | deltatime_t waited = monotimediff(mononow(), p->pend_time); | |||
336 | connection_buf cib; | |||
337 | dbg("checking connection "PRI_CONNECTION" for stuck phase 2s (waited %jd, patience 3*%jd)",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("checking connection ""\"%s\"%s"" for stuck phase 2s (waited %jd, patience 3*%jd)" , (c)->name, str_connection_instance(c, &cib), deltasecs (waited), deltasecs(c->dpd_timeout)); } } | |||
338 | pri_connection(c, &cib), deltasecs(waited),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("checking connection ""\"%s\"%s"" for stuck phase 2s (waited %jd, patience 3*%jd)" , (c)->name, str_connection_instance(c, &cib), deltasecs (waited), deltasecs(c->dpd_timeout)); } } | |||
339 | deltasecs(c->dpd_timeout)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("checking connection ""\"%s\"%s"" for stuck phase 2s (waited %jd, patience 3*%jd)" , (c)->name, str_connection_instance(c, &cib), deltasecs (waited), deltasecs(c->dpd_timeout)); } }; | |||
340 | if (deltasecs(c->dpd_timeout) > 0) { | |||
341 | if (!monobefore(mononow(), | |||
342 | monotime_add(p->pend_time, | |||
343 | deltatimescale(3, 1, c->dpd_timeout)))) { | |||
344 | connection_buf cib; | |||
345 | dbg("connection "PRI_CONNECTION" stuck, restarting",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("connection ""\"%s\"%s"" stuck, restarting", ( c)->name, str_connection_instance(c, &cib)); } } | |||
346 | pri_connection(c, &cib)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("connection ""\"%s\"%s"" stuck, restarting", ( c)->name, str_connection_instance(c, &cib)); } }; | |||
347 | return TRUE1; | |||
348 | } | |||
349 | } | |||
350 | pp = &p->next; | |||
351 | } | |||
352 | return FALSE0; | |||
353 | } | |||
354 | ||||
355 | /* a IKE SA negotiation has been replaced; update any pending */ | |||
356 | void update_pending(struct ike_sa *old_ike, struct ike_sa *new_ike) | |||
357 | { | |||
358 | struct pending *p, **pp; | |||
359 | ||||
360 | pp = host_pair_first_pending(old_ike->sa.st_connection); | |||
361 | if (pp == NULL((void*)0)) | |||
362 | return; | |||
363 | ||||
364 | for (p = *pp; p != NULL((void*)0); p = p->next) | |||
365 | if (p->ike == old_ike) | |||
366 | p->ike = new_ike; | |||
367 | } | |||
368 | ||||
369 | /* a IKE SA negotiation has failed; discard any pending */ | |||
370 | void flush_pending_by_state(struct ike_sa *ike) | |||
371 | { | |||
372 | struct pending **pp, *p; | |||
373 | ||||
374 | pp = host_pair_first_pending(ike->sa.st_connection); | |||
375 | if (pp == NULL((void*)0)) | |||
376 | return; | |||
377 | ||||
378 | while ((p = *pp) != NULL((void*)0)) { | |||
379 | if (p->ike == ike) { | |||
380 | /* we don't have to worry about deref to free'ed | |||
381 | * *pp, because delete_pending updates pp to | |||
382 | * point to the next element before it frees *pp | |||
383 | */ | |||
384 | delete_pending(pp); /* in effect, advances pp */ | |||
385 | } else { | |||
386 | pp = &p->next; | |||
387 | } | |||
388 | } | |||
389 | } | |||
390 | ||||
391 | /* a connection has been deleted; discard any related pending */ | |||
392 | void flush_pending_by_connection(const struct connection *c) | |||
393 | { | |||
394 | struct pending **pp, *p; | |||
395 | ||||
396 | pp = host_pair_first_pending(c); | |||
397 | if (pp == NULL((void*)0)) | |||
398 | return; | |||
399 | ||||
400 | while ((p = *pp) != NULL((void*)0)) { | |||
401 | if (p->connection == c) { | |||
402 | p->connection = NULL((void*)0); /* prevent delete_pending from releasing */ | |||
403 | delete_pending(pp); /* in effect, advances pp */ | |||
404 | } else { | |||
405 | pp = &p->next; | |||
406 | } | |||
407 | } | |||
408 | } | |||
409 | ||||
410 | void show_pending_phase2(struct show *s, | |||
411 | const struct connection *c, | |||
412 | const struct ike_sa *ike) | |||
413 | { | |||
414 | struct pending **pp, *p; | |||
415 | ||||
416 | pp = host_pair_first_pending(c); | |||
417 | if (pp == NULL((void*)0)) | |||
418 | return; | |||
419 | ||||
420 | for (p = *pp; p != NULL((void*)0); p = p->next) { | |||
421 | if (p->ike == ike) { | |||
422 | /* connection-name state-number [replacing state-number] */ | |||
423 | SHOW_JAMBUF(RC_COMMENT, s, buf)for (struct jambuf *buf = show_jambuf(s); buf != ((void*)0); jambuf_to_show (buf, s, RC_COMMENT), buf = ((void*)0)) { | |||
424 | jam(buf, "#%lu: pending ", p->ike->sa.st_serialno); | |||
425 | jam_string(buf, (ike->sa.st_ike_version == IKEv2) ? "CHILD SA" : "Phase 2"); | |||
426 | jam(buf, " for "); | |||
427 | jam_connection(buf, c); | |||
428 | if (p->replacing != SOS_NOBODY0) { | |||
429 | jam(buf, " replacing #%lu", p->replacing); | |||
430 | } | |||
431 | } | |||
432 | } | |||
433 | } | |||
434 | } | |||
435 | ||||
436 | bool_Bool in_pending_use(const struct connection *c) | |||
437 | { | |||
438 | /* see if it is being used by a pending */ | |||
439 | struct pending **pp, *p; | |||
440 | ||||
441 | pp = host_pair_first_pending(c); | |||
442 | if (pp == NULL((void*)0)) | |||
443 | return FALSE0; | |||
444 | ||||
445 | for (p = *pp; p != NULL((void*)0); p = p->next) | |||
446 | if (p->connection == c) | |||
447 | return TRUE1; /* in use, so we're done */ | |||
448 | ||||
449 | return FALSE0; | |||
450 | } |