1 /* $OpenBSD: pfkey.c,v 1.29 2018/06/28 02:37:26 gsoares 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/ioctl.h>
35 #include <sys/select.h>
36 #include <sys/socket.h>
37 #include <sys/queue.h>
38 #include <sys/sysctl.h>
39 #include <net/pfkeyv2.h>
40 #include <netinet/ip_ipsp.h>
41
42 #include <errno.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47
48 #include "sasyncd.h"
49 #include "monitor.h"
50 #include "net.h"
51
52 struct pfkey_msg
53 {
54 SIMPLEQ_ENTRY(pfkey_msg) next;
55
56 u_int8_t *buf;
57 u_int32_t len;
58 };
59
60 SIMPLEQ_HEAD(, pfkey_msg) pfkey_msglist;
61
62 static const char *msgtypes[] = {
63 "RESERVED", "GETSPI", "UPDATE", "ADD", "DELETE", "GET", "ACQUIRE",
64 "REGISTER", "EXPIRE", "FLUSH", "DUMP", "X_PROMISC", "X_ADDFLOW",
65 "X_DELFLOW", "X_GRPSPIS", "X_ASKPOLICY", "X_SPDDUMP"
66 };
67
68 #define CHUNK sizeof(u_int64_t)
69
70 static const char *pfkey_print_type(struct sadb_msg *);
71
72 static int
pfkey_write(u_int8_t * buf,ssize_t len)73 pfkey_write(u_int8_t *buf, ssize_t len)
74 {
75 struct sadb_msg *msg = (struct sadb_msg *)buf;
76 ssize_t n;
77
78 if (cfgstate.pfkey_socket == -1)
79 return 0;
80
81 do {
82 n = write(cfgstate.pfkey_socket, buf, len);
83 } while (n == -1 && (errno == EAGAIN || errno == EINTR));
84 if (n == -1) {
85 log_err("pfkey: msg %s write() failed on socket %d",
86 pfkey_print_type(msg), cfgstate.pfkey_socket);
87 return -1;
88 }
89
90 return 0;
91 }
92
93 int
pfkey_set_promisc(void)94 pfkey_set_promisc(void)
95 {
96 struct sadb_msg msg;
97 static u_int32_t seq = 1;
98
99 memset(&msg, 0, sizeof msg);
100 msg.sadb_msg_version = PF_KEY_V2;
101 msg.sadb_msg_seq = seq++;
102 msg.sadb_msg_satype = 1; /* Special; 1 to enable, 0 to disable */
103 msg.sadb_msg_type = SADB_X_PROMISC;
104 msg.sadb_msg_pid = getpid();
105 msg.sadb_msg_len = sizeof msg / CHUNK;
106
107 return pfkey_write((u_int8_t *)&msg, sizeof msg);
108 }
109
110 /* Send a SADB_FLUSH PFKEY message to peer 'p' */
111 static void
pfkey_send_flush(struct syncpeer * p)112 pfkey_send_flush(struct syncpeer *p)
113 {
114 struct sadb_msg *m = calloc(1, sizeof *m);
115 static u_int32_t seq = 1;
116
117 if (m) {
118 m->sadb_msg_version = PF_KEY_V2;
119 m->sadb_msg_seq = seq++;
120 m->sadb_msg_type = SADB_FLUSH;
121 m->sadb_msg_satype = SADB_SATYPE_UNSPEC;
122 m->sadb_msg_pid = getpid();
123 m->sadb_msg_len = sizeof *m / CHUNK;
124
125 log_msg(2, "pfkey_send_flush: sending FLUSH to peer %s",
126 p->name);
127 net_queue(p, MSG_PFKEYDATA, (u_int8_t *)m, sizeof *m);
128 }
129 }
130
131 static const char *
pfkey_print_type(struct sadb_msg * msg)132 pfkey_print_type(struct sadb_msg *msg)
133 {
134 static char uk[20];
135
136 if (msg->sadb_msg_type < sizeof msgtypes / sizeof msgtypes[0])
137 return msgtypes[msg->sadb_msg_type];
138 else {
139 snprintf(uk, sizeof uk, "<unknown(%d)>", msg->sadb_msg_type);
140 return uk;
141 }
142 }
143
144 static struct sadb_ext *
pfkey_find_ext(struct sadb_msg * msg,u_int16_t type)145 pfkey_find_ext(struct sadb_msg *msg, u_int16_t type)
146 {
147 struct sadb_ext *ext;
148 u_int8_t *e;
149
150 for (e = (u_int8_t *)msg + sizeof *msg;
151 e < (u_int8_t *)msg + msg->sadb_msg_len * CHUNK;
152 e += ext->sadb_ext_len * CHUNK) {
153 ext = (struct sadb_ext *)e;
154 if (ext->sadb_ext_len == 0)
155 break;
156 if (ext->sadb_ext_type != type)
157 continue;
158 return ext;
159 }
160 return NULL;
161 }
162
163 /* Return: 0 means ok to sync msg, 1 means to skip it */
164 static int
pfkey_msg_filter(struct sadb_msg * msg)165 pfkey_msg_filter(struct sadb_msg *msg)
166 {
167 struct sockaddr *src = 0, *dst = 0;
168 struct syncpeer *p;
169 struct sadb_ext *ext;
170 u_int8_t *max;
171
172 switch (msg->sadb_msg_type) {
173 case SADB_X_PROMISC:
174 case SADB_DUMP:
175 case SADB_GET:
176 case SADB_GETSPI:
177 case SADB_ACQUIRE:
178 case SADB_X_ASKPOLICY:
179 case SADB_REGISTER:
180 /* Some messages should not be synced. */
181 return 1;
182
183 case SADB_ADD:
184 /* No point in syncing LARVAL SAs */
185 if (pfkey_find_ext(msg, SADB_EXT_KEY_ENCRYPT) == 0)
186 return 1;
187 case SADB_DELETE:
188 case SADB_X_ADDFLOW:
189 case SADB_X_DELFLOW:
190 case SADB_EXPIRE:
191 /* Continue below */
192 break;
193 case SADB_FLUSH:
194 if ((cfgstate.flags & FM_MASK) == FM_NEVER)
195 return 1;
196 break;
197 default:
198 return 0;
199 }
200
201 if ((cfgstate.flags & SKIP_LOCAL_SAS) == 0)
202 return 0;
203
204 /* SRC or DST address of this msg must not be one of our peers. */
205 ext = pfkey_find_ext(msg, SADB_EXT_ADDRESS_SRC);
206 if (ext)
207 src = (struct sockaddr *)((struct sadb_address *)ext + 1);
208 ext = pfkey_find_ext(msg, SADB_EXT_ADDRESS_DST);
209 if (ext)
210 dst = (struct sockaddr *)((struct sadb_address *)ext + 1);
211 if (!src && !dst)
212 return 0;
213
214 max = (u_int8_t *)msg + msg->sadb_msg_len * CHUNK;
215 if (src && ((u_int8_t *)src + src->sa_len) > max)
216 return 1;
217 if (dst && ((u_int8_t *)dst + dst->sa_len) > max)
218 return 1;
219
220 /* Found SRC or DST, check it against our peers */
221 for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link)) {
222 if (p->socket < 0 || p->sa->sa_family !=
223 (src ? src->sa_family : dst->sa_family))
224 continue;
225
226 switch (p->sa->sa_family) {
227 case AF_INET:
228 if (src && memcmp(
229 &((struct sockaddr_in *)p->sa)->sin_addr.s_addr,
230 &((struct sockaddr_in *)src)->sin_addr.s_addr,
231 sizeof(struct in_addr)) == 0)
232 return 1;
233 if (dst && memcmp(
234 &((struct sockaddr_in *)p->sa)->sin_addr.s_addr,
235 &((struct sockaddr_in *)dst)->sin_addr.s_addr,
236 sizeof(struct in_addr)) == 0)
237 return 1;
238 break;
239 case AF_INET6:
240 if (src &&
241 memcmp(&((struct sockaddr_in6 *)p->sa)->sin6_addr,
242 &((struct sockaddr_in6 *)src)->sin6_addr,
243 sizeof(struct in_addr)) == 0)
244 return 1;
245 if (dst &&
246 memcmp(&((struct sockaddr_in6 *)p->sa)->sin6_addr,
247 &((struct sockaddr_in6 *)dst)->sin6_addr,
248 sizeof(struct in_addr)) == 0)
249 return 1;
250 break;
251 }
252 }
253 return 0;
254 }
255
256 static int
pfkey_handle_message(struct sadb_msg * m)257 pfkey_handle_message(struct sadb_msg *m)
258 {
259 struct sadb_msg *msg = m;
260
261 /*
262 * Report errors, but ignore for DELETE (both isakmpd and kernel will
263 * expire the SA, if the kernel is first, DELETE returns failure).
264 */
265 if (msg->sadb_msg_errno && msg->sadb_msg_type != SADB_DELETE &&
266 msg->sadb_msg_pid == (u_int32_t)getpid()) {
267 errno = msg->sadb_msg_errno;
268 log_msg(1, "pfkey error (%s)", pfkey_print_type(msg));
269 }
270
271 /* We only want promiscuous messages here, skip all others. */
272 if (msg->sadb_msg_type != SADB_X_PROMISC ||
273 (msg->sadb_msg_len * CHUNK) < 2 * sizeof *msg) {
274 free(m);
275 return 0;
276 }
277 /* Move next msg to start of the buffer. */
278 msg++;
279
280 /*
281 * We should not listen to PFKEY messages when we are not running
282 * as MASTER, or the pid is our own.
283 */
284 if (cfgstate.runstate != MASTER ||
285 msg->sadb_msg_pid == (u_int32_t)getpid()) {
286 free(m);
287 return 0;
288 }
289
290 if (pfkey_msg_filter(msg)) {
291 free(m);
292 return 0;
293 }
294
295 switch (msg->sadb_msg_type) {
296 case SADB_UPDATE:
297 /*
298 * Tweak -- the peers do not have a larval SA to update, so
299 * instead we ADD it here.
300 */
301 msg->sadb_msg_type = SADB_ADD;
302 /* FALLTHROUGH */
303
304 default:
305 /* Pass the rest along to our peers. */
306 memmove(m, msg, msg->sadb_msg_len * CHUNK); /* for realloc */
307 return net_queue(NULL, MSG_PFKEYDATA, (u_int8_t *)m,
308 m->sadb_msg_len * CHUNK);
309 }
310
311 return 0;
312 }
313
314 static int
pfkey_read(void)315 pfkey_read(void)
316 {
317 struct sadb_msg hdr, *msg;
318 u_int8_t *data;
319 ssize_t datalen;
320 int fd = cfgstate.pfkey_socket;
321
322 if (recv(fd, &hdr, sizeof hdr, MSG_PEEK) != sizeof hdr) {
323 log_err("pfkey_read: recv() failed");
324 return -1;
325 }
326 datalen = hdr.sadb_msg_len * CHUNK;
327 data = reallocarray(NULL, hdr.sadb_msg_len, CHUNK);
328 if (!data) {
329 log_err("pfkey_read: malloc(%lu) failed", datalen);
330 return -1;
331 }
332 msg = (struct sadb_msg *)data;
333
334 if (read(fd, data, datalen) != datalen) {
335 log_err("pfkey_read: read() failed, %lu bytes", datalen);
336 free(data);
337 return -1;
338 }
339
340 return pfkey_handle_message(msg);
341 }
342
343 int
pfkey_init(int reinit)344 pfkey_init(int reinit)
345 {
346 int fd;
347
348 fd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
349 if (fd == -1) {
350 perror("failed to open PF_KEY socket");
351 return -1;
352 }
353 cfgstate.pfkey_socket = fd;
354
355 if (cfgstate.runstate == MASTER)
356 pfkey_set_promisc();
357
358 if (reinit)
359 return (fd > -1 ? 0 : -1);
360
361 SIMPLEQ_INIT(&pfkey_msglist);
362 return 0;
363 }
364
365 void
pfkey_set_rfd(fd_set * fds)366 pfkey_set_rfd(fd_set *fds)
367 {
368 if (cfgstate.pfkey_socket != -1)
369 FD_SET(cfgstate.pfkey_socket, fds);
370 }
371
372 void
pfkey_set_pending_wfd(fd_set * fds)373 pfkey_set_pending_wfd(fd_set *fds)
374 {
375 if (cfgstate.pfkey_socket != -1 && SIMPLEQ_FIRST(&pfkey_msglist))
376 FD_SET(cfgstate.pfkey_socket, fds);
377 }
378
379 void
pfkey_read_message(fd_set * fds)380 pfkey_read_message(fd_set *fds)
381 {
382 if (cfgstate.pfkey_socket != -1)
383 if (FD_ISSET(cfgstate.pfkey_socket, fds))
384 (void)pfkey_read();
385 }
386
387 void
pfkey_send_message(fd_set * fds)388 pfkey_send_message(fd_set *fds)
389 {
390 struct pfkey_msg *pmsg = SIMPLEQ_FIRST(&pfkey_msglist);
391
392 if (!pmsg || !FD_ISSET(cfgstate.pfkey_socket, fds))
393 return;
394
395 if (cfgstate.pfkey_socket == -1)
396 if (pfkey_init(1)) /* Reinit socket */
397 return;
398
399 (void)pfkey_write(pmsg->buf, pmsg->len);
400
401 SIMPLEQ_REMOVE_HEAD(&pfkey_msglist, next);
402 free(pmsg->buf);
403 free(pmsg);
404
405 return;
406 }
407
408 int
pfkey_queue_message(u_int8_t * data,u_int32_t datalen)409 pfkey_queue_message(u_int8_t *data, u_int32_t datalen)
410 {
411 struct pfkey_msg *pmsg;
412 struct sadb_msg *sadb = (struct sadb_msg *)data;
413 static u_int32_t seq = 1;
414
415 pmsg = malloc(sizeof *pmsg);
416 if (!pmsg) {
417 log_err("malloc()");
418 return -1;
419 }
420 memset(pmsg, 0, sizeof *pmsg);
421
422 pmsg->buf = data;
423 pmsg->len = datalen;
424
425 sadb->sadb_msg_pid = getpid();
426 sadb->sadb_msg_seq = seq++;
427 log_msg(2, "pfkey_queue_message: pfkey %s len %zu seq %u",
428 pfkey_print_type(sadb), sadb->sadb_msg_len * CHUNK,
429 sadb->sadb_msg_seq);
430
431 SIMPLEQ_INSERT_TAIL(&pfkey_msglist, pmsg, next);
432 return 0;
433 }
434
435 void
pfkey_shutdown(void)436 pfkey_shutdown(void)
437 {
438 struct pfkey_msg *p = SIMPLEQ_FIRST(&pfkey_msglist);
439
440 while ((p = SIMPLEQ_FIRST(&pfkey_msglist))) {
441 SIMPLEQ_REMOVE_HEAD(&pfkey_msglist, next);
442 free(p->buf);
443 free(p);
444 }
445
446 if (cfgstate.pfkey_socket > -1)
447 close(cfgstate.pfkey_socket);
448 }
449
450 /* ------------------------------------------------------------------------- */
451
452 void
pfkey_snapshot(void * v)453 pfkey_snapshot(void *v)
454 {
455 struct syncpeer *p = (struct syncpeer *)v;
456 struct sadb_msg *m;
457 u_int8_t *sadb, *spd, *max, *next, *sendbuf;
458 u_int32_t sadbsz, spdsz;
459
460 if (!p)
461 return;
462
463 if (monitor_get_pfkey_snap(&sadb, &sadbsz, &spd, &spdsz)) {
464 log_msg(0, "pfkey_snapshot: failed to get pfkey snapshot");
465 return;
466 }
467
468 /* XXX needs moving if snapshot is called more than once per peer */
469 if ((cfgstate.flags & FM_MASK) == FM_STARTUP)
470 pfkey_send_flush(p);
471
472 /* Parse SADB data */
473 if (sadbsz && sadb) {
474 dump_buf(2, sadb, sadbsz, "pfkey_snapshot: SADB data");
475 max = sadb + sadbsz;
476 for (next = sadb; next < max;
477 next += m->sadb_msg_len * CHUNK) {
478 m = (struct sadb_msg *)next;
479 if (m->sadb_msg_len == 0)
480 break;
481
482 /* Tweak and send this SA to the peer. */
483 m->sadb_msg_type = SADB_ADD;
484
485 if (pfkey_msg_filter(m))
486 continue;
487
488 /* Allocate msgbuffer, net_queue() will free it. */
489 sendbuf = calloc(m->sadb_msg_len, CHUNK);
490 if (sendbuf) {
491 memcpy(sendbuf, m, m->sadb_msg_len * CHUNK);
492 net_queue(p, MSG_PFKEYDATA, sendbuf,
493 m->sadb_msg_len * CHUNK);
494 log_msg(2, "pfkey_snapshot: sync SA %p len %zu "
495 "to peer %s", m,
496 m->sadb_msg_len * CHUNK, p->name);
497 }
498 }
499 freezero(sadb, sadbsz);
500 }
501
502 /* Parse SPD data */
503 if (spdsz && spd) {
504 dump_buf(2, spd, spdsz, "pfkey_snapshot: SPD data");
505 max = spd + spdsz;
506 for (next = spd; next < max; next += m->sadb_msg_len * CHUNK) {
507 m = (struct sadb_msg *)next;
508 if (m->sadb_msg_len == 0)
509 break;
510
511 /* Tweak msg type. */
512 m->sadb_msg_type = SADB_X_ADDFLOW;
513
514 if (pfkey_msg_filter(m))
515 continue;
516
517 /* Allocate msgbuffer, freed by net_queue(). */
518 sendbuf = calloc(m->sadb_msg_len, CHUNK);
519 if (sendbuf) {
520 memcpy(sendbuf, m, m->sadb_msg_len * CHUNK);
521 net_queue(p, MSG_PFKEYDATA, sendbuf,
522 m->sadb_msg_len * CHUNK);
523 log_msg(2, "pfkey_snapshot: sync FLOW %p len "
524 "%zu to peer %s", m,
525 m->sadb_msg_len * CHUNK, p->name);
526 }
527 }
528 /* Cleanup. */
529 freezero(spd, spdsz);
530 }
531
532 net_ctl_send_endsnap(p);
533 return;
534 }
535