1*2f1aa25bSmpi /* $OpenBSD: connection.c,v 1.41 2018/01/15 09:54:48 mpi Exp $ */
240f7ee3dSniklas /* $EOM: connection.c,v 1.28 2000/11/23 12:21:18 niklas Exp $ */
35ddb0317Sniklas
45ddb0317Sniklas /*
542af7185Sniklas * Copyright (c) 1999, 2000, 2001 Niklas Hallqvist. All rights reserved.
622d612abSniklas * Copyright (c) 1999 Hakan Olsson. All rights reserved.
75ddb0317Sniklas *
85ddb0317Sniklas * Redistribution and use in source and binary forms, with or without
95ddb0317Sniklas * modification, are permitted provided that the following conditions
105ddb0317Sniklas * are met:
115ddb0317Sniklas * 1. Redistributions of source code must retain the above copyright
125ddb0317Sniklas * notice, this list of conditions and the following disclaimer.
135ddb0317Sniklas * 2. Redistributions in binary form must reproduce the above copyright
145ddb0317Sniklas * notice, this list of conditions and the following disclaimer in the
155ddb0317Sniklas * documentation and/or other materials provided with the distribution.
165ddb0317Sniklas *
175ddb0317Sniklas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
185ddb0317Sniklas * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
195ddb0317Sniklas * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
205ddb0317Sniklas * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
215ddb0317Sniklas * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
225ddb0317Sniklas * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
235ddb0317Sniklas * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245ddb0317Sniklas * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255ddb0317Sniklas * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
265ddb0317Sniklas * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275ddb0317Sniklas */
285ddb0317Sniklas
295ddb0317Sniklas /*
305ddb0317Sniklas * This code was written under funding by Ericsson Radio Systems.
315ddb0317Sniklas */
325ddb0317Sniklas
335ddb0317Sniklas #include <sys/queue.h>
34f6511159Sniklas #include <sys/socket.h>
355ddb0317Sniklas #include <stdlib.h>
365ddb0317Sniklas #include <string.h>
375ddb0317Sniklas
385ddb0317Sniklas #include "conf.h"
395ddb0317Sniklas #include "connection.h"
40454877a4Sniklas #include "doi.h"
41937dccddSniklas #include "ipsec.h"
423a722197Shshoexer #include "pf_key_v2.h"
43937dccddSniklas
44454877a4Sniklas /* XXX isakmp.h only required for compare_ids(). */
45937dccddSniklas #include "isakmp.h"
46937dccddSniklas
475ddb0317Sniklas #include "log.h"
485ddb0317Sniklas #include "timer.h"
4914f1d06aSmpf #include "ui.h"
50937dccddSniklas #include "util.h"
515ddb0317Sniklas
525ddb0317Sniklas /* How often should we check that connections we require to be up, are up? */
535ddb0317Sniklas #define CHECK_INTERVAL 60
545ddb0317Sniklas
554c8c122bSho static void connection_passive_teardown(char *);
564c8c122bSho
57fb9475d6Sderaadt struct connection {
585ddb0317Sniklas TAILQ_ENTRY(connection) link;
595ddb0317Sniklas char *name;
605ddb0317Sniklas struct event *ev;
615ddb0317Sniklas };
625ddb0317Sniklas
63fb9475d6Sderaadt struct connection_passive {
64937dccddSniklas TAILQ_ENTRY(connection_passive) link;
65937dccddSniklas char *name;
66937dccddSniklas u_int8_t *local_id, *remote_id;
67937dccddSniklas size_t local_sz, remote_sz;
68937dccddSniklas
69937dccddSniklas #if 0
70937dccddSniklas /* XXX Potential additions to 'connection_passive'. */
71937dccddSniklas char *isakmp_peer;
72937dccddSniklas struct sa *sa; /* XXX "Soft" ref to active sa? */
736ee513e5Sjca struct timespec sa_expiration; /* XXX *sa may expire. */
74937dccddSniklas #endif
75937dccddSniklas };
76937dccddSniklas
775ddb0317Sniklas TAILQ_HEAD(connection_head, connection) connections;
78937dccddSniklas TAILQ_HEAD(passive_head, connection_passive) connections_passive;
795ddb0317Sniklas
805ddb0317Sniklas /*
815ddb0317Sniklas * This is where we setup all the connections we want there right from the
825ddb0317Sniklas * start.
835ddb0317Sniklas */
845ddb0317Sniklas void
connection_init(void)8530c1e3c7Sho connection_init(void)
865ddb0317Sniklas {
87937dccddSniklas struct conf_list *conns, *attrs;
881cda6f75Sderaadt struct conf_list_node *conn, *attr = NULL;
89937dccddSniklas
90937dccddSniklas /*
91937dccddSniklas * Passive connections normally include: all "active" connections that
92937dccddSniklas * are not flagged "Active-Only", plus all connections listed in
93937dccddSniklas * the 'Passive-Connections' list.
94937dccddSniklas */
955ddb0317Sniklas TAILQ_INIT(&connections);
96937dccddSniklas TAILQ_INIT(&connections_passive);
97937dccddSniklas
985ddb0317Sniklas conns = conf_get_list("Phase 2", "Connections");
99fb9475d6Sderaadt if (conns) {
1005ddb0317Sniklas for (conn = TAILQ_FIRST(&conns->fields); conn;
101fb9475d6Sderaadt conn = TAILQ_NEXT(conn, link)) {
1025ddb0317Sniklas if (connection_setup(conn->field))
103df915834Shshoexer log_print("connection_init: could not setup "
104df915834Shshoexer "\"%s\"", conn->field);
105937dccddSniklas
106937dccddSniklas /* XXX Break/abort here if connection_setup failed? */
107937dccddSniklas
108937dccddSniklas /*
109df915834Shshoexer * XXX This code (i.e. the attribute lookup) seems
110df915834Shshoexer * like a likely candidate for factoring out into a
111df915834Shshoexer * function of its own.
112937dccddSniklas */
113937dccddSniklas attrs = conf_get_list(conn->field, "Flags");
114937dccddSniklas if (attrs)
115937dccddSniklas for (attr = TAILQ_FIRST(&attrs->fields); attr;
116937dccddSniklas attr = TAILQ_NEXT(attr, link))
117df915834Shshoexer if (strcasecmp("active-only",
118df915834Shshoexer attr->field) == 0)
119937dccddSniklas break;
120937dccddSniklas if (!attrs || (attrs && !attr))
121937dccddSniklas if (connection_record_passive(conn->field))
122df915834Shshoexer log_print("connection_init: could not "
123df915834Shshoexer "record connection \"%s\"",
124df915834Shshoexer conn->field);
125937dccddSniklas if (attrs)
126937dccddSniklas conf_free_list(attrs);
127937dccddSniklas
1285ddb0317Sniklas }
1295ddb0317Sniklas conf_free_list(conns);
1305ddb0317Sniklas }
131937dccddSniklas conns = conf_get_list("Phase 2", "Passive-Connections");
132fb9475d6Sderaadt if (conns) {
133937dccddSniklas for (conn = TAILQ_FIRST(&conns->fields); conn;
134937dccddSniklas conn = TAILQ_NEXT(conn, link))
135937dccddSniklas if (connection_record_passive(conn->field))
136df915834Shshoexer log_print("connection_init: could not record "
137df915834Shshoexer "passive connection \"%s\"", conn->field);
138937dccddSniklas conf_free_list(conns);
139937dccddSniklas }
1405ddb0317Sniklas }
1415ddb0317Sniklas
1425ddb0317Sniklas /* Check the connection in VCONN and schedule another check later. */
1435ddb0317Sniklas static void
connection_checker(void * vconn)1445ddb0317Sniklas connection_checker(void *vconn)
1455ddb0317Sniklas {
1466ee513e5Sjca struct timespec now;
1475ddb0317Sniklas struct connection *conn = vconn;
1488fe2399aSmpi char *name;
1495ddb0317Sniklas
1506ee513e5Sjca clock_gettime(CLOCK_MONOTONIC, &now);
15150eea14cSho now.tv_sec += conf_get_num("General", "check-interval",
15250eea14cSho CHECK_INTERVAL);
153fb9475d6Sderaadt conn->ev = timer_add_event("connection_checker",
154fb9475d6Sderaadt connection_checker, conn, &now);
1555ddb0317Sniklas if (!conn->ev)
1568fe2399aSmpi log_print("%s: could not add timer event", __func__);
1578fe2399aSmpi if (ui_daemon_passive)
1588fe2399aSmpi return;
1598fe2399aSmpi
1608fe2399aSmpi name = strdup(conn->name);
1618fe2399aSmpi if (!name) {
1628fe2399aSmpi log_print("%s: strdup (\"%s\") failed", __func__, conn->name);
1638fe2399aSmpi return;
1648fe2399aSmpi }
1658fe2399aSmpi pf_key_v2_connection_check(name);
1665ddb0317Sniklas }
1675ddb0317Sniklas
1685ddb0317Sniklas /* Find the connection named NAME. */
1695ddb0317Sniklas static struct connection *
connection_lookup(char * name)1705ddb0317Sniklas connection_lookup(char *name)
1715ddb0317Sniklas {
1725ddb0317Sniklas struct connection *conn;
1735ddb0317Sniklas
174df915834Shshoexer for (conn = TAILQ_FIRST(&connections); conn;
175df915834Shshoexer conn = TAILQ_NEXT(conn, link))
1765ddb0317Sniklas if (strcasecmp(conn->name, name) == 0)
1775ddb0317Sniklas return conn;
1785ddb0317Sniklas return 0;
1795ddb0317Sniklas }
1805ddb0317Sniklas
18122d612abSniklas /* Does the connection named NAME exist? */
18222d612abSniklas int
connection_exist(char * name)18322d612abSniklas connection_exist(char *name)
18422d612abSniklas {
1850eb823c5Sniklas return (connection_lookup(name) != 0);
18622d612abSniklas }
18722d612abSniklas
188937dccddSniklas /* Find the passive connection named NAME. */
189937dccddSniklas static struct connection_passive *
connection_passive_lookup_by_name(char * name)190937dccddSniklas connection_passive_lookup_by_name(char *name)
191937dccddSniklas {
192937dccddSniklas struct connection_passive *conn;
193937dccddSniklas
194937dccddSniklas for (conn = TAILQ_FIRST(&connections_passive); conn;
195937dccddSniklas conn = TAILQ_NEXT(conn, link))
196937dccddSniklas if (strcasecmp(conn->name, name) == 0)
197937dccddSniklas return conn;
198937dccddSniklas return 0;
199937dccddSniklas }
200937dccddSniklas
201937dccddSniklas /*
202937dccddSniklas * IDs of different types cannot be the same.
203937dccddSniklas * XXX Rename to ipsec_compare_id, and move to ipsec.c ?
204937dccddSniklas */
205937dccddSniklas static int
compare_ids(u_int8_t * id1,u_int8_t * id2,size_t idlen)206937dccddSniklas compare_ids(u_int8_t *id1, u_int8_t *id2, size_t idlen)
207937dccddSniklas {
208937dccddSniklas int id1_type, id2_type;
209937dccddSniklas
210937dccddSniklas id1_type = GET_ISAKMP_ID_TYPE(id1);
211937dccddSniklas id2_type = GET_ISAKMP_ID_TYPE(id2);
212937dccddSniklas
213fb9475d6Sderaadt return id1_type == id2_type ? memcmp(id1 + ISAKMP_ID_DATA_OFF,
214fb9475d6Sderaadt id2 + ISAKMP_ID_DATA_OFF, idlen - ISAKMP_ID_DATA_OFF) : -1;
215937dccddSniklas }
216937dccddSniklas
217937dccddSniklas /* Find the connection named with matching IDs. */
218937dccddSniklas char *
connection_passive_lookup_by_ids(u_int8_t * id1,u_int8_t * id2)219937dccddSniklas connection_passive_lookup_by_ids(u_int8_t *id1, u_int8_t *id2)
220937dccddSniklas {
221937dccddSniklas struct connection_passive *conn;
222937dccddSniklas
223937dccddSniklas for (conn = TAILQ_FIRST(&connections_passive); conn;
224fb9475d6Sderaadt conn = TAILQ_NEXT(conn, link)) {
2250eb823c5Sniklas if (!conn->remote_id)
226e21c3de4Sniklas continue;
227e21c3de4Sniklas
228937dccddSniklas /*
229df915834Shshoexer * If both IDs match what we have saved, return the name.
230df915834Shshoexer * Don't bother in which order they are.
231937dccddSniklas */
232fb9475d6Sderaadt if ((compare_ids(id1, conn->local_id, conn->local_sz) == 0 &&
233fb9475d6Sderaadt compare_ids(id2, conn->remote_id, conn->remote_sz) == 0) ||
234fb9475d6Sderaadt (compare_ids(id1, conn->remote_id, conn->remote_sz) == 0 &&
235fb9475d6Sderaadt compare_ids(id2, conn->local_id, conn->local_sz) == 0)) {
23651ca15aeSniklas LOG_DBG((LOG_MISC, 60,
23750eea14cSho "connection_passive_lookup_by_ids: "
23850eea14cSho "returned \"%s\"", conn->name));
239937dccddSniklas return conn->name;
240937dccddSniklas }
241937dccddSniklas }
242e21c3de4Sniklas
243fb9475d6Sderaadt /*
244fb9475d6Sderaadt * In the road warrior case, we do not know the remote ID. In that
245e21c3de4Sniklas * case we will just match against the local ID.
246e21c3de4Sniklas */
247e21c3de4Sniklas for (conn = TAILQ_FIRST(&connections_passive); conn;
248fb9475d6Sderaadt conn = TAILQ_NEXT(conn, link)) {
2490eb823c5Sniklas if (!conn->remote_id)
250e21c3de4Sniklas continue;
251e21c3de4Sniklas
252fb9475d6Sderaadt if (compare_ids(id1, conn->local_id, conn->local_sz) == 0 ||
253fb9475d6Sderaadt compare_ids(id2, conn->local_id, conn->local_sz) == 0) {
254e21c3de4Sniklas LOG_DBG((LOG_MISC, 60,
255e46ba839Shshoexer "connection_passive_lookup_by_ids: returned \"%s\""
256e21c3de4Sniklas " only matched local id", conn->name));
257e21c3de4Sniklas return conn->name;
258e21c3de4Sniklas }
259e21c3de4Sniklas }
26051ca15aeSniklas LOG_DBG((LOG_MISC, 60,
26151ca15aeSniklas "connection_passive_lookup_by_ids: no match"));
262937dccddSniklas return 0;
263937dccddSniklas }
264937dccddSniklas
2655ddb0317Sniklas /*
2665ddb0317Sniklas * Setup NAME to be a connection that should be up "always", i.e. if it dies,
2675ddb0317Sniklas * for whatever reason, it should be tried to be brought up, over and over
2685ddb0317Sniklas * again.
2695ddb0317Sniklas */
2705ddb0317Sniklas int
connection_setup(char * name)2715ddb0317Sniklas connection_setup(char *name)
2725ddb0317Sniklas {
2735ddb0317Sniklas struct connection *conn = 0;
2746ee513e5Sjca struct timespec now;
2755ddb0317Sniklas
2765ddb0317Sniklas /* Check for trials to add duplicate connections. */
277fb9475d6Sderaadt if (connection_lookup(name)) {
278d2a2baa1Sho LOG_DBG((LOG_MISC, 10,
279d2a2baa1Sho "connection_setup: cannot add \"%s\" twice", name));
2805ddb0317Sniklas return 0;
2815ddb0317Sniklas }
2825ddb0317Sniklas conn = calloc(1, sizeof *conn);
283fb9475d6Sderaadt if (!conn) {
2840cd3ca40Sho log_error("connection_setup: calloc (1, %lu) failed",
2850cd3ca40Sho (unsigned long)sizeof *conn);
2865ddb0317Sniklas goto fail;
2875ddb0317Sniklas }
2885ddb0317Sniklas conn->name = strdup(name);
289fb9475d6Sderaadt if (!conn->name) {
2905ddb0317Sniklas log_error("connection_setup: strdup (\"%s\") failed", name);
2915ddb0317Sniklas goto fail;
2925ddb0317Sniklas }
2936ee513e5Sjca clock_gettime(CLOCK_MONOTONIC, &now);
294df915834Shshoexer conn->ev = timer_add_event("connection_checker", connection_checker,
295df915834Shshoexer conn, &now);
296fb9475d6Sderaadt if (!conn->ev) {
2975ddb0317Sniklas log_print("connection_setup: could not add timer event");
2985ddb0317Sniklas goto fail;
2995ddb0317Sniklas }
3005ddb0317Sniklas TAILQ_INSERT_TAIL(&connections, conn, link);
3015ddb0317Sniklas return 0;
3025ddb0317Sniklas
3035ddb0317Sniklas fail:
304fb9475d6Sderaadt if (conn) {
3055ddb0317Sniklas free(conn->name);
3065ddb0317Sniklas free(conn);
3075ddb0317Sniklas }
3085ddb0317Sniklas return -1;
3095ddb0317Sniklas }
3105ddb0317Sniklas
311937dccddSniklas int
connection_record_passive(char * name)312937dccddSniklas connection_record_passive(char *name)
313937dccddSniklas {
314937dccddSniklas struct connection_passive *conn;
315937dccddSniklas char *local_id, *remote_id;
316937dccddSniklas
317fb9475d6Sderaadt if (connection_passive_lookup_by_name(name)) {
31851ca15aeSniklas LOG_DBG((LOG_MISC, 10,
319937dccddSniklas "connection_record_passive: cannot add \"%s\" twice",
32051ca15aeSniklas name));
321937dccddSniklas return 0;
322937dccddSniklas }
323937dccddSniklas local_id = conf_get_str(name, "Local-ID");
324fb9475d6Sderaadt if (!local_id) {
325937dccddSniklas log_print("connection_record_passive: "
326fb9475d6Sderaadt "\"Local-ID\" is missing from section [%s]", name);
327937dccddSniklas return -1;
328937dccddSniklas }
329e21c3de4Sniklas /* If the remote id lookup fails we defer it to later */
330e21c3de4Sniklas remote_id = conf_get_str(name, "Remote-ID");
331e21c3de4Sniklas
332937dccddSniklas conn = calloc(1, sizeof *conn);
333fb9475d6Sderaadt if (!conn) {
3347eb3b581Sderaadt log_error("connection_record_passive: calloc (1, %lu) failed",
3357eb3b581Sderaadt (unsigned long)sizeof *conn);
336937dccddSniklas return -1;
337937dccddSniklas }
338937dccddSniklas conn->name = strdup(name);
339fb9475d6Sderaadt if (!conn->name) {
340d2a2baa1Sho log_error("connection_record_passive: strdup (\"%s\") failed",
341d2a2baa1Sho name);
342937dccddSniklas goto fail;
343937dccddSniklas }
34461d575f0Sangelos /* XXX IPsec DOI-specific. */
345937dccddSniklas conn->local_id = ipsec_build_id(local_id, &conn->local_sz);
346937dccddSniklas if (!conn->local_id)
347937dccddSniklas goto fail;
348937dccddSniklas
349fb9475d6Sderaadt if (remote_id) {
350937dccddSniklas conn->remote_id = ipsec_build_id(remote_id, &conn->remote_sz);
351937dccddSniklas if (!conn->remote_id)
352937dccddSniklas goto fail;
353fb9475d6Sderaadt } else
3540eb823c5Sniklas conn->remote_id = 0;
355937dccddSniklas
356937dccddSniklas TAILQ_INSERT_TAIL(&connections_passive, conn, link);
357937dccddSniklas
35851ca15aeSniklas LOG_DBG((LOG_MISC, 60,
359fb9475d6Sderaadt "connection_record_passive: passive connection \"%s\" added",
360fb9475d6Sderaadt conn->name));
361937dccddSniklas return 0;
362937dccddSniklas
363937dccddSniklas fail:
364937dccddSniklas free(conn->local_id);
365937dccddSniklas free(conn->name);
366937dccddSniklas free(conn);
367937dccddSniklas return -1;
368937dccddSniklas }
369937dccddSniklas
3705ddb0317Sniklas /* Remove the connection named NAME. */
3715ddb0317Sniklas void
connection_teardown(char * name)3725ddb0317Sniklas connection_teardown(char *name)
3735ddb0317Sniklas {
3745ddb0317Sniklas struct connection *conn;
3755ddb0317Sniklas
3765ddb0317Sniklas conn = connection_lookup(name);
3775ddb0317Sniklas if (!conn)
3785ddb0317Sniklas return;
3795ddb0317Sniklas
3805ddb0317Sniklas TAILQ_REMOVE(&connections, conn, link);
3815ddb0317Sniklas timer_remove_event(conn->ev);
3825ddb0317Sniklas free(conn->name);
3835ddb0317Sniklas free(conn);
3845ddb0317Sniklas }
385937dccddSniklas
386937dccddSniklas /* Remove the passive connection named NAME. */
3874c8c122bSho static void
connection_passive_teardown(char * name)388937dccddSniklas connection_passive_teardown(char *name)
389937dccddSniklas {
390937dccddSniklas struct connection_passive *conn;
391937dccddSniklas
392937dccddSniklas conn = connection_passive_lookup_by_name(name);
393937dccddSniklas if (!conn)
394937dccddSniklas return;
395937dccddSniklas
396937dccddSniklas TAILQ_REMOVE(&connections_passive, conn, link);
397937dccddSniklas free(conn->name);
398937dccddSniklas free(conn->local_id);
399937dccddSniklas free(conn->remote_id);
400937dccddSniklas free(conn);
401937dccddSniklas }
402937dccddSniklas
403937dccddSniklas void
connection_report(void)404937dccddSniklas connection_report(void)
405937dccddSniklas {
406937dccddSniklas struct connection *conn;
4076ee513e5Sjca struct timespec now;
408f6511159Sniklas struct connection_passive *pconn;
409454877a4Sniklas struct doi *doi = doi_lookup(ISAKMP_DOI_ISAKMP);
410937dccddSniklas
4116ee513e5Sjca clock_gettime(CLOCK_MONOTONIC, &now);
412d2a2baa1Sho for (conn = TAILQ_FIRST(&connections); conn;
413d2a2baa1Sho conn = TAILQ_NEXT(conn, link))
41451ca15aeSniklas LOG_DBG((LOG_REPORT, 0,
4151c04898dSguenther "connection_report: connection %s next check %lld seconds",
416937dccddSniklas (conn->name ? conn->name : "<unnamed>"),
4171c04898dSguenther (long long)(conn->ev->expiration.tv_sec - now.tv_sec)));
418937dccddSniklas for (pconn = TAILQ_FIRST(&connections_passive); pconn;
419937dccddSniklas pconn = TAILQ_NEXT(pconn, link))
42051ca15aeSniklas LOG_DBG((LOG_REPORT, 0,
421937dccddSniklas "connection_report: passive connection %s %s", pconn->name,
422454877a4Sniklas doi->decode_ids("local_id: %s, remote_id: %s",
423454877a4Sniklas pconn->local_id, pconn->local_sz,
424454877a4Sniklas pconn->remote_id, pconn->remote_sz, 1)));
425937dccddSniklas }
426937dccddSniklas
42705782133Sniklas /* Reinitialize all connections (SIGHUP handling). */
428937dccddSniklas void
connection_reinit(void)429937dccddSniklas connection_reinit(void)
430937dccddSniklas {
43105782133Sniklas struct connection *conn, *next;
43205782133Sniklas struct connection_passive *pconn, *pnext;
433937dccddSniklas
43451ca15aeSniklas LOG_DBG((LOG_MISC, 30,
43551ca15aeSniklas "connection_reinit: reinitializing connection list"));
436937dccddSniklas
437937dccddSniklas /* Remove all present connections. */
438fb9475d6Sderaadt for (conn = TAILQ_FIRST(&connections); conn; conn = next) {
439d317b4b1Stholo next = TAILQ_NEXT(conn, link);
440937dccddSniklas connection_teardown(conn->name);
44105782133Sniklas }
442937dccddSniklas
443fb9475d6Sderaadt for (pconn = TAILQ_FIRST(&connections_passive); pconn; pconn = pnext) {
444d317b4b1Stholo pnext = TAILQ_NEXT(pconn, link);
445937dccddSniklas connection_passive_teardown(pconn->name);
44605782133Sniklas }
447937dccddSniklas
448937dccddSniklas /* Setup new connections, as the (new) config directs. */
449937dccddSniklas connection_init();
450937dccddSniklas }
451