Annotation of sys/netinet/ip_ipsp.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ip_ipsp.c,v 1.168 2007/02/14 00:53:48 jsg Exp $ */
! 2: /*
! 3: * The authors of this code are John Ioannidis (ji@tla.org),
! 4: * Angelos D. Keromytis (kermit@csd.uch.gr),
! 5: * Niels Provos (provos@physnet.uni-hamburg.de) and
! 6: * Niklas Hallqvist (niklas@appli.se).
! 7: *
! 8: * The original version of this code was written by John Ioannidis
! 9: * for BSD/OS in Athens, Greece, in November 1995.
! 10: *
! 11: * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
! 12: * by Angelos D. Keromytis.
! 13: *
! 14: * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
! 15: * and Niels Provos.
! 16: *
! 17: * Additional features in 1999 by Angelos D. Keromytis and Niklas Hallqvist.
! 18: *
! 19: * Copyright (c) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
! 20: * Angelos D. Keromytis and Niels Provos.
! 21: * Copyright (c) 1999 Niklas Hallqvist.
! 22: * Copyright (c) 2001, Angelos D. Keromytis.
! 23: *
! 24: * Permission to use, copy, and modify this software with or without fee
! 25: * is hereby granted, provided that this entire notice is included in
! 26: * all copies of any software which is or includes a copy or
! 27: * modification of this software.
! 28: * You may use this code under the GNU public license if you so wish. Please
! 29: * contribute changes back to the authors under this freer than GPL license
! 30: * so that we may further the use of strong encryption without limitations to
! 31: * all.
! 32: *
! 33: * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
! 34: * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
! 35: * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
! 36: * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
! 37: * PURPOSE.
! 38: */
! 39:
! 40: #include "pf.h"
! 41:
! 42: #include <sys/param.h>
! 43: #include <sys/mbuf.h>
! 44: #include <sys/socket.h>
! 45: #include <sys/kernel.h>
! 46: #include <sys/sysctl.h>
! 47:
! 48: #include <net/if.h>
! 49: #include <net/route.h>
! 50:
! 51: #if NPF > 0
! 52: #include <net/pfvar.h>
! 53: #endif
! 54:
! 55: #ifdef INET
! 56: #include <netinet/in.h>
! 57: #include <netinet/in_systm.h>
! 58: #include <netinet/ip.h>
! 59: #include <netinet/in_pcb.h>
! 60: #endif /* INET */
! 61:
! 62: #ifdef INET6
! 63: #ifndef INET
! 64: #include <netinet/in.h>
! 65: #endif
! 66: #include <netinet6/in6_var.h>
! 67: #endif /* INET6 */
! 68:
! 69: #include <netinet/ip_ipsp.h>
! 70: #include <net/pfkeyv2.h>
! 71: #include <crypto/xform.h>
! 72: #include <dev/rndvar.h>
! 73:
! 74: #ifdef DDB
! 75: #include <ddb/db_output.h>
! 76: void tdb_hashstats(void);
! 77: #endif
! 78:
! 79: #ifdef ENCDEBUG
! 80: #define DPRINTF(x) if (encdebug) printf x
! 81: #else
! 82: #define DPRINTF(x)
! 83: #endif
! 84:
! 85: int ipsp_kern(int, char **, int);
! 86: u_int8_t get_sa_require(struct inpcb *);
! 87: void tdb_rehash(void);
! 88: void tdb_timeout(void *v);
! 89: void tdb_firstuse(void *v);
! 90: void tdb_soft_timeout(void *v);
! 91: void tdb_soft_firstuse(void *v);
! 92:
! 93: extern int ipsec_auth_default_level;
! 94: extern int ipsec_esp_trans_default_level;
! 95: extern int ipsec_esp_network_default_level;
! 96: extern int ipsec_ipcomp_default_level;
! 97:
! 98: extern int encdebug;
! 99: int ipsec_in_use = 0;
! 100: u_int64_t ipsec_last_added = 0;
! 101:
! 102: struct ipsec_policy_head ipsec_policy_head =
! 103: TAILQ_HEAD_INITIALIZER(ipsec_policy_head);
! 104: struct ipsec_acquire_head ipsec_acquire_head =
! 105: TAILQ_HEAD_INITIALIZER(ipsec_acquire_head);
! 106:
! 107: /*
! 108: * This is the proper place to define the various encapsulation transforms.
! 109: */
! 110:
! 111: struct xformsw xformsw[] = {
! 112: #ifdef IPSEC
! 113: { XF_IP4, 0, "IPv4 Simple Encapsulation",
! 114: ipe4_attach, ipe4_init, ipe4_zeroize,
! 115: (int (*)(struct mbuf *, struct tdb *, int, int))ipe4_input,
! 116: ipip_output, },
! 117: { XF_AH, XFT_AUTH, "IPsec AH",
! 118: ah_attach, ah_init, ah_zeroize,
! 119: ah_input, ah_output, },
! 120: { XF_ESP, XFT_CONF|XFT_AUTH, "IPsec ESP",
! 121: esp_attach, esp_init, esp_zeroize,
! 122: esp_input, esp_output, },
! 123: { XF_IPCOMP, XFT_COMP, "IPcomp",
! 124: ipcomp_attach, ipcomp_init, ipcomp_zeroize,
! 125: ipcomp_input, ipcomp_output, },
! 126: #endif /* IPSEC */
! 127: #ifdef TCP_SIGNATURE
! 128: { XF_TCPSIGNATURE, XFT_AUTH, "TCP MD5 Signature Option, RFC 2385",
! 129: tcp_signature_tdb_attach, tcp_signature_tdb_init,
! 130: tcp_signature_tdb_zeroize, tcp_signature_tdb_input,
! 131: tcp_signature_tdb_output, }
! 132: #endif /* TCP_SIGNATURE */
! 133: };
! 134:
! 135: struct xformsw *xformswNXFORMSW = &xformsw[sizeof(xformsw)/sizeof(xformsw[0])];
! 136:
! 137: unsigned char ipseczeroes[IPSEC_ZEROES_SIZE]; /* zeroes! */
! 138:
! 139: #define TDB_HASHSIZE_INIT 32
! 140:
! 141: static struct tdb **tdbh = NULL;
! 142: static struct tdb **tdbaddr = NULL;
! 143: static struct tdb **tdbsrc = NULL;
! 144: static u_int tdb_hashmask = TDB_HASHSIZE_INIT - 1;
! 145: static int tdb_count;
! 146:
! 147: /*
! 148: * Our hashing function needs to stir things with a non-zero random multiplier
! 149: * so we cannot be DoS-attacked via choosing of the data to hash.
! 150: */
! 151: int
! 152: tdb_hash(u_int32_t spi, union sockaddr_union *dst, u_int8_t proto)
! 153: {
! 154: static u_int32_t mult1 = 0, mult2 = 0;
! 155: u_int8_t *ptr = (u_int8_t *) dst;
! 156: int i, shift;
! 157: u_int64_t hash;
! 158: int val32 = 0;
! 159:
! 160: while (mult1 == 0)
! 161: mult1 = arc4random();
! 162: while (mult2 == 0)
! 163: mult2 = arc4random();
! 164:
! 165: hash = (spi ^ proto) * mult1;
! 166: for (i = 0; i < SA_LEN(&dst->sa); i++) {
! 167: val32 = (val32 << 8) | ptr[i];
! 168: if (i % 4 == 3) {
! 169: hash ^= val32 * mult2;
! 170: val32 = 0;
! 171: }
! 172: }
! 173:
! 174: if (i % 4 != 0)
! 175: hash ^= val32 * mult2;
! 176:
! 177: shift = ffs(tdb_hashmask + 1);
! 178: while ((hash & ~tdb_hashmask) != 0)
! 179: hash = (hash >> shift) ^ (hash & tdb_hashmask);
! 180:
! 181: return hash;
! 182: }
! 183:
! 184: /*
! 185: * Reserve an SPI; the SA is not valid yet though. We use 0 as
! 186: * an error return value.
! 187: */
! 188: u_int32_t
! 189: reserve_spi(u_int32_t sspi, u_int32_t tspi, union sockaddr_union *src,
! 190: union sockaddr_union *dst, u_int8_t sproto, int *errval)
! 191: {
! 192: struct tdb *tdbp;
! 193: u_int32_t spi;
! 194: int nums, s;
! 195:
! 196: /* Don't accept ranges only encompassing reserved SPIs. */
! 197: if (sproto != IPPROTO_IPCOMP &&
! 198: (tspi < sspi || tspi <= SPI_RESERVED_MAX)) {
! 199: (*errval) = EINVAL;
! 200: return 0;
! 201: }
! 202: if (sproto == IPPROTO_IPCOMP && (tspi < sspi ||
! 203: tspi <= CPI_RESERVED_MAX ||
! 204: tspi >= CPI_PRIVATE_MIN)) {
! 205: (*errval) = EINVAL;
! 206: return 0;
! 207: }
! 208:
! 209: /* Limit the range to not include reserved areas. */
! 210: if (sspi <= SPI_RESERVED_MAX)
! 211: sspi = SPI_RESERVED_MAX + 1;
! 212:
! 213: /* For IPCOMP the CPI is only 16 bits long, what a good idea.... */
! 214:
! 215: if (sproto == IPPROTO_IPCOMP) {
! 216: u_int32_t t;
! 217: if (sspi >= 0x10000)
! 218: sspi = 0xffff;
! 219: if (tspi >= 0x10000)
! 220: tspi = 0xffff;
! 221: if (sspi > tspi) {
! 222: t = sspi; sspi = tspi; tspi = t;
! 223: }
! 224: }
! 225:
! 226: if (sspi == tspi) /* Asking for a specific SPI. */
! 227: nums = 1;
! 228: else
! 229: nums = 100; /* Arbitrarily chosen */
! 230:
! 231: while (nums--) {
! 232: if (sspi == tspi) /* Specific SPI asked. */
! 233: spi = tspi;
! 234: else /* Range specified */
! 235: spi = sspi + (arc4random() % (tspi - sspi));
! 236:
! 237: /* Don't allocate reserved SPIs. */
! 238: if (spi >= SPI_RESERVED_MIN && spi <= SPI_RESERVED_MAX)
! 239: continue;
! 240: else
! 241: spi = htonl(spi);
! 242:
! 243: /* Check whether we're using this SPI already. */
! 244: s = spltdb();
! 245: tdbp = gettdb(spi, dst, sproto);
! 246: splx(s);
! 247:
! 248: if (tdbp != (struct tdb *) NULL)
! 249: continue;
! 250:
! 251: tdbp = tdb_alloc();
! 252:
! 253: tdbp->tdb_spi = spi;
! 254: bcopy(&dst->sa, &tdbp->tdb_dst.sa, SA_LEN(&dst->sa));
! 255: bcopy(&src->sa, &tdbp->tdb_src.sa, SA_LEN(&src->sa));
! 256: tdbp->tdb_sproto = sproto;
! 257: tdbp->tdb_flags |= TDBF_INVALID; /* Mark SA invalid for now. */
! 258: tdbp->tdb_satype = SADB_SATYPE_UNSPEC;
! 259: puttdb(tdbp);
! 260:
! 261: /* Setup a "silent" expiration (since TDBF_INVALID's set). */
! 262: if (ipsec_keep_invalid > 0) {
! 263: tdbp->tdb_flags |= TDBF_TIMER;
! 264: tdbp->tdb_exp_timeout = ipsec_keep_invalid;
! 265: timeout_add(&tdbp->tdb_timer_tmo,
! 266: hz * ipsec_keep_invalid);
! 267: }
! 268:
! 269: return spi;
! 270: }
! 271:
! 272: (*errval) = EEXIST;
! 273: return 0;
! 274: }
! 275:
! 276: /*
! 277: * An IPSP SAID is really the concatenation of the SPI found in the
! 278: * packet, the destination address of the packet and the IPsec protocol.
! 279: * When we receive an IPSP packet, we need to look up its tunnel descriptor
! 280: * block, based on the SPI in the packet and the destination address (which
! 281: * is really one of our addresses if we received the packet!
! 282: *
! 283: * Caller is responsible for setting at least spltdb().
! 284: */
! 285: struct tdb *
! 286: gettdb(u_int32_t spi, union sockaddr_union *dst, u_int8_t proto)
! 287: {
! 288: u_int32_t hashval;
! 289: struct tdb *tdbp;
! 290:
! 291: if (tdbh == NULL)
! 292: return (struct tdb *) NULL;
! 293:
! 294: hashval = tdb_hash(spi, dst, proto);
! 295:
! 296: for (tdbp = tdbh[hashval]; tdbp != NULL; tdbp = tdbp->tdb_hnext)
! 297: if ((tdbp->tdb_spi == spi) && (tdbp->tdb_sproto == proto) &&
! 298: !bcmp(&tdbp->tdb_dst, dst, SA_LEN(&dst->sa)))
! 299: break;
! 300:
! 301: return tdbp;
! 302: }
! 303:
! 304: /*
! 305: * Same as gettdb() but compare SRC as well, so we
! 306: * use the tdbsrc[] hash table. Setting spi to 0
! 307: * matches all SPIs.
! 308: */
! 309: struct tdb *
! 310: gettdbbysrcdst(u_int32_t spi, union sockaddr_union *src,
! 311: union sockaddr_union *dst, u_int8_t proto)
! 312: {
! 313: u_int32_t hashval;
! 314: struct tdb *tdbp;
! 315: union sockaddr_union su_null;
! 316:
! 317: if (tdbsrc == NULL)
! 318: return (struct tdb *) NULL;
! 319:
! 320: hashval = tdb_hash(0, src, proto);
! 321:
! 322: for (tdbp = tdbsrc[hashval]; tdbp != NULL; tdbp = tdbp->tdb_snext)
! 323: if (tdbp->tdb_sproto == proto &&
! 324: (spi == 0 || tdbp->tdb_spi == spi) &&
! 325: ((tdbp->tdb_flags & TDBF_INVALID) == 0) &&
! 326: (tdbp->tdb_dst.sa.sa_family == AF_UNSPEC ||
! 327: !bcmp(&tdbp->tdb_dst, dst, SA_LEN(&dst->sa))) &&
! 328: !bcmp(&tdbp->tdb_src, src, SA_LEN(&src->sa)))
! 329: break;
! 330:
! 331: if (tdbp != NULL)
! 332: return (tdbp);
! 333:
! 334: bzero(&su_null, sizeof(su_null));
! 335: su_null.sa.sa_len = sizeof(struct sockaddr);
! 336: hashval = tdb_hash(0, &su_null, proto);
! 337:
! 338: for (tdbp = tdbsrc[hashval]; tdbp != NULL; tdbp = tdbp->tdb_snext)
! 339: if (tdbp->tdb_sproto == proto &&
! 340: (spi == 0 || tdbp->tdb_spi == spi) &&
! 341: ((tdbp->tdb_flags & TDBF_INVALID) == 0) &&
! 342: (tdbp->tdb_dst.sa.sa_family == AF_UNSPEC ||
! 343: !bcmp(&tdbp->tdb_dst, dst, SA_LEN(&dst->sa))) &&
! 344: tdbp->tdb_src.sa.sa_family == AF_UNSPEC)
! 345: break;
! 346:
! 347: return (tdbp);
! 348: }
! 349:
! 350: /*
! 351: * Check that credentials and IDs match. Return true if so. The t*
! 352: * range of arguments contains information from TDBs; the p*
! 353: * range of arguments contains information from policies or
! 354: * already established TDBs.
! 355: */
! 356: int
! 357: ipsp_aux_match(struct tdb *tdb,
! 358: struct ipsec_ref *psrcid,
! 359: struct ipsec_ref *pdstid,
! 360: struct ipsec_ref *plcred,
! 361: struct ipsec_ref *prcred,
! 362: struct sockaddr_encap *pfilter,
! 363: struct sockaddr_encap *pfiltermask)
! 364: {
! 365: if (psrcid != NULL)
! 366: if (tdb->tdb_srcid == NULL ||
! 367: !ipsp_ref_match(tdb->tdb_srcid, psrcid))
! 368: return 0;
! 369:
! 370: if (pdstid != NULL)
! 371: if (tdb->tdb_dstid == NULL ||
! 372: !ipsp_ref_match(tdb->tdb_dstid, pdstid))
! 373: return 0;
! 374:
! 375: if (plcred != NULL)
! 376: if (tdb->tdb_local_cred == NULL ||
! 377: !ipsp_ref_match(tdb->tdb_local_cred, plcred))
! 378: return 0;
! 379:
! 380: if (prcred != NULL)
! 381: if (tdb->tdb_remote_cred == NULL ||
! 382: !ipsp_ref_match(tdb->tdb_remote_cred, prcred))
! 383: return 0;
! 384:
! 385: /* Check for filter matches. */
! 386: if (tdb->tdb_filter.sen_type) {
! 387: /*
! 388: * XXX We should really be doing a subnet-check (see
! 389: * whether the TDB-associated filter is a subset
! 390: * of the policy's. For now, an exact match will solve
! 391: * most problems (all this will do is make every
! 392: * policy get its own SAs).
! 393: */
! 394: if (bcmp(&tdb->tdb_filter, pfilter,
! 395: sizeof(struct sockaddr_encap)) ||
! 396: bcmp(&tdb->tdb_filtermask, pfiltermask,
! 397: sizeof(struct sockaddr_encap)))
! 398: return 0;
! 399: }
! 400:
! 401: return 1;
! 402: }
! 403:
! 404: /*
! 405: * Get an SA given the remote address, the security protocol type, and
! 406: * the desired IDs.
! 407: */
! 408: struct tdb *
! 409: gettdbbyaddr(union sockaddr_union *dst, u_int8_t sproto,
! 410: struct ipsec_ref *srcid, struct ipsec_ref *dstid,
! 411: struct ipsec_ref *local_cred, struct mbuf *m, int af,
! 412: struct sockaddr_encap *filter, struct sockaddr_encap *filtermask)
! 413: {
! 414: u_int32_t hashval;
! 415: struct tdb *tdbp;
! 416:
! 417: if (tdbaddr == NULL)
! 418: return (struct tdb *) NULL;
! 419:
! 420: hashval = tdb_hash(0, dst, sproto);
! 421:
! 422: for (tdbp = tdbaddr[hashval]; tdbp != NULL; tdbp = tdbp->tdb_anext)
! 423: if ((tdbp->tdb_sproto == sproto) &&
! 424: ((tdbp->tdb_flags & TDBF_INVALID) == 0) &&
! 425: (!bcmp(&tdbp->tdb_dst, dst, SA_LEN(&dst->sa)))) {
! 426: /* Do IDs and local credentials match ? */
! 427: if (!ipsp_aux_match(tdbp, srcid, dstid,
! 428: local_cred, NULL, filter, filtermask))
! 429: continue;
! 430: break;
! 431: }
! 432:
! 433: return tdbp;
! 434: }
! 435:
! 436: /*
! 437: * Get an SA given the source address, the security protocol type, and
! 438: * the desired IDs.
! 439: */
! 440: struct tdb *
! 441: gettdbbysrc(union sockaddr_union *src, u_int8_t sproto,
! 442: struct ipsec_ref *srcid, struct ipsec_ref *dstid,
! 443: struct mbuf *m, int af, struct sockaddr_encap *filter,
! 444: struct sockaddr_encap *filtermask)
! 445: {
! 446: u_int32_t hashval;
! 447: struct tdb *tdbp;
! 448:
! 449: if (tdbsrc == NULL)
! 450: return (struct tdb *) NULL;
! 451:
! 452: hashval = tdb_hash(0, src, sproto);
! 453:
! 454: for (tdbp = tdbsrc[hashval]; tdbp != NULL; tdbp = tdbp->tdb_snext)
! 455: if ((tdbp->tdb_sproto == sproto) &&
! 456: ((tdbp->tdb_flags & TDBF_INVALID) == 0) &&
! 457: (!bcmp(&tdbp->tdb_src, src, SA_LEN(&src->sa)))) {
! 458: /* Check whether IDs match */
! 459: if (!ipsp_aux_match(tdbp, dstid, srcid, NULL, NULL,
! 460: filter, filtermask))
! 461: continue;
! 462: break;
! 463: }
! 464:
! 465: return tdbp;
! 466: }
! 467:
! 468: #if DDB
! 469: void
! 470: tdb_hashstats(void)
! 471: {
! 472: int i, cnt, buckets[16];
! 473: struct tdb *tdbp;
! 474:
! 475: if (tdbh == NULL) {
! 476: db_printf("no tdb hash table\n");
! 477: return;
! 478: }
! 479:
! 480: bzero (buckets, sizeof(buckets));
! 481: for (i = 0; i <= tdb_hashmask; i++) {
! 482: cnt = 0;
! 483: for (tdbp = tdbh[i]; cnt < 16 && tdbp != NULL;
! 484: tdbp = tdbp->tdb_hnext)
! 485: cnt++;
! 486: buckets[cnt]++;
! 487: }
! 488:
! 489: db_printf("tdb cnt\t\tbucket cnt\n");
! 490: for (i = 0; i < 16; i++)
! 491: if (buckets[i] > 0)
! 492: db_printf("%d%c\t\t%d\n", i, i == 15 ? "+" : "",
! 493: buckets[i]);
! 494: }
! 495: #endif /* DDB */
! 496:
! 497: /*
! 498: * Caller is responsible for setting at least spltdb().
! 499: */
! 500: int
! 501: tdb_walk(int (*walker)(struct tdb *, void *, int), void *arg)
! 502: {
! 503: int i, rval = 0;
! 504: struct tdb *tdbp, *next;
! 505:
! 506: if (tdbh == NULL)
! 507: return ENOENT;
! 508:
! 509: for (i = 0; i <= tdb_hashmask; i++)
! 510: for (tdbp = tdbh[i]; rval == 0 && tdbp != NULL; tdbp = next) {
! 511: next = tdbp->tdb_hnext;
! 512: if (i == tdb_hashmask && next == NULL)
! 513: rval = walker(tdbp, (void *)arg, 1);
! 514: else
! 515: rval = walker(tdbp, (void *)arg, 0);
! 516: }
! 517:
! 518: return rval;
! 519: }
! 520:
! 521: /*
! 522: * Called at splsoftclock().
! 523: */
! 524: void
! 525: tdb_timeout(void *v)
! 526: {
! 527: struct tdb *tdb = v;
! 528:
! 529: if (!(tdb->tdb_flags & TDBF_TIMER))
! 530: return;
! 531:
! 532: /* If it's an "invalid" TDB do a silent expiration. */
! 533: if (!(tdb->tdb_flags & TDBF_INVALID))
! 534: pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
! 535: tdb_delete(tdb);
! 536: }
! 537:
! 538: void
! 539: tdb_firstuse(void *v)
! 540: {
! 541: struct tdb *tdb = v;
! 542:
! 543: if (!(tdb->tdb_flags & TDBF_SOFT_FIRSTUSE))
! 544: return;
! 545:
! 546: /* If the TDB hasn't been used, don't renew it. */
! 547: if (tdb->tdb_first_use != 0)
! 548: pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
! 549: tdb_delete(tdb);
! 550: }
! 551:
! 552: void
! 553: tdb_soft_timeout(void *v)
! 554: {
! 555: struct tdb *tdb = v;
! 556:
! 557: if (!(tdb->tdb_flags & TDBF_SOFT_TIMER))
! 558: return;
! 559:
! 560: /* Soft expirations. */
! 561: pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
! 562: tdb->tdb_flags &= ~TDBF_SOFT_TIMER;
! 563: }
! 564:
! 565: void
! 566: tdb_soft_firstuse(void *v)
! 567: {
! 568: struct tdb *tdb = v;
! 569:
! 570: if (!(tdb->tdb_flags & TDBF_SOFT_FIRSTUSE))
! 571: return;
! 572:
! 573: /* If the TDB hasn't been used, don't renew it. */
! 574: if (tdb->tdb_first_use != 0)
! 575: pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
! 576: tdb->tdb_flags &= ~TDBF_SOFT_FIRSTUSE;
! 577: }
! 578:
! 579: /*
! 580: * Caller is responsible for spltdb().
! 581: */
! 582: void
! 583: tdb_rehash(void)
! 584: {
! 585: struct tdb **new_tdbh, **new_tdbaddr, **new_srcaddr, *tdbp, *tdbnp;
! 586: u_int i, old_hashmask = tdb_hashmask;
! 587: u_int32_t hashval;
! 588:
! 589: tdb_hashmask = (tdb_hashmask << 1) | 1;
! 590:
! 591: MALLOC(new_tdbh, struct tdb **,
! 592: sizeof(struct tdb *) * (tdb_hashmask + 1), M_TDB, M_WAITOK);
! 593: MALLOC(new_tdbaddr, struct tdb **,
! 594: sizeof(struct tdb *) * (tdb_hashmask + 1), M_TDB, M_WAITOK);
! 595: MALLOC(new_srcaddr, struct tdb **,
! 596: sizeof(struct tdb *) * (tdb_hashmask + 1), M_TDB, M_WAITOK);
! 597:
! 598: bzero(new_tdbh, sizeof(struct tdb *) * (tdb_hashmask + 1));
! 599: bzero(new_tdbaddr, sizeof(struct tdb *) * (tdb_hashmask + 1));
! 600: bzero(new_srcaddr, sizeof(struct tdb *) * (tdb_hashmask + 1));
! 601:
! 602: for (i = 0; i <= old_hashmask; i++) {
! 603: for (tdbp = tdbh[i]; tdbp != NULL; tdbp = tdbnp) {
! 604: tdbnp = tdbp->tdb_hnext;
! 605: hashval = tdb_hash(tdbp->tdb_spi, &tdbp->tdb_dst,
! 606: tdbp->tdb_sproto);
! 607: tdbp->tdb_hnext = new_tdbh[hashval];
! 608: new_tdbh[hashval] = tdbp;
! 609: }
! 610:
! 611: for (tdbp = tdbaddr[i]; tdbp != NULL; tdbp = tdbnp) {
! 612: tdbnp = tdbp->tdb_anext;
! 613: hashval = tdb_hash(0, &tdbp->tdb_dst,
! 614: tdbp->tdb_sproto);
! 615: tdbp->tdb_anext = new_tdbaddr[hashval];
! 616: new_tdbaddr[hashval] = tdbp;
! 617: }
! 618:
! 619: for (tdbp = tdbsrc[i]; tdbp != NULL; tdbp = tdbnp) {
! 620: tdbnp = tdbp->tdb_snext;
! 621: hashval = tdb_hash(0, &tdbp->tdb_src,
! 622: tdbp->tdb_sproto);
! 623: tdbp->tdb_snext = new_srcaddr[hashval];
! 624: new_srcaddr[hashval] = tdbp;
! 625: }
! 626: }
! 627:
! 628: FREE(tdbh, M_TDB);
! 629: tdbh = new_tdbh;
! 630:
! 631: FREE(tdbaddr, M_TDB);
! 632: tdbaddr = new_tdbaddr;
! 633:
! 634: FREE(tdbsrc, M_TDB);
! 635: tdbsrc = new_srcaddr;
! 636: }
! 637:
! 638: /*
! 639: * Add TDB in the hash table.
! 640: */
! 641: void
! 642: puttdb(struct tdb *tdbp)
! 643: {
! 644: u_int32_t hashval;
! 645: int s = spltdb();
! 646:
! 647: if (tdbh == NULL) {
! 648: MALLOC(tdbh, struct tdb **,
! 649: sizeof(struct tdb *) * (tdb_hashmask + 1),
! 650: M_TDB, M_WAITOK);
! 651: MALLOC(tdbaddr, struct tdb **,
! 652: sizeof(struct tdb *) * (tdb_hashmask + 1),
! 653: M_TDB, M_WAITOK);
! 654: MALLOC(tdbsrc, struct tdb **,
! 655: sizeof(struct tdb *) * (tdb_hashmask + 1),
! 656: M_TDB, M_WAITOK);
! 657:
! 658: bzero(tdbh, sizeof(struct tdb *) * (tdb_hashmask + 1));
! 659: bzero(tdbaddr, sizeof(struct tdb *) * (tdb_hashmask + 1));
! 660: bzero(tdbsrc, sizeof(struct tdb *) * (tdb_hashmask + 1));
! 661: }
! 662:
! 663: hashval = tdb_hash(tdbp->tdb_spi, &tdbp->tdb_dst, tdbp->tdb_sproto);
! 664:
! 665: /*
! 666: * Rehash if this tdb would cause a bucket to have more than
! 667: * two items and if the number of tdbs exceed 10% of the
! 668: * bucket count. This number is arbitratily chosen and is
! 669: * just a measure to not keep rehashing when adding and
! 670: * removing tdbs which happens to always end up in the same
! 671: * bucket, which is not uncommon when doing manual keying.
! 672: */
! 673: if (tdbh[hashval] != NULL && tdbh[hashval]->tdb_hnext != NULL &&
! 674: tdb_count * 10 > tdb_hashmask + 1) {
! 675: tdb_rehash();
! 676: hashval = tdb_hash(tdbp->tdb_spi, &tdbp->tdb_dst,
! 677: tdbp->tdb_sproto);
! 678: }
! 679:
! 680: tdbp->tdb_hnext = tdbh[hashval];
! 681: tdbh[hashval] = tdbp;
! 682:
! 683: hashval = tdb_hash(0, &tdbp->tdb_dst, tdbp->tdb_sproto);
! 684: tdbp->tdb_anext = tdbaddr[hashval];
! 685: tdbaddr[hashval] = tdbp;
! 686:
! 687: hashval = tdb_hash(0, &tdbp->tdb_src, tdbp->tdb_sproto);
! 688: tdbp->tdb_snext = tdbsrc[hashval];
! 689: tdbsrc[hashval] = tdbp;
! 690:
! 691: tdb_count++;
! 692:
! 693: ipsec_last_added = time_second;
! 694:
! 695: splx(s);
! 696: }
! 697:
! 698: /*
! 699: * Caller is responsible to set at least spltdb().
! 700: */
! 701: void
! 702: tdb_delete(struct tdb *tdbp)
! 703: {
! 704: struct tdb *tdbpp;
! 705: u_int32_t hashval;
! 706: int s;
! 707:
! 708: if (tdbh == NULL)
! 709: return;
! 710:
! 711: hashval = tdb_hash(tdbp->tdb_spi, &tdbp->tdb_dst, tdbp->tdb_sproto);
! 712:
! 713: s = spltdb();
! 714: if (tdbh[hashval] == tdbp) {
! 715: tdbpp = tdbp;
! 716: tdbh[hashval] = tdbp->tdb_hnext;
! 717: } else {
! 718: for (tdbpp = tdbh[hashval]; tdbpp != NULL;
! 719: tdbpp = tdbpp->tdb_hnext) {
! 720: if (tdbpp->tdb_hnext == tdbp) {
! 721: tdbpp->tdb_hnext = tdbp->tdb_hnext;
! 722: tdbpp = tdbp;
! 723: break;
! 724: }
! 725: }
! 726: }
! 727:
! 728: tdbp->tdb_hnext = NULL;
! 729:
! 730: hashval = tdb_hash(0, &tdbp->tdb_dst, tdbp->tdb_sproto);
! 731:
! 732: if (tdbaddr[hashval] == tdbp) {
! 733: tdbpp = tdbp;
! 734: tdbaddr[hashval] = tdbp->tdb_anext;
! 735: } else {
! 736: for (tdbpp = tdbaddr[hashval]; tdbpp != NULL;
! 737: tdbpp = tdbpp->tdb_anext) {
! 738: if (tdbpp->tdb_anext == tdbp) {
! 739: tdbpp->tdb_anext = tdbp->tdb_anext;
! 740: tdbpp = tdbp;
! 741: break;
! 742: }
! 743: }
! 744: }
! 745:
! 746: hashval = tdb_hash(0, &tdbp->tdb_src, tdbp->tdb_sproto);
! 747:
! 748: if (tdbsrc[hashval] == tdbp) {
! 749: tdbpp = tdbp;
! 750: tdbsrc[hashval] = tdbp->tdb_snext;
! 751: }
! 752: else {
! 753: for (tdbpp = tdbsrc[hashval]; tdbpp != NULL;
! 754: tdbpp = tdbpp->tdb_snext) {
! 755: if (tdbpp->tdb_snext == tdbp) {
! 756: tdbpp->tdb_snext = tdbp->tdb_snext;
! 757: tdbpp = tdbp;
! 758: break;
! 759: }
! 760: }
! 761: }
! 762:
! 763: tdbp->tdb_snext = NULL;
! 764: tdb_free(tdbp);
! 765: tdb_count--;
! 766:
! 767: splx(s);
! 768: }
! 769:
! 770: /*
! 771: * Allocate a TDB and initialize a few basic fields.
! 772: */
! 773: struct tdb *
! 774: tdb_alloc(void)
! 775: {
! 776: struct tdb *tdbp;
! 777:
! 778: MALLOC(tdbp, struct tdb *, sizeof(struct tdb), M_TDB, M_WAITOK);
! 779: bzero((caddr_t) tdbp, sizeof(struct tdb));
! 780:
! 781: /* Init Incoming SA-Binding Queues. */
! 782: TAILQ_INIT(&tdbp->tdb_inp_out);
! 783: TAILQ_INIT(&tdbp->tdb_inp_in);
! 784:
! 785: TAILQ_INIT(&tdbp->tdb_policy_head);
! 786:
! 787: /* Record establishment time. */
! 788: tdbp->tdb_established = time_second;
! 789:
! 790: /* Initialize timeouts. */
! 791: timeout_set(&tdbp->tdb_timer_tmo, tdb_timeout, tdbp);
! 792: timeout_set(&tdbp->tdb_first_tmo, tdb_firstuse, tdbp);
! 793: timeout_set(&tdbp->tdb_stimer_tmo, tdb_soft_timeout, tdbp);
! 794: timeout_set(&tdbp->tdb_sfirst_tmo, tdb_soft_firstuse, tdbp);
! 795:
! 796: return tdbp;
! 797: }
! 798:
! 799: void
! 800: tdb_free(struct tdb *tdbp)
! 801: {
! 802: struct ipsec_policy *ipo;
! 803: struct inpcb *inp;
! 804:
! 805: if (tdbp->tdb_xform) {
! 806: (*(tdbp->tdb_xform->xf_zeroize))(tdbp);
! 807: tdbp->tdb_xform = NULL;
! 808: }
! 809:
! 810: /* Cleanup inp references. */
! 811: for (inp = TAILQ_FIRST(&tdbp->tdb_inp_in); inp;
! 812: inp = TAILQ_FIRST(&tdbp->tdb_inp_in)) {
! 813: TAILQ_REMOVE(&tdbp->tdb_inp_in, inp, inp_tdb_in_next);
! 814: inp->inp_tdb_in = NULL;
! 815: }
! 816:
! 817: for (inp = TAILQ_FIRST(&tdbp->tdb_inp_out); inp;
! 818: inp = TAILQ_FIRST(&tdbp->tdb_inp_out)) {
! 819: TAILQ_REMOVE(&tdbp->tdb_inp_out, inp, inp_tdb_out_next);
! 820: inp->inp_tdb_out = NULL;
! 821: }
! 822:
! 823: /* Cleanup SPD references. */
! 824: for (ipo = TAILQ_FIRST(&tdbp->tdb_policy_head); ipo;
! 825: ipo = TAILQ_FIRST(&tdbp->tdb_policy_head)) {
! 826: TAILQ_REMOVE(&tdbp->tdb_policy_head, ipo, ipo_tdb_next);
! 827: ipo->ipo_tdb = NULL;
! 828: ipo->ipo_last_searched = 0; /* Force a re-search. */
! 829: }
! 830:
! 831: /* Remove expiration timeouts. */
! 832: tdbp->tdb_flags &= ~(TDBF_FIRSTUSE | TDBF_SOFT_FIRSTUSE | TDBF_TIMER |
! 833: TDBF_SOFT_TIMER);
! 834: timeout_del(&tdbp->tdb_timer_tmo);
! 835: timeout_del(&tdbp->tdb_first_tmo);
! 836: timeout_del(&tdbp->tdb_stimer_tmo);
! 837: timeout_del(&tdbp->tdb_sfirst_tmo);
! 838:
! 839: if (tdbp->tdb_local_auth) {
! 840: ipsp_reffree(tdbp->tdb_local_auth);
! 841: tdbp->tdb_local_auth = NULL;
! 842: }
! 843:
! 844: if (tdbp->tdb_remote_auth) {
! 845: ipsp_reffree(tdbp->tdb_remote_auth);
! 846: tdbp->tdb_remote_auth = NULL;
! 847: }
! 848:
! 849: if (tdbp->tdb_srcid) {
! 850: ipsp_reffree(tdbp->tdb_srcid);
! 851: tdbp->tdb_srcid = NULL;
! 852: }
! 853:
! 854: if (tdbp->tdb_dstid) {
! 855: ipsp_reffree(tdbp->tdb_dstid);
! 856: tdbp->tdb_dstid = NULL;
! 857: }
! 858:
! 859: if (tdbp->tdb_local_cred) {
! 860: ipsp_reffree(tdbp->tdb_local_cred);
! 861: tdbp->tdb_local_cred = NULL;
! 862: }
! 863:
! 864: if (tdbp->tdb_remote_cred) {
! 865: ipsp_reffree(tdbp->tdb_remote_cred);
! 866: tdbp->tdb_remote_cred = NULL;
! 867: }
! 868:
! 869: #if NPF > 0
! 870: if (tdbp->tdb_tag) {
! 871: pf_tag_unref(tdbp->tdb_tag);
! 872: tdbp->tdb_tag = 0;
! 873: }
! 874: #endif
! 875:
! 876: if ((tdbp->tdb_onext) && (tdbp->tdb_onext->tdb_inext == tdbp))
! 877: tdbp->tdb_onext->tdb_inext = NULL;
! 878:
! 879: if ((tdbp->tdb_inext) && (tdbp->tdb_inext->tdb_onext == tdbp))
! 880: tdbp->tdb_inext->tdb_onext = NULL;
! 881:
! 882: FREE(tdbp, M_TDB);
! 883: }
! 884:
! 885: /*
! 886: * Do further initializations of a TDB.
! 887: */
! 888: int
! 889: tdb_init(struct tdb *tdbp, u_int16_t alg, struct ipsecinit *ii)
! 890: {
! 891: struct xformsw *xsp;
! 892: int err;
! 893:
! 894: for (xsp = xformsw; xsp < xformswNXFORMSW; xsp++) {
! 895: if (xsp->xf_type == alg) {
! 896: err = (*(xsp->xf_init))(tdbp, xsp, ii);
! 897: return err;
! 898: }
! 899: }
! 900:
! 901: DPRINTF(("tdb_init(): no alg %d for spi %08x, addr %s, proto %d\n",
! 902: alg, ntohl(tdbp->tdb_spi), ipsp_address(tdbp->tdb_dst),
! 903: tdbp->tdb_sproto));
! 904:
! 905: return EINVAL;
! 906: }
! 907:
! 908: /*
! 909: * Check which transformations are required.
! 910: */
! 911: u_int8_t
! 912: get_sa_require(struct inpcb *inp)
! 913: {
! 914: u_int8_t sareq = 0;
! 915:
! 916: if (inp != NULL) {
! 917: sareq |= inp->inp_seclevel[SL_AUTH] >= IPSEC_LEVEL_USE ?
! 918: NOTIFY_SATYPE_AUTH : 0;
! 919: sareq |= inp->inp_seclevel[SL_ESP_TRANS] >= IPSEC_LEVEL_USE ?
! 920: NOTIFY_SATYPE_CONF : 0;
! 921: sareq |= inp->inp_seclevel[SL_ESP_NETWORK] >= IPSEC_LEVEL_USE ?
! 922: NOTIFY_SATYPE_TUNNEL : 0;
! 923: } else {
! 924: sareq |= ipsec_auth_default_level >= IPSEC_LEVEL_USE ?
! 925: NOTIFY_SATYPE_AUTH : 0;
! 926: sareq |= ipsec_esp_trans_default_level >= IPSEC_LEVEL_USE ?
! 927: NOTIFY_SATYPE_CONF : 0;
! 928: sareq |= ipsec_esp_network_default_level >= IPSEC_LEVEL_USE ?
! 929: NOTIFY_SATYPE_TUNNEL : 0;
! 930: }
! 931:
! 932: return (sareq);
! 933: }
! 934:
! 935: /*
! 936: * Add an inpcb to the list of inpcb which reference this tdb directly.
! 937: */
! 938: void
! 939: tdb_add_inp(struct tdb *tdb, struct inpcb *inp, int inout)
! 940: {
! 941: if (inout) {
! 942: if (inp->inp_tdb_in) {
! 943: if (inp->inp_tdb_in == tdb)
! 944: return;
! 945:
! 946: TAILQ_REMOVE(&inp->inp_tdb_in->tdb_inp_in, inp,
! 947: inp_tdb_in_next);
! 948: }
! 949:
! 950: inp->inp_tdb_in = tdb;
! 951: TAILQ_INSERT_TAIL(&tdb->tdb_inp_in, inp, inp_tdb_in_next);
! 952: } else {
! 953: if (inp->inp_tdb_out) {
! 954: if (inp->inp_tdb_out == tdb)
! 955: return;
! 956:
! 957: TAILQ_REMOVE(&inp->inp_tdb_out->tdb_inp_out, inp,
! 958: inp_tdb_out_next);
! 959: }
! 960:
! 961: inp->inp_tdb_out = tdb;
! 962: TAILQ_INSERT_TAIL(&tdb->tdb_inp_out, inp, inp_tdb_out_next);
! 963: }
! 964: }
! 965:
! 966: /* Return a printable string for the IPv4 address. */
! 967: char *
! 968: inet_ntoa4(struct in_addr ina)
! 969: {
! 970: static char buf[4][4 * sizeof "123" + 4];
! 971: unsigned char *ucp = (unsigned char *) &ina;
! 972: static int i = 3;
! 973:
! 974: i = (i + 1) % 4;
! 975: snprintf(buf[i], sizeof buf[0], "%d.%d.%d.%d",
! 976: ucp[0] & 0xff, ucp[1] & 0xff,
! 977: ucp[2] & 0xff, ucp[3] & 0xff);
! 978: return (buf[i]);
! 979: }
! 980:
! 981: /* Return a printable string for the address. */
! 982: char *
! 983: ipsp_address(union sockaddr_union sa)
! 984: {
! 985: switch (sa.sa.sa_family) {
! 986: #if INET
! 987: case AF_INET:
! 988: return inet_ntoa4(sa.sin.sin_addr);
! 989: #endif /* INET */
! 990:
! 991: #if INET6
! 992: case AF_INET6:
! 993: return ip6_sprintf(&sa.sin6.sin6_addr);
! 994: #endif /* INET6 */
! 995:
! 996: default:
! 997: return "(unknown address family)";
! 998: }
! 999: }
! 1000:
! 1001: /* Check whether an IP{4,6} address is unspecified. */
! 1002: int
! 1003: ipsp_is_unspecified(union sockaddr_union addr)
! 1004: {
! 1005: switch (addr.sa.sa_family) {
! 1006: #ifdef INET
! 1007: case AF_INET:
! 1008: if (addr.sin.sin_addr.s_addr == INADDR_ANY)
! 1009: return 1;
! 1010: else
! 1011: return 0;
! 1012: #endif /* INET */
! 1013:
! 1014: #ifdef INET6
! 1015: case AF_INET6:
! 1016: if (IN6_IS_ADDR_UNSPECIFIED(&addr.sin6.sin6_addr))
! 1017: return 1;
! 1018: else
! 1019: return 0;
! 1020: #endif /* INET6 */
! 1021:
! 1022: case 0: /* No family set. */
! 1023: default:
! 1024: return 1;
! 1025: }
! 1026: }
! 1027:
! 1028: /* Free reference-counted structure. */
! 1029: void
! 1030: ipsp_reffree(struct ipsec_ref *ipr)
! 1031: {
! 1032: #ifdef DIAGNOSTIC
! 1033: if (ipr->ref_count <= 0)
! 1034: printf("ipsp_reffree: illegal reference count %d for "
! 1035: "object %p (len = %d, malloctype = %d)\n",
! 1036: ipr->ref_count, ipr, ipr->ref_len, ipr->ref_malloctype);
! 1037: #endif
! 1038: if (--ipr->ref_count <= 0)
! 1039: FREE(ipr, ipr->ref_malloctype);
! 1040: }
! 1041:
! 1042: /* Mark a TDB as TDBF_SKIPCRYPTO. */
! 1043: void
! 1044: ipsp_skipcrypto_mark(struct tdb_ident *tdbi)
! 1045: {
! 1046: struct tdb *tdb;
! 1047: int s = spltdb();
! 1048:
! 1049: tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
! 1050: if (tdb != NULL) {
! 1051: tdb->tdb_flags |= TDBF_SKIPCRYPTO;
! 1052: tdb->tdb_last_marked = time_second;
! 1053: }
! 1054: splx(s);
! 1055: }
! 1056:
! 1057: /* Unmark a TDB as TDBF_SKIPCRYPTO. */
! 1058: void
! 1059: ipsp_skipcrypto_unmark(struct tdb_ident *tdbi)
! 1060: {
! 1061: struct tdb *tdb;
! 1062: int s = spltdb();
! 1063:
! 1064: tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
! 1065: if (tdb != NULL) {
! 1066: tdb->tdb_flags &= ~TDBF_SKIPCRYPTO;
! 1067: tdb->tdb_last_marked = time_second;
! 1068: }
! 1069: splx(s);
! 1070: }
! 1071:
! 1072: /* Return true if the two structures match. */
! 1073: int
! 1074: ipsp_ref_match(struct ipsec_ref *ref1, struct ipsec_ref *ref2)
! 1075: {
! 1076: if (ref1->ref_type != ref2->ref_type ||
! 1077: ref1->ref_len != ref2->ref_len ||
! 1078: bcmp(ref1 + 1, ref2 + 1, ref1->ref_len))
! 1079: return 0;
! 1080:
! 1081: return 1;
! 1082: }
! 1083:
! 1084: #ifdef notyet
! 1085: /*
! 1086: * Go down a chain of IPv4/IPv6/ESP/AH/IPiP chains creating an tag for each
! 1087: * IPsec header encountered. The offset where the first header, as well
! 1088: * as its type are given to us.
! 1089: */
! 1090: struct m_tag *
! 1091: ipsp_parse_headers(struct mbuf *m, int off, u_int8_t proto)
! 1092: {
! 1093: int ipv4sa = 0, s, esphlen = 0, trail = 0, i;
! 1094: SLIST_HEAD(packet_tags, m_tag) tags;
! 1095: unsigned char lasteight[8];
! 1096: struct tdb_ident *tdbi;
! 1097: struct m_tag *mtag;
! 1098: struct tdb *tdb;
! 1099:
! 1100: #ifdef INET
! 1101: struct ip iph;
! 1102: #endif /* INET */
! 1103:
! 1104: #ifdef INET6
! 1105: struct in6_addr ip6_dst;
! 1106: #endif /* INET6 */
! 1107:
! 1108: /* We have to start with a known network protocol. */
! 1109: if (proto != IPPROTO_IPV4 && proto != IPPROTO_IPV6)
! 1110: return NULL;
! 1111:
! 1112: SLIST_INIT(&tags);
! 1113:
! 1114: while (1) {
! 1115: switch (proto) {
! 1116: #ifdef INET
! 1117: case IPPROTO_IPV4: /* Also IPPROTO_IPIP */
! 1118: {
! 1119: /*
! 1120: * Save the IP header (we need both the
! 1121: * address and ip_hl).
! 1122: */
! 1123: m_copydata(m, off, sizeof(struct ip), (caddr_t) &iph);
! 1124: ipv4sa = 1;
! 1125: proto = iph.ip_p;
! 1126: off += iph.ip_hl << 2;
! 1127: break;
! 1128: }
! 1129: #endif /* INET */
! 1130:
! 1131: #ifdef INET6
! 1132: case IPPROTO_IPV6:
! 1133: {
! 1134: int nxtp, l;
! 1135:
! 1136: /* Copy the IPv6 address. */
! 1137: m_copydata(m, off + offsetof(struct ip6_hdr, ip6_dst),
! 1138: sizeof(struct ip6_hdr), (caddr_t) &ip6_dst);
! 1139: ipv4sa = 0;
! 1140:
! 1141: /*
! 1142: * Go down the chain of headers until we encounter a
! 1143: * non-option.
! 1144: */
! 1145: for (l = ip6_nexthdr(m, off, proto, &nxtp); l != -1;
! 1146: l = ip6_nexthdr(m, off, proto, &nxtp)) {
! 1147: off += l;
! 1148: proto = nxtp;
! 1149:
! 1150: /* Construct a tag. */
! 1151: if (nxtp == IPPROTO_AH) {
! 1152: mtag = m_tag_get(PACKET_TAG_IPSEC_IN_CRYPTO_DONE,
! 1153: sizeof(struct tdb_ident),
! 1154: M_NOWAIT);
! 1155:
! 1156: if (mtag == NULL)
! 1157: return SLIST_FIRST(&tags);
! 1158:
! 1159: tdbi = (struct tdb_ident *) (mtag + 1);
! 1160: bzero(tdbi, sizeof(struct tdb_ident));
! 1161:
! 1162: m_copydata(m, off + sizeof(u_int32_t),
! 1163: sizeof(u_int32_t),
! 1164: (caddr_t) &tdbi->spi);
! 1165:
! 1166: tdbi->proto = IPPROTO_AH;
! 1167: tdbi->dst.sin6.sin6_family = AF_INET6;
! 1168: tdbi->dst.sin6.sin6_len =
! 1169: sizeof(struct sockaddr_in6);
! 1170: tdbi->dst.sin6.sin6_addr = ip6_dst;
! 1171: SLIST_INSERT_HEAD(&tags,
! 1172: mtag, m_tag_link);
! 1173: }
! 1174: else
! 1175: if (nxtp == IPPROTO_IPV6)
! 1176: m_copydata(m, off +
! 1177: offsetof(struct ip6_hdr,
! 1178: ip6_dst),
! 1179: sizeof(struct ip6_hdr),
! 1180: (caddr_t) &ip6_dst);
! 1181: }
! 1182: break;
! 1183: }
! 1184: #endif /* INET6 */
! 1185:
! 1186: case IPPROTO_ESP:
! 1187: /* Verify that this has been decrypted. */
! 1188: {
! 1189: union sockaddr_union su;
! 1190: u_int32_t spi;
! 1191:
! 1192: m_copydata(m, off, sizeof(u_int32_t), (caddr_t) &spi);
! 1193: bzero(&su, sizeof(union sockaddr_union));
! 1194:
! 1195: s = spltdb();
! 1196:
! 1197: #ifdef INET
! 1198: if (ipv4sa) {
! 1199: su.sin.sin_family = AF_INET;
! 1200: su.sin.sin_len = sizeof(struct sockaddr_in);
! 1201: su.sin.sin_addr = iph.ip_dst;
! 1202: }
! 1203: #endif /* INET */
! 1204:
! 1205: #ifdef INET6
! 1206: if (!ipv4sa) {
! 1207: su.sin6.sin6_family = AF_INET6;
! 1208: su.sin6.sin6_len = sizeof(struct sockaddr_in6);
! 1209: su.sin6.sin6_addr = ip6_dst;
! 1210: }
! 1211: #endif /* INET6 */
! 1212:
! 1213: tdb = gettdb(spi, &su, IPPROTO_ESP);
! 1214: if (tdb == NULL) {
! 1215: splx(s);
! 1216: return SLIST_FIRST(&tags);
! 1217: }
! 1218:
! 1219: /* How large is the ESP header ? We use this later. */
! 1220: if (tdb->tdb_flags & TDBF_NOREPLAY)
! 1221: esphlen = sizeof(u_int32_t) + tdb->tdb_ivlen;
! 1222: else
! 1223: esphlen = 2 * sizeof(u_int32_t) +
! 1224: tdb->tdb_ivlen;
! 1225:
! 1226: /*
! 1227: * Verify decryption. If the SA is using
! 1228: * random padding (as the "old" ESP SAs were
! 1229: * bound to do, there's nothing we can do to
! 1230: * see if the payload has been decrypted.
! 1231: */
! 1232: if (tdb->tdb_flags & TDBF_RANDOMPADDING) {
! 1233: splx(s);
! 1234: return SLIST_FIRST(&tags);
! 1235: }
! 1236:
! 1237: /* Update the length of trailing ESP authenticators. */
! 1238: if (tdb->tdb_authalgxform)
! 1239: trail += AH_HMAC_HASHLEN;
! 1240:
! 1241: splx(s);
! 1242:
! 1243: /* Copy the last 10 bytes. */
! 1244: m_copydata(m, m->m_pkthdr.len - trail - 8, 8,
! 1245: lasteight);
! 1246:
! 1247: /* Verify the self-describing padding values. */
! 1248: if (lasteight[6] != 0) {
! 1249: if (lasteight[6] != lasteight[5])
! 1250: return SLIST_FIRST(&tags);
! 1251:
! 1252: for (i = 4; lasteight[i + 1] != 1 && i >= 0;
! 1253: i--)
! 1254: if (lasteight[i + 1] !=
! 1255: lasteight[i] + 1)
! 1256: return SLIST_FIRST(&tags);
! 1257: }
! 1258: }
! 1259: /* FALLTHROUGH */
! 1260: case IPPROTO_AH:
! 1261: mtag = m_tag_get(PACKET_TAG_IPSEC_IN_CRYPTO_DONE,
! 1262: sizeof(struct tdb_ident), M_NOWAIT);
! 1263: if (mtag == NULL)
! 1264: return SLIST_FIRST(&tags);
! 1265:
! 1266: tdbi = (struct tdb_ident *) (mtag + 1);
! 1267: bzero(tdbi, sizeof(struct tdb_ident));
! 1268:
! 1269: /* Get SPI off the relevant header. */
! 1270: if (proto == IPPROTO_AH)
! 1271: m_copydata(m, off + sizeof(u_int32_t),
! 1272: sizeof(u_int32_t), (caddr_t) &tdbi->spi);
! 1273: else /* IPPROTO_ESP */
! 1274: m_copydata(m, off, sizeof(u_int32_t),
! 1275: (caddr_t) &tdbi->spi);
! 1276:
! 1277: tdbi->proto = proto; /* AH or ESP */
! 1278:
! 1279: #ifdef INET
! 1280: /* Last network header was IPv4. */
! 1281: if (ipv4sa) {
! 1282: tdbi->dst.sin.sin_family = AF_INET;
! 1283: tdbi->dst.sin.sin_len =
! 1284: sizeof(struct sockaddr_in);
! 1285: tdbi->dst.sin.sin_addr = iph.ip_dst;
! 1286: }
! 1287: #endif /* INET */
! 1288:
! 1289: #ifdef INET6
! 1290: /* Last network header was IPv6. */
! 1291: if (!ipv4sa) {
! 1292: tdbi->dst.sin6.sin6_family = AF_INET6;
! 1293: tdbi->dst.sin6.sin6_len =
! 1294: sizeof(struct sockaddr_in6);
! 1295: tdbi->dst.sin6.sin6_addr = ip6_dst;
! 1296: }
! 1297: #endif /* INET6 */
! 1298:
! 1299: SLIST_INSERT_HEAD(&tags, mtag, m_tag_link);
! 1300:
! 1301: /* Update next protocol/header and header offset. */
! 1302: if (proto == IPPROTO_AH) {
! 1303: u_int8_t foo[2];
! 1304:
! 1305: m_copydata(m, off, 2 * sizeof(u_int8_t), foo);
! 1306: proto = foo[0];
! 1307: off += (foo[1] + 2) << 2;
! 1308: } else {/* IPPROTO_ESP */
! 1309: /* Initialized in IPPROTO_ESP case. */
! 1310: off += esphlen;
! 1311: proto = lasteight[7];
! 1312: }
! 1313: break;
! 1314:
! 1315: default:
! 1316: return SLIST_FIRST(&tags); /* We're done. */
! 1317: }
! 1318: }
! 1319: }
! 1320: #endif /* notyet */
CVSweb