xref: /openbsd-src/usr.sbin/sasyncd/pfkey.c (revision be2ce17214630dc045e8a62ddcbc01c71d3eecc0)
1*be2ce172Sgsoares /*	$OpenBSD: pfkey.c,v 1.29 2018/06/28 02:37:26 gsoares Exp $	*/
27aea46c5Sho 
37aea46c5Sho /*
47aea46c5Sho  * Copyright (c) 2005 H�kan Olsson.  All rights reserved.
57aea46c5Sho  *
67aea46c5Sho  * Redistribution and use in source and binary forms, with or without
77aea46c5Sho  * modification, are permitted provided that the following conditions
87aea46c5Sho  * are met:
97aea46c5Sho  *
107aea46c5Sho  * 1. Redistributions of source code must retain the above copyright
117aea46c5Sho  *    notice, this list of conditions and the following disclaimer.
127aea46c5Sho  * 2. Redistributions in binary form must reproduce the above copyright
137aea46c5Sho  *    notice, this list of conditions and the following disclaimer in the
147aea46c5Sho  *    documentation and/or other materials provided with the distribution.
157aea46c5Sho  *
167aea46c5Sho  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
177aea46c5Sho  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
187aea46c5Sho  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
197aea46c5Sho  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
207aea46c5Sho  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
217aea46c5Sho  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
227aea46c5Sho  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
237aea46c5Sho  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
247aea46c5Sho  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
257aea46c5Sho  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
267aea46c5Sho  */
277aea46c5Sho 
287aea46c5Sho /*
297aea46c5Sho  * This code was written under funding by Multicom Security AB.
307aea46c5Sho  */
317aea46c5Sho 
327aea46c5Sho 
337aea46c5Sho #include <sys/types.h>
347aea46c5Sho #include <sys/ioctl.h>
35498aec4fSguenther #include <sys/select.h>
367aea46c5Sho #include <sys/socket.h>
377aea46c5Sho #include <sys/queue.h>
387aea46c5Sho #include <sys/sysctl.h>
397aea46c5Sho #include <net/pfkeyv2.h>
4094f5df21Sho #include <netinet/ip_ipsp.h>
417aea46c5Sho 
427aea46c5Sho #include <errno.h>
437aea46c5Sho #include <stdio.h>
447aea46c5Sho #include <stdlib.h>
457aea46c5Sho #include <string.h>
467aea46c5Sho #include <unistd.h>
477aea46c5Sho 
487aea46c5Sho #include "sasyncd.h"
496ba6c827Smpf #include "monitor.h"
5074a71167Sho #include "net.h"
517aea46c5Sho 
527aea46c5Sho struct pfkey_msg
537aea46c5Sho {
547aea46c5Sho 	SIMPLEQ_ENTRY(pfkey_msg)	next;
557aea46c5Sho 
567aea46c5Sho 	u_int8_t	*buf;
577aea46c5Sho 	u_int32_t	 len;
587aea46c5Sho };
597aea46c5Sho 
607aea46c5Sho SIMPLEQ_HEAD(, pfkey_msg)		pfkey_msglist;
617aea46c5Sho 
627aea46c5Sho static const char *msgtypes[] = {
637aea46c5Sho 	"RESERVED", "GETSPI", "UPDATE", "ADD", "DELETE", "GET", "ACQUIRE",
647aea46c5Sho 	"REGISTER", "EXPIRE", "FLUSH", "DUMP", "X_PROMISC", "X_ADDFLOW",
65e07e1b37Sho 	"X_DELFLOW", "X_GRPSPIS", "X_ASKPOLICY", "X_SPDDUMP"
667aea46c5Sho };
677aea46c5Sho 
687aea46c5Sho #define CHUNK sizeof(u_int64_t)
697aea46c5Sho 
7094f5df21Sho static const char *pfkey_print_type(struct sadb_msg *);
717aea46c5Sho 
727aea46c5Sho static int
pfkey_write(u_int8_t * buf,ssize_t len)737aea46c5Sho pfkey_write(u_int8_t *buf, ssize_t len)
747aea46c5Sho {
757aea46c5Sho 	struct sadb_msg *msg = (struct sadb_msg *)buf;
768f1602f9Shenning 	ssize_t n;
777aea46c5Sho 
787aea46c5Sho 	if (cfgstate.pfkey_socket == -1)
797aea46c5Sho 		return 0;
807aea46c5Sho 
818f1602f9Shenning 	do {
828f1602f9Shenning 		n = write(cfgstate.pfkey_socket, buf, len);
838f1602f9Shenning 	} while (n == -1 && (errno == EAGAIN || errno == EINTR));
848f1602f9Shenning 	if (n == -1) {
8526461eb5Smoritz 		log_err("pfkey: msg %s write() failed on socket %d",
867aea46c5Sho 		    pfkey_print_type(msg), cfgstate.pfkey_socket);
877aea46c5Sho 		return -1;
887aea46c5Sho 	}
897aea46c5Sho 
907aea46c5Sho 	return 0;
917aea46c5Sho }
927aea46c5Sho 
937aea46c5Sho int
pfkey_set_promisc(void)947aea46c5Sho pfkey_set_promisc(void)
957aea46c5Sho {
967aea46c5Sho 	struct sadb_msg	msg;
977aea46c5Sho 	static u_int32_t seq = 1;
987aea46c5Sho 
997aea46c5Sho 	memset(&msg, 0, sizeof msg);
1007aea46c5Sho 	msg.sadb_msg_version = PF_KEY_V2;
1017aea46c5Sho 	msg.sadb_msg_seq = seq++;
1027aea46c5Sho 	msg.sadb_msg_satype = 1; /* Special; 1 to enable, 0 to disable */
1037aea46c5Sho 	msg.sadb_msg_type = SADB_X_PROMISC;
1047aea46c5Sho 	msg.sadb_msg_pid = getpid();
1057aea46c5Sho 	msg.sadb_msg_len = sizeof msg / CHUNK;
1067aea46c5Sho 
1077aea46c5Sho 	return pfkey_write((u_int8_t *)&msg, sizeof msg);
1087aea46c5Sho }
1097aea46c5Sho 
11074a71167Sho /* Send a SADB_FLUSH PFKEY message to peer 'p' */
11174a71167Sho static void
pfkey_send_flush(struct syncpeer * p)11274a71167Sho pfkey_send_flush(struct syncpeer *p)
11374a71167Sho {
11435de856eSderaadt 	struct sadb_msg *m = calloc(1, sizeof *m);
11574a71167Sho 	static u_int32_t seq = 1;
11674a71167Sho 
11774a71167Sho 	if (m) {
11874a71167Sho 		m->sadb_msg_version = PF_KEY_V2;
11974a71167Sho 		m->sadb_msg_seq = seq++;
12074a71167Sho 		m->sadb_msg_type = SADB_FLUSH;
12174a71167Sho 		m->sadb_msg_satype = SADB_SATYPE_UNSPEC;
12274a71167Sho 		m->sadb_msg_pid = getpid();
12374a71167Sho 		m->sadb_msg_len = sizeof *m / CHUNK;
12474a71167Sho 
1259353ff65Skjell 		log_msg(2, "pfkey_send_flush: sending FLUSH to peer %s",
12674a71167Sho 		    p->name);
12774a71167Sho 		net_queue(p, MSG_PFKEYDATA, (u_int8_t *)m, sizeof *m);
12874a71167Sho 	}
12974a71167Sho }
13074a71167Sho 
1317aea46c5Sho static const char *
pfkey_print_type(struct sadb_msg * msg)1327aea46c5Sho pfkey_print_type(struct sadb_msg *msg)
1337aea46c5Sho {
13494f5df21Sho 	static char	uk[20];
13594f5df21Sho 
1367aea46c5Sho 	if (msg->sadb_msg_type < sizeof msgtypes / sizeof msgtypes[0])
1377aea46c5Sho 		return msgtypes[msg->sadb_msg_type];
13894f5df21Sho 	else {
13994f5df21Sho 		snprintf(uk, sizeof uk, "<unknown(%d)>", msg->sadb_msg_type);
14094f5df21Sho 		return uk;
14194f5df21Sho 	}
1427aea46c5Sho }
1437aea46c5Sho 
144ea2aab39Sho static struct sadb_ext *
pfkey_find_ext(struct sadb_msg * msg,u_int16_t type)145ea2aab39Sho pfkey_find_ext(struct sadb_msg *msg, u_int16_t type)
146ea2aab39Sho {
147ea2aab39Sho 	struct sadb_ext	*ext;
148ea2aab39Sho 	u_int8_t	*e;
149ea2aab39Sho 
150ea2aab39Sho 	for (e = (u_int8_t *)msg + sizeof *msg;
151ea2aab39Sho 	     e < (u_int8_t *)msg + msg->sadb_msg_len * CHUNK;
152ea2aab39Sho 	     e += ext->sadb_ext_len * CHUNK) {
153ea2aab39Sho 		ext = (struct sadb_ext *)e;
154ea2aab39Sho 		if (ext->sadb_ext_len == 0)
155ea2aab39Sho 			break;
156ea2aab39Sho 		if (ext->sadb_ext_type != type)
157ea2aab39Sho 			continue;
158ea2aab39Sho 		return ext;
159ea2aab39Sho 	}
160ea2aab39Sho 	return NULL;
161ea2aab39Sho }
162ea2aab39Sho 
163ea2aab39Sho /* Return: 0 means ok to sync msg, 1 means to skip it */
164ea2aab39Sho static int
pfkey_msg_filter(struct sadb_msg * msg)165ea2aab39Sho pfkey_msg_filter(struct sadb_msg *msg)
166ea2aab39Sho {
167ea2aab39Sho 	struct sockaddr		*src = 0, *dst = 0;
168ea2aab39Sho 	struct syncpeer		*p;
169ea2aab39Sho 	struct sadb_ext		*ext;
170ea2aab39Sho 	u_int8_t		*max;
171ea2aab39Sho 
172ea2aab39Sho 	switch (msg->sadb_msg_type) {
17327cda758Smpf 	case SADB_X_PROMISC:
17427cda758Smpf 	case SADB_DUMP:
17527cda758Smpf 	case SADB_GET:
17627cda758Smpf 	case SADB_GETSPI:
17727cda758Smpf 	case SADB_ACQUIRE:
17827cda758Smpf 	case SADB_X_ASKPOLICY:
17927cda758Smpf 	case SADB_REGISTER:
18027cda758Smpf 		/* Some messages should not be synced. */
18127cda758Smpf 		return 1;
18227cda758Smpf 
183ea2aab39Sho 	case SADB_ADD:
184ea2aab39Sho 		/* No point in syncing LARVAL SAs */
185ea2aab39Sho 		if (pfkey_find_ext(msg, SADB_EXT_KEY_ENCRYPT) == 0)
186ea2aab39Sho 			return 1;
187ea2aab39Sho 	case SADB_DELETE:
188ea2aab39Sho 	case SADB_X_ADDFLOW:
189ea2aab39Sho 	case SADB_X_DELFLOW:
190ea2aab39Sho 	case SADB_EXPIRE:
191ea2aab39Sho 		/* Continue below */
192ea2aab39Sho 		break;
193ea2aab39Sho 	case SADB_FLUSH:
194ea2aab39Sho 		if ((cfgstate.flags & FM_MASK) == FM_NEVER)
195ea2aab39Sho 			return 1;
196ea2aab39Sho 		break;
197ea2aab39Sho 	default:
198ea2aab39Sho 		return 0;
199ea2aab39Sho 	}
200ea2aab39Sho 
201ea2aab39Sho 	if ((cfgstate.flags & SKIP_LOCAL_SAS) == 0)
202ea2aab39Sho 		return 0;
203ea2aab39Sho 
204ea2aab39Sho 	/* SRC or DST address of this msg must not be one of our peers. */
205ea2aab39Sho 	ext = pfkey_find_ext(msg, SADB_EXT_ADDRESS_SRC);
206ea2aab39Sho 	if (ext)
207ea2aab39Sho 		src = (struct sockaddr *)((struct sadb_address *)ext + 1);
208ea2aab39Sho 	ext = pfkey_find_ext(msg, SADB_EXT_ADDRESS_DST);
209ea2aab39Sho 	if (ext)
210ea2aab39Sho 		dst = (struct sockaddr *)((struct sadb_address *)ext + 1);
211ea2aab39Sho 	if (!src && !dst)
212ea2aab39Sho 		return 0;
213ea2aab39Sho 
214ea2aab39Sho 	max = (u_int8_t *)msg + msg->sadb_msg_len * CHUNK;
215ea2aab39Sho 	if (src && ((u_int8_t *)src + src->sa_len) > max)
216ea2aab39Sho 		return 1;
217ea2aab39Sho 	if (dst && ((u_int8_t *)dst + dst->sa_len) > max)
218ea2aab39Sho 		return 1;
219ea2aab39Sho 
220ea2aab39Sho 	/* Found SRC or DST, check it against our peers */
221ea2aab39Sho 	for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link)) {
222ea2aab39Sho 		if (p->socket < 0 || p->sa->sa_family !=
223ea2aab39Sho 		    (src ? src->sa_family : dst->sa_family))
224ea2aab39Sho 			continue;
225ea2aab39Sho 
226ea2aab39Sho 		switch (p->sa->sa_family) {
227ea2aab39Sho 		case AF_INET:
228ea2aab39Sho 			if (src && memcmp(
229ea2aab39Sho 			    &((struct sockaddr_in *)p->sa)->sin_addr.s_addr,
230ea2aab39Sho 			    &((struct sockaddr_in *)src)->sin_addr.s_addr,
231ea2aab39Sho 			    sizeof(struct in_addr)) == 0)
232ea2aab39Sho 				return 1;
233ea2aab39Sho 			if (dst && memcmp(
234ea2aab39Sho 			    &((struct sockaddr_in *)p->sa)->sin_addr.s_addr,
235ea2aab39Sho 			    &((struct sockaddr_in *)dst)->sin_addr.s_addr,
236ea2aab39Sho 			    sizeof(struct in_addr)) == 0)
237ea2aab39Sho 				return 1;
238ea2aab39Sho 			break;
239ea2aab39Sho 		case AF_INET6:
240ea2aab39Sho 			if (src &&
241ea2aab39Sho 			    memcmp(&((struct sockaddr_in6 *)p->sa)->sin6_addr,
242ea2aab39Sho 			    &((struct sockaddr_in6 *)src)->sin6_addr,
243ea2aab39Sho 			    sizeof(struct in_addr)) == 0)
244ea2aab39Sho 				return 1;
245ea2aab39Sho 			if (dst &&
246ea2aab39Sho 			    memcmp(&((struct sockaddr_in6 *)p->sa)->sin6_addr,
247ea2aab39Sho 			    &((struct sockaddr_in6 *)dst)->sin6_addr,
248ea2aab39Sho 			    sizeof(struct in_addr)) == 0)
249ea2aab39Sho 				return 1;
250ea2aab39Sho 			break;
251ea2aab39Sho 		}
252ea2aab39Sho 	}
253ea2aab39Sho 	return 0;
254ea2aab39Sho }
255ea2aab39Sho 
2567aea46c5Sho static int
pfkey_handle_message(struct sadb_msg * m)2577aea46c5Sho pfkey_handle_message(struct sadb_msg *m)
2587aea46c5Sho {
2597aea46c5Sho 	struct sadb_msg	*msg = m;
2607aea46c5Sho 
2617aea46c5Sho 	/*
2627aea46c5Sho 	 * Report errors, but ignore for DELETE (both isakmpd and kernel will
2637aea46c5Sho 	 * expire the SA, if the kernel is first, DELETE returns failure).
2647aea46c5Sho 	 */
26594f5df21Sho 	if (msg->sadb_msg_errno && msg->sadb_msg_type != SADB_DELETE &&
26694f5df21Sho 	    msg->sadb_msg_pid == (u_int32_t)getpid()) {
2677aea46c5Sho 		errno = msg->sadb_msg_errno;
26894f5df21Sho 		log_msg(1, "pfkey error (%s)", pfkey_print_type(msg));
2697aea46c5Sho 	}
2707aea46c5Sho 
2717aea46c5Sho 	/* We only want promiscuous messages here, skip all others. */
2727aea46c5Sho 	if (msg->sadb_msg_type != SADB_X_PROMISC ||
27354626cc1Sho 	    (msg->sadb_msg_len * CHUNK) < 2 * sizeof *msg) {
2747aea46c5Sho 		free(m);
2757aea46c5Sho 		return 0;
2767aea46c5Sho 	}
27754626cc1Sho 	/* Move next msg to start of the buffer. */
2787aea46c5Sho 	msg++;
2797aea46c5Sho 
2807aea46c5Sho 	/*
2817aea46c5Sho 	 * We should not listen to PFKEY messages when we are not running
2827aea46c5Sho 	 * as MASTER, or the pid is our own.
2837aea46c5Sho 	 */
2847aea46c5Sho 	if (cfgstate.runstate != MASTER ||
2857aea46c5Sho 	    msg->sadb_msg_pid == (u_int32_t)getpid()) {
2867aea46c5Sho 		free(m);
2877aea46c5Sho 		return 0;
2887aea46c5Sho 	}
2897aea46c5Sho 
290ea2aab39Sho 	if (pfkey_msg_filter(msg)) {
29174a71167Sho 		free(m);
29274a71167Sho 		return 0;
29374a71167Sho 	}
29474a71167Sho 
2957aea46c5Sho 	switch (msg->sadb_msg_type) {
2967aea46c5Sho 	case SADB_UPDATE:
2977aea46c5Sho 		/*
2987aea46c5Sho 		 * Tweak -- the peers do not have a larval SA to update, so
2997aea46c5Sho 		 * instead we ADD it here.
3007aea46c5Sho 		 */
3017aea46c5Sho 		msg->sadb_msg_type = SADB_ADD;
3027aea46c5Sho 		/* FALLTHROUGH */
3037aea46c5Sho 
3047aea46c5Sho 	default:
3051de92cabSdavid 		/* Pass the rest along to our peers. */
30654626cc1Sho 		memmove(m, msg, msg->sadb_msg_len * CHUNK); /* for realloc */
30754626cc1Sho 		return net_queue(NULL, MSG_PFKEYDATA, (u_int8_t *)m,
30854626cc1Sho 		    m->sadb_msg_len * CHUNK);
3097aea46c5Sho 	}
3107aea46c5Sho 
3117aea46c5Sho 	return 0;
3127aea46c5Sho }
3137aea46c5Sho 
3147aea46c5Sho static int
pfkey_read(void)3157aea46c5Sho pfkey_read(void)
3167aea46c5Sho {
3177aea46c5Sho 	struct sadb_msg  hdr, *msg;
3187aea46c5Sho 	u_int8_t	*data;
3197aea46c5Sho 	ssize_t		 datalen;
3207aea46c5Sho 	int		 fd = cfgstate.pfkey_socket;
3217aea46c5Sho 
3227aea46c5Sho 	if (recv(fd, &hdr, sizeof hdr, MSG_PEEK) != sizeof hdr) {
3237aea46c5Sho 		log_err("pfkey_read: recv() failed");
3247aea46c5Sho 		return -1;
3257aea46c5Sho 	}
3267953660eSchl 	datalen = hdr.sadb_msg_len * CHUNK;
3273bd0d19cSderaadt 	data = reallocarray(NULL, hdr.sadb_msg_len, CHUNK);
3287aea46c5Sho 	if (!data) {
3297aea46c5Sho 		log_err("pfkey_read: malloc(%lu) failed", datalen);
3307aea46c5Sho 		return -1;
3317aea46c5Sho 	}
3327aea46c5Sho 	msg = (struct sadb_msg *)data;
3337aea46c5Sho 
3347aea46c5Sho 	if (read(fd, data, datalen) != datalen) {
3357aea46c5Sho 		log_err("pfkey_read: read() failed, %lu bytes", datalen);
3367aea46c5Sho 		free(data);
3377aea46c5Sho 		return -1;
3387aea46c5Sho 	}
3397aea46c5Sho 
3407aea46c5Sho 	return pfkey_handle_message(msg);
3417aea46c5Sho }
3427aea46c5Sho 
3437aea46c5Sho int
pfkey_init(int reinit)3447aea46c5Sho pfkey_init(int reinit)
3457aea46c5Sho {
3467aea46c5Sho 	int fd;
3477aea46c5Sho 
3487aea46c5Sho 	fd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
3497aea46c5Sho 	if (fd == -1) {
3507aea46c5Sho 		perror("failed to open PF_KEY socket");
3517aea46c5Sho 		return -1;
3527aea46c5Sho 	}
3537aea46c5Sho 	cfgstate.pfkey_socket = fd;
3547aea46c5Sho 
3557aea46c5Sho 	if (cfgstate.runstate == MASTER)
3567aea46c5Sho 		pfkey_set_promisc();
35754626cc1Sho 
35854626cc1Sho 	if (reinit)
3597aea46c5Sho 		return (fd > -1 ? 0 : -1);
3607aea46c5Sho 
3617aea46c5Sho 	SIMPLEQ_INIT(&pfkey_msglist);
3627aea46c5Sho 	return 0;
3637aea46c5Sho }
3647aea46c5Sho 
3657aea46c5Sho void
pfkey_set_rfd(fd_set * fds)3667aea46c5Sho pfkey_set_rfd(fd_set *fds)
3677aea46c5Sho {
3687aea46c5Sho 	if (cfgstate.pfkey_socket != -1)
3697aea46c5Sho 		FD_SET(cfgstate.pfkey_socket, fds);
3707aea46c5Sho }
3717aea46c5Sho 
3727aea46c5Sho void
pfkey_set_pending_wfd(fd_set * fds)3737aea46c5Sho pfkey_set_pending_wfd(fd_set *fds)
3747aea46c5Sho {
3757aea46c5Sho 	if (cfgstate.pfkey_socket != -1 && SIMPLEQ_FIRST(&pfkey_msglist))
3767aea46c5Sho 		FD_SET(cfgstate.pfkey_socket, fds);
3777aea46c5Sho }
3787aea46c5Sho 
3797aea46c5Sho void
pfkey_read_message(fd_set * fds)3807aea46c5Sho pfkey_read_message(fd_set *fds)
3817aea46c5Sho {
3827aea46c5Sho 	if (cfgstate.pfkey_socket != -1)
3837aea46c5Sho 		if (FD_ISSET(cfgstate.pfkey_socket, fds))
3847aea46c5Sho 			(void)pfkey_read();
3857aea46c5Sho }
3867aea46c5Sho 
3877aea46c5Sho void
pfkey_send_message(fd_set * fds)3887aea46c5Sho pfkey_send_message(fd_set *fds)
3897aea46c5Sho {
3907aea46c5Sho 	struct pfkey_msg *pmsg = SIMPLEQ_FIRST(&pfkey_msglist);
3917aea46c5Sho 
3927aea46c5Sho 	if (!pmsg || !FD_ISSET(cfgstate.pfkey_socket, fds))
3937aea46c5Sho 		return;
3947aea46c5Sho 
3957aea46c5Sho 	if (cfgstate.pfkey_socket == -1)
3967aea46c5Sho 		if (pfkey_init(1)) /* Reinit socket */
3977aea46c5Sho 			return;
3987aea46c5Sho 
3997aea46c5Sho 	(void)pfkey_write(pmsg->buf, pmsg->len);
4007aea46c5Sho 
4017aea46c5Sho 	SIMPLEQ_REMOVE_HEAD(&pfkey_msglist, next);
4027aea46c5Sho 	free(pmsg->buf);
4037aea46c5Sho 	free(pmsg);
4049945a12eSmcbride 
4057aea46c5Sho 	return;
4067aea46c5Sho }
4077aea46c5Sho 
4087aea46c5Sho int
pfkey_queue_message(u_int8_t * data,u_int32_t datalen)4097aea46c5Sho pfkey_queue_message(u_int8_t *data, u_int32_t datalen)
4107aea46c5Sho {
4117aea46c5Sho 	struct pfkey_msg	*pmsg;
4127aea46c5Sho 	struct sadb_msg		*sadb = (struct sadb_msg *)data;
4137aea46c5Sho 	static u_int32_t	 seq = 1;
4147aea46c5Sho 
41535de856eSderaadt 	pmsg = malloc(sizeof *pmsg);
4167aea46c5Sho 	if (!pmsg) {
4177aea46c5Sho 		log_err("malloc()");
4187aea46c5Sho 		return -1;
4197aea46c5Sho 	}
4207aea46c5Sho 	memset(pmsg, 0, sizeof *pmsg);
4217aea46c5Sho 
4227aea46c5Sho 	pmsg->buf = data;
4237aea46c5Sho 	pmsg->len = datalen;
4247aea46c5Sho 
4257aea46c5Sho 	sadb->sadb_msg_pid = getpid();
4267aea46c5Sho 	sadb->sadb_msg_seq = seq++;
42746f033a3Sbenno 	log_msg(2, "pfkey_queue_message: pfkey %s len %zu seq %u",
4281d55a410Sho 	    pfkey_print_type(sadb), sadb->sadb_msg_len * CHUNK,
4291d55a410Sho 	    sadb->sadb_msg_seq);
4307aea46c5Sho 
4317aea46c5Sho 	SIMPLEQ_INSERT_TAIL(&pfkey_msglist, pmsg, next);
4327aea46c5Sho 	return 0;
4337aea46c5Sho }
4347aea46c5Sho 
4357aea46c5Sho void
pfkey_shutdown(void)4367aea46c5Sho pfkey_shutdown(void)
4377aea46c5Sho {
4387aea46c5Sho 	struct pfkey_msg *p = SIMPLEQ_FIRST(&pfkey_msglist);
4397aea46c5Sho 
4407aea46c5Sho 	while ((p = SIMPLEQ_FIRST(&pfkey_msglist))) {
4417aea46c5Sho 		SIMPLEQ_REMOVE_HEAD(&pfkey_msglist, next);
4427aea46c5Sho 		free(p->buf);
4437aea46c5Sho 		free(p);
4447aea46c5Sho 	}
4457aea46c5Sho 
4467aea46c5Sho 	if (cfgstate.pfkey_socket > -1)
4477aea46c5Sho 		close(cfgstate.pfkey_socket);
4487aea46c5Sho }
4497aea46c5Sho 
4507aea46c5Sho /* ------------------------------------------------------------------------- */
4517aea46c5Sho 
4527aea46c5Sho void
pfkey_snapshot(void * v)4537aea46c5Sho pfkey_snapshot(void *v)
4547aea46c5Sho {
45594f5df21Sho 	struct syncpeer		*p = (struct syncpeer *)v;
4567aea46c5Sho 	struct sadb_msg		*m;
45794f5df21Sho 	u_int8_t		*sadb, *spd, *max, *next, *sendbuf;
45894f5df21Sho 	u_int32_t		 sadbsz, spdsz;
4597aea46c5Sho 
46094f5df21Sho 	if (!p)
4617aea46c5Sho 		return;
46294f5df21Sho 
46394f5df21Sho 	if (monitor_get_pfkey_snap(&sadb, &sadbsz, &spd, &spdsz)) {
46494f5df21Sho 		log_msg(0, "pfkey_snapshot: failed to get pfkey snapshot");
4657aea46c5Sho 		return;
4667aea46c5Sho 	}
4677aea46c5Sho 
46874a71167Sho 	/* XXX needs moving if snapshot is called more than once per peer */
469ea2aab39Sho 	if ((cfgstate.flags & FM_MASK) == FM_STARTUP)
47074a71167Sho 		pfkey_send_flush(p);
47174a71167Sho 
47294f5df21Sho 	/* Parse SADB data */
4739fdb5ecdSho 	if (sadbsz && sadb) {
4749353ff65Skjell 		dump_buf(2, sadb, sadbsz, "pfkey_snapshot: SADB data");
47594f5df21Sho 		max = sadb + sadbsz;
4769fdb5ecdSho 		for (next = sadb; next < max;
4779fdb5ecdSho 		     next += m->sadb_msg_len * CHUNK) {
47894f5df21Sho 			m = (struct sadb_msg *)next;
47994f5df21Sho 			if (m->sadb_msg_len == 0)
48094f5df21Sho 				break;
48194f5df21Sho 
482b5c6b925Sho 			/* Tweak and send this SA to the peer. */
48394f5df21Sho 			m->sadb_msg_type = SADB_ADD;
48494f5df21Sho 
485ea2aab39Sho 			if (pfkey_msg_filter(m))
486ea2aab39Sho 				continue;
487ea2aab39Sho 
4889fdb5ecdSho 			/* Allocate msgbuffer, net_queue() will free it. */
48935de856eSderaadt 			sendbuf = calloc(m->sadb_msg_len, CHUNK);
49094f5df21Sho 			if (sendbuf) {
49194f5df21Sho 				memcpy(sendbuf, m, m->sadb_msg_len * CHUNK);
49294f5df21Sho 				net_queue(p, MSG_PFKEYDATA, sendbuf,
49394f5df21Sho 				    m->sadb_msg_len * CHUNK);
49446f033a3Sbenno 				log_msg(2, "pfkey_snapshot: sync SA %p len %zu "
495e07e1b37Sho 				    "to peer %s", m,
496e07e1b37Sho 				    m->sadb_msg_len * CHUNK, p->name);
4977aea46c5Sho 			}
4987aea46c5Sho 		}
4991e82d711Sderaadt 		freezero(sadb, sadbsz);
5009fdb5ecdSho 	}
50194f5df21Sho 
50294f5df21Sho 	/* Parse SPD data */
5039fdb5ecdSho 	if (spdsz && spd) {
5049353ff65Skjell 		dump_buf(2, spd, spdsz, "pfkey_snapshot: SPD data");
50594f5df21Sho 		max = spd + spdsz;
506e07e1b37Sho 		for (next = spd; next < max; next += m->sadb_msg_len * CHUNK) {
507e07e1b37Sho 			m = (struct sadb_msg *)next;
508e07e1b37Sho 			if (m->sadb_msg_len == 0)
509e07e1b37Sho 				break;
51094f5df21Sho 
511e07e1b37Sho 			/* Tweak msg type. */
512e07e1b37Sho 			m->sadb_msg_type = SADB_X_ADDFLOW;
513e07e1b37Sho 
514ea2aab39Sho 			if (pfkey_msg_filter(m))
515ea2aab39Sho 				continue;
516ea2aab39Sho 
517e07e1b37Sho 			/* Allocate msgbuffer, freed by net_queue(). */
51835de856eSderaadt 			sendbuf = calloc(m->sadb_msg_len, CHUNK);
519e07e1b37Sho 			if (sendbuf) {
520e07e1b37Sho 				memcpy(sendbuf, m, m->sadb_msg_len * CHUNK);
521e07e1b37Sho 				net_queue(p, MSG_PFKEYDATA, sendbuf,
522e07e1b37Sho 				    m->sadb_msg_len * CHUNK);
5239353ff65Skjell 				log_msg(2, "pfkey_snapshot: sync FLOW %p len "
52446f033a3Sbenno 				    "%zu to peer %s", m,
525e07e1b37Sho 				    m->sadb_msg_len * CHUNK, p->name);
526e07e1b37Sho 			}
527e07e1b37Sho 		}
52894f5df21Sho 		/* Cleanup. */
5291e82d711Sderaadt 		freezero(spd, spdsz);
5309fdb5ecdSho 	}
5319945a12eSmcbride 
5329945a12eSmcbride 	net_ctl_send_endsnap(p);
5337aea46c5Sho 	return;
5347aea46c5Sho }
535