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