xref: /openbsd/sbin/isakmpd/transport.c (revision 09467b48)
1 /* $OpenBSD: transport.c,v 1.38 2017/12/05 20:31:45 jca Exp $	 */
2 /* $EOM: transport.c,v 1.43 2000/10/10 12:36:39 provos Exp $	 */
3 
4 /*
5  * Copyright (c) 1998, 1999 Niklas Hallqvist.  All rights reserved.
6  * Copyright (c) 2001, 2004 H�kan Olsson.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /*
30  * This code was written under funding by Ericsson Radio Systems.
31  */
32 
33 #include <sys/queue.h>
34 #include <netdb.h>
35 #include <string.h>
36 
37 #include "conf.h"
38 #include "exchange.h"
39 #include "log.h"
40 #include "message.h"
41 #include "sa.h"
42 #include "timer.h"
43 #include "transport.h"
44 #include "virtual.h"
45 
46 /* If no retransmit limit is given, use this as a default.  */
47 #define RETRANSMIT_DEFAULT 10
48 
49 LIST_HEAD(transport_method_list, transport_vtbl) transport_method_list;
50 
51 /* Call the reinit function of the various transports.  */
52 void
53 transport_reinit(void)
54 {
55 	struct transport_vtbl *method;
56 
57 	for (method = LIST_FIRST(&transport_method_list); method;
58 	    method = LIST_NEXT(method, link))
59 		if (method->reinit)
60 			method->reinit();
61 }
62 
63 /* Initialize the transport maintenance module.  */
64 void
65 transport_init(void)
66 {
67 	LIST_INIT(&transport_list);
68 	LIST_INIT(&transport_method_list);
69 }
70 
71 /* Register another transport T.  */
72 void
73 transport_setup(struct transport *t, int toplevel)
74 {
75 	if (toplevel) {
76 		/* Only the toplevel (virtual) transport has sendqueues.  */
77 		LOG_DBG((LOG_TRANSPORT, 70,
78 		    "transport_setup: virtual transport %p", t));
79 		TAILQ_INIT(&t->sendq);
80 		TAILQ_INIT(&t->prio_sendq);
81 		t->refcnt = 0;
82 	} else {
83 		/* udp and udp_encap trp goes into the transport list.  */
84 		LOG_DBG((LOG_TRANSPORT, 70,
85 		    "transport_setup: added %p to transport list", t));
86 		LIST_INSERT_HEAD(&transport_list, t, link);
87 		t->refcnt = 1;
88 	}
89 	t->flags = 0;
90 }
91 
92 /* Add a referer to transport T.  */
93 void
94 transport_reference(struct transport *t)
95 {
96 	t->refcnt++;
97 	LOG_DBG((LOG_TRANSPORT, 95,
98 	    "transport_reference: transport %p now has %d references", t,
99 	    t->refcnt));
100 }
101 
102 /*
103  * Remove a referer from transport T, removing all of T when no referers left.
104  */
105 void
106 transport_release(struct transport *t)
107 {
108 	LOG_DBG((LOG_TRANSPORT, 95,
109 	    "transport_release: transport %p had %d references", t,
110 	    t->refcnt));
111 	if (--t->refcnt)
112 		return;
113 
114 	LOG_DBG((LOG_TRANSPORT, 70, "transport_release: freeing %p", t));
115 	t->vtbl->remove(t);
116 }
117 
118 void
119 transport_report(void)
120 {
121 	struct virtual_transport *v;
122 	struct transport *t;
123 	struct message *msg;
124 
125 	for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) {
126 		LOG_DBG((LOG_REPORT, 0,
127 		    "transport_report: transport %p flags %x refcnt %d", t,
128 		    t->flags, t->refcnt));
129 
130 		/* XXX Report sth on the virtual transport?  */
131 		t->vtbl->report(t);
132 
133 		/*
134 		 * This is the reason message_dump_raw lives outside
135 		 * message.c.
136 		 */
137 		v = (struct virtual_transport *)t->virtual;
138 		if ((v->encap_is_active && v->encap == t) ||
139 		    (!v->encap_is_active && v->main == t)) {
140 			for (msg = TAILQ_FIRST(&t->virtual->prio_sendq); msg;
141 			    msg = TAILQ_NEXT(msg, link))
142 				message_dump_raw("udp_report(prio)", msg,
143 				    LOG_REPORT);
144 
145 			for (msg = TAILQ_FIRST(&t->virtual->sendq); msg;
146 			    msg = TAILQ_NEXT(msg, link))
147 				message_dump_raw("udp_report", msg,
148 				    LOG_REPORT);
149 		}
150 	}
151 }
152 
153 int
154 transport_prio_sendqs_empty(void)
155 {
156 	struct transport *t;
157 
158 	for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link))
159 		if (TAILQ_FIRST(&t->virtual->prio_sendq))
160 			return 0;
161 	return 1;
162 }
163 
164 /* Register another transport method T.  */
165 void
166 transport_method_add(struct transport_vtbl *t)
167 {
168 	LIST_INSERT_HEAD(&transport_method_list, t, link);
169 }
170 
171 /*
172  * Build up a file descriptor set FDS with all transport descriptors we want
173  * to read from.  Return the number of file descriptors select(2) needs to
174  * check in order to cover the ones we setup in here.
175  */
176 int
177 transport_fd_set(fd_set * fds)
178 {
179 	struct transport *t;
180 	int	n;
181 	int	max = -1;
182 
183 	for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link))
184 		if (t->virtual->flags & TRANSPORT_LISTEN) {
185 			n = t->vtbl->fd_set(t, fds, 1);
186 			if (n > max)
187 				max = n;
188 
189 			LOG_DBG((LOG_TRANSPORT, 95, "transport_fd_set: "
190 			    "transport %p (virtual %p) fd %d", t,
191 			    t->virtual, n));
192 		}
193 	return max + 1;
194 }
195 
196 /*
197  * Build up a file descriptor set FDS with all the descriptors belonging to
198  * transport where messages are queued for transmittal.  Return the number
199  * of file descriptors select(2) needs to check in order to cover the ones
200  * we setup in here.
201  */
202 int
203 transport_pending_wfd_set(fd_set * fds)
204 {
205 	struct transport *t;
206 	int	n;
207 	int	max = -1;
208 
209 	for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) {
210 		if (TAILQ_FIRST(&t->virtual->sendq) ||
211 		    TAILQ_FIRST(&t->virtual->prio_sendq)) {
212 			n = t->vtbl->fd_set(t, fds, 1);
213 			LOG_DBG((LOG_TRANSPORT, 95,
214 			    "transport_pending_wfd_set: "
215 			    "transport %p (virtual %p) fd %d pending", t,
216 			    t->virtual, n));
217 			if (n > max)
218 				max = n;
219 		}
220 	}
221 	return max + 1;
222 }
223 
224 /*
225  * For each transport with a file descriptor in FDS, try to get an
226  * incoming message and start processing it.
227  */
228 void
229 transport_handle_messages(fd_set *fds)
230 {
231 	struct transport *t;
232 
233 	for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) {
234 		if ((t->flags & TRANSPORT_LISTEN) &&
235 		    (*t->vtbl->fd_isset)(t, fds)) {
236 			(*t->virtual->vtbl->handle_message)(t);
237 			(*t->vtbl->fd_set)(t, fds, 0);
238 		}
239 	}
240 }
241 
242 /*
243  * Send the first queued message on the transports found whose file
244  * descriptor is in FDS and has messages queued.  Remove the fd bit from
245  * FDS as soon as one message has been sent on it so other transports
246  * sharing the socket won't get service without an intervening select
247  * call.  Perhaps a fairness strategy should be implemented between
248  * such transports.  Now early transports in the list will potentially
249  * be favoured to later ones sharing the file descriptor.
250  */
251 void
252 transport_send_messages(fd_set * fds)
253 {
254 	struct transport *t, *next;
255 	struct message *msg;
256 	struct exchange *exchange;
257 	struct sockaddr *dst;
258 	struct timespec expiration;
259 	int             expiry, ok_to_drop_message;
260 	char peer[NI_MAXHOST], peersv[NI_MAXSERV];
261 
262 	/*
263 	 * Reference all transports first so noone will disappear while in
264 	 * use.
265 	 */
266 	for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link))
267 		transport_reference(t->virtual);
268 
269 	for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) {
270 		if ((TAILQ_FIRST(&t->virtual->sendq) ||
271 		    TAILQ_FIRST(&t->virtual->prio_sendq)) &&
272 		    t->vtbl->fd_isset(t, fds)) {
273 			/* Remove fd bit.  */
274 			t->vtbl->fd_set(t, fds, 0);
275 
276 			/* Prefer a message from the prioritized sendq.  */
277 			if (TAILQ_FIRST(&t->virtual->prio_sendq)) {
278 				msg = TAILQ_FIRST(&t->virtual->prio_sendq);
279 				TAILQ_REMOVE(&t->virtual->prio_sendq, msg,
280 				    link);
281 			} else {
282 				msg = TAILQ_FIRST(&t->virtual->sendq);
283 				TAILQ_REMOVE(&t->virtual->sendq, msg, link);
284 			}
285 
286 			msg->flags &= ~MSG_IN_TRANSIT;
287 			exchange = msg->exchange;
288 			exchange->in_transit = 0;
289 
290 			/*
291 			 * We disregard the potential error message here,
292 			 * hoping that the retransmit will go better.
293 			 * XXX Consider a retry/fatal error discriminator.
294 			 */
295 			t->virtual->vtbl->send_message(msg, 0);
296 			msg->xmits++;
297 
298 			/*
299 			 * This piece of code has been proven to be quite
300 			 * delicate. Think twice for before altering.
301 			 * Here's an outline:
302 			 *
303 			 * If this message is not the one which finishes an
304 			 * exchange, check if we have reached the number of
305 			 * retransmit before queuing it up for another.
306 			 *
307 			 * If it is a finishing message we still may have to
308 			 * keep it around for an on-demand retransmit when
309 			 * seeing a duplicate of our peer's previous message.
310 			 */
311 			if ((msg->flags & MSG_LAST) == 0) {
312 				if (msg->flags & MSG_DONTRETRANSMIT)
313 					exchange->last_sent = 0;
314 				else if (msg->xmits > conf_get_num("General",
315 				    "retransmits", RETRANSMIT_DEFAULT)) {
316 					t->virtual->vtbl->get_dst(t->virtual, &dst);
317 					if (getnameinfo(dst, SA_LEN(dst), peer,
318 					    sizeof peer, peersv, sizeof peersv,
319 					    NI_NUMERICHOST | NI_NUMERICSERV)) {
320 						strlcpy(peer, "<unknown>", sizeof peer);
321 						strlcpy(peersv, "<?>", sizeof peersv);
322 					}
323 					log_print("transport_send_messages: "
324 					    "giving up on exchange %s, no "
325 					    "response from peer %s:%s",
326 					    exchange->name ? exchange->name :
327 					    "<unnamed>", peer, peersv);
328 
329 					exchange->last_sent = 0;
330 #ifdef notyet
331 					exchange_free(exchange);
332 					exchange = 0;
333 #endif
334 				} else {
335 					clock_gettime(CLOCK_MONOTONIC,
336 					    &expiration);
337 
338 					/*
339 					 * XXX Calculate from round trip
340 					 * timings and a backoff func.
341 					 */
342 					expiry = msg->xmits * 2 + 5;
343 					expiration.tv_sec += expiry;
344 					LOG_DBG((LOG_TRANSPORT, 30,
345 					    "transport_send_messages: "
346 					    "message %p scheduled for "
347 					    "retransmission %d in %d secs",
348 					    msg, msg->xmits, expiry));
349 					if (msg->retrans)
350 						timer_remove_event(msg->retrans);
351 					msg->retrans
352 					    = timer_add_event("message_send_expire",
353 						(void (*) (void *)) message_send_expire,
354 						msg, &expiration);
355 					/*
356 					 * If we cannot retransmit, we
357 					 * cannot...
358 					 */
359 					exchange->last_sent =
360 					    msg->retrans ? msg : 0;
361 				}
362 			} else
363 				exchange->last_sent =
364 				    exchange->last_received ? msg : 0;
365 
366 			/*
367 			 * If this message is not referred to for later
368 			 * retransmission it will be ok for us to drop it
369 			 * after the post-send function. But as the post-send
370 			 * function may remove the exchange, we need to
371 			 * remember this fact here.
372 			 */
373 			ok_to_drop_message = exchange->last_sent == 0;
374 
375 			/*
376 			 * If this is not a retransmit call post-send
377 			 * functions that allows parallel work to be done
378 			 * while the network and peer does their share of
379 			 * the job.  Note that a post-send function may take
380 			 * away the exchange we belong to, but only if no
381 			 * retransmits are possible.
382 			 */
383 			if (msg->xmits == 1)
384 				message_post_send(msg);
385 
386 			if (ok_to_drop_message)
387 				message_free(msg);
388 		}
389 	}
390 
391 	for (t = LIST_FIRST(&transport_list); t; t = next) {
392 		next = LIST_NEXT(t, link);
393 		transport_release(t->virtual);
394 	}
395 }
396 
397 /*
398  * Textual search after the transport method denoted by NAME, then create
399  * a transport connected to the peer with address ADDR, given in a transport-
400  * specific string format.
401  */
402 struct transport *
403 transport_create(char *name, char *addr)
404 {
405 	struct transport_vtbl *method;
406 
407 	for (method = LIST_FIRST(&transport_method_list); method;
408 	    method = LIST_NEXT(method, link))
409 		if (strcmp(method->name, name) == 0)
410 			return (*method->create) (addr);
411 	return 0;
412 }
413