Annotation of sys/net/pfkeyv2.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: pfkeyv2.c,v 1.115 2007/06/22 12:14:05 markus Exp $ */
! 2:
! 3: /*
! 4: * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995
! 5: *
! 6: * NRL grants permission for redistribution and use in source and binary
! 7: * forms, with or without modification, of the software and documentation
! 8: * created at NRL provided that the following conditions 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: * 3. All advertising materials mentioning features or use of this software
! 16: * must display the following acknowledgements:
! 17: * This product includes software developed by the University of
! 18: * California, Berkeley and its contributors.
! 19: * This product includes software developed at the Information
! 20: * Technology Division, US Naval Research Laboratory.
! 21: * 4. Neither the name of the NRL nor the names of its contributors
! 22: * may be used to endorse or promote products derived from this software
! 23: * without specific prior written permission.
! 24: *
! 25: * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
! 26: * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 27: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
! 28: * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR
! 29: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
! 30: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
! 31: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
! 32: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
! 33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
! 34: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
! 35: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 36: *
! 37: * The views and conclusions contained in the software and documentation
! 38: * are those of the authors and should not be interpreted as representing
! 39: * official policies, either expressed or implied, of the US Naval
! 40: * Research Laboratory (NRL).
! 41: */
! 42:
! 43: /*
! 44: * Copyright (c) 1995, 1996, 1997, 1998, 1999 Craig Metz. All rights reserved.
! 45: *
! 46: * Redistribution and use in source and binary forms, with or without
! 47: * modification, are permitted provided that the following conditions
! 48: * are met:
! 49: * 1. Redistributions of source code must retain the above copyright
! 50: * notice, this list of conditions and the following disclaimer.
! 51: * 2. Redistributions in binary form must reproduce the above copyright
! 52: * notice, this list of conditions and the following disclaimer in the
! 53: * documentation and/or other materials provided with the distribution.
! 54: * 3. Neither the name of the author nor the names of any contributors
! 55: * may be used to endorse or promote products derived from this software
! 56: * without specific prior written permission.
! 57: *
! 58: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 59: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 60: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 61: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 62: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 63: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 64: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 65: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 66: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 67: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 68: * SUCH DAMAGE.
! 69: */
! 70:
! 71: #include "pf.h"
! 72:
! 73: #include <sys/types.h>
! 74: #include <sys/param.h>
! 75: #include <sys/socket.h>
! 76: #include <sys/systm.h>
! 77: #include <sys/mbuf.h>
! 78: #include <sys/kernel.h>
! 79: #include <sys/proc.h>
! 80: #include <net/route.h>
! 81: #include <netinet/ip_ipsp.h>
! 82: #include <net/pfkeyv2.h>
! 83: #include <netinet/ip_ah.h>
! 84: #include <netinet/ip_esp.h>
! 85: #include <netinet/ip_ipcomp.h>
! 86: #include <crypto/blf.h>
! 87:
! 88: #if NPF > 0
! 89: #include <net/if.h>
! 90: #include <net/pfvar.h>
! 91: #endif
! 92:
! 93: #define PFKEYV2_PROTOCOL 2
! 94: #define GETSPI_TRIES 10
! 95:
! 96: /* Static globals */
! 97: static struct pfkeyv2_socket *pfkeyv2_sockets = NULL;
! 98: static struct pfkey_version pfkeyv2_version;
! 99: static uint32_t pfkeyv2_seq = 1;
! 100: static int nregistered = 0;
! 101: static int npromisc = 0;
! 102:
! 103: static const struct sadb_alg ealgs[] = {
! 104: { SADB_EALG_NULL, 0, 0, 0 },
! 105: { SADB_EALG_DESCBC, 64, 64, 64 },
! 106: { SADB_EALG_3DESCBC, 64, 192, 192 },
! 107: { SADB_X_EALG_BLF, 64, 40, BLF_MAXKEYLEN * 8},
! 108: { SADB_X_EALG_CAST, 64, 40, 128},
! 109: { SADB_X_EALG_SKIPJACK, 64, 80, 80},
! 110: { SADB_X_EALG_AES, 128, 128, 256},
! 111: { SADB_X_EALG_AESCTR, 128, 128 + 32, 256 + 32}
! 112: };
! 113:
! 114: static const struct sadb_alg aalgs[] = {
! 115: { SADB_AALG_SHA1HMAC, 0, 160, 160 },
! 116: { SADB_AALG_MD5HMAC, 0, 128, 128 },
! 117: { SADB_X_AALG_RIPEMD160HMAC, 0, 160, 160 },
! 118: { SADB_X_AALG_SHA2_256, 0, 256, 256 },
! 119: { SADB_X_AALG_SHA2_384, 0, 384, 384 },
! 120: { SADB_X_AALG_SHA2_512, 0, 512, 512 }
! 121: };
! 122:
! 123: static const struct sadb_alg calgs[] = {
! 124: { SADB_X_CALG_DEFLATE, 0, 0, 0},
! 125: { SADB_X_CALG_LZS, 0, 0, 0}
! 126: };
! 127:
! 128: extern uint64_t sadb_exts_allowed_out[SADB_MAX+1];
! 129: extern uint64_t sadb_exts_required_out[SADB_MAX+1];
! 130:
! 131: extern struct pool ipsec_policy_pool;
! 132:
! 133: /*
! 134: * Wrapper around m_devget(); copy data from contiguous buffer to mbuf
! 135: * chain.
! 136: */
! 137: int
! 138: pfdatatopacket(void *data, int len, struct mbuf **packet)
! 139: {
! 140: if (!(*packet = m_devget(data, len, 0, NULL, NULL)))
! 141: return (ENOMEM);
! 142: return (0);
! 143: }
! 144:
! 145: /*
! 146: * Create a new PF_KEYv2 socket.
! 147: */
! 148: int
! 149: pfkeyv2_create(struct socket *socket)
! 150: {
! 151: struct pfkeyv2_socket *pfkeyv2_socket;
! 152:
! 153: if (!(pfkeyv2_socket = malloc(sizeof(struct pfkeyv2_socket),
! 154: M_PFKEY, M_DONTWAIT)))
! 155: return (ENOMEM);
! 156:
! 157: bzero(pfkeyv2_socket, sizeof(struct pfkeyv2_socket));
! 158: pfkeyv2_socket->next = pfkeyv2_sockets;
! 159: pfkeyv2_socket->socket = socket;
! 160: pfkeyv2_socket->pid = curproc->p_pid;
! 161:
! 162: pfkeyv2_sockets = pfkeyv2_socket;
! 163:
! 164: return (0);
! 165: }
! 166:
! 167: /*
! 168: * Close a PF_KEYv2 socket.
! 169: */
! 170: int
! 171: pfkeyv2_release(struct socket *socket)
! 172: {
! 173: struct pfkeyv2_socket **pp;
! 174:
! 175: for (pp = &pfkeyv2_sockets; *pp && ((*pp)->socket != socket);
! 176: pp = &((*pp)->next))
! 177: /*EMPTY*/;
! 178:
! 179: if (*pp) {
! 180: struct pfkeyv2_socket *pfkeyv2_socket;
! 181:
! 182: pfkeyv2_socket = *pp;
! 183: *pp = (*pp)->next;
! 184:
! 185: if (pfkeyv2_socket->flags & PFKEYV2_SOCKETFLAGS_REGISTERED)
! 186: nregistered--;
! 187:
! 188: if (pfkeyv2_socket->flags & PFKEYV2_SOCKETFLAGS_PROMISC)
! 189: npromisc--;
! 190:
! 191: free(pfkeyv2_socket, M_PFKEY);
! 192: }
! 193:
! 194: return (0);
! 195: }
! 196:
! 197: /*
! 198: * Send a PFKEYv2 message, possibly to many receivers, based on the
! 199: * satype of the socket (which is set by the REGISTER message), and the
! 200: * third argument.
! 201: */
! 202: int
! 203: pfkeyv2_sendmessage(void **headers, int mode, struct socket *socket,
! 204: u_int8_t satype, int count)
! 205: {
! 206: int i, j, rval;
! 207: void *p, *buffer = NULL;
! 208: struct mbuf *packet;
! 209: struct pfkeyv2_socket *s;
! 210: struct sadb_msg *smsg;
! 211:
! 212: /* Find out how much space we'll need... */
! 213: j = sizeof(struct sadb_msg);
! 214:
! 215: for (i = 1; i <= SADB_EXT_MAX; i++)
! 216: if (headers[i])
! 217: j += ((struct sadb_ext *)headers[i])->sadb_ext_len *
! 218: sizeof(uint64_t);
! 219:
! 220: /* ...and allocate it */
! 221: if (!(buffer = malloc(j + sizeof(struct sadb_msg), M_PFKEY,
! 222: M_DONTWAIT))) {
! 223: rval = ENOMEM;
! 224: goto ret;
! 225: }
! 226:
! 227: p = buffer + sizeof(struct sadb_msg);
! 228: bcopy(headers[0], p, sizeof(struct sadb_msg));
! 229: ((struct sadb_msg *) p)->sadb_msg_len = j / sizeof(uint64_t);
! 230: p += sizeof(struct sadb_msg);
! 231:
! 232: /* Copy payloads in the packet */
! 233: for (i = 1; i <= SADB_EXT_MAX; i++)
! 234: if (headers[i]) {
! 235: ((struct sadb_ext *) headers[i])->sadb_ext_type = i;
! 236: bcopy(headers[i], p, EXTLEN(headers[i]));
! 237: p += EXTLEN(headers[i]);
! 238: }
! 239:
! 240: if ((rval = pfdatatopacket(buffer + sizeof(struct sadb_msg),
! 241: j, &packet)) != 0)
! 242: goto ret;
! 243:
! 244: switch (mode) {
! 245: case PFKEYV2_SENDMESSAGE_UNICAST:
! 246: /*
! 247: * Send message to the specified socket, plus all
! 248: * promiscuous listeners.
! 249: */
! 250: pfkey_sendup(socket, packet, 0);
! 251:
! 252: /*
! 253: * Promiscuous messages contain the original message
! 254: * encapsulated in another sadb_msg header.
! 255: */
! 256: bzero(buffer, sizeof(struct sadb_msg));
! 257: smsg = (struct sadb_msg *) buffer;
! 258: smsg->sadb_msg_version = PF_KEY_V2;
! 259: smsg->sadb_msg_type = SADB_X_PROMISC;
! 260: smsg->sadb_msg_len = (sizeof(struct sadb_msg) + j) /
! 261: sizeof(uint64_t);
! 262: smsg->sadb_msg_seq = 0;
! 263:
! 264: /* Copy to mbuf chain */
! 265: if ((rval = pfdatatopacket(buffer, sizeof(struct sadb_msg) + j,
! 266: &packet)) != 0)
! 267: goto ret;
! 268:
! 269: /*
! 270: * Search for promiscuous listeners, skipping the
! 271: * original destination.
! 272: */
! 273: for (s = pfkeyv2_sockets; s; s = s->next)
! 274: if ((s->flags & PFKEYV2_SOCKETFLAGS_PROMISC) &&
! 275: (s->socket != socket))
! 276: pfkey_sendup(s->socket, packet, 1);
! 277:
! 278: /* Done, let's be a bit paranoid */
! 279: m_zero(packet);
! 280: m_freem(packet);
! 281: break;
! 282:
! 283: case PFKEYV2_SENDMESSAGE_REGISTERED:
! 284: /*
! 285: * Send the message to all registered sockets that match
! 286: * the specified satype (e.g., all IPSEC-ESP negotiators)
! 287: */
! 288: for (s = pfkeyv2_sockets; s; s = s->next)
! 289: if (s->flags & PFKEYV2_SOCKETFLAGS_REGISTERED) {
! 290: if (!satype) /* Just send to everyone registered */
! 291: pfkey_sendup(s->socket, packet, 1);
! 292: else {
! 293: /* Check for specified satype */
! 294: if ((1 << satype) & s->registration)
! 295: pfkey_sendup(s->socket, packet, 1);
! 296: }
! 297: }
! 298:
! 299: /* Free last/original copy of the packet */
! 300: m_freem(packet);
! 301:
! 302: /* Encapsulate the original message "inside" an sadb_msg header */
! 303: bzero(buffer, sizeof(struct sadb_msg));
! 304: smsg = (struct sadb_msg *) buffer;
! 305: smsg->sadb_msg_version = PF_KEY_V2;
! 306: smsg->sadb_msg_type = SADB_X_PROMISC;
! 307: smsg->sadb_msg_len = (sizeof(struct sadb_msg) + j) /
! 308: sizeof(uint64_t);
! 309: smsg->sadb_msg_seq = 0;
! 310:
! 311: /* Convert to mbuf chain */
! 312: if ((rval = pfdatatopacket(buffer, sizeof(struct sadb_msg) + j,
! 313: &packet)) != 0)
! 314: goto ret;
! 315:
! 316: /* Send to all registered promiscuous listeners */
! 317: for (s = pfkeyv2_sockets; s; s = s->next)
! 318: if ((s->flags & PFKEYV2_SOCKETFLAGS_PROMISC) &&
! 319: !(s->flags & PFKEYV2_SOCKETFLAGS_REGISTERED))
! 320: pfkey_sendup(s->socket, packet, 1);
! 321:
! 322: m_freem(packet);
! 323: break;
! 324:
! 325: case PFKEYV2_SENDMESSAGE_BROADCAST:
! 326: /* Send message to all sockets */
! 327: for (s = pfkeyv2_sockets; s; s = s->next)
! 328: pfkey_sendup(s->socket, packet, 1);
! 329:
! 330: m_freem(packet);
! 331: break;
! 332: }
! 333:
! 334: ret:
! 335: if (buffer != NULL) {
! 336: bzero(buffer, j + sizeof(struct sadb_msg));
! 337: free(buffer, M_PFKEY);
! 338: }
! 339:
! 340: return (rval);
! 341: }
! 342:
! 343: /*
! 344: * Get SPD information for an ACQUIRE. We setup the message such that
! 345: * the SRC/DST payloads are relative to us (regardless of whether the
! 346: * SPD rule was for incoming or outgoing packets).
! 347: */
! 348: int
! 349: pfkeyv2_policy(struct ipsec_acquire *ipa, void **headers, void **buffer)
! 350: {
! 351: union sockaddr_union sunion;
! 352: struct sadb_protocol *sp;
! 353: int rval, i, dir;
! 354: void *p;
! 355:
! 356: /* Find out how big a buffer we need */
! 357: i = 4 * sizeof(struct sadb_address) + sizeof(struct sadb_protocol);
! 358: bzero(&sunion, sizeof(union sockaddr_union));
! 359:
! 360: switch (ipa->ipa_info.sen_type) {
! 361: #ifdef INET
! 362: case SENT_IP4:
! 363: i += 4 * PADUP(sizeof(struct sockaddr_in));
! 364: sunion.sa.sa_family = AF_INET;
! 365: sunion.sa.sa_len = sizeof(struct sockaddr_in);
! 366: dir = ipa->ipa_info.sen_direction;
! 367: break;
! 368: #endif /* INET */
! 369:
! 370: #ifdef INET6
! 371: case SENT_IP6:
! 372: i += 4 * PADUP(sizeof(struct sockaddr_in6));
! 373: sunion.sa.sa_family = AF_INET6;
! 374: sunion.sa.sa_len = sizeof(struct sockaddr_in6);
! 375: dir = ipa->ipa_info.sen_ip6_direction;
! 376: break;
! 377: #endif /* INET6 */
! 378:
! 379: default:
! 380: return (EINVAL);
! 381: }
! 382:
! 383: if (!(p = malloc(i, M_PFKEY, M_DONTWAIT))) {
! 384: rval = ENOMEM;
! 385: goto ret;
! 386: } else {
! 387: *buffer = p;
! 388: bzero(p, i);
! 389: }
! 390:
! 391: if (dir == IPSP_DIRECTION_OUT)
! 392: headers[SADB_X_EXT_SRC_FLOW] = p;
! 393: else
! 394: headers[SADB_X_EXT_DST_FLOW] = p;
! 395: switch (sunion.sa.sa_family) {
! 396: #ifdef INET
! 397: case AF_INET:
! 398: sunion.sin.sin_addr = ipa->ipa_info.sen_ip_src;
! 399: sunion.sin.sin_port = ipa->ipa_info.sen_sport;
! 400: break;
! 401: #endif /* INET */
! 402:
! 403: #ifdef INET6
! 404: case AF_INET6:
! 405: sunion.sin6.sin6_addr = ipa->ipa_info.sen_ip6_src;
! 406: sunion.sin6.sin6_port = ipa->ipa_info.sen_ip6_sport;
! 407: break;
! 408: #endif /* INET6 */
! 409: }
! 410: export_address(&p, (struct sockaddr *) &sunion);
! 411:
! 412: if (dir == IPSP_DIRECTION_OUT)
! 413: headers[SADB_X_EXT_SRC_MASK] = p;
! 414: else
! 415: headers[SADB_X_EXT_DST_MASK] = p;
! 416: switch (sunion.sa.sa_family) {
! 417: #ifdef INET
! 418: case AF_INET:
! 419: sunion.sin.sin_addr = ipa->ipa_mask.sen_ip_src;
! 420: sunion.sin.sin_port = ipa->ipa_mask.sen_sport;
! 421: break;
! 422: #endif /* INET */
! 423:
! 424: #ifdef INET6
! 425: case AF_INET6:
! 426: sunion.sin6.sin6_addr = ipa->ipa_mask.sen_ip6_src;
! 427: sunion.sin6.sin6_port = ipa->ipa_mask.sen_ip6_sport;
! 428: break;
! 429: #endif /* INET6 */
! 430: }
! 431: export_address(&p, (struct sockaddr *) &sunion);
! 432:
! 433: if (dir == IPSP_DIRECTION_OUT)
! 434: headers[SADB_X_EXT_DST_FLOW] = p;
! 435: else
! 436: headers[SADB_X_EXT_SRC_FLOW] = p;
! 437: switch (sunion.sa.sa_family) {
! 438: #ifdef INET
! 439: case AF_INET:
! 440: sunion.sin.sin_addr = ipa->ipa_info.sen_ip_dst;
! 441: sunion.sin.sin_port = ipa->ipa_info.sen_dport;
! 442: break;
! 443: #endif /* INET */
! 444:
! 445: #ifdef INET6
! 446: case AF_INET6:
! 447: sunion.sin6.sin6_addr = ipa->ipa_info.sen_ip6_dst;
! 448: sunion.sin6.sin6_port = ipa->ipa_info.sen_ip6_dport;
! 449: break;
! 450: #endif /* INET6 */
! 451: }
! 452: export_address(&p, (struct sockaddr *) &sunion);
! 453:
! 454: if (dir == IPSP_DIRECTION_OUT)
! 455: headers[SADB_X_EXT_DST_MASK] = p;
! 456: else
! 457: headers[SADB_X_EXT_SRC_MASK] = p;
! 458: switch (sunion.sa.sa_family) {
! 459: #ifdef INET
! 460: case AF_INET:
! 461: sunion.sin.sin_addr = ipa->ipa_mask.sen_ip_dst;
! 462: sunion.sin.sin_port = ipa->ipa_mask.sen_dport;
! 463: break;
! 464: #endif /* INET */
! 465:
! 466: #ifdef INET6
! 467: case AF_INET6:
! 468: sunion.sin6.sin6_addr = ipa->ipa_mask.sen_ip6_dst;
! 469: sunion.sin6.sin6_port = ipa->ipa_mask.sen_ip6_dport;
! 470: break;
! 471: #endif /* INET6 */
! 472: }
! 473: export_address(&p, (struct sockaddr *) &sunion);
! 474:
! 475: headers[SADB_X_EXT_FLOW_TYPE] = p;
! 476: sp = p;
! 477: sp->sadb_protocol_len = sizeof(struct sadb_protocol) /
! 478: sizeof(u_int64_t);
! 479: switch (sunion.sa.sa_family) {
! 480: #ifdef INET
! 481: case AF_INET:
! 482: if (ipa->ipa_mask.sen_proto)
! 483: sp->sadb_protocol_proto = ipa->ipa_info.sen_proto;
! 484: sp->sadb_protocol_direction = ipa->ipa_info.sen_direction;
! 485: break;
! 486: #endif /* INET */
! 487:
! 488: #ifdef INET6
! 489: case AF_INET6:
! 490: if (ipa->ipa_mask.sen_ip6_proto)
! 491: sp->sadb_protocol_proto = ipa->ipa_info.sen_ip6_proto;
! 492: sp->sadb_protocol_direction = ipa->ipa_info.sen_ip6_direction;
! 493: break;
! 494: #endif /* INET6 */
! 495: }
! 496:
! 497: rval = 0;
! 498:
! 499: ret:
! 500: return (rval);
! 501: }
! 502:
! 503: /*
! 504: * Get all the information contained in an SA to a PFKEYV2 message.
! 505: */
! 506: int
! 507: pfkeyv2_get(struct tdb *sa, void **headers, void **buffer, int *lenp)
! 508: {
! 509: int rval, i;
! 510: void *p;
! 511:
! 512: /* Find how much space we need */
! 513: i = sizeof(struct sadb_sa) + sizeof(struct sadb_lifetime);
! 514:
! 515: if (sa->tdb_soft_allocations || sa->tdb_soft_bytes ||
! 516: sa->tdb_soft_timeout || sa->tdb_soft_first_use)
! 517: i += sizeof(struct sadb_lifetime);
! 518:
! 519: if (sa->tdb_exp_allocations || sa->tdb_exp_bytes ||
! 520: sa->tdb_exp_timeout || sa->tdb_exp_first_use)
! 521: i += sizeof(struct sadb_lifetime);
! 522:
! 523: if (sa->tdb_last_used)
! 524: i += sizeof(struct sadb_lifetime);
! 525:
! 526: if (sa->tdb_src.sa.sa_family)
! 527: i += sizeof(struct sadb_address) + PADUP(SA_LEN(&sa->tdb_src.sa));
! 528:
! 529: if (sa->tdb_dst.sa.sa_family)
! 530: i += sizeof(struct sadb_address) + PADUP(SA_LEN(&sa->tdb_dst.sa));
! 531:
! 532: if (sa->tdb_proxy.sa.sa_family)
! 533: i += sizeof(struct sadb_address) + PADUP(SA_LEN(&sa->tdb_proxy.sa));
! 534:
! 535: if (sa->tdb_srcid)
! 536: i += PADUP(sa->tdb_srcid->ref_len) + sizeof(struct sadb_ident);
! 537:
! 538: if (sa->tdb_dstid)
! 539: i += PADUP(sa->tdb_dstid->ref_len) + sizeof(struct sadb_ident);
! 540:
! 541: if (sa->tdb_local_cred)
! 542: i += PADUP(sa->tdb_local_cred->ref_len) + sizeof(struct sadb_x_cred);
! 543:
! 544: if (sa->tdb_remote_cred)
! 545: i += PADUP(sa->tdb_remote_cred->ref_len) + sizeof(struct sadb_x_cred);
! 546:
! 547: if (sa->tdb_local_auth)
! 548: i += PADUP(sa->tdb_local_auth->ref_len) + sizeof(struct sadb_x_cred);
! 549:
! 550: if (sa->tdb_remote_auth)
! 551: i += PADUP(sa->tdb_remote_auth->ref_len) + sizeof(struct sadb_x_cred);
! 552:
! 553: if (sa->tdb_amxkey)
! 554: i+= PADUP(sa->tdb_amxkeylen) + sizeof(struct sadb_key);
! 555:
! 556: if (sa->tdb_emxkey)
! 557: i+= PADUP(sa->tdb_emxkeylen) + sizeof(struct sadb_key);
! 558:
! 559: if (sa->tdb_filter.sen_type) {
! 560: i += 2 * sizeof(struct sadb_protocol);
! 561:
! 562: /* We'll need four of them: src, src mask, dst, dst mask. */
! 563: switch (sa->tdb_filter.sen_type) {
! 564: #ifdef INET
! 565: case SENT_IP4:
! 566: i += 4 * PADUP(sizeof(struct sockaddr_in));
! 567: i += 4 * sizeof(struct sadb_address);
! 568: break;
! 569: #endif /* INET */
! 570: #ifdef INET6
! 571: case SENT_IP6:
! 572: i += 4 * PADUP(sizeof(struct sockaddr_in6));
! 573: i += 4 * sizeof(struct sadb_address);
! 574: break;
! 575: #endif /* INET6 */
! 576: default:
! 577: rval = EINVAL;
! 578: goto ret;
! 579: }
! 580: }
! 581:
! 582: if (sa->tdb_udpencap_port)
! 583: i+= sizeof(struct sadb_x_udpencap);
! 584:
! 585: #if NPF > 0
! 586: if (sa->tdb_tag)
! 587: i+= PADUP(PF_TAG_NAME_SIZE) + sizeof(struct sadb_x_tag);
! 588: #endif
! 589:
! 590: if (lenp)
! 591: *lenp = i;
! 592:
! 593: if (buffer == NULL) {
! 594: rval = 0;
! 595: goto ret;
! 596: }
! 597:
! 598: if (!(p = malloc(i, M_PFKEY, M_DONTWAIT))) {
! 599: rval = ENOMEM;
! 600: goto ret;
! 601: } else {
! 602: *buffer = p;
! 603: bzero(p, i);
! 604: }
! 605:
! 606: headers[SADB_EXT_SA] = p;
! 607:
! 608: export_sa(&p, sa); /* Export SA information (mostly flags) */
! 609:
! 610: /* Export lifetimes where applicable */
! 611: headers[SADB_EXT_LIFETIME_CURRENT] = p;
! 612: export_lifetime(&p, sa, PFKEYV2_LIFETIME_CURRENT);
! 613:
! 614: if (sa->tdb_soft_allocations || sa->tdb_soft_bytes ||
! 615: sa->tdb_soft_first_use || sa->tdb_soft_timeout) {
! 616: headers[SADB_EXT_LIFETIME_SOFT] = p;
! 617: export_lifetime(&p, sa, PFKEYV2_LIFETIME_SOFT);
! 618: }
! 619:
! 620: if (sa->tdb_exp_allocations || sa->tdb_exp_bytes ||
! 621: sa->tdb_exp_first_use || sa->tdb_exp_timeout) {
! 622: headers[SADB_EXT_LIFETIME_HARD] = p;
! 623: export_lifetime(&p, sa, PFKEYV2_LIFETIME_HARD);
! 624: }
! 625:
! 626: if (sa->tdb_last_used) {
! 627: headers[SADB_X_EXT_LIFETIME_LASTUSE] = p;
! 628: export_lifetime(&p, sa, PFKEYV2_LIFETIME_LASTUSE);
! 629: }
! 630:
! 631: /* Export TDB source address */
! 632: headers[SADB_EXT_ADDRESS_SRC] = p;
! 633: export_address(&p, (struct sockaddr *) &sa->tdb_src);
! 634:
! 635: /* Export TDB destination address */
! 636: headers[SADB_EXT_ADDRESS_DST] = p;
! 637: export_address(&p, (struct sockaddr *) &sa->tdb_dst);
! 638:
! 639: /* Export TDB proxy address, if present */
! 640: if (SA_LEN(&sa->tdb_proxy.sa)) {
! 641: headers[SADB_EXT_ADDRESS_PROXY] = p;
! 642: export_address(&p, (struct sockaddr *) &sa->tdb_proxy);
! 643: }
! 644:
! 645: /* Export source identity, if present */
! 646: if (sa->tdb_srcid) {
! 647: headers[SADB_EXT_IDENTITY_SRC] = p;
! 648: export_identity(&p, sa, PFKEYV2_IDENTITY_SRC);
! 649: }
! 650:
! 651: /* Export destination identity, if present */
! 652: if (sa->tdb_dstid) {
! 653: headers[SADB_EXT_IDENTITY_DST] = p;
! 654: export_identity(&p, sa, PFKEYV2_IDENTITY_DST);
! 655: }
! 656:
! 657: /* Export credentials, if present */
! 658: if (sa->tdb_local_cred) {
! 659: headers[SADB_X_EXT_LOCAL_CREDENTIALS] = p;
! 660: export_credentials(&p, sa, PFKEYV2_CRED_LOCAL);
! 661: }
! 662:
! 663: if (sa->tdb_remote_cred) {
! 664: headers[SADB_X_EXT_REMOTE_CREDENTIALS] = p;
! 665: export_credentials(&p, sa, PFKEYV2_CRED_REMOTE);
! 666: }
! 667:
! 668: /* Export authentication information, if present */
! 669: if (sa->tdb_local_auth) {
! 670: headers[SADB_X_EXT_LOCAL_AUTH] = p;
! 671: export_auth(&p, sa, PFKEYV2_AUTH_LOCAL);
! 672: }
! 673:
! 674: if (sa->tdb_remote_auth) {
! 675: headers[SADB_X_EXT_REMOTE_AUTH] = p;
! 676: export_auth(&p, sa, PFKEYV2_AUTH_REMOTE);
! 677: }
! 678:
! 679: /* Export authentication key, if present */
! 680: if (sa->tdb_amxkey) {
! 681: headers[SADB_EXT_KEY_AUTH] = p;
! 682: export_key(&p, sa, PFKEYV2_AUTHENTICATION_KEY);
! 683: }
! 684:
! 685: /* Export encryption key, if present */
! 686: if (sa->tdb_emxkey) {
! 687: headers[SADB_EXT_KEY_ENCRYPT] = p;
! 688: export_key(&p, sa, PFKEYV2_ENCRYPTION_KEY);
! 689: }
! 690:
! 691: /* Export flow/filter, if present */
! 692: if (sa->tdb_filter.sen_type)
! 693: export_flow(&p, IPSP_IPSEC_USE, &sa->tdb_filter,
! 694: &sa->tdb_filtermask, headers);
! 695:
! 696: /* Export UDP encapsulation port, if present */
! 697: if (sa->tdb_udpencap_port) {
! 698: headers[SADB_X_EXT_UDPENCAP] = p;
! 699: export_udpencap(&p, sa);
! 700: }
! 701:
! 702: #if NPF > 0
! 703: /* Export tag information, if present */
! 704: if (sa->tdb_tag) {
! 705: headers[SADB_X_EXT_TAG] = p;
! 706: export_tag(&p, sa);
! 707: }
! 708: #endif
! 709:
! 710: rval = 0;
! 711:
! 712: ret:
! 713: return (rval);
! 714: }
! 715:
! 716: /*
! 717: * Dump a TDB.
! 718: */
! 719: int
! 720: pfkeyv2_dump_walker(struct tdb *sa, void *state, int last)
! 721: {
! 722: struct dump_state *dump_state = (struct dump_state *) state;
! 723: void *headers[SADB_EXT_MAX+1], *buffer;
! 724: int rval;
! 725:
! 726: /* If not satype was specified, dump all TDBs */
! 727: if (!dump_state->sadb_msg->sadb_msg_satype ||
! 728: (sa->tdb_satype == dump_state->sadb_msg->sadb_msg_satype)) {
! 729: bzero(headers, sizeof(headers));
! 730: headers[0] = (void *) dump_state->sadb_msg;
! 731:
! 732: /* Get the information from the TDB to a PFKEYv2 message */
! 733: if ((rval = pfkeyv2_get(sa, headers, &buffer, NULL)) != 0)
! 734: return (rval);
! 735:
! 736: if (last)
! 737: ((struct sadb_msg *)headers[0])->sadb_msg_seq = 0;
! 738:
! 739: /* Send the message to the specified socket */
! 740: rval = pfkeyv2_sendmessage(headers,
! 741: PFKEYV2_SENDMESSAGE_UNICAST, dump_state->socket, 0, 0);
! 742:
! 743: free(buffer, M_PFKEY);
! 744: if (rval)
! 745: return (rval);
! 746: }
! 747:
! 748: return (0);
! 749: }
! 750:
! 751: /*
! 752: * Delete an SA.
! 753: */
! 754: int
! 755: pfkeyv2_flush_walker(struct tdb *sa, void *satype_vp, int last)
! 756: {
! 757: if (!(*((u_int8_t *) satype_vp)) ||
! 758: sa->tdb_satype == *((u_int8_t *) satype_vp))
! 759: tdb_delete(sa);
! 760: return (0);
! 761: }
! 762:
! 763: /*
! 764: * Convert between SATYPEs and IPsec protocols, taking into consideration
! 765: * sysctl variables enabling/disabling ESP/AH and the presence of the old
! 766: * IPsec transforms.
! 767: */
! 768: int
! 769: pfkeyv2_get_proto_alg(u_int8_t satype, u_int8_t *sproto, int *alg)
! 770: {
! 771: switch (satype) {
! 772: #ifdef IPSEC
! 773: case SADB_SATYPE_AH:
! 774: if (!ah_enable)
! 775: return (EOPNOTSUPP);
! 776:
! 777: *sproto = IPPROTO_AH;
! 778:
! 779: if(alg != NULL)
! 780: *alg = satype = XF_AH;
! 781:
! 782: break;
! 783:
! 784: case SADB_SATYPE_ESP:
! 785: if (!esp_enable)
! 786: return (EOPNOTSUPP);
! 787:
! 788: *sproto = IPPROTO_ESP;
! 789:
! 790: if(alg != NULL)
! 791: *alg = satype = XF_ESP;
! 792:
! 793: break;
! 794:
! 795: case SADB_X_SATYPE_IPIP:
! 796: *sproto = IPPROTO_IPIP;
! 797:
! 798: if (alg != NULL)
! 799: *alg = XF_IP4;
! 800:
! 801: break;
! 802:
! 803: case SADB_X_SATYPE_IPCOMP:
! 804: if (!ipcomp_enable)
! 805: return (EOPNOTSUPP);
! 806:
! 807: *sproto = IPPROTO_IPCOMP;
! 808:
! 809: if(alg != NULL)
! 810: *alg = satype = XF_IPCOMP;
! 811:
! 812: break;
! 813: #endif /* IPSEC */
! 814: #ifdef TCP_SIGNATURE
! 815: case SADB_X_SATYPE_TCPSIGNATURE:
! 816: *sproto = IPPROTO_TCP;
! 817:
! 818: if (alg != NULL)
! 819: *alg = XF_TCPSIGNATURE;
! 820:
! 821: break;
! 822: #endif /* TCP_SIGNATURE */
! 823:
! 824: default: /* Nothing else supported */
! 825: return (EOPNOTSUPP);
! 826: }
! 827:
! 828: return (0);
! 829: }
! 830:
! 831: /*
! 832: * Handle all messages from userland to kernel.
! 833: */
! 834: int
! 835: pfkeyv2_send(struct socket *socket, void *message, int len)
! 836: {
! 837: int i, j, rval = 0, mode = PFKEYV2_SENDMESSAGE_BROADCAST;
! 838: int delflag = 0, s;
! 839: struct sockaddr_encap encapdst, encapnetmask, encapgw;
! 840: struct ipsec_policy *ipo, *tmpipo;
! 841: struct ipsec_acquire *ipa;
! 842:
! 843: struct pfkeyv2_socket *pfkeyv2_socket, *so = NULL;
! 844:
! 845: void *freeme = NULL, *bckptr = NULL;
! 846: void *headers[SADB_EXT_MAX + 1];
! 847:
! 848: union sockaddr_union *sunionp;
! 849:
! 850: struct tdb sa, *sa2 = NULL;
! 851:
! 852: struct sadb_msg *smsg;
! 853: struct sadb_spirange *sprng;
! 854: struct sadb_sa *ssa;
! 855: struct sadb_supported *ssup;
! 856: struct sadb_ident *sid;
! 857:
! 858: /* Verify that we received this over a legitimate pfkeyv2 socket */
! 859: bzero(headers, sizeof(headers));
! 860:
! 861: for (pfkeyv2_socket = pfkeyv2_sockets; pfkeyv2_socket;
! 862: pfkeyv2_socket = pfkeyv2_socket->next)
! 863: if (pfkeyv2_socket->socket == socket)
! 864: break;
! 865:
! 866: if (!pfkeyv2_socket) {
! 867: rval = EINVAL;
! 868: goto ret;
! 869: }
! 870:
! 871: /* If we have any promiscuous listeners, send them a copy of the message */
! 872: if (npromisc) {
! 873: struct mbuf *packet;
! 874:
! 875: if (!(freeme = malloc(sizeof(struct sadb_msg) + len, M_PFKEY,
! 876: M_DONTWAIT))) {
! 877: rval = ENOMEM;
! 878: goto ret;
! 879: }
! 880:
! 881: /* Initialize encapsulating header */
! 882: bzero(freeme, sizeof(struct sadb_msg));
! 883: smsg = (struct sadb_msg *) freeme;
! 884: smsg->sadb_msg_version = PF_KEY_V2;
! 885: smsg->sadb_msg_type = SADB_X_PROMISC;
! 886: smsg->sadb_msg_len = (sizeof(struct sadb_msg) + len) /
! 887: sizeof(uint64_t);
! 888: smsg->sadb_msg_seq = curproc->p_pid;
! 889:
! 890: bcopy(message, freeme + sizeof(struct sadb_msg), len);
! 891:
! 892: /* Convert to mbuf chain */
! 893: if ((rval = pfdatatopacket(freeme,
! 894: sizeof(struct sadb_msg) + len, &packet)) != 0)
! 895: goto ret;
! 896:
! 897: /* Send to all promiscuous listeners */
! 898: for (so = pfkeyv2_sockets; so; so = so->next)
! 899: if (so->flags & PFKEYV2_SOCKETFLAGS_PROMISC)
! 900: pfkey_sendup(so->socket, packet, 1);
! 901:
! 902: /* Paranoid */
! 903: m_zero(packet);
! 904: m_freem(packet);
! 905:
! 906: /* Even more paranoid */
! 907: bzero(freeme, sizeof(struct sadb_msg) + len);
! 908: free(freeme, M_PFKEY);
! 909: freeme = NULL;
! 910: }
! 911:
! 912: /* Validate message format */
! 913: if ((rval = pfkeyv2_parsemessage(message, len, headers)) != 0)
! 914: goto ret;
! 915:
! 916: smsg = (struct sadb_msg *) headers[0];
! 917: switch (smsg->sadb_msg_type) {
! 918: case SADB_GETSPI: /* Reserve an SPI */
! 919: bzero(&sa, sizeof(struct tdb));
! 920:
! 921: sa.tdb_satype = smsg->sadb_msg_satype;
! 922: if ((rval = pfkeyv2_get_proto_alg(sa.tdb_satype,
! 923: &sa.tdb_sproto, 0)))
! 924: goto ret;
! 925:
! 926: import_address((struct sockaddr *) &sa.tdb_src,
! 927: headers[SADB_EXT_ADDRESS_SRC]);
! 928: import_address((struct sockaddr *) &sa.tdb_dst,
! 929: headers[SADB_EXT_ADDRESS_DST]);
! 930:
! 931: /* Find an unused SA identifier */
! 932: sprng = (struct sadb_spirange *) headers[SADB_EXT_SPIRANGE];
! 933: sa.tdb_spi = reserve_spi(sprng->sadb_spirange_min,
! 934: sprng->sadb_spirange_max, &sa.tdb_src, &sa.tdb_dst,
! 935: sa.tdb_sproto, &rval);
! 936: if (sa.tdb_spi == 0)
! 937: goto ret;
! 938:
! 939: /* Send a message back telling what the SA (the SPI really) is */
! 940: if (!(freeme = malloc(sizeof(struct sadb_sa), M_PFKEY,
! 941: M_DONTWAIT))) {
! 942: rval = ENOMEM;
! 943: goto ret;
! 944: }
! 945:
! 946: bzero(freeme, sizeof(struct sadb_sa));
! 947: headers[SADB_EXT_SPIRANGE] = NULL;
! 948: headers[SADB_EXT_SA] = freeme;
! 949: bckptr = freeme;
! 950:
! 951: /* We really only care about the SPI, but we'll export the SA */
! 952: export_sa((void **) &bckptr, &sa);
! 953: break;
! 954:
! 955: case SADB_UPDATE:
! 956: ssa = (struct sadb_sa *) headers[SADB_EXT_SA];
! 957: sunionp = (union sockaddr_union *) (headers[SADB_EXT_ADDRESS_DST] +
! 958: sizeof(struct sadb_address));
! 959:
! 960: /* Either all or none of the flow must be included */
! 961: if ((headers[SADB_X_EXT_SRC_FLOW] ||
! 962: headers[SADB_X_EXT_PROTOCOL] ||
! 963: headers[SADB_X_EXT_FLOW_TYPE] ||
! 964: headers[SADB_X_EXT_DST_FLOW] ||
! 965: headers[SADB_X_EXT_SRC_MASK] ||
! 966: headers[SADB_X_EXT_DST_MASK]) &&
! 967: !(headers[SADB_X_EXT_SRC_FLOW] &&
! 968: headers[SADB_X_EXT_PROTOCOL] &&
! 969: headers[SADB_X_EXT_FLOW_TYPE] &&
! 970: headers[SADB_X_EXT_DST_FLOW] &&
! 971: headers[SADB_X_EXT_SRC_MASK] &&
! 972: headers[SADB_X_EXT_DST_MASK])) {
! 973: rval = EINVAL;
! 974: goto ret;
! 975: }
! 976: #ifdef IPSEC
! 977: /* UDP encap has to be enabled and is only supported for ESP */
! 978: if (headers[SADB_X_EXT_UDPENCAP] &&
! 979: (!udpencap_enable ||
! 980: smsg->sadb_msg_satype != SADB_SATYPE_ESP)) {
! 981: rval = EINVAL;
! 982: goto ret;
! 983: }
! 984: #endif /* IPSEC */
! 985:
! 986: s = spltdb();
! 987:
! 988: /* Find TDB */
! 989: sa2 = gettdb(ssa->sadb_sa_spi, sunionp,
! 990: SADB_X_GETSPROTO(smsg->sadb_msg_satype));
! 991:
! 992: /* If there's no such SA, we're done */
! 993: if (sa2 == NULL) {
! 994: rval = ESRCH;
! 995: goto splxret;
! 996: }
! 997:
! 998: /* If this is a reserved SA */
! 999: if (sa2->tdb_flags & TDBF_INVALID) {
! 1000: struct tdb *newsa;
! 1001: struct ipsecinit ii;
! 1002: int alg;
! 1003:
! 1004: /* Create new TDB */
! 1005: freeme = tdb_alloc();
! 1006: bzero(&ii, sizeof(struct ipsecinit));
! 1007:
! 1008: newsa = (struct tdb *) freeme;
! 1009: newsa->tdb_satype = smsg->sadb_msg_satype;
! 1010:
! 1011: if ((rval = pfkeyv2_get_proto_alg(newsa->tdb_satype,
! 1012: &newsa->tdb_sproto, &alg))) {
! 1013: tdb_free(freeme);
! 1014: freeme = NULL;
! 1015: goto splxret;
! 1016: }
! 1017:
! 1018: /* Initialize SA */
! 1019: import_sa(newsa, headers[SADB_EXT_SA], &ii);
! 1020: import_address((struct sockaddr *) &newsa->tdb_src,
! 1021: headers[SADB_EXT_ADDRESS_SRC]);
! 1022: import_address((struct sockaddr *) &newsa->tdb_dst,
! 1023: headers[SADB_EXT_ADDRESS_DST]);
! 1024: import_address((struct sockaddr *) &newsa->tdb_proxy,
! 1025: headers[SADB_EXT_ADDRESS_PROXY]);
! 1026: import_lifetime(newsa,
! 1027: headers[SADB_EXT_LIFETIME_CURRENT],
! 1028: PFKEYV2_LIFETIME_CURRENT);
! 1029: import_lifetime(newsa, headers[SADB_EXT_LIFETIME_SOFT],
! 1030: PFKEYV2_LIFETIME_SOFT);
! 1031: import_lifetime(newsa, headers[SADB_EXT_LIFETIME_HARD],
! 1032: PFKEYV2_LIFETIME_HARD);
! 1033: import_key(&ii, headers[SADB_EXT_KEY_AUTH],
! 1034: PFKEYV2_AUTHENTICATION_KEY);
! 1035: import_key(&ii, headers[SADB_EXT_KEY_ENCRYPT],
! 1036: PFKEYV2_ENCRYPTION_KEY);
! 1037: import_identity(newsa, headers[SADB_EXT_IDENTITY_SRC],
! 1038: PFKEYV2_IDENTITY_SRC);
! 1039: import_identity(newsa, headers[SADB_EXT_IDENTITY_DST],
! 1040: PFKEYV2_IDENTITY_DST);
! 1041: import_credentials(newsa,
! 1042: headers[SADB_X_EXT_LOCAL_CREDENTIALS],
! 1043: PFKEYV2_CRED_LOCAL);
! 1044: import_credentials(newsa,
! 1045: headers[SADB_X_EXT_REMOTE_CREDENTIALS],
! 1046: PFKEYV2_CRED_REMOTE);
! 1047: import_auth(newsa, headers[SADB_X_EXT_LOCAL_AUTH],
! 1048: PFKEYV2_AUTH_LOCAL);
! 1049: import_auth(newsa, headers[SADB_X_EXT_REMOTE_AUTH],
! 1050: PFKEYV2_AUTH_REMOTE);
! 1051: import_flow(&newsa->tdb_filter, &newsa->tdb_filtermask,
! 1052: headers[SADB_X_EXT_SRC_FLOW],
! 1053: headers[SADB_X_EXT_SRC_MASK],
! 1054: headers[SADB_X_EXT_DST_FLOW],
! 1055: headers[SADB_X_EXT_DST_MASK],
! 1056: headers[SADB_X_EXT_PROTOCOL],
! 1057: headers[SADB_X_EXT_FLOW_TYPE]);
! 1058: import_udpencap(newsa, headers[SADB_X_EXT_UDPENCAP]);
! 1059: #if NPF > 0
! 1060: import_tag(newsa, headers[SADB_X_EXT_TAG]);
! 1061: #endif
! 1062:
! 1063: headers[SADB_EXT_KEY_AUTH] = NULL;
! 1064: headers[SADB_EXT_KEY_ENCRYPT] = NULL;
! 1065: headers[SADB_X_EXT_LOCAL_AUTH] = NULL;
! 1066:
! 1067: newsa->tdb_seq = smsg->sadb_msg_seq;
! 1068:
! 1069: rval = tdb_init(newsa, alg, &ii);
! 1070: if (rval) {
! 1071: rval = EINVAL;
! 1072: tdb_free(freeme);
! 1073: freeme = NULL;
! 1074: goto splxret;
! 1075: }
! 1076:
! 1077: newsa->tdb_cur_allocations = sa2->tdb_cur_allocations;
! 1078:
! 1079: /* Delete old version of the SA, insert new one */
! 1080: tdb_delete(sa2);
! 1081: puttdb((struct tdb *) freeme);
! 1082: sa2 = freeme = NULL;
! 1083: } else {
! 1084: /*
! 1085: * The SA is already initialized, so we're only allowed to
! 1086: * change lifetimes and some other information; we're
! 1087: * not allowed to change keys, addresses or identities.
! 1088: */
! 1089: if (headers[SADB_EXT_ADDRESS_PROXY] ||
! 1090: headers[SADB_EXT_KEY_AUTH] ||
! 1091: headers[SADB_EXT_KEY_ENCRYPT] ||
! 1092: headers[SADB_EXT_IDENTITY_SRC] ||
! 1093: headers[SADB_EXT_IDENTITY_DST] ||
! 1094: headers[SADB_EXT_SENSITIVITY]) {
! 1095: rval = EINVAL;
! 1096: goto splxret;
! 1097: }
! 1098:
! 1099: import_sa(sa2, headers[SADB_EXT_SA], NULL);
! 1100: import_lifetime(sa2,
! 1101: headers[SADB_EXT_LIFETIME_CURRENT],
! 1102: PFKEYV2_LIFETIME_CURRENT);
! 1103: import_lifetime(sa2, headers[SADB_EXT_LIFETIME_SOFT],
! 1104: PFKEYV2_LIFETIME_SOFT);
! 1105: import_lifetime(sa2, headers[SADB_EXT_LIFETIME_HARD],
! 1106: PFKEYV2_LIFETIME_HARD);
! 1107: import_udpencap(sa2, headers[SADB_X_EXT_UDPENCAP]);
! 1108: #if NPF > 0
! 1109: import_tag(sa2, headers[SADB_X_EXT_TAG]);
! 1110: #endif
! 1111: }
! 1112:
! 1113: splx(s);
! 1114: break;
! 1115: case SADB_ADD:
! 1116: ssa = (struct sadb_sa *) headers[SADB_EXT_SA];
! 1117: sunionp = (union sockaddr_union *) (headers[SADB_EXT_ADDRESS_DST] +
! 1118: sizeof(struct sadb_address));
! 1119:
! 1120: /* Either all or none of the flow must be included */
! 1121: if ((headers[SADB_X_EXT_SRC_FLOW] ||
! 1122: headers[SADB_X_EXT_PROTOCOL] ||
! 1123: headers[SADB_X_EXT_FLOW_TYPE] ||
! 1124: headers[SADB_X_EXT_DST_FLOW] ||
! 1125: headers[SADB_X_EXT_SRC_MASK] ||
! 1126: headers[SADB_X_EXT_DST_MASK]) &&
! 1127: !(headers[SADB_X_EXT_SRC_FLOW] &&
! 1128: headers[SADB_X_EXT_PROTOCOL] &&
! 1129: headers[SADB_X_EXT_FLOW_TYPE] &&
! 1130: headers[SADB_X_EXT_DST_FLOW] &&
! 1131: headers[SADB_X_EXT_SRC_MASK] &&
! 1132: headers[SADB_X_EXT_DST_MASK])) {
! 1133: rval = EINVAL;
! 1134: goto ret;
! 1135: }
! 1136: #ifdef IPSEC
! 1137: /* UDP encap has to be enabled and is only supported for ESP */
! 1138: if (headers[SADB_X_EXT_UDPENCAP] &&
! 1139: (!udpencap_enable ||
! 1140: smsg->sadb_msg_satype != SADB_SATYPE_ESP)) {
! 1141: rval = EINVAL;
! 1142: goto ret;
! 1143: }
! 1144: #endif /* IPSEC */
! 1145:
! 1146: s = spltdb();
! 1147:
! 1148: sa2 = gettdb(ssa->sadb_sa_spi, sunionp,
! 1149: SADB_X_GETSPROTO(smsg->sadb_msg_satype));
! 1150:
! 1151: /* We can't add an existing SA! */
! 1152: if (sa2 != NULL) {
! 1153: rval = EEXIST;
! 1154: goto splxret;
! 1155: }
! 1156:
! 1157: /* We can only add "mature" SAs */
! 1158: if (ssa->sadb_sa_state != SADB_SASTATE_MATURE) {
! 1159: rval = EINVAL;
! 1160: goto splxret;
! 1161: }
! 1162:
! 1163: /* Allocate and initialize new TDB */
! 1164: freeme = tdb_alloc();
! 1165:
! 1166: {
! 1167: struct tdb *newsa = (struct tdb *) freeme;
! 1168: struct ipsecinit ii;
! 1169: int alg;
! 1170:
! 1171: bzero(&ii, sizeof(struct ipsecinit));
! 1172:
! 1173: newsa->tdb_satype = smsg->sadb_msg_satype;
! 1174: if ((rval = pfkeyv2_get_proto_alg(newsa->tdb_satype,
! 1175: &newsa->tdb_sproto, &alg))) {
! 1176: tdb_free(freeme);
! 1177: freeme = NULL;
! 1178: goto splxret;
! 1179: }
! 1180:
! 1181: import_sa(newsa, headers[SADB_EXT_SA], &ii);
! 1182: import_address((struct sockaddr *) &newsa->tdb_src,
! 1183: headers[SADB_EXT_ADDRESS_SRC]);
! 1184: import_address((struct sockaddr *) &newsa->tdb_dst,
! 1185: headers[SADB_EXT_ADDRESS_DST]);
! 1186: import_address((struct sockaddr *) &newsa->tdb_proxy,
! 1187: headers[SADB_EXT_ADDRESS_PROXY]);
! 1188:
! 1189: import_lifetime(newsa,
! 1190: headers[SADB_EXT_LIFETIME_CURRENT],
! 1191: PFKEYV2_LIFETIME_CURRENT);
! 1192: import_lifetime(newsa, headers[SADB_EXT_LIFETIME_SOFT],
! 1193: PFKEYV2_LIFETIME_SOFT);
! 1194: import_lifetime(newsa, headers[SADB_EXT_LIFETIME_HARD],
! 1195: PFKEYV2_LIFETIME_HARD);
! 1196:
! 1197: import_key(&ii, headers[SADB_EXT_KEY_AUTH],
! 1198: PFKEYV2_AUTHENTICATION_KEY);
! 1199: import_key(&ii, headers[SADB_EXT_KEY_ENCRYPT],
! 1200: PFKEYV2_ENCRYPTION_KEY);
! 1201:
! 1202: import_identity(newsa, headers[SADB_EXT_IDENTITY_SRC],
! 1203: PFKEYV2_IDENTITY_SRC);
! 1204: import_identity(newsa, headers[SADB_EXT_IDENTITY_DST],
! 1205: PFKEYV2_IDENTITY_DST);
! 1206:
! 1207: import_credentials(newsa,
! 1208: headers[SADB_X_EXT_LOCAL_CREDENTIALS],
! 1209: PFKEYV2_CRED_LOCAL);
! 1210: import_credentials(newsa,
! 1211: headers[SADB_X_EXT_REMOTE_CREDENTIALS],
! 1212: PFKEYV2_CRED_REMOTE);
! 1213: import_auth(newsa, headers[SADB_X_EXT_LOCAL_AUTH],
! 1214: PFKEYV2_AUTH_LOCAL);
! 1215: import_auth(newsa, headers[SADB_X_EXT_REMOTE_AUTH],
! 1216: PFKEYV2_AUTH_REMOTE);
! 1217: import_flow(&newsa->tdb_filter, &newsa->tdb_filtermask,
! 1218: headers[SADB_X_EXT_SRC_FLOW],
! 1219: headers[SADB_X_EXT_SRC_MASK],
! 1220: headers[SADB_X_EXT_DST_FLOW],
! 1221: headers[SADB_X_EXT_DST_MASK],
! 1222: headers[SADB_X_EXT_PROTOCOL],
! 1223: headers[SADB_X_EXT_FLOW_TYPE]);
! 1224: import_udpencap(newsa, headers[SADB_X_EXT_UDPENCAP]);
! 1225: #if NPF > 0
! 1226: import_tag(newsa, headers[SADB_X_EXT_TAG]);
! 1227: #endif
! 1228:
! 1229: headers[SADB_EXT_KEY_AUTH] = NULL;
! 1230: headers[SADB_EXT_KEY_ENCRYPT] = NULL;
! 1231: headers[SADB_X_EXT_LOCAL_AUTH] = NULL;
! 1232:
! 1233: newsa->tdb_seq = smsg->sadb_msg_seq;
! 1234:
! 1235: rval = tdb_init(newsa, alg, &ii);
! 1236: if (rval) {
! 1237: rval = EINVAL;
! 1238: tdb_free(freeme);
! 1239: freeme = NULL;
! 1240: goto splxret;
! 1241: }
! 1242: }
! 1243:
! 1244: /* Add TDB in table */
! 1245: puttdb((struct tdb *) freeme);
! 1246:
! 1247: splx(s);
! 1248:
! 1249: freeme = NULL;
! 1250: break;
! 1251:
! 1252: case SADB_DELETE:
! 1253: ssa = (struct sadb_sa *) headers[SADB_EXT_SA];
! 1254: sunionp =
! 1255: (union sockaddr_union *)(headers[SADB_EXT_ADDRESS_DST] +
! 1256: sizeof(struct sadb_address));
! 1257: s = spltdb();
! 1258:
! 1259: sa2 = gettdb(ssa->sadb_sa_spi, sunionp,
! 1260: SADB_X_GETSPROTO(smsg->sadb_msg_satype));
! 1261: if (sa2 == NULL) {
! 1262: rval = ESRCH;
! 1263: goto splxret;
! 1264: }
! 1265:
! 1266: tdb_delete(sa2);
! 1267:
! 1268: splx(s);
! 1269:
! 1270: sa2 = NULL;
! 1271: break;
! 1272:
! 1273: case SADB_X_ASKPOLICY:
! 1274: /* Get the relevant policy */
! 1275: ipa = ipsec_get_acquire(((struct sadb_x_policy *) headers[SADB_X_EXT_POLICY])->sadb_x_policy_seq);
! 1276: if (ipa == NULL) {
! 1277: rval = ESRCH;
! 1278: goto ret;
! 1279: }
! 1280:
! 1281: rval = pfkeyv2_policy(ipa, headers, &freeme);
! 1282: if (rval)
! 1283: mode = PFKEYV2_SENDMESSAGE_UNICAST;
! 1284:
! 1285: break;
! 1286:
! 1287: case SADB_GET:
! 1288: ssa = (struct sadb_sa *) headers[SADB_EXT_SA];
! 1289: sunionp =
! 1290: (union sockaddr_union *)(headers[SADB_EXT_ADDRESS_DST] +
! 1291: sizeof(struct sadb_address));
! 1292:
! 1293: s = spltdb();
! 1294:
! 1295: sa2 = gettdb(ssa->sadb_sa_spi, sunionp,
! 1296: SADB_X_GETSPROTO(smsg->sadb_msg_satype));
! 1297: if (sa2 == NULL) {
! 1298: rval = ESRCH;
! 1299: goto splxret;
! 1300: }
! 1301:
! 1302: rval = pfkeyv2_get(sa2, headers, &freeme, NULL);
! 1303: if (rval)
! 1304: mode = PFKEYV2_SENDMESSAGE_UNICAST;
! 1305:
! 1306: splx(s);
! 1307:
! 1308: break;
! 1309:
! 1310: case SADB_REGISTER:
! 1311: if (!(pfkeyv2_socket->flags & PFKEYV2_SOCKETFLAGS_REGISTERED)) {
! 1312: pfkeyv2_socket->flags |= PFKEYV2_SOCKETFLAGS_REGISTERED;
! 1313: nregistered++;
! 1314: }
! 1315:
! 1316: i = sizeof(struct sadb_supported) + sizeof(ealgs);
! 1317:
! 1318: if (!(freeme = malloc(i, M_PFKEY, M_DONTWAIT))) {
! 1319: rval = ENOMEM;
! 1320: goto ret;
! 1321: }
! 1322:
! 1323: bzero(freeme, i);
! 1324:
! 1325: ssup = (struct sadb_supported *) freeme;
! 1326: ssup->sadb_supported_len = i / sizeof(uint64_t);
! 1327:
! 1328: {
! 1329: void *p = freeme + sizeof(struct sadb_supported);
! 1330:
! 1331: bcopy(&ealgs[0], p, sizeof(ealgs));
! 1332: }
! 1333:
! 1334: headers[SADB_EXT_SUPPORTED_ENCRYPT] = freeme;
! 1335:
! 1336: i = sizeof(struct sadb_supported) + sizeof(aalgs);
! 1337:
! 1338: if (!(freeme = malloc(i, M_PFKEY, M_DONTWAIT))) {
! 1339: rval = ENOMEM;
! 1340: goto ret;
! 1341: }
! 1342:
! 1343: /* Keep track what this socket has registered for */
! 1344: pfkeyv2_socket->registration |= (1 << ((struct sadb_msg *)message)->sadb_msg_satype);
! 1345:
! 1346: bzero(freeme, i);
! 1347:
! 1348: ssup = (struct sadb_supported *) freeme;
! 1349: ssup->sadb_supported_len = i / sizeof(uint64_t);
! 1350:
! 1351: {
! 1352: void *p = freeme + sizeof(struct sadb_supported);
! 1353:
! 1354: bcopy(&aalgs[0], p, sizeof(aalgs));
! 1355: }
! 1356:
! 1357: headers[SADB_EXT_SUPPORTED_AUTH] = freeme;
! 1358:
! 1359: i = sizeof(struct sadb_supported) + sizeof(calgs);
! 1360:
! 1361: if (!(freeme = malloc(i, M_PFKEY, M_DONTWAIT))) {
! 1362: rval = ENOMEM;
! 1363: goto ret;
! 1364: }
! 1365:
! 1366: bzero(freeme, i);
! 1367:
! 1368: ssup = (struct sadb_supported *) freeme;
! 1369: ssup->sadb_supported_len = i / sizeof(uint64_t);
! 1370:
! 1371: {
! 1372: void *p = freeme + sizeof(struct sadb_supported);
! 1373:
! 1374: bcopy(&calgs[0], p, sizeof(calgs));
! 1375: }
! 1376:
! 1377: headers[SADB_X_EXT_SUPPORTED_COMP] = freeme;
! 1378:
! 1379: break;
! 1380:
! 1381: case SADB_ACQUIRE:
! 1382: case SADB_EXPIRE:
! 1383: /* Nothing to handle */
! 1384: rval = 0;
! 1385: break;
! 1386:
! 1387: case SADB_FLUSH:
! 1388: rval = 0;
! 1389:
! 1390: switch (smsg->sadb_msg_satype) {
! 1391: case SADB_SATYPE_UNSPEC:
! 1392: s = spltdb();
! 1393:
! 1394: /*
! 1395: * Go through the list of policies, delete those that
! 1396: * are not socket-attached.
! 1397: */
! 1398: for (ipo = TAILQ_FIRST(&ipsec_policy_head);
! 1399: ipo != NULL; ipo = tmpipo) {
! 1400: tmpipo = TAILQ_NEXT(ipo, ipo_list);
! 1401: if (!(ipo->ipo_flags & IPSP_POLICY_SOCKET))
! 1402: ipsec_delete_policy(ipo);
! 1403: }
! 1404: splx(s);
! 1405: /* FALLTHROUGH */
! 1406: case SADB_SATYPE_AH:
! 1407: case SADB_SATYPE_ESP:
! 1408: case SADB_X_SATYPE_IPIP:
! 1409: case SADB_X_SATYPE_IPCOMP:
! 1410: #ifdef TCP_SIGNATURE
! 1411: case SADB_X_SATYPE_TCPSIGNATURE:
! 1412: #endif /* TCP_SIGNATURE */
! 1413: s = spltdb();
! 1414:
! 1415: tdb_walk(pfkeyv2_flush_walker,
! 1416: (u_int8_t *) &(smsg->sadb_msg_satype));
! 1417:
! 1418: splx(s);
! 1419: break;
! 1420:
! 1421: default:
! 1422: rval = EINVAL; /* Unknown/unsupported type */
! 1423: }
! 1424:
! 1425: break;
! 1426:
! 1427: case SADB_DUMP:
! 1428: {
! 1429: struct dump_state dump_state;
! 1430: dump_state.sadb_msg = (struct sadb_msg *) headers[0];
! 1431: dump_state.socket = socket;
! 1432:
! 1433: s = spltdb();
! 1434: rval = tdb_walk(pfkeyv2_dump_walker, &dump_state);
! 1435: splx(s);
! 1436:
! 1437: if (!rval)
! 1438: goto realret;
! 1439:
! 1440: if ((rval == ENOMEM) || (rval == ENOBUFS))
! 1441: rval = 0;
! 1442: }
! 1443: break;
! 1444:
! 1445: case SADB_X_GRPSPIS:
! 1446: {
! 1447: struct tdb *tdb1, *tdb2, *tdb3;
! 1448: struct sadb_protocol *sa_proto;
! 1449:
! 1450: ssa = (struct sadb_sa *) headers[SADB_EXT_SA];
! 1451: sunionp = (union sockaddr_union *) (headers[SADB_EXT_ADDRESS_DST] +
! 1452: sizeof(struct sadb_address));
! 1453:
! 1454: s = spltdb();
! 1455:
! 1456: tdb1 = gettdb(ssa->sadb_sa_spi, sunionp,
! 1457: SADB_X_GETSPROTO(smsg->sadb_msg_satype));
! 1458: if (tdb1 == NULL) {
! 1459: rval = ESRCH;
! 1460: goto splxret;
! 1461: }
! 1462:
! 1463: ssa = (struct sadb_sa *) headers[SADB_X_EXT_SA2];
! 1464: sunionp = (union sockaddr_union *) (headers[SADB_X_EXT_DST2] +
! 1465: sizeof(struct sadb_address));
! 1466: sa_proto = ((struct sadb_protocol *) headers[SADB_X_EXT_PROTOCOL]);
! 1467:
! 1468: tdb2 = gettdb(ssa->sadb_sa_spi, sunionp,
! 1469: SADB_X_GETSPROTO(sa_proto->sadb_protocol_proto));
! 1470: if (tdb2 == NULL) {
! 1471: rval = ESRCH;
! 1472: goto splxret;
! 1473: }
! 1474:
! 1475: /* Detect cycles */
! 1476: for (tdb3 = tdb2; tdb3; tdb3 = tdb3->tdb_onext)
! 1477: if (tdb3 == tdb1) {
! 1478: rval = ESRCH;
! 1479: goto splxret;
! 1480: }
! 1481:
! 1482: /* Maintenance */
! 1483: if ((tdb1->tdb_onext) &&
! 1484: (tdb1->tdb_onext->tdb_inext == tdb1))
! 1485: tdb1->tdb_onext->tdb_inext = NULL;
! 1486:
! 1487: if ((tdb2->tdb_inext) &&
! 1488: (tdb2->tdb_inext->tdb_onext == tdb2))
! 1489: tdb2->tdb_inext->tdb_onext = NULL;
! 1490:
! 1491: /* Link them */
! 1492: tdb1->tdb_onext = tdb2;
! 1493: tdb2->tdb_inext = tdb1;
! 1494:
! 1495: splx(s);
! 1496: }
! 1497: break;
! 1498:
! 1499: case SADB_X_DELFLOW:
! 1500: delflag = 1;
! 1501: /*FALLTHROUGH*/
! 1502: case SADB_X_ADDFLOW:
! 1503: {
! 1504: struct sadb_protocol *sab;
! 1505: union sockaddr_union *ssrc;
! 1506: struct route_enc re;
! 1507: int exists = 0;
! 1508:
! 1509: sab = (struct sadb_protocol *) headers[SADB_X_EXT_FLOW_TYPE];
! 1510:
! 1511: if ((sab->sadb_protocol_direction != IPSP_DIRECTION_IN) &&
! 1512: (sab->sadb_protocol_direction != IPSP_DIRECTION_OUT)) {
! 1513: rval = EINVAL;
! 1514: goto ret;
! 1515: }
! 1516:
! 1517: /* If the security protocol wasn't specified, pretend it was ESP */
! 1518: if (smsg->sadb_msg_satype == 0)
! 1519: smsg->sadb_msg_satype = SADB_SATYPE_ESP;
! 1520:
! 1521: if (headers[SADB_EXT_ADDRESS_DST])
! 1522: sunionp = (union sockaddr_union *)
! 1523: (headers[SADB_EXT_ADDRESS_DST] +
! 1524: sizeof(struct sadb_address));
! 1525: else
! 1526: sunionp = NULL;
! 1527:
! 1528: if (headers[SADB_EXT_ADDRESS_SRC])
! 1529: ssrc = (union sockaddr_union *)
! 1530: (headers[SADB_EXT_ADDRESS_SRC] +
! 1531: sizeof(struct sadb_address));
! 1532: else
! 1533: ssrc = NULL;
! 1534:
! 1535: import_flow(&encapdst, &encapnetmask,
! 1536: headers[SADB_X_EXT_SRC_FLOW], headers[SADB_X_EXT_SRC_MASK],
! 1537: headers[SADB_X_EXT_DST_FLOW], headers[SADB_X_EXT_DST_MASK],
! 1538: headers[SADB_X_EXT_PROTOCOL], headers[SADB_X_EXT_FLOW_TYPE]);
! 1539:
! 1540: /* Determine whether the exact same SPD entry already exists. */
! 1541: bzero(&encapgw, sizeof(struct sockaddr_encap));
! 1542: bzero(&re, sizeof(struct route_enc));
! 1543: bcopy(&encapdst, &re.re_dst, sizeof(struct sockaddr_encap));
! 1544:
! 1545: s = spltdb();
! 1546:
! 1547: rtalloc((struct route *) &re);
! 1548: if (re.re_rt != NULL) {
! 1549: ipo = ((struct sockaddr_encap *) re.re_rt->rt_gateway)->sen_ipsp;
! 1550: RTFREE(re.re_rt);
! 1551:
! 1552: /* Verify that the entry is identical */
! 1553: if (bcmp(&ipo->ipo_addr, &encapdst,
! 1554: sizeof(struct sockaddr_encap)) ||
! 1555: bcmp(&ipo->ipo_mask, &encapnetmask,
! 1556: sizeof(struct sockaddr_encap)))
! 1557: ipo = NULL; /* Fall through */
! 1558: else
! 1559: exists = 1;
! 1560: } else
! 1561: ipo = NULL;
! 1562:
! 1563: /*
! 1564: * If the existing policy is static, only delete or update
! 1565: * it if the new one is also static.
! 1566: */
! 1567: if (exists && (ipo->ipo_flags & IPSP_POLICY_STATIC)) {
! 1568: if (!(sab->sadb_protocol_flags &
! 1569: SADB_X_POLICYFLAGS_POLICY)) {
! 1570: splx(s);
! 1571: goto ret;
! 1572: }
! 1573: }
! 1574:
! 1575: /* Delete ? */
! 1576: if (delflag) {
! 1577: if (exists) {
! 1578: rval = ipsec_delete_policy(ipo);
! 1579: splx(s);
! 1580: goto ret;
! 1581: }
! 1582:
! 1583: /* If we were asked to delete something non-existant, error. */
! 1584: splx(s);
! 1585: rval = ESRCH;
! 1586: break;
! 1587: }
! 1588:
! 1589: if (!exists) {
! 1590: if (ipsec_policy_pool_initialized == 0) {
! 1591: ipsec_policy_pool_initialized = 1;
! 1592: pool_init(&ipsec_policy_pool,
! 1593: sizeof(struct ipsec_policy), 0, 0, 0,
! 1594: "ipsec policy", NULL);
! 1595: }
! 1596:
! 1597: /* Allocate policy entry */
! 1598: ipo = pool_get(&ipsec_policy_pool, 0);
! 1599: if (ipo == NULL) {
! 1600: splx(s);
! 1601: rval = ENOMEM;
! 1602: goto ret;
! 1603: }
! 1604:
! 1605: bzero(ipo, sizeof(struct ipsec_policy));
! 1606: ipo->ipo_ref_count = 1;
! 1607: TAILQ_INIT(&ipo->ipo_acquires);
! 1608:
! 1609: /* Finish initialization of SPD entry */
! 1610: encapgw.sen_len = SENT_LEN;
! 1611: encapgw.sen_family = PF_KEY;
! 1612: encapgw.sen_type = SENT_IPSP;
! 1613: encapgw.sen_ipsp = ipo;
! 1614:
! 1615: /* Initialize policy entry */
! 1616: bcopy(&encapdst, &ipo->ipo_addr,
! 1617: sizeof(struct sockaddr_encap));
! 1618: bcopy(&encapnetmask, &ipo->ipo_mask,
! 1619: sizeof(struct sockaddr_encap));
! 1620: }
! 1621:
! 1622: switch (((struct sadb_protocol *) headers[SADB_X_EXT_FLOW_TYPE])->sadb_protocol_proto) {
! 1623: case SADB_X_FLOW_TYPE_USE:
! 1624: ipo->ipo_type = IPSP_IPSEC_USE;
! 1625: break;
! 1626:
! 1627: case SADB_X_FLOW_TYPE_ACQUIRE:
! 1628: ipo->ipo_type = IPSP_IPSEC_ACQUIRE;
! 1629: break;
! 1630:
! 1631: case SADB_X_FLOW_TYPE_REQUIRE:
! 1632: ipo->ipo_type = IPSP_IPSEC_REQUIRE;
! 1633: break;
! 1634:
! 1635: case SADB_X_FLOW_TYPE_DENY:
! 1636: ipo->ipo_type = IPSP_DENY;
! 1637: break;
! 1638:
! 1639: case SADB_X_FLOW_TYPE_BYPASS:
! 1640: ipo->ipo_type = IPSP_PERMIT;
! 1641: break;
! 1642:
! 1643: case SADB_X_FLOW_TYPE_DONTACQ:
! 1644: ipo->ipo_type = IPSP_IPSEC_DONTACQ;
! 1645: break;
! 1646:
! 1647: default:
! 1648: if (!exists)
! 1649: pool_put(&ipsec_policy_pool, ipo);
! 1650: else
! 1651: ipsec_delete_policy(ipo);
! 1652:
! 1653: splx(s);
! 1654: rval = EINVAL;
! 1655: goto ret;
! 1656: }
! 1657:
! 1658: if (sab->sadb_protocol_flags & SADB_X_POLICYFLAGS_POLICY)
! 1659: ipo->ipo_flags |= IPSP_POLICY_STATIC;
! 1660:
! 1661: if (sunionp)
! 1662: bcopy(sunionp, &ipo->ipo_dst,
! 1663: sizeof(union sockaddr_union));
! 1664: else
! 1665: bzero(&ipo->ipo_dst, sizeof(union sockaddr_union));
! 1666:
! 1667: if (ssrc)
! 1668: bcopy(ssrc, &ipo->ipo_src,
! 1669: sizeof(union sockaddr_union));
! 1670: else
! 1671: bzero(&ipo->ipo_src, sizeof(union sockaddr_union));
! 1672:
! 1673: ipo->ipo_sproto = SADB_X_GETSPROTO(smsg->sadb_msg_satype);
! 1674:
! 1675: if (ipo->ipo_srcid) {
! 1676: ipsp_reffree(ipo->ipo_srcid);
! 1677: ipo->ipo_srcid = NULL;
! 1678: }
! 1679:
! 1680: if (ipo->ipo_dstid) {
! 1681: ipsp_reffree(ipo->ipo_dstid);
! 1682: ipo->ipo_dstid = NULL;
! 1683: }
! 1684:
! 1685: if ((sid = headers[SADB_EXT_IDENTITY_SRC]) != NULL) {
! 1686: int clen = (sid->sadb_ident_len * sizeof(u_int64_t)) -
! 1687: sizeof(struct sadb_ident);
! 1688:
! 1689: MALLOC(ipo->ipo_srcid, struct ipsec_ref *, clen +
! 1690: sizeof(struct ipsec_ref), M_CREDENTIALS, M_DONTWAIT);
! 1691: if (ipo->ipo_srcid == NULL) {
! 1692: if (exists)
! 1693: ipsec_delete_policy(ipo);
! 1694: else
! 1695: pool_put(&ipsec_policy_pool, ipo);
! 1696: splx(s);
! 1697: rval = ENOBUFS;
! 1698: goto ret;
! 1699: }
! 1700: ipo->ipo_srcid->ref_type = sid->sadb_ident_type;
! 1701: ipo->ipo_srcid->ref_len = clen;
! 1702: ipo->ipo_srcid->ref_count = 1;
! 1703: ipo->ipo_srcid->ref_malloctype = M_CREDENTIALS;
! 1704: bcopy(sid + 1, ipo->ipo_srcid + 1, ipo->ipo_srcid->ref_len);
! 1705: }
! 1706:
! 1707: if ((sid = headers[SADB_EXT_IDENTITY_DST]) != NULL) {
! 1708: int clen = (sid->sadb_ident_len * sizeof(u_int64_t)) -
! 1709: sizeof(struct sadb_ident);
! 1710:
! 1711: MALLOC(ipo->ipo_dstid, struct ipsec_ref *,
! 1712: clen + sizeof(struct ipsec_ref),
! 1713: M_CREDENTIALS, M_DONTWAIT);
! 1714: if (ipo->ipo_dstid == NULL) {
! 1715: if (exists)
! 1716: ipsec_delete_policy(ipo);
! 1717: else {
! 1718: if (ipo->ipo_dstid)
! 1719: ipsp_reffree(ipo->ipo_dstid);
! 1720: pool_put(&ipsec_policy_pool, ipo);
! 1721: }
! 1722:
! 1723: splx(s);
! 1724: rval = ENOBUFS;
! 1725: goto ret;
! 1726: }
! 1727: ipo->ipo_dstid->ref_type = sid->sadb_ident_type;
! 1728: ipo->ipo_dstid->ref_len = clen;
! 1729: ipo->ipo_dstid->ref_count = 1;
! 1730: ipo->ipo_dstid->ref_malloctype = M_CREDENTIALS;
! 1731: bcopy(sid + 1, ipo->ipo_dstid + 1,
! 1732: ipo->ipo_dstid->ref_len);
! 1733: }
! 1734:
! 1735: /* Flow type */
! 1736: if (!exists) {
! 1737: /* Add SPD entry */
! 1738: if ((rval = rtrequest(RTM_ADD,
! 1739: (struct sockaddr *) &encapdst,
! 1740: (struct sockaddr *) &encapgw,
! 1741: (struct sockaddr *) &encapnetmask,
! 1742: RTF_UP | RTF_GATEWAY | RTF_STATIC,
! 1743: (struct rtentry **) 0, 0)) != 0) {
! 1744: /* Remove from linked list of policies on TDB */
! 1745: if (ipo->ipo_tdb)
! 1746: TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head,
! 1747: ipo, ipo_tdb_next);
! 1748:
! 1749: if (ipo->ipo_srcid)
! 1750: ipsp_reffree(ipo->ipo_srcid);
! 1751: if (ipo->ipo_dstid)
! 1752: ipsp_reffree(ipo->ipo_dstid);
! 1753: pool_put(&ipsec_policy_pool, ipo);
! 1754:
! 1755: splx(s);
! 1756: goto ret;
! 1757: }
! 1758:
! 1759: TAILQ_INSERT_HEAD(&ipsec_policy_head, ipo, ipo_list);
! 1760: ipsec_in_use++;
! 1761: } else {
! 1762: ipo->ipo_last_searched = ipo->ipo_flags = 0;
! 1763: }
! 1764:
! 1765: splx(s);
! 1766: }
! 1767: break;
! 1768:
! 1769: case SADB_X_PROMISC:
! 1770: if (len >= 2 * sizeof(struct sadb_msg)) {
! 1771: struct mbuf *packet;
! 1772:
! 1773: if ((rval = pfdatatopacket(message, len, &packet)) != 0)
! 1774: goto ret;
! 1775:
! 1776: for (so = pfkeyv2_sockets; so; so = so->next)
! 1777: if ((so != pfkeyv2_socket) &&
! 1778: (!smsg->sadb_msg_seq ||
! 1779: (smsg->sadb_msg_seq == pfkeyv2_socket->pid)))
! 1780: pfkey_sendup(so->socket, packet, 1);
! 1781:
! 1782: m_freem(packet);
! 1783: } else {
! 1784: if (len != sizeof(struct sadb_msg)) {
! 1785: rval = EINVAL;
! 1786: goto ret;
! 1787: }
! 1788:
! 1789: i = (pfkeyv2_socket->flags &
! 1790: PFKEYV2_SOCKETFLAGS_PROMISC) ? 1 : 0;
! 1791: j = smsg->sadb_msg_satype ? 1 : 0;
! 1792:
! 1793: if (i ^ j) {
! 1794: if (j) {
! 1795: pfkeyv2_socket->flags |=
! 1796: PFKEYV2_SOCKETFLAGS_PROMISC;
! 1797: npromisc++;
! 1798: } else {
! 1799: pfkeyv2_socket->flags &=
! 1800: ~PFKEYV2_SOCKETFLAGS_PROMISC;
! 1801: npromisc--;
! 1802: }
! 1803: }
! 1804: }
! 1805:
! 1806:
! 1807: break;
! 1808:
! 1809: default:
! 1810: rval = EINVAL;
! 1811: goto ret;
! 1812: }
! 1813:
! 1814: ret:
! 1815: if (rval) {
! 1816: if ((rval == EINVAL) || (rval == ENOMEM) || (rval == ENOBUFS))
! 1817: goto realret;
! 1818:
! 1819: for (i = 1; i <= SADB_EXT_MAX; i++)
! 1820: headers[i] = NULL;
! 1821:
! 1822: smsg->sadb_msg_errno = abs(rval);
! 1823: } else {
! 1824: uint64_t seen = 0LL;
! 1825:
! 1826: for (i = 1; i <= SADB_EXT_MAX; i++)
! 1827: if (headers[i])
! 1828: seen |= (1LL << i);
! 1829:
! 1830: if ((seen & sadb_exts_allowed_out[smsg->sadb_msg_type])
! 1831: != seen)
! 1832: goto realret;
! 1833:
! 1834: if ((seen & sadb_exts_required_out[smsg->sadb_msg_type]) !=
! 1835: sadb_exts_required_out[smsg->sadb_msg_type])
! 1836: goto realret;
! 1837: }
! 1838:
! 1839: rval = pfkeyv2_sendmessage(headers, mode, socket, 0, 0);
! 1840:
! 1841: realret:
! 1842: if (freeme)
! 1843: free(freeme, M_PFKEY);
! 1844:
! 1845: free(message, M_PFKEY);
! 1846:
! 1847: return (rval);
! 1848:
! 1849: splxret:
! 1850: splx(s);
! 1851: goto ret;
! 1852: }
! 1853:
! 1854: /*
! 1855: * Send an ACQUIRE message to key management, to get a new SA.
! 1856: */
! 1857: int
! 1858: pfkeyv2_acquire(struct ipsec_policy *ipo, union sockaddr_union *gw,
! 1859: union sockaddr_union *laddr, u_int32_t *seq, struct sockaddr_encap *ddst)
! 1860: {
! 1861: void *p, *headers[SADB_EXT_MAX + 1], *buffer = NULL;
! 1862: struct sadb_ident *srcid, *dstid;
! 1863: struct sadb_x_cred *lcred, *lauth;
! 1864: struct sadb_comb *sadb_comb;
! 1865: struct sadb_address *sadd;
! 1866: struct sadb_prop *sa_prop;
! 1867: struct sadb_msg *smsg;
! 1868: int rval = 0;
! 1869: int i, j;
! 1870:
! 1871: *seq = pfkeyv2_seq++;
! 1872:
! 1873: if (!nregistered) {
! 1874: rval = ESRCH;
! 1875: goto ret;
! 1876: }
! 1877:
! 1878: /* How large a buffer do we need... XXX we only do one proposal for now */
! 1879: i = sizeof(struct sadb_msg) +
! 1880: (laddr == NULL ? 0 : sizeof(struct sadb_address) +
! 1881: PADUP(SA_LEN(&ipo->ipo_src.sa))) +
! 1882: sizeof(struct sadb_address) + PADUP(SA_LEN(&gw->sa)) +
! 1883: sizeof(struct sadb_prop) + 1 * sizeof(struct sadb_comb);
! 1884:
! 1885: if (ipo->ipo_srcid)
! 1886: i += sizeof(struct sadb_ident) + PADUP(ipo->ipo_srcid->ref_len);
! 1887:
! 1888: if (ipo->ipo_dstid)
! 1889: i += sizeof(struct sadb_ident) + PADUP(ipo->ipo_dstid->ref_len);
! 1890:
! 1891: if (ipo->ipo_local_cred)
! 1892: i += sizeof(struct sadb_x_cred) + PADUP(ipo->ipo_local_cred->ref_len);
! 1893:
! 1894: if (ipo->ipo_local_auth)
! 1895: i += sizeof(struct sadb_x_cred) + PADUP(ipo->ipo_local_auth->ref_len);
! 1896:
! 1897: /* Allocate */
! 1898: if (!(p = malloc(i, M_PFKEY, M_DONTWAIT))) {
! 1899: rval = ENOMEM;
! 1900: goto ret;
! 1901: }
! 1902:
! 1903: bzero(headers, sizeof(headers));
! 1904:
! 1905: buffer = p;
! 1906: bzero(p, i);
! 1907:
! 1908: headers[0] = p;
! 1909: p += sizeof(struct sadb_msg);
! 1910:
! 1911: smsg = (struct sadb_msg *) headers[0];
! 1912: smsg->sadb_msg_version = PF_KEY_V2;
! 1913: smsg->sadb_msg_type = SADB_ACQUIRE;
! 1914: smsg->sadb_msg_len = i / sizeof(uint64_t);
! 1915: smsg->sadb_msg_seq = *seq;
! 1916:
! 1917: if (ipo->ipo_sproto == IPPROTO_ESP)
! 1918: smsg->sadb_msg_satype = SADB_SATYPE_ESP;
! 1919: else if (ipo->ipo_sproto == IPPROTO_AH)
! 1920: smsg->sadb_msg_satype = SADB_SATYPE_AH;
! 1921: else if (ipo->ipo_sproto == IPPROTO_IPCOMP)
! 1922: smsg->sadb_msg_satype = SADB_X_SATYPE_IPCOMP;
! 1923:
! 1924: if (laddr) {
! 1925: headers[SADB_EXT_ADDRESS_SRC] = p;
! 1926: p += sizeof(struct sadb_address) + PADUP(SA_LEN(&laddr->sa));
! 1927: sadd = (struct sadb_address *) headers[SADB_EXT_ADDRESS_SRC];
! 1928: sadd->sadb_address_len = (sizeof(struct sadb_address) +
! 1929: SA_LEN(&laddr->sa) + sizeof(uint64_t) - 1) /
! 1930: sizeof(uint64_t);
! 1931: bcopy(laddr, headers[SADB_EXT_ADDRESS_SRC] +
! 1932: sizeof(struct sadb_address), SA_LEN(&laddr->sa));
! 1933: }
! 1934:
! 1935: headers[SADB_EXT_ADDRESS_DST] = p;
! 1936: p += sizeof(struct sadb_address) + PADUP(SA_LEN(&gw->sa));
! 1937: sadd = (struct sadb_address *) headers[SADB_EXT_ADDRESS_DST];
! 1938: sadd->sadb_address_len = (sizeof(struct sadb_address) +
! 1939: SA_LEN(&gw->sa) + sizeof(uint64_t) - 1) / sizeof(uint64_t);
! 1940: bcopy(gw, headers[SADB_EXT_ADDRESS_DST] + sizeof(struct sadb_address),
! 1941: SA_LEN(&gw->sa));
! 1942:
! 1943: if (ipo->ipo_srcid) {
! 1944: headers[SADB_EXT_IDENTITY_SRC] = p;
! 1945: p += sizeof(struct sadb_ident) + PADUP(ipo->ipo_srcid->ref_len);
! 1946: srcid = (struct sadb_ident *) headers[SADB_EXT_IDENTITY_SRC];
! 1947: srcid->sadb_ident_len = (sizeof(struct sadb_ident) +
! 1948: PADUP(ipo->ipo_srcid->ref_len)) / sizeof(u_int64_t);
! 1949: srcid->sadb_ident_type = ipo->ipo_srcid->ref_type;
! 1950: bcopy(ipo->ipo_srcid + 1, headers[SADB_EXT_IDENTITY_SRC] +
! 1951: sizeof(struct sadb_ident), ipo->ipo_srcid->ref_len);
! 1952: }
! 1953:
! 1954: if (ipo->ipo_dstid) {
! 1955: headers[SADB_EXT_IDENTITY_DST] = p;
! 1956: p += sizeof(struct sadb_ident) + PADUP(ipo->ipo_dstid->ref_len);
! 1957: dstid = (struct sadb_ident *) headers[SADB_EXT_IDENTITY_DST];
! 1958: dstid->sadb_ident_len = (sizeof(struct sadb_ident) +
! 1959: PADUP(ipo->ipo_dstid->ref_len)) / sizeof(u_int64_t);
! 1960: dstid->sadb_ident_type = ipo->ipo_dstid->ref_type;
! 1961: bcopy(ipo->ipo_dstid + 1, headers[SADB_EXT_IDENTITY_DST] +
! 1962: sizeof(struct sadb_ident), ipo->ipo_dstid->ref_len);
! 1963: }
! 1964:
! 1965: if (ipo->ipo_local_cred) {
! 1966: headers[SADB_X_EXT_LOCAL_CREDENTIALS] = p;
! 1967: p += sizeof(struct sadb_x_cred) + PADUP(ipo->ipo_local_cred->ref_len);
! 1968: lcred = (struct sadb_x_cred *) headers[SADB_X_EXT_LOCAL_CREDENTIALS];
! 1969: lcred->sadb_x_cred_len = (sizeof(struct sadb_x_cred) +
! 1970: PADUP(ipo->ipo_local_cred->ref_len)) / sizeof(u_int64_t);
! 1971: switch (ipo->ipo_local_cred->ref_type) {
! 1972: case IPSP_CRED_KEYNOTE:
! 1973: lcred->sadb_x_cred_type = SADB_X_CREDTYPE_KEYNOTE;
! 1974: break;
! 1975: case IPSP_CRED_X509:
! 1976: lcred->sadb_x_cred_type = SADB_X_CREDTYPE_X509;
! 1977: break;
! 1978: }
! 1979: bcopy(ipo->ipo_local_cred + 1, headers[SADB_X_EXT_LOCAL_CREDENTIALS] +
! 1980: sizeof(struct sadb_x_cred), ipo->ipo_local_cred->ref_len);
! 1981: }
! 1982:
! 1983: if (ipo->ipo_local_auth) {
! 1984: headers[SADB_X_EXT_LOCAL_AUTH] = p;
! 1985: p += sizeof(struct sadb_x_cred) + PADUP(ipo->ipo_local_auth->ref_len);
! 1986: lauth = (struct sadb_x_cred *) headers[SADB_X_EXT_LOCAL_AUTH];
! 1987: lauth->sadb_x_cred_len = (sizeof(struct sadb_x_cred) +
! 1988: PADUP(ipo->ipo_local_auth->ref_len)) / sizeof(u_int64_t);
! 1989: switch (ipo->ipo_local_auth->ref_type) {
! 1990: case IPSP_AUTH_PASSPHRASE:
! 1991: lauth->sadb_x_cred_type = SADB_X_AUTHTYPE_PASSPHRASE;
! 1992: break;
! 1993: case IPSP_AUTH_RSA:
! 1994: lauth->sadb_x_cred_type = SADB_X_AUTHTYPE_RSA;
! 1995: break;
! 1996: }
! 1997:
! 1998: bcopy(ipo->ipo_local_auth + 1, headers[SADB_X_EXT_LOCAL_AUTH] +
! 1999: sizeof(struct sadb_x_cred), ipo->ipo_local_auth->ref_len);
! 2000: }
! 2001:
! 2002: headers[SADB_EXT_PROPOSAL] = p;
! 2003: p += sizeof(struct sadb_prop);
! 2004: sa_prop = (struct sadb_prop *) headers[SADB_EXT_PROPOSAL];
! 2005: sa_prop->sadb_prop_num = 1; /* XXX One proposal only */
! 2006: sa_prop->sadb_prop_len = (sizeof(struct sadb_prop) +
! 2007: (sizeof(struct sadb_comb) * sa_prop->sadb_prop_num)) /
! 2008: sizeof(uint64_t);
! 2009:
! 2010: sadb_comb = p;
! 2011:
! 2012: /* XXX Should actually ask the crypto layer what's supported */
! 2013: for (j = 0; j < sa_prop->sadb_prop_num; j++) {
! 2014: sadb_comb->sadb_comb_flags = 0;
! 2015:
! 2016: if (ipsec_require_pfs)
! 2017: sadb_comb->sadb_comb_flags |= SADB_SAFLAGS_PFS;
! 2018:
! 2019: /* Set the encryption algorithm */
! 2020: if (ipo->ipo_sproto == IPPROTO_ESP) {
! 2021: if (!strncasecmp(ipsec_def_enc, "aes",
! 2022: sizeof("aes"))) {
! 2023: sadb_comb->sadb_comb_encrypt = SADB_X_EALG_AES;
! 2024: sadb_comb->sadb_comb_encrypt_minbits = 128;
! 2025: sadb_comb->sadb_comb_encrypt_maxbits = 256;
! 2026: } else if (!strncasecmp(ipsec_def_enc, "aesctr",
! 2027: sizeof("aesctr"))) {
! 2028: sadb_comb->sadb_comb_encrypt = SADB_X_EALG_AESCTR;
! 2029: sadb_comb->sadb_comb_encrypt_minbits = 128+32;
! 2030: sadb_comb->sadb_comb_encrypt_maxbits = 256+32;
! 2031: } else if (!strncasecmp(ipsec_def_enc, "3des",
! 2032: sizeof("3des"))) {
! 2033: sadb_comb->sadb_comb_encrypt = SADB_EALG_3DESCBC;
! 2034: sadb_comb->sadb_comb_encrypt_minbits = 192;
! 2035: sadb_comb->sadb_comb_encrypt_maxbits = 192;
! 2036: } else if (!strncasecmp(ipsec_def_enc, "des",
! 2037: sizeof("des"))) {
! 2038: sadb_comb->sadb_comb_encrypt = SADB_EALG_DESCBC;
! 2039: sadb_comb->sadb_comb_encrypt_minbits = 64;
! 2040: sadb_comb->sadb_comb_encrypt_maxbits = 64;
! 2041: } else if (!strncasecmp(ipsec_def_enc, "blowfish",
! 2042: sizeof("blowfish"))) {
! 2043: sadb_comb->sadb_comb_encrypt = SADB_X_EALG_BLF;
! 2044: sadb_comb->sadb_comb_encrypt_minbits = 40;
! 2045: sadb_comb->sadb_comb_encrypt_maxbits = BLF_MAXKEYLEN * 8;
! 2046: } else if (!strncasecmp(ipsec_def_enc, "skipjack",
! 2047: sizeof("skipjack"))) {
! 2048: sadb_comb->sadb_comb_encrypt = SADB_X_EALG_SKIPJACK;
! 2049: sadb_comb->sadb_comb_encrypt_minbits = 80;
! 2050: sadb_comb->sadb_comb_encrypt_maxbits = 80;
! 2051: } else if (!strncasecmp(ipsec_def_enc, "cast128",
! 2052: sizeof("cast128"))) {
! 2053: sadb_comb->sadb_comb_encrypt = SADB_X_EALG_CAST;
! 2054: sadb_comb->sadb_comb_encrypt_minbits = 40;
! 2055: sadb_comb->sadb_comb_encrypt_maxbits = 128;
! 2056: }
! 2057: } else if (ipo->ipo_sproto == IPPROTO_IPCOMP) {
! 2058: /* Set the compression algorithm */
! 2059: if (!strncasecmp(ipsec_def_comp, "deflate",
! 2060: sizeof("deflate"))) {
! 2061: sadb_comb->sadb_comb_encrypt = SADB_X_CALG_DEFLATE;
! 2062: sadb_comb->sadb_comb_encrypt_minbits = 0;
! 2063: sadb_comb->sadb_comb_encrypt_maxbits = 0;
! 2064: } else if (!strncasecmp(ipsec_def_comp, "lzs",
! 2065: sizeof("lzs"))) {
! 2066: sadb_comb->sadb_comb_encrypt = SADB_X_CALG_LZS;
! 2067: sadb_comb->sadb_comb_encrypt_minbits = 0;
! 2068: sadb_comb->sadb_comb_encrypt_maxbits = 0;
! 2069: }
! 2070: }
! 2071:
! 2072: /* Set the authentication algorithm */
! 2073: if (!strncasecmp(ipsec_def_auth, "hmac-sha1",
! 2074: sizeof("hmac-sha1"))) {
! 2075: sadb_comb->sadb_comb_auth = SADB_AALG_SHA1HMAC;
! 2076: sadb_comb->sadb_comb_auth_minbits = 160;
! 2077: sadb_comb->sadb_comb_auth_maxbits = 160;
! 2078: } else if (!strncasecmp(ipsec_def_auth, "hmac-ripemd160",
! 2079: sizeof("hmac_ripemd160"))) {
! 2080: sadb_comb->sadb_comb_auth = SADB_X_AALG_RIPEMD160HMAC;
! 2081: sadb_comb->sadb_comb_auth_minbits = 160;
! 2082: sadb_comb->sadb_comb_auth_maxbits = 160;
! 2083: } else if (!strncasecmp(ipsec_def_auth, "hmac-md5",
! 2084: sizeof("hmac-md5"))) {
! 2085: sadb_comb->sadb_comb_auth = SADB_AALG_MD5HMAC;
! 2086: sadb_comb->sadb_comb_auth_minbits = 128;
! 2087: sadb_comb->sadb_comb_auth_maxbits = 128;
! 2088: } else if (!strncasecmp(ipsec_def_auth, "hmac-sha2-256",
! 2089: sizeof("hmac-sha2-256"))) {
! 2090: sadb_comb->sadb_comb_auth = SADB_X_AALG_SHA2_256;
! 2091: sadb_comb->sadb_comb_auth_minbits = 256;
! 2092: sadb_comb->sadb_comb_auth_maxbits = 256;
! 2093: } else if (!strncasecmp(ipsec_def_auth, "hmac-sha2-384",
! 2094: sizeof("hmac-sha2-384"))) {
! 2095: sadb_comb->sadb_comb_auth = SADB_X_AALG_SHA2_384;
! 2096: sadb_comb->sadb_comb_auth_minbits = 384;
! 2097: sadb_comb->sadb_comb_auth_maxbits = 384;
! 2098: } else if (!strncasecmp(ipsec_def_auth, "hmac-sha2-512",
! 2099: sizeof("hmac-sha2-512"))) {
! 2100: sadb_comb->sadb_comb_auth = SADB_X_AALG_SHA2_512;
! 2101: sadb_comb->sadb_comb_auth_minbits = 512;
! 2102: sadb_comb->sadb_comb_auth_maxbits = 512;
! 2103: }
! 2104:
! 2105: sadb_comb->sadb_comb_soft_allocations = ipsec_soft_allocations;
! 2106: sadb_comb->sadb_comb_hard_allocations = ipsec_exp_allocations;
! 2107:
! 2108: sadb_comb->sadb_comb_soft_bytes = ipsec_soft_bytes;
! 2109: sadb_comb->sadb_comb_hard_bytes = ipsec_exp_bytes;
! 2110:
! 2111: sadb_comb->sadb_comb_soft_addtime = ipsec_soft_timeout;
! 2112: sadb_comb->sadb_comb_hard_addtime = ipsec_exp_timeout;
! 2113:
! 2114: sadb_comb->sadb_comb_soft_usetime = ipsec_soft_first_use;
! 2115: sadb_comb->sadb_comb_hard_usetime = ipsec_exp_first_use;
! 2116: sadb_comb++;
! 2117: }
! 2118:
! 2119: /* Send the ACQUIRE message to all compliant registered listeners. */
! 2120: if ((rval = pfkeyv2_sendmessage(headers,
! 2121: PFKEYV2_SENDMESSAGE_REGISTERED, NULL, smsg->sadb_msg_satype, 0))
! 2122: != 0)
! 2123: goto ret;
! 2124:
! 2125: rval = 0;
! 2126: ret:
! 2127: if (buffer != NULL) {
! 2128: bzero(buffer, i);
! 2129: free(buffer, M_PFKEY);
! 2130: }
! 2131:
! 2132: return (rval);
! 2133: }
! 2134:
! 2135: /*
! 2136: * Notify key management that an expiration went off. The second argument
! 2137: * specifies the type of expiration (soft or hard).
! 2138: */
! 2139: int
! 2140: pfkeyv2_expire(struct tdb *sa, u_int16_t type)
! 2141: {
! 2142: void *p, *headers[SADB_EXT_MAX+1], *buffer = NULL;
! 2143: struct sadb_msg *smsg;
! 2144: int rval = 0;
! 2145: int i;
! 2146:
! 2147: switch (sa->tdb_sproto) {
! 2148: case IPPROTO_AH:
! 2149: case IPPROTO_ESP:
! 2150: case IPPROTO_IPIP:
! 2151: case IPPROTO_IPCOMP:
! 2152: #ifdef TCP_SIGNATURE
! 2153: case IPPROTO_TCP:
! 2154: #endif /* TCP_SIGNATURE */
! 2155: break;
! 2156:
! 2157: default:
! 2158: rval = EOPNOTSUPP;
! 2159: goto ret;
! 2160: }
! 2161:
! 2162: i = sizeof(struct sadb_msg) + sizeof(struct sadb_sa) +
! 2163: 2 * sizeof(struct sadb_lifetime) +
! 2164: sizeof(struct sadb_address) + PADUP(SA_LEN(&sa->tdb_src.sa)) +
! 2165: sizeof(struct sadb_address) + PADUP(SA_LEN(&sa->tdb_dst.sa));
! 2166:
! 2167: if (!(p = malloc(i, M_PFKEY, M_DONTWAIT))) {
! 2168: rval = ENOMEM;
! 2169: goto ret;
! 2170: }
! 2171:
! 2172: bzero(headers, sizeof(headers));
! 2173:
! 2174: buffer = p;
! 2175: bzero(p, i);
! 2176:
! 2177: headers[0] = p;
! 2178: p += sizeof(struct sadb_msg);
! 2179:
! 2180: smsg = (struct sadb_msg *) headers[0];
! 2181: smsg->sadb_msg_version = PF_KEY_V2;
! 2182: smsg->sadb_msg_type = SADB_EXPIRE;
! 2183: smsg->sadb_msg_satype = sa->tdb_satype;
! 2184: smsg->sadb_msg_len = i / sizeof(uint64_t);
! 2185: smsg->sadb_msg_seq = pfkeyv2_seq++;
! 2186:
! 2187: headers[SADB_EXT_SA] = p;
! 2188: export_sa(&p, sa);
! 2189:
! 2190: headers[SADB_EXT_LIFETIME_CURRENT] = p;
! 2191: export_lifetime(&p, sa, 2);
! 2192:
! 2193: headers[type] = p;
! 2194: export_lifetime(&p, sa, type == SADB_EXT_LIFETIME_SOFT ?
! 2195: PFKEYV2_LIFETIME_SOFT : PFKEYV2_LIFETIME_HARD);
! 2196:
! 2197: headers[SADB_EXT_ADDRESS_SRC] = p;
! 2198: export_address(&p, (struct sockaddr *) &sa->tdb_src);
! 2199:
! 2200: headers[SADB_EXT_ADDRESS_DST] = p;
! 2201: export_address(&p, (struct sockaddr *) &sa->tdb_dst);
! 2202:
! 2203: if ((rval = pfkeyv2_sendmessage(headers, PFKEYV2_SENDMESSAGE_BROADCAST,
! 2204: NULL, 0, 0)) != 0)
! 2205: goto ret;
! 2206:
! 2207: rval = 0;
! 2208:
! 2209: ret:
! 2210: if (buffer != NULL) {
! 2211: bzero(buffer, i);
! 2212: free(buffer, M_PFKEY);
! 2213: }
! 2214:
! 2215: return (rval);
! 2216: }
! 2217:
! 2218: struct pfkeyv2_sysctl_walk {
! 2219: void *w_where;
! 2220: size_t w_len;
! 2221: int w_op;
! 2222: u_int8_t w_satype;
! 2223: };
! 2224:
! 2225: int
! 2226: pfkeyv2_sysctl_walker(struct tdb *sa, void *arg, int last)
! 2227: {
! 2228: struct pfkeyv2_sysctl_walk *w = (struct pfkeyv2_sysctl_walk *)arg;
! 2229: void *buffer = NULL;
! 2230: int error = 0;
! 2231: int buflen, i;
! 2232:
! 2233: if (w->w_satype != SADB_SATYPE_UNSPEC &&
! 2234: w->w_satype != sa->tdb_satype)
! 2235: return (0);
! 2236:
! 2237: if (w->w_where) {
! 2238: void *headers[SADB_EXT_MAX+1];
! 2239: struct sadb_msg msg;
! 2240:
! 2241: bzero(headers, sizeof(headers));
! 2242: if ((error = pfkeyv2_get(sa, headers, &buffer, &buflen)) != 0)
! 2243: goto done;
! 2244: if (w->w_len < sizeof(msg) + buflen) {
! 2245: error = ENOMEM;
! 2246: goto done;
! 2247: }
! 2248: /* prepend header */
! 2249: bzero(&msg, sizeof(msg));
! 2250: msg.sadb_msg_version = PF_KEY_V2;
! 2251: msg.sadb_msg_satype = sa->tdb_satype;
! 2252: msg.sadb_msg_type = SADB_DUMP;
! 2253: msg.sadb_msg_len = (sizeof(msg) + buflen) / sizeof(uint64_t);
! 2254: if ((error = copyout(&msg, w->w_where, sizeof(msg))) != 0)
! 2255: goto done;
! 2256: w->w_where += sizeof(msg);
! 2257: w->w_len -= sizeof(msg);
! 2258: /* set extension type */
! 2259: for (i = 1; i <= SADB_EXT_MAX; i++)
! 2260: if (headers[i])
! 2261: ((struct sadb_ext *)
! 2262: headers[i])->sadb_ext_type = i;
! 2263: if ((error = copyout(buffer, w->w_where, buflen)) != 0)
! 2264: goto done;
! 2265: w->w_where += buflen;
! 2266: w->w_len -= buflen;
! 2267: } else {
! 2268: if ((error = pfkeyv2_get(sa, NULL, NULL, &buflen)) != 0)
! 2269: return (error);
! 2270: w->w_len += buflen;
! 2271: w->w_len += sizeof(struct sadb_msg);
! 2272: }
! 2273:
! 2274: done:
! 2275: if (buffer)
! 2276: free(buffer, M_PFKEY);
! 2277: return (error);
! 2278: }
! 2279:
! 2280: int
! 2281: pfkeyv2_dump_policy(struct ipsec_policy *ipo, void **headers, void **buffer,
! 2282: int *lenp)
! 2283: {
! 2284: struct sadb_ident *ident;
! 2285: int i, rval, perm;
! 2286: void *p;
! 2287:
! 2288: /* Find how much space we need. */
! 2289: i = 2 * sizeof(struct sadb_protocol);
! 2290:
! 2291: /* We'll need four of them: src, src mask, dst, dst mask. */
! 2292: switch (ipo->ipo_addr.sen_type) {
! 2293: #ifdef INET
! 2294: case SENT_IP4:
! 2295: i += 4 * PADUP(sizeof(struct sockaddr_in));
! 2296: i += 4 * sizeof(struct sadb_address);
! 2297: break;
! 2298: #endif /* INET */
! 2299: #ifdef INET6
! 2300: case SENT_IP6:
! 2301: i += 4 * PADUP(sizeof(struct sockaddr_in6));
! 2302: i += 4 * sizeof(struct sadb_address);
! 2303: break;
! 2304: #endif /* INET6 */
! 2305: default:
! 2306: return (EINVAL);
! 2307: }
! 2308:
! 2309: /* Local address, might be zeroed. */
! 2310: switch (ipo->ipo_src.sa.sa_family) {
! 2311: case 0:
! 2312: break;
! 2313: #ifdef INET
! 2314: case AF_INET:
! 2315: i += PADUP(sizeof(struct sockaddr_in));
! 2316: i += sizeof(struct sadb_address);
! 2317: break;
! 2318: #endif /* INET */
! 2319: #ifdef INET6
! 2320: case AF_INET6:
! 2321: i += PADUP(sizeof(struct sockaddr_in6));
! 2322: i += sizeof(struct sadb_address);
! 2323: break;
! 2324: #endif /* INET6 */
! 2325: default:
! 2326: return (EINVAL);
! 2327: }
! 2328:
! 2329: /* Remote address, might be zeroed. XXX ??? */
! 2330: switch (ipo->ipo_dst.sa.sa_family) {
! 2331: case 0:
! 2332: break;
! 2333: #ifdef INET
! 2334: case AF_INET:
! 2335: i += PADUP(sizeof(struct sockaddr_in));
! 2336: i += sizeof(struct sadb_address);
! 2337: break;
! 2338: #endif /* INET */
! 2339: #ifdef INET6
! 2340: case AF_INET6:
! 2341: i += PADUP(sizeof(struct sockaddr_in6));
! 2342: i += sizeof(struct sadb_address);
! 2343: break;
! 2344: #endif /* INET6 */
! 2345: default:
! 2346: return (EINVAL);
! 2347: }
! 2348:
! 2349: if (ipo->ipo_srcid)
! 2350: i += sizeof(struct sadb_ident) + PADUP(ipo->ipo_srcid->ref_len);
! 2351: if (ipo->ipo_dstid)
! 2352: i += sizeof(struct sadb_ident) + PADUP(ipo->ipo_dstid->ref_len);
! 2353:
! 2354: if (lenp)
! 2355: *lenp = i;
! 2356:
! 2357: if (buffer == NULL) {
! 2358: rval = 0;
! 2359: goto ret;
! 2360: }
! 2361:
! 2362: if (!(p = malloc(i, M_PFKEY, M_DONTWAIT))) {
! 2363: rval = ENOMEM;
! 2364: goto ret;
! 2365: } else {
! 2366: *buffer = p;
! 2367: bzero(p, i);
! 2368: }
! 2369:
! 2370: /* Local address. */
! 2371: if (ipo->ipo_src.sa.sa_family) {
! 2372: headers[SADB_EXT_ADDRESS_SRC] = p;
! 2373: export_address(&p, (struct sockaddr *)&ipo->ipo_src);
! 2374: }
! 2375:
! 2376: /* Remote address. */
! 2377: if (ipo->ipo_dst.sa.sa_family) {
! 2378: headers[SADB_EXT_ADDRESS_DST] = p;
! 2379: export_address(&p, (struct sockaddr *)&ipo->ipo_dst);
! 2380: }
! 2381:
! 2382: /* Get actual flow. */
! 2383: export_flow(&p, ipo->ipo_type, &ipo->ipo_addr, &ipo->ipo_mask,
! 2384: headers);
! 2385:
! 2386: /* Add ids only when we are root. */
! 2387: perm = suser(curproc, 0);
! 2388: if (perm == 0 && ipo->ipo_srcid) {
! 2389: headers[SADB_EXT_IDENTITY_SRC] = p;
! 2390: p += sizeof(struct sadb_ident) + PADUP(ipo->ipo_srcid->ref_len);
! 2391: ident = (struct sadb_ident *)headers[SADB_EXT_IDENTITY_SRC];
! 2392: ident->sadb_ident_len = (sizeof(struct sadb_ident) +
! 2393: PADUP(ipo->ipo_srcid->ref_len)) / sizeof(uint64_t);
! 2394: ident->sadb_ident_type = ipo->ipo_srcid->ref_type;
! 2395: bcopy(ipo->ipo_srcid + 1, headers[SADB_EXT_IDENTITY_SRC] +
! 2396: sizeof(struct sadb_ident), ipo->ipo_srcid->ref_len);
! 2397: }
! 2398: if (perm == 0 && ipo->ipo_dstid) {
! 2399: headers[SADB_EXT_IDENTITY_DST] = p;
! 2400: p += sizeof(struct sadb_ident) + PADUP(ipo->ipo_dstid->ref_len);
! 2401: ident = (struct sadb_ident *)headers[SADB_EXT_IDENTITY_DST];
! 2402: ident->sadb_ident_len = (sizeof(struct sadb_ident) +
! 2403: PADUP(ipo->ipo_dstid->ref_len)) / sizeof(uint64_t);
! 2404: ident->sadb_ident_type = ipo->ipo_dstid->ref_type;
! 2405: bcopy(ipo->ipo_dstid + 1, headers[SADB_EXT_IDENTITY_DST] +
! 2406: sizeof(struct sadb_ident), ipo->ipo_dstid->ref_len);
! 2407: }
! 2408:
! 2409: rval = 0;
! 2410: ret:
! 2411: return (rval);
! 2412: }
! 2413:
! 2414: /*
! 2415: * Caller is responsible for setting at least spltdb().
! 2416: */
! 2417: int
! 2418: pfkeyv2_ipo_walk(int (*walker)(struct ipsec_policy *, void *), void *arg)
! 2419: {
! 2420: int rval = 0;
! 2421: struct ipsec_policy *ipo;
! 2422:
! 2423: TAILQ_FOREACH(ipo, &ipsec_policy_head, ipo_list)
! 2424: rval = walker(ipo, (void *)arg);
! 2425: return (rval);
! 2426: }
! 2427:
! 2428: int
! 2429: pfkeyv2_sysctl_policydumper(struct ipsec_policy *ipo, void *arg)
! 2430: {
! 2431: struct pfkeyv2_sysctl_walk *w = (struct pfkeyv2_sysctl_walk *)arg;
! 2432: void *buffer = 0;
! 2433: int i, buflen, error = 0;
! 2434:
! 2435: /* Do not dump policies attached to a socket. */
! 2436: if (ipo->ipo_flags & IPSP_POLICY_SOCKET)
! 2437: return (0);
! 2438:
! 2439: if (w->w_where) {
! 2440: void *headers[SADB_EXT_MAX + 1];
! 2441: struct sadb_msg msg;
! 2442:
! 2443: bzero(headers, sizeof(headers));
! 2444: if ((error = pfkeyv2_dump_policy(ipo, headers, &buffer,
! 2445: &buflen)) != 0)
! 2446: goto done;
! 2447: if (w->w_len < buflen) {
! 2448: error = ENOMEM;
! 2449: goto done;
! 2450: }
! 2451: /* prepend header */
! 2452: bzero(&msg, sizeof(msg));
! 2453: msg.sadb_msg_version = PF_KEY_V2;
! 2454: if (ipo->ipo_sproto == IPPROTO_ESP)
! 2455: msg.sadb_msg_satype = SADB_SATYPE_ESP;
! 2456: else if (ipo->ipo_sproto == IPPROTO_AH)
! 2457: msg.sadb_msg_satype = SADB_SATYPE_AH;
! 2458: else if (ipo->ipo_sproto == IPPROTO_IPCOMP)
! 2459: msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP;
! 2460: else if (ipo->ipo_sproto == IPPROTO_IPIP)
! 2461: msg.sadb_msg_satype = SADB_X_SATYPE_IPIP;
! 2462: msg.sadb_msg_type = SADB_X_SPDDUMP;
! 2463: msg.sadb_msg_len = (sizeof(msg) + buflen) / sizeof(uint64_t);
! 2464: if ((error = copyout(&msg, w->w_where, sizeof(msg))) != 0)
! 2465: goto done;
! 2466: w->w_where += sizeof(msg);
! 2467: w->w_len -= sizeof(msg);
! 2468: /* set extension type */
! 2469: for (i = 1; i < SADB_EXT_MAX; i++)
! 2470: if (headers[i])
! 2471: ((struct sadb_ext *)
! 2472: headers[i])->sadb_ext_type = i;
! 2473: if ((error = copyout(buffer, w->w_where, buflen)) != 0)
! 2474: goto done;
! 2475: w->w_where += buflen;
! 2476: w->w_len -= buflen;
! 2477: } else {
! 2478: if ((error = pfkeyv2_dump_policy(ipo, NULL, NULL,
! 2479: &buflen)) != 0)
! 2480: goto done;
! 2481: w->w_len += buflen;
! 2482: w->w_len += sizeof(struct sadb_msg);
! 2483: }
! 2484:
! 2485: done:
! 2486: if (buffer)
! 2487: free(buffer, M_PFKEY);
! 2488: return (error);
! 2489: }
! 2490:
! 2491: int
! 2492: pfkeyv2_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
! 2493: void *new, size_t newlen)
! 2494: {
! 2495: struct pfkeyv2_sysctl_walk w;
! 2496: int s, error = EINVAL;
! 2497:
! 2498: if (new)
! 2499: return (EPERM);
! 2500: if (namelen < 1)
! 2501: return (EINVAL);
! 2502: w.w_op = name[0];
! 2503: w.w_satype = name[1];
! 2504: w.w_where = oldp;
! 2505: w.w_len = oldp ? *oldlenp : 0;
! 2506:
! 2507: switch(w.w_op) {
! 2508: case NET_KEY_SADB_DUMP:
! 2509: if ((error = suser(curproc, 0)) != 0)
! 2510: return (error);
! 2511: s = spltdb();
! 2512: error = tdb_walk(pfkeyv2_sysctl_walker, &w);
! 2513: splx(s);
! 2514: if (oldp)
! 2515: *oldlenp = w.w_where - oldp;
! 2516: else
! 2517: *oldlenp = w.w_len;
! 2518: break;
! 2519:
! 2520: case NET_KEY_SPD_DUMP:
! 2521: s = spltdb();
! 2522: error = pfkeyv2_ipo_walk(pfkeyv2_sysctl_policydumper, &w);
! 2523: splx(s);
! 2524: if (oldp)
! 2525: *oldlenp = w.w_where - oldp;
! 2526: else
! 2527: *oldlenp = w.w_len;
! 2528: break;
! 2529: }
! 2530:
! 2531: return (error);
! 2532: }
! 2533:
! 2534: int
! 2535: pfkeyv2_init(void)
! 2536: {
! 2537: int rval;
! 2538:
! 2539: bzero(&pfkeyv2_version, sizeof(struct pfkey_version));
! 2540: pfkeyv2_version.protocol = PFKEYV2_PROTOCOL;
! 2541: pfkeyv2_version.create = &pfkeyv2_create;
! 2542: pfkeyv2_version.release = &pfkeyv2_release;
! 2543: pfkeyv2_version.send = &pfkeyv2_send;
! 2544: pfkeyv2_version.sysctl = &pfkeyv2_sysctl;
! 2545:
! 2546: rval = pfkey_register(&pfkeyv2_version);
! 2547: return (rval);
! 2548: }
! 2549:
! 2550: int
! 2551: pfkeyv2_cleanup(void)
! 2552: {
! 2553: pfkey_unregister(&pfkeyv2_version);
! 2554: return (0);
! 2555: }
CVSweb