net.c revision 1.5
1/*	$OpenBSD: net.c,v 1.5 2005/05/24 02:35:39 ho Exp $	*/
2
3/*
4 * Copyright (c) 2005 H�kan Olsson.  All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/*
29 * This code was written under funding by Multicom Security AB.
30 */
31
32
33#include <sys/types.h>
34#include <sys/socket.h>
35#include <sys/time.h>
36#include <netinet/in.h>
37#include <arpa/inet.h>
38#include <ifaddrs.h>
39#include <netdb.h>
40
41#include <openssl/aes.h>
42#include <openssl/sha.h>
43
44#include <errno.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <unistd.h>
49
50#include "sasyncd.h"
51#include "net.h"
52
53struct msg {
54	u_int8_t	*buf;
55	u_int32_t	 len;
56	int		 refcnt;
57};
58
59struct qmsg {
60	SIMPLEQ_ENTRY(qmsg)	next;
61	struct msg	*msg;
62};
63
64int	listen_socket;
65AES_KEY	aes_key[2];
66#define AES_IV_LEN	AES_BLOCK_SIZE
67
68/* We never send (or expect to receive) messages smaller/larger than this. */
69#define MSG_MINLEN	12
70#define MSG_MAXLEN	4096
71
72/* Local prototypes. */
73static u_int8_t *net_read(struct syncpeer *, u_int32_t *, u_int32_t *);
74static int	 net_set_sa(struct sockaddr *, char *, in_port_t);
75static void	 net_check_peers(void *);
76
77/* Pretty-print a buffer. */
78void
79dump_buf(int lvl, u_int8_t *b, u_int32_t len, char *title)
80{
81	u_int32_t	i, off, blen;
82	u_int8_t	*buf;
83	const char	def[] = "Buffer:";
84
85	if (cfgstate.verboselevel < lvl)
86		return;
87
88	blen = 2 * (len + len / 36) + 3 + (title ? strlen(title) : sizeof def);
89	if (!(buf = (u_int8_t *)calloc(1, blen)))
90		return;
91
92	snprintf(buf, blen, "%s\n ", title ? title : def);
93	off = strlen(buf);
94	for (i = 0; i < len; i++, off+=2) {
95		snprintf(buf + off, blen - off, "%02x", b[i]);
96		if ((i+1) % 36 == 0) {
97			off += 2;
98			snprintf(buf + off, blen - off, "\n ");
99		}
100	}
101	log_msg(lvl, "%s", buf);
102	free(buf);
103}
104
105int
106net_init(void)
107{
108	struct sockaddr_storage sa_storage;
109	struct sockaddr *sa = (struct sockaddr *)&sa_storage;
110	struct syncpeer *p;
111	char		 host[NI_MAXHOST], port[NI_MAXSERV];
112	int		 r;
113
114	/* The shared key needs to be 128, 192 or 256 bits */
115	r = strlen(cfgstate.sharedkey) << 3;
116	if (r != 128 && r != 192 && r != 256) {
117		fprintf(stderr, "Bad shared key length (%d bits), "
118		    "should be 128, 192 or 256\n", r);
119		return -1;
120	}
121
122	if (AES_set_encrypt_key(cfgstate.sharedkey, r, &aes_key[0]) ||
123	    AES_set_decrypt_key(cfgstate.sharedkey, r, &aes_key[1])) {
124		fprintf(stderr, "Bad AES shared key\n");
125		return -1;
126	}
127
128	/* Setup listening socket.  */
129	memset(&sa_storage, 0, sizeof sa_storage);
130	if (net_set_sa(sa, cfgstate.listen_on, cfgstate.listen_port)) {
131		log_msg(0, "net_init: could not find listen address (%s)",
132		    cfgstate.listen_on);
133		return -1;
134	}
135
136	listen_socket = socket(sa->sa_family, SOCK_STREAM, 0);
137	if (listen_socket < 0) {
138		perror("socket()");
139		close(listen_socket);
140		return -1;
141	}
142	r = 1;
143	if (setsockopt(listen_socket, SOL_SOCKET,
144	    cfgstate.listen_on ? SO_REUSEADDR : SO_REUSEPORT, (void *)&r,
145	    sizeof r)) {
146		perror("setsockopt()");
147		close(listen_socket);
148		return -1;
149	}
150	if (bind(listen_socket, sa, sizeof(struct sockaddr_in))) {
151		perror("bind()");
152		close(listen_socket);
153		return -1;
154	}
155	if (listen(listen_socket, 10)) {
156		perror("listen()");
157		close(listen_socket);
158		return -1;
159	}
160
161	if (getnameinfo(sa, sa->sa_len, host, sizeof host, port, sizeof port,
162		NI_NUMERICHOST | NI_NUMERICSERV))
163		log_msg(2, "listening on port %u fd %d", cfgstate.listen_port,
164		    listen_socket);
165	else
166		log_msg(2, "listening on %s port %s fd %d", host, port,
167		    listen_socket);
168
169	for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link)) {
170		p->socket = -1;
171		SIMPLEQ_INIT(&p->msgs);
172	}
173
174	net_check_peers(0);
175	return 0;
176}
177
178static void
179net_enqueue(struct syncpeer *p, struct msg *m)
180{
181	struct qmsg	*qm;
182
183	if (p->socket < 0)
184		return;
185
186	qm = (struct qmsg *)malloc(sizeof *qm);
187	if (!qm) {
188		log_err("malloc()");
189		return;
190	}
191
192	memset(qm, 0, sizeof *qm);
193	qm->msg = m;
194	m->refcnt++;
195
196	SIMPLEQ_INSERT_TAIL(&p->msgs, qm, next);
197	return;
198}
199
200/*
201 * Queue a message for transmission to a particular peer,
202 * or to all peers if no peer is specified.
203 */
204int
205net_queue(struct syncpeer *p0, u_int32_t msgtype, u_int8_t *buf, u_int32_t len)
206{
207	struct syncpeer *p = p0;
208	struct msg	*m;
209	SHA_CTX		 ctx;
210	u_int8_t	 hash[SHA_DIGEST_LENGTH];
211	u_int8_t	 iv[AES_IV_LEN], tmp_iv[AES_IV_LEN];
212	u_int32_t	 v, padlen = 0;
213	int		 i, offset;
214
215	m = (struct msg *)calloc(1, sizeof *m);
216	if (!m) {
217		log_err("calloc()");
218		free(buf);
219		return -1;
220	}
221
222	/* Generate hash */
223	SHA1_Init(&ctx);
224	SHA1_Update(&ctx, buf, len);
225	SHA1_Final(hash, &ctx);
226	dump_buf(5, hash, sizeof hash, "net_queue: computed hash");
227
228	/* Padding required? */
229	i = len % AES_IV_LEN;
230	if (i) {
231		u_int8_t *pbuf;
232		i = AES_IV_LEN - i;
233		pbuf = realloc(buf, len + i);
234		if (!pbuf) {
235			log_err("net_queue: realloc()");
236			free(buf);
237			free(m);
238			return -1;
239		}
240		padlen = i;
241		while (i > 0)
242			pbuf[len++] = (u_int8_t)i--;
243		buf = pbuf;
244	}
245
246	/* Get random IV */
247	for (i = 0; i <= sizeof iv - sizeof v; i += sizeof v) {
248		v = arc4random();
249		memcpy(&iv[i], &v, sizeof v);
250	}
251	dump_buf(5, iv, sizeof iv, "net_queue: IV");
252	memcpy(tmp_iv, iv, sizeof tmp_iv);
253
254	/* Encrypt */
255	dump_buf(5, buf, len, "net_queue: pre encrypt");
256	AES_cbc_encrypt(buf, buf, len, &aes_key[0], tmp_iv, AES_ENCRYPT);
257	dump_buf(5, buf, len, "net_queue: post encrypt");
258
259	/* Allocate send buffer */
260	m->len = len + sizeof iv + sizeof hash + 3 * sizeof(u_int32_t);
261	m->buf = (u_int8_t *)malloc(m->len);
262	if (!m->buf) {
263		free(m);
264		free(buf);
265		log_err("net_queue: calloc()");
266		return -1;
267	}
268	offset = 0;
269
270	/* Fill it (order must match parsing code in net_read()) */
271	v = htonl(m->len - sizeof(u_int32_t));
272	memcpy(m->buf + offset, &v, sizeof v);
273	offset += sizeof v;
274	v = htonl(msgtype);
275	memcpy(m->buf + offset, &v, sizeof v);
276	offset += sizeof v;
277	v = htonl(padlen);
278	memcpy(m->buf + offset, &v, sizeof v);
279	offset += sizeof v;
280	memcpy(m->buf + offset, hash, sizeof hash);
281	offset += sizeof hash;
282	memcpy(m->buf + offset, iv, sizeof iv);
283	offset += sizeof iv;
284	memcpy(m->buf + offset, buf, len);
285	free(buf);
286
287	if (p)
288		net_enqueue(p, m);
289	else
290		for (p = LIST_FIRST(&cfgstate.peerlist); p;
291		     p = LIST_NEXT(p, link))
292			net_enqueue(p, m);
293
294	if (!m->refcnt) {
295		free(m->buf);
296		free(m);
297	}
298
299	return 0;
300}
301
302/* Set all write pending filedescriptors. */
303int
304net_set_pending_wfds(fd_set *fds)
305{
306	struct syncpeer *p;
307	int		max_fd = -1;
308
309	for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link))
310		if (p->socket > -1 && SIMPLEQ_FIRST(&p->msgs)) {
311			FD_SET(p->socket, fds);
312			if (p->socket > max_fd)
313				max_fd = p->socket;
314		}
315	return max_fd + 1;
316}
317
318/*
319 * Set readable filedescriptors. They are basically the same as for write,
320 * plus the listening socket.
321 */
322int
323net_set_rfds(fd_set *fds)
324{
325	struct syncpeer *p;
326	int		max_fd = -1;
327
328	for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link)) {
329		if (p->socket > -1)
330			FD_SET(p->socket, fds);
331		if (p->socket > max_fd)
332			max_fd = p->socket;
333	}
334	FD_SET(listen_socket, fds);
335	if (listen_socket > max_fd)
336		max_fd = listen_socket;
337	return max_fd + 1;
338}
339
340void
341net_handle_messages(fd_set *fds)
342{
343	struct sockaddr_storage	sa_storage, sa_storage2;
344	struct sockaddr	*sa = (struct sockaddr *)&sa_storage;
345	struct sockaddr	*sa2 = (struct sockaddr *)&sa_storage2;
346	socklen_t	socklen;
347	struct syncpeer *p;
348	u_int8_t	*msg;
349	u_int32_t	 msgtype, msglen;
350	int		 newsock, found;
351
352	if (FD_ISSET(listen_socket, fds)) {
353		/* Accept a new incoming connection */
354		socklen = sizeof sa_storage;
355		newsock = accept(listen_socket, sa, &socklen);
356		if (newsock > -1) {
357			/* Setup the syncpeer structure */
358			found = 0;
359			for (p = LIST_FIRST(&cfgstate.peerlist); p && !found;
360			     p = LIST_NEXT(p, link)) {
361				struct sockaddr_in *sin, *sin2;
362				struct sockaddr_in6 *sin6, *sin62;
363
364				/* Match? */
365				if (net_set_sa(sa2, p->name, 0))
366					continue;
367				if (sa->sa_family != sa2->sa_family)
368					continue;
369				if (sa->sa_family == AF_INET) {
370					sin = (struct sockaddr_in *)sa;
371					sin2 = (struct sockaddr_in *)sa2;
372					if (memcmp(&sin->sin_addr,
373					    &sin2->sin_addr,
374					    sizeof(struct in_addr)))
375						continue;
376				} else {
377					sin6 = (struct sockaddr_in6 *)sa;
378					sin62 = (struct sockaddr_in6 *)sa2;
379					if (memcmp(&sin6->sin6_addr,
380					    &sin62->sin6_addr,
381					    sizeof(struct in6_addr)))
382						continue;
383				}
384				/* Match! */
385				found++;
386				p->socket = newsock;
387				log_msg(1, "net: peer \"%s\" connected",
388				    p->name);
389				if (cfgstate.runstate == MASTER)
390					timer_add("pfkey_snapshot", 2,
391					    pfkey_snapshot, p);
392			}
393			if (!found) {
394				log_msg(1, "net: found no matching peer for "
395				    "accepted socket, closing.");
396				close(newsock);
397			}
398		} else
399			log_err("accept()");
400	}
401
402	for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link)) {
403		if (p->socket < 0 || !FD_ISSET(p->socket, fds))
404			continue;
405		msg = net_read(p, &msgtype, &msglen);
406		if (!msg)
407			continue;
408
409		log_msg(4, "net_handle_messages: got msg type %u len %u from "
410		    "peer %s", msgtype, msglen, p->name);
411
412		switch (msgtype) {
413		case MSG_SYNCCTL:
414			net_ctl_handle_msg(p, msg, msglen);
415			free(msg);
416			break;
417
418		case MSG_PFKEYDATA:
419			if (p->runstate != MASTER ||
420			    cfgstate.runstate == MASTER) {
421				log_msg(1, "net: got PFKEY message from "
422				    "non-MASTER peer");
423				free(msg);
424				if (cfgstate.runstate == MASTER)
425					net_ctl_send_state(p);
426				else
427					net_ctl_send_error(p, 0);
428			} else if (pfkey_queue_message(msg, msglen))
429				free(msg);
430			break;
431
432		default:
433			log_msg(0, "net: got unknown message type %u len %u "
434			    "from peer %s", msgtype, msglen, p->name);
435			free(msg);
436			net_ctl_send_error(p, 0);
437		}
438	}
439}
440
441void
442net_send_messages(fd_set *fds)
443{
444	struct syncpeer *p;
445	struct qmsg	*qm;
446	struct msg	*m;
447	ssize_t		 r;
448
449	for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link)) {
450		if (p->socket < 0 || !FD_ISSET(p->socket, fds))
451			continue;
452		qm = SIMPLEQ_FIRST(&p->msgs);
453		if (!qm) {
454			/* XXX Log */
455			continue;
456		}
457		m = qm->msg;
458
459		log_msg(4, "net_send_messages: msg %p len %d ref %d "
460		    "to peer %s", m, m->len, m->refcnt, p->name);
461
462		/* write message */
463		r = write(p->socket, m->buf, m->len);
464		if (r == -1) {
465			net_disconnect_peer(p);
466			log_msg(0, "net_send_messages: write() failed, "
467			    "peer disconnected");
468		} else if (r < (ssize_t)m->len) {
469			/* retransmit later */
470			continue;
471		}
472
473		/* cleanup */
474		SIMPLEQ_REMOVE_HEAD(&p->msgs, next);
475		free(qm);
476
477		if (--m->refcnt < 1) {
478			log_msg(4, "net_send_messages: freeing msg %p", m);
479			free(m->buf);
480			free(m);
481		}
482	}
483	return;
484}
485
486void
487net_disconnect_peer(struct syncpeer *p)
488{
489	if (p->socket > -1) {
490		log_msg(1, "net_disconnect_peer: peer \"%s\" removed",
491		    p->name);
492		close(p->socket);
493	}
494	p->socket = -1;
495}
496
497void
498net_shutdown(void)
499{
500	struct syncpeer *p;
501	struct qmsg	*qm;
502	struct msg	*m;
503
504	while ((p = LIST_FIRST(&cfgstate.peerlist))) {
505		while ((qm = SIMPLEQ_FIRST(&p->msgs))) {
506			SIMPLEQ_REMOVE_HEAD(&p->msgs, next);
507			m = qm->msg;
508			if (--m->refcnt < 1) {
509				free(m->buf);
510				free(m);
511			}
512			free(qm);
513		}
514		net_disconnect_peer(p);
515		if (p->name)
516			free(p->name);
517		LIST_REMOVE(p, link);
518		free(p);
519	}
520
521	if (listen_socket > -1)
522		close(listen_socket);
523}
524
525/*
526 * Helper functions (local) below here.
527 */
528
529static u_int8_t *
530net_read(struct syncpeer *p, u_int32_t *msgtype, u_int32_t *msglen)
531{
532	u_int8_t	*msg, *blob, *rhash, *iv, hash[SHA_DIGEST_LENGTH];
533	u_int32_t	 v, blob_len;
534	int		 padlen = 0, offset = 0, r;
535	SHA_CTX		 ctx;
536
537	/* Read blob length */
538	r = read(p->socket, &v, sizeof v);
539	if (r != (ssize_t)sizeof v) {
540		if (r < 1)
541			net_disconnect_peer(p);
542		return NULL;
543	}
544
545	blob_len = ntohl(v);
546	if (blob_len < sizeof hash + AES_IV_LEN + 2 * sizeof(u_int32_t))
547		return NULL;
548	*msglen = blob_len - sizeof hash - AES_IV_LEN - 2 * sizeof(u_int32_t);
549	if (*msglen < MSG_MINLEN || *msglen > MSG_MAXLEN)
550		return NULL;
551
552	/* Read message blob */
553	blob = (u_int8_t *)malloc(blob_len);
554	if (!blob) {
555		log_err("net_read: malloc()");
556		return NULL;
557	}
558	r = read(p->socket, blob, blob_len);
559	if (r < 1) {
560		net_disconnect_peer(p);
561		free(blob);
562		return NULL;
563	} else if (r < (ssize_t)blob_len) {
564		/* XXX wait and read more? */
565		fprintf(stderr, "net_read: wanted %d, got %d\n", blob_len, r);
566		free(blob);
567		return NULL;
568	}
569
570	offset = 0;
571	memcpy(&v, blob + offset, sizeof v);
572	*msgtype = ntohl(v);
573	offset += sizeof v;
574
575	if (*msgtype > MSG_MAXTYPE) {
576		free(blob);
577		return NULL;
578	}
579
580	memcpy(&v, blob + offset, sizeof v);
581	padlen = ntohl(v);
582	offset += sizeof v;
583
584	rhash = blob + offset;
585	iv    = rhash + sizeof hash;
586	msg = (u_int8_t *)malloc(*msglen);
587	if (!msg) {
588		free(blob);
589		return NULL;
590	}
591	memcpy(msg, iv + AES_IV_LEN, *msglen);
592
593	dump_buf(5, rhash, sizeof hash, "net_read: got hash");
594	dump_buf(5, iv, AES_IV_LEN, "net_read: got IV");
595	dump_buf(5, msg, *msglen, "net_read: pre decrypt");
596	AES_cbc_encrypt(msg, msg, *msglen, &aes_key[1], iv, AES_DECRYPT);
597	dump_buf(5, msg, *msglen, "net_read: post decrypt");
598	*msglen -= padlen;
599
600	SHA1_Init(&ctx);
601	SHA1_Update(&ctx, msg, *msglen);
602	SHA1_Final(hash, &ctx);
603	dump_buf(5, hash, sizeof hash, "net_read: computed hash");
604
605	if (memcmp(hash, rhash, sizeof hash) != 0) {
606		free(blob);
607		log_msg(0, "net_read: got bad message (typo in shared key?)");
608		return NULL;
609	}
610	free(blob);
611	return msg;
612}
613
614static int
615net_set_sa(struct sockaddr *sa, char *name, in_port_t port)
616{
617	struct sockaddr_in	*sin = (struct sockaddr_in *)sa;
618	struct sockaddr_in6	*sin6 = (struct sockaddr_in6 *)sa;
619	struct ifaddrs		*ifap, *ifa;
620
621	if (!name) {
622		/* XXX Assume IPv4 */
623		sa->sa_family = AF_INET;
624		sin->sin_port = htons(port);
625		sin->sin_len = sizeof *sin;
626		return 0;
627	}
628
629	if (inet_pton(AF_INET, name, &sin->sin_addr) == 1) {
630		sa->sa_family = AF_INET;
631		sin->sin_port = htons(port);
632		sin->sin_len = sizeof *sin;
633		return 0;
634	}
635
636	if (inet_pton(AF_INET6, name, &sin6->sin6_addr) == 1) {
637		sa->sa_family = AF_INET6;
638		sin6->sin6_port = htons(port);
639		sin6->sin6_len = sizeof *sin6;
640		return 0;
641	}
642
643	/* inet_pton failed. fail here if name is not cfgstate.listen_on */
644	if (strcmp(cfgstate.listen_on, name) != 0)
645		return -1;
646
647	/* Is cfgstate.listen_on the name of one our interfaces? */
648	if (getifaddrs(&ifap) != 0) {
649		perror("getifaddrs()");
650		return -1;
651	}
652	sa->sa_family = AF_UNSPEC;
653	for (ifa = ifap; ifa && sa->sa_family == AF_UNSPEC;
654	     ifa = ifa->ifa_next) {
655		if (!ifa->ifa_name || !ifa->ifa_addr)
656			continue;
657		if (strcmp(ifa->ifa_name, name) != 0)
658			continue;
659
660		switch (ifa->ifa_addr->sa_family) {
661		case AF_INET:
662			sa->sa_family = AF_INET;
663			sin->sin_port = htons(port);
664			sin->sin_len = sizeof *sin;
665			memcpy(&sin->sin_addr,
666			    &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr,
667			    sizeof sin->sin_addr);
668			break;
669
670		case AF_INET6:
671			sa->sa_family = AF_INET6;
672			sin6->sin6_port = htons(port);
673			sin6->sin6_len = sizeof *sin6;
674			memcpy(&sin6->sin6_addr,
675			    &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr,
676			    sizeof sin6->sin6_addr);
677			break;
678		}
679	}
680	freeifaddrs(ifap);
681	return sa->sa_family == AF_UNSPEC ? -1 : 0;
682}
683
684
685static void
686got_sigalrm(int s)
687{
688	return;
689}
690
691void
692net_connect(void)
693{
694	struct sockaddr_storage sa_storage;
695	struct itimerval	iv;
696	struct sockaddr	*sa = (struct sockaddr *)&sa_storage;
697	struct syncpeer	*p;
698
699	signal(SIGALRM, got_sigalrm);
700	memset(&iv, 0, sizeof iv);
701	iv.it_value.tv_sec = 5;
702	iv.it_interval.tv_sec = 5;
703	setitimer(ITIMER_REAL, &iv, NULL);
704
705	for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link)) {
706		if (p->socket > -1)
707			continue;
708
709		memset(sa, 0, sizeof sa_storage);
710		if (net_set_sa(sa, p->name, cfgstate.listen_port))
711			continue;
712		p->socket = socket(sa->sa_family, SOCK_STREAM, 0);
713		if (p->socket < 0) {
714			log_err("peer \"%s\": socket()", p->name);
715			continue;
716		}
717		if (connect(p->socket, sa, sa->sa_len)) {
718			log_msg(1, "net_connect: peer \"%s\" not ready yet",
719			    p->name);
720			net_disconnect_peer(p);
721			continue;
722		}
723		if (net_ctl_send_state(p)) {
724			log_msg(0, "net_connect: peer \"%s\" failed", p->name);
725			net_disconnect_peer(p);
726			continue;
727		}
728		log_msg(1, "net_connect: peer \"%s\" connected, fd %d",
729		    p->name, p->socket);
730
731		/* Schedule a pfkey sync to the newly connected peer. */
732		if (cfgstate.runstate == MASTER)
733			timer_add("pfkey_snapshot", 2, pfkey_snapshot, p);
734	}
735
736	timerclear(&iv.it_value);
737	timerclear(&iv.it_interval);
738	setitimer(ITIMER_REAL, &iv, NULL);
739	signal(SIGALRM, SIG_IGN);
740
741	return;
742}
743
744static void
745net_check_peers(void *arg)
746{
747	net_connect();
748
749	(void)timer_add("peer recheck", 600, net_check_peers, 0);
750}
751
752