diff options
author | Angelos D. Keromytis <angelos@cvs.openbsd.org> | 2001-06-26 03:52:43 +0000 |
---|---|---|
committer | Angelos D. Keromytis <angelos@cvs.openbsd.org> | 2001-06-26 03:52:43 +0000 |
commit | 61c02c4209050b64dec4b2427ec81f8596fb505e (patch) | |
tree | d15d89acf65e5e15b948f86575a5744bb7fe7a6f | |
parent | 01e8077361902845f37735cc3b7b170810f100d6 (diff) |
KNF
-rw-r--r-- | sys/netinet/ip_ipsp.c | 1902 | ||||
-rw-r--r-- | sys/netinet/ip_ipsp.h | 3 | ||||
-rw-r--r-- | sys/netinet/ip_spd.c | 1392 |
3 files changed, 1623 insertions, 1674 deletions
diff --git a/sys/netinet/ip_ipsp.c b/sys/netinet/ip_ipsp.c index 90d98d84e1e..b74e6526a5d 100644 --- a/sys/netinet/ip_ipsp.c +++ b/sys/netinet/ip_ipsp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_ipsp.c,v 1.135 2001/06/25 05:11:58 angelos Exp $ */ +/* $OpenBSD: ip_ipsp.c,v 1.136 2001/06/26 03:52:40 angelos Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), * Angelos D. Keromytis (kermit@csd.uch.gr), @@ -71,13 +71,13 @@ void tdb_hashstats(void); #endif #ifdef ENCDEBUG -#define DPRINTF(x) if (encdebug) printf x +#define DPRINTF(x) if (encdebug) printf x #else -#define DPRINTF(x) +#define DPRINTF(x) #endif #ifdef __GNUC__ -#define INLINE static __inline +#define INLINE static __inline #endif int ipsp_kern __P((int, char **, int)); @@ -107,21 +107,21 @@ struct ipsec_acquire_head ipsec_acquire_head = */ struct xformsw xformsw[] = { - { XF_IP4, 0, "IPv4 Simple Encapsulation", - ipe4_attach, ipe4_init, ipe4_zeroize, - (int (*)(struct mbuf *, struct tdb *, int, int))ipe4_input, - ipip_output, }, - { XF_AH, XFT_AUTH, "IPsec AH", - ah_attach, ah_init, ah_zeroize, - ah_input, ah_output, }, - { XF_ESP, XFT_CONF|XFT_AUTH, "IPsec ESP", - esp_attach, esp_init, esp_zeroize, - esp_input, esp_output, }, + { XF_IP4, 0, "IPv4 Simple Encapsulation", + ipe4_attach, ipe4_init, ipe4_zeroize, + (int (*)(struct mbuf *, struct tdb *, int, int))ipe4_input, + ipip_output, }, + { XF_AH, XFT_AUTH, "IPsec AH", + ah_attach, ah_init, ah_zeroize, + ah_input, ah_output, }, + { XF_ESP, XFT_CONF|XFT_AUTH, "IPsec ESP", + esp_attach, esp_init, esp_zeroize, + esp_input, esp_output, }, #ifdef TCP_SIGNATURE - { XF_TCPSIGNATURE, XFT_AUTH, "TCP MD5 Signature Option, RFC 2385", - tcp_signature_tdb_attach, tcp_signature_tdb_init, - tcp_signature_tdb_zeroize, tcp_signature_tdb_input, - tcp_signature_tdb_output, } + { XF_TCPSIGNATURE, XFT_AUTH, "TCP MD5 Signature Option, RFC 2385", + tcp_signature_tdb_attach, tcp_signature_tdb_init, + tcp_signature_tdb_zeroize, tcp_signature_tdb_input, + tcp_signature_tdb_output, } #endif /* TCP_SIGNATURE */ }; @@ -129,7 +129,8 @@ struct xformsw *xformswNXFORMSW = &xformsw[sizeof(xformsw)/sizeof(xformsw[0])]; unsigned char ipseczeroes[IPSEC_ZEROES_SIZE]; /* zeroes! */ -#define TDB_HASHSIZE_INIT 32 +#define TDB_HASHSIZE_INIT 32 + static struct tdb **tdbh = NULL; static struct tdb **tdbaddr = NULL; static struct tdb **tdbsrc = NULL; @@ -143,36 +144,34 @@ static int tdb_count; INLINE int tdb_hash(u_int32_t spi, union sockaddr_union *dst, u_int8_t proto) { - static u_int32_t mult1 = 0, mult2 = 0; - u_int8_t *ptr = (u_int8_t *) dst; - int i, shift; - u_int64_t hash; - int val32 = 0; - - while (mult1 == 0) - mult1 = arc4random(); - while (mult2 == 0) - mult2 = arc4random(); - - hash = (spi ^ proto) * mult1; - for (i = 0; i < SA_LEN(&dst->sa); i++) - { - val32 = (val32 << 8) | ptr[i]; - if (i % 4 == 3) - { - hash ^= val32 * mult2; - val32 = 0; + static u_int32_t mult1 = 0, mult2 = 0; + u_int8_t *ptr = (u_int8_t *) dst; + int i, shift; + u_int64_t hash; + int val32 = 0; + + while (mult1 == 0) + mult1 = arc4random(); + while (mult2 == 0) + mult2 = arc4random(); + + hash = (spi ^ proto) * mult1; + for (i = 0; i < SA_LEN(&dst->sa); i++) { + val32 = (val32 << 8) | ptr[i]; + if (i % 4 == 3) { + hash ^= val32 * mult2; + val32 = 0; + } } - } - if (i % 4 != 0) - hash ^= val32 * mult2; + if (i % 4 != 0) + hash ^= val32 * mult2; - shift = ffs(tdb_hashmask + 1); - while ((hash & ~tdb_hashmask) != 0) - hash = (hash >> shift) ^ (hash & tdb_hashmask); + shift = ffs(tdb_hashmask + 1); + while ((hash & ~tdb_hashmask) != 0) + hash = (hash >> shift) ^ (hash & tdb_hashmask); - return hash; + return hash; } /* @@ -181,72 +180,69 @@ tdb_hash(u_int32_t spi, union sockaddr_union *dst, u_int8_t proto) */ u_int32_t reserve_spi(u_int32_t sspi, u_int32_t tspi, union sockaddr_union *src, - union sockaddr_union *dst, u_int8_t sproto, int *errval) + union sockaddr_union *dst, u_int8_t sproto, int *errval) { - struct tdb *tdbp; - u_int32_t spi; - int nums, s; - - /* Don't accept ranges only encompassing reserved SPIs. */ - if (tspi < sspi || tspi <= SPI_RESERVED_MAX) - { - (*errval) = EINVAL; - return 0; - } - - /* Limit the range to not include reserved areas. */ - if (sspi <= SPI_RESERVED_MAX) - sspi = SPI_RESERVED_MAX + 1; - - if (sspi == tspi) /* Asking for a specific SPI */ - nums = 1; - else - nums = 100; /* Arbitrarily chosen */ - - while (nums--) - { - if (sspi == tspi) /* Specific SPI asked */ - spi = tspi; - else /* Range specified */ - spi = sspi + (arc4random() % (tspi - sspi)); - - /* Don't allocate reserved SPIs. */ - if (spi >= SPI_RESERVED_MIN && spi <= SPI_RESERVED_MAX) - continue; - else - spi = htonl(spi); - - /* Check whether we're using this SPI already */ - s = spltdb(); - tdbp = gettdb(spi, dst, sproto); - splx(s); + struct tdb *tdbp; + u_int32_t spi; + int nums, s; - if (tdbp != (struct tdb *) NULL) - continue; - - tdbp = tdb_alloc(); - - tdbp->tdb_spi = spi; - bcopy(&dst->sa, &tdbp->tdb_dst.sa, SA_LEN(&dst->sa)); - bcopy(&src->sa, &tdbp->tdb_src.sa, SA_LEN(&src->sa)); - tdbp->tdb_sproto = sproto; - tdbp->tdb_flags |= TDBF_INVALID; /* Mark SA as invalid for now */ - tdbp->tdb_satype = SADB_SATYPE_UNSPEC; - puttdb(tdbp); - - /* Setup a "silent" expiration (since TDBF_INVALID's set) */ - if (ipsec_keep_invalid > 0) - { - tdbp->tdb_flags |= TDBF_TIMER; - tdbp->tdb_exp_timeout = ipsec_keep_invalid; - timeout_add(&tdbp->tdb_timer_tmo, hz * ipsec_keep_invalid); + /* Don't accept ranges only encompassing reserved SPIs. */ + if (tspi < sspi || tspi <= SPI_RESERVED_MAX) { + (*errval) = EINVAL; + return 0; } - return spi; - } + /* Limit the range to not include reserved areas. */ + if (sspi <= SPI_RESERVED_MAX) + sspi = SPI_RESERVED_MAX + 1; + + if (sspi == tspi) /* Asking for a specific SPI */ + nums = 1; + else + nums = 100; /* Arbitrarily chosen */ + + while (nums--) { + if (sspi == tspi) /* Specific SPI asked */ + spi = tspi; + else /* Range specified */ + spi = sspi + (arc4random() % (tspi - sspi)); + + /* Don't allocate reserved SPIs. */ + if (spi >= SPI_RESERVED_MIN && spi <= SPI_RESERVED_MAX) + continue; + else + spi = htonl(spi); + + /* Check whether we're using this SPI already */ + s = spltdb(); + tdbp = gettdb(spi, dst, sproto); + splx(s); + + if (tdbp != (struct tdb *) NULL) + continue; + + tdbp = tdb_alloc(); + + tdbp->tdb_spi = spi; + bcopy(&dst->sa, &tdbp->tdb_dst.sa, SA_LEN(&dst->sa)); + bcopy(&src->sa, &tdbp->tdb_src.sa, SA_LEN(&src->sa)); + tdbp->tdb_sproto = sproto; + tdbp->tdb_flags |= TDBF_INVALID; /* Mark SA invalid for now */ + tdbp->tdb_satype = SADB_SATYPE_UNSPEC; + puttdb(tdbp); + + /* Setup a "silent" expiration (since TDBF_INVALID's set) */ + if (ipsec_keep_invalid > 0) { + tdbp->tdb_flags |= TDBF_TIMER; + tdbp->tdb_exp_timeout = ipsec_keep_invalid; + timeout_add(&tdbp->tdb_timer_tmo, hz * ipsec_keep_invalid); + } + + return spi; + } - (*errval) = EEXIST; - return 0; + (*errval) = EEXIST; + return 0; } /* @@ -261,21 +257,21 @@ reserve_spi(u_int32_t sspi, u_int32_t tspi, union sockaddr_union *src, struct tdb * gettdb(u_int32_t spi, union sockaddr_union *dst, u_int8_t proto) { - u_int32_t hashval; - struct tdb *tdbp; + u_int32_t hashval; + struct tdb *tdbp; - if (tdbh == NULL) - return (struct tdb *) NULL; + if (tdbh == NULL) + return (struct tdb *) NULL; - hashval = tdb_hash(spi, dst, proto); + hashval = tdb_hash(spi, dst, proto); - for (tdbp = tdbh[hashval]; tdbp != NULL; tdbp = tdbp->tdb_hnext) - if ((tdbp->tdb_spi == spi) && - !bcmp(&tdbp->tdb_dst, dst, SA_LEN(&dst->sa)) && - (tdbp->tdb_sproto == proto)) - break; + for (tdbp = tdbh[hashval]; tdbp != NULL; tdbp = tdbp->tdb_hnext) + if ((tdbp->tdb_spi == spi) && + !bcmp(&tdbp->tdb_dst, dst, SA_LEN(&dst->sa)) && + (tdbp->tdb_sproto == proto)) + break; - return tdbp; + return tdbp; } /* @@ -284,77 +280,64 @@ gettdb(u_int32_t spi, union sockaddr_union *dst, u_int8_t proto) */ struct tdb * gettdbbyaddr(union sockaddr_union *dst, struct ipsec_policy *ipo, - struct mbuf *m, int af) + struct mbuf *m, int af) { - u_int32_t hashval; - struct tdb *tdbp; - - if (tdbaddr == NULL) - return (struct tdb *) NULL; - - hashval = tdb_hash(0, dst, ipo->ipo_sproto); - - for (tdbp = tdbaddr[hashval]; tdbp != NULL; tdbp = tdbp->tdb_anext) - if ((tdbp->tdb_sproto == ipo->ipo_sproto) && - ((tdbp->tdb_flags & TDBF_INVALID) == 0) && - (!bcmp(&tdbp->tdb_dst, dst, SA_LEN(&dst->sa)))) - { - /* - * If the IDs are not set, this was probably a manually-keyed - * SA, so it can be used for any type of traffic. - */ - if (tdbp->tdb_srcid != NULL) - { - if (ipo->ipo_srcid != NULL) - { - if (!ipsp_ref_match(ipo->ipo_srcid, tdbp->tdb_srcid)) - continue; - } - - /* Otherwise, this is fine */ - } - else - if (ipo->ipo_srcid != NULL) - continue; - - if (tdbp->tdb_dstid != NULL) - { - if (ipo->ipo_dstid != NULL) - { - if (!ipsp_ref_match(ipo->ipo_dstid, tdbp->tdb_dstid)) - continue; - } - - /* Otherwise, this is fine */ - } - else - if (ipo->ipo_dstid != NULL) - continue; - - /* Check for credential matches */ - if (tdbp->tdb_local_cred != NULL) - { - if (ipo->ipo_local_cred != NULL) - { - if (!ipsp_ref_match(ipo->ipo_local_cred, - tdbp->tdb_local_cred)) - continue; - } - } - else - if (ipo->ipo_local_cred != NULL) - continue; /* If no credential was used in the TDB, try - * to establish a new SA with the given - * credential, since some type of access control - * may be done on the other side based on that - * credential. - */ + u_int32_t hashval; + struct tdb *tdbp; + + if (tdbaddr == NULL) + return (struct tdb *) NULL; + + hashval = tdb_hash(0, dst, ipo->ipo_sproto); - /* XXX Check for filter matches */ - break; - } + for (tdbp = tdbaddr[hashval]; tdbp != NULL; tdbp = tdbp->tdb_anext) + if ((tdbp->tdb_sproto == ipo->ipo_sproto) && + ((tdbp->tdb_flags & TDBF_INVALID) == 0) && + (!bcmp(&tdbp->tdb_dst, dst, SA_LEN(&dst->sa)))) { + /* + * If the IDs are not set, this was probably a manually-keyed + * SA, so it can be used for any type of traffic. + */ + if (tdbp->tdb_srcid != NULL) { + if (ipo->ipo_srcid != NULL && + !ipsp_ref_match(ipo->ipo_srcid, + tdbp->tdb_srcid)) + continue; + /* Otherwise, this is fine */ + } else if (ipo->ipo_srcid != NULL) + continue; + + if (tdbp->tdb_dstid != NULL) { + if (ipo->ipo_dstid != NULL && + !ipsp_ref_match(ipo->ipo_dstid, + tdbp->tdb_dstid)) + continue; + /* Otherwise, this is fine */ + } else if (ipo->ipo_dstid != NULL) + continue; + + /* Check for credential matches */ + if (tdbp->tdb_local_cred != NULL) { + if (ipo->ipo_local_cred != NULL && + !ipsp_ref_match(ipo->ipo_local_cred, + tdbp->tdb_local_cred)) + continue; + } else if (ipo->ipo_local_cred != NULL) + continue; /* If no credential was used + * in the TDB, try to + * establish a new SA with + * the given credential, + * since some type of access + * control may be done on + * the other side based on + * that credential. + */ + + /* XXX Check for filter matches */ + break; + } - return tdbp; + return tdbp; } /* @@ -363,86 +346,75 @@ gettdbbyaddr(union sockaddr_union *dst, struct ipsec_policy *ipo, */ struct tdb * gettdbbysrc(union sockaddr_union *src, struct ipsec_policy *ipo, - struct mbuf *m, int af) + struct mbuf *m, int af) { - u_int32_t hashval; - struct tdb *tdbp; - - if (tdbsrc == NULL) - return (struct tdb *) NULL; - - hashval = tdb_hash(0, src, ipo->ipo_sproto); - - for (tdbp = tdbsrc[hashval]; tdbp != NULL; tdbp = tdbp->tdb_snext) - if ((tdbp->tdb_sproto == ipo->ipo_sproto) && - ((tdbp->tdb_flags & TDBF_INVALID) == 0) && - (!bcmp(&tdbp->tdb_src, src, SA_LEN(&src->sa)))) - { - /* - * If the IDs are not set, this was probably a manually-keyed - * SA, so it can be used for any type of traffic. - */ - if (tdbp->tdb_srcid != NULL) - { - if (ipo->ipo_dstid != NULL) - { - if (!ipsp_ref_match(ipo->ipo_dstid, tdbp->tdb_srcid)) - continue; - } - - /* Otherwise, this is fine */ - } - else - if (ipo->ipo_dstid != NULL) - continue; - - if (tdbp->tdb_dstid != NULL) - { - if (ipo->ipo_srcid != NULL) - { - if (!ipsp_ref_match(ipo->ipo_srcid, tdbp->tdb_dstid)) - continue; - } - - /* Otherwise, this is fine */ - } - else - if (ipo->ipo_srcid != NULL) - continue; - - /* XXX Check for filter matches */ - break; - } - - return tdbp; + u_int32_t hashval; + struct tdb *tdbp; + + if (tdbsrc == NULL) + return (struct tdb *) NULL; + + hashval = tdb_hash(0, src, ipo->ipo_sproto); + + for (tdbp = tdbsrc[hashval]; tdbp != NULL; tdbp = tdbp->tdb_snext) + if ((tdbp->tdb_sproto == ipo->ipo_sproto) && + ((tdbp->tdb_flags & TDBF_INVALID) == 0) && + (!bcmp(&tdbp->tdb_src, src, SA_LEN(&src->sa)))) { + /* + * If the IDs are not set, this was probably a manually-keyed + * SA, so it can be used for any type of traffic. + */ + if (tdbp->tdb_srcid != NULL) { + if (ipo->ipo_dstid != NULL && + !ipsp_ref_match(ipo->ipo_dstid, + tdbp->tdb_srcid)) + continue; + /* Otherwise, this is fine */ + } else if (ipo->ipo_dstid != NULL) + continue; + + if (tdbp->tdb_dstid != NULL) { + if (ipo->ipo_srcid != NULL && + !ipsp_ref_match(ipo->ipo_srcid, + tdbp->tdb_dstid)) + continue; + /* Otherwise, this is fine */ + } else if (ipo->ipo_srcid != NULL) + continue; + + /* XXX Check for filter matches */ + break; + } + + return tdbp; } #if DDB void tdb_hashstats(void) { - int i, cnt, buckets[16]; - struct tdb *tdbp; - - if (tdbh == NULL) - { - db_printf("no tdb hash table\n"); - return; - } - - bzero (buckets, sizeof(buckets)); - for (i = 0; i <= tdb_hashmask; i++) - { - cnt = 0; - for (tdbp = tdbh[i]; cnt < 16 && tdbp != NULL; tdbp = tdbp->tdb_hnext) - cnt++; - buckets[cnt]++; - } - - db_printf("tdb cnt\t\tbucket cnt\n"); - for (i = 0; i < 16; i++) - if (buckets[i] > 0) - db_printf("%d%c\t\t%d\n", i, i == 15 ? "+" : "", buckets[i]); + int i, cnt, buckets[16]; + struct tdb *tdbp; + + if (tdbh == NULL) { + db_printf("no tdb hash table\n"); + return; + } + + bzero (buckets, sizeof(buckets)); + for (i = 0; i <= tdb_hashmask; i++) { + cnt = 0; + for (tdbp = tdbh[i]; cnt < 16 && tdbp != NULL; + tdbp = tdbp->tdb_hnext) + cnt++; + buckets[cnt]++; + } + + db_printf("tdb cnt\t\tbucket cnt\n"); + for (i = 0; i < 16; i++) + if (buckets[i] > 0) + db_printf("%d%c\t\t%d\n", i, i == 15 ? "+" : "", + buckets[i]); } #endif /* DDB */ @@ -452,23 +424,22 @@ tdb_hashstats(void) int tdb_walk(int (*walker)(struct tdb *, void *, int), void *arg) { - int i, rval = 0; - struct tdb *tdbp, *next; - - if (tdbh == NULL) - return ENOENT; - - for (i = 0; i <= tdb_hashmask; i++) - for (tdbp = tdbh[i]; rval == 0 && tdbp != NULL; tdbp = next) - { - next = tdbp->tdb_hnext; - if (i == tdb_hashmask && next == NULL) - rval = walker(tdbp, (void *)arg, 1); - else - rval = walker(tdbp, (void *)arg, 0); - } - - return rval; + int i, rval = 0; + struct tdb *tdbp, *next; + + if (tdbh == NULL) + return ENOENT; + + for (i = 0; i <= tdb_hashmask; i++) + for (tdbp = tdbh[i]; rval == 0 && tdbp != NULL; tdbp = next) { + next = tdbp->tdb_hnext; + if (i == tdb_hashmask && next == NULL) + rval = walker(tdbp, (void *)arg, 1); + else + rval = walker(tdbp, (void *)arg, 0); + } + + return rval; } /* @@ -535,59 +506,55 @@ tdb_soft_firstuse(void *v) void tdb_rehash(void) { - struct tdb **new_tdbh, **new_tdbaddr, **new_srcaddr, *tdbp, *tdbnp; - u_int i, old_hashmask = tdb_hashmask; - u_int32_t hashval; - - tdb_hashmask = (tdb_hashmask << 1) | 1; - - MALLOC(new_tdbh, struct tdb **, sizeof(struct tdb *) * (tdb_hashmask + 1), - M_TDB, M_WAITOK); - MALLOC(new_tdbaddr, struct tdb **, - sizeof(struct tdb *) * (tdb_hashmask + 1), M_TDB, M_WAITOK); - MALLOC(new_srcaddr, struct tdb **, - sizeof(struct tdb *) * (tdb_hashmask + 1), M_TDB, M_WAITOK); - - bzero(new_tdbh, sizeof(struct tdb *) * (tdb_hashmask + 1)); - bzero(new_tdbaddr, sizeof(struct tdb *) * (tdb_hashmask + 1)); - bzero(new_srcaddr, sizeof(struct tdb *) * (tdb_hashmask + 1)); - - for (i = 0; i <= old_hashmask; i++) - { - for (tdbp = tdbh[i]; tdbp != NULL; tdbp = tdbnp) - { - tdbnp = tdbp->tdb_hnext; - hashval = tdb_hash(tdbp->tdb_spi, &tdbp->tdb_dst, - tdbp->tdb_sproto); - tdbp->tdb_hnext = new_tdbh[hashval]; - new_tdbh[hashval] = tdbp; - } + struct tdb **new_tdbh, **new_tdbaddr, **new_srcaddr, *tdbp, *tdbnp; + u_int i, old_hashmask = tdb_hashmask; + u_int32_t hashval; + + tdb_hashmask = (tdb_hashmask << 1) | 1; + + MALLOC(new_tdbh, struct tdb **, sizeof(struct tdb *) * (tdb_hashmask + 1), + M_TDB, M_WAITOK); + MALLOC(new_tdbaddr, struct tdb **, + sizeof(struct tdb *) * (tdb_hashmask + 1), M_TDB, M_WAITOK); + MALLOC(new_srcaddr, struct tdb **, + sizeof(struct tdb *) * (tdb_hashmask + 1), M_TDB, M_WAITOK); + + bzero(new_tdbh, sizeof(struct tdb *) * (tdb_hashmask + 1)); + bzero(new_tdbaddr, sizeof(struct tdb *) * (tdb_hashmask + 1)); + bzero(new_srcaddr, sizeof(struct tdb *) * (tdb_hashmask + 1)); + + for (i = 0; i <= old_hashmask; i++) { + for (tdbp = tdbh[i]; tdbp != NULL; tdbp = tdbnp) { + tdbnp = tdbp->tdb_hnext; + hashval = tdb_hash(tdbp->tdb_spi, &tdbp->tdb_dst, + tdbp->tdb_sproto); + tdbp->tdb_hnext = new_tdbh[hashval]; + new_tdbh[hashval] = tdbp; + } - for (tdbp = tdbaddr[i]; tdbp != NULL; tdbp = tdbnp) - { - tdbnp = tdbp->tdb_anext; - hashval = tdb_hash(0, &tdbp->tdb_dst, tdbp->tdb_sproto); - tdbp->tdb_anext = new_tdbaddr[hashval]; - new_tdbaddr[hashval] = tdbp; - } + for (tdbp = tdbaddr[i]; tdbp != NULL; tdbp = tdbnp) { + tdbnp = tdbp->tdb_anext; + hashval = tdb_hash(0, &tdbp->tdb_dst, tdbp->tdb_sproto); + tdbp->tdb_anext = new_tdbaddr[hashval]; + new_tdbaddr[hashval] = tdbp; + } - for (tdbp = tdbsrc[i]; tdbp != NULL; tdbp = tdbnp) - { - tdbnp = tdbp->tdb_snext; - hashval = tdb_hash(0, &tdbp->tdb_src, tdbp->tdb_sproto); - tdbp->tdb_snext = new_srcaddr[hashval]; - new_srcaddr[hashval] = tdbp; + for (tdbp = tdbsrc[i]; tdbp != NULL; tdbp = tdbnp) { + tdbnp = tdbp->tdb_snext; + hashval = tdb_hash(0, &tdbp->tdb_src, tdbp->tdb_sproto); + tdbp->tdb_snext = new_srcaddr[hashval]; + new_srcaddr[hashval] = tdbp; + } } - } - FREE(tdbh, M_TDB); - tdbh = new_tdbh; + FREE(tdbh, M_TDB); + tdbh = new_tdbh; - FREE(tdbaddr, M_TDB); - tdbaddr = new_tdbaddr; + FREE(tdbaddr, M_TDB); + tdbaddr = new_tdbaddr; - FREE(tdbsrc, M_TDB); - tdbsrc = new_srcaddr; + FREE(tdbsrc, M_TDB); + tdbsrc = new_srcaddr; } /* @@ -596,57 +563,57 @@ tdb_rehash(void) void puttdb(struct tdb *tdbp) { - u_int32_t hashval; - int s = spltdb(); - - if (tdbh == NULL) - { - MALLOC(tdbh, struct tdb **, sizeof(struct tdb *) * (tdb_hashmask + 1), - M_TDB, M_WAITOK); - MALLOC(tdbaddr, struct tdb **, - sizeof(struct tdb *) * (tdb_hashmask + 1), - M_TDB, M_WAITOK); - MALLOC(tdbsrc, struct tdb **, - sizeof(struct tdb *) * (tdb_hashmask + 1), - M_TDB, M_WAITOK); - - bzero(tdbh, sizeof(struct tdb *) * (tdb_hashmask + 1)); - bzero(tdbaddr, sizeof(struct tdb *) * (tdb_hashmask + 1)); - bzero(tdbsrc, sizeof(struct tdb *) * (tdb_hashmask + 1)); - } - - hashval = tdb_hash(tdbp->tdb_spi, &tdbp->tdb_dst, tdbp->tdb_sproto); - - /* - * Rehash if this tdb would cause a bucket to have more than two items - * and if the number of tdbs exceed 10% of the bucket count. This - * number is arbitratily chosen and is just a measure to not keep rehashing - * when adding and removing tdbs which happens to always end up in the - * same bucket, which is not uncommon when doing manual keying. - */ - if (tdbh[hashval] != NULL && tdbh[hashval]->tdb_hnext != NULL && - tdb_count * 10 > tdb_hashmask + 1) - { - tdb_rehash(); + u_int32_t hashval; + int s = spltdb(); + + if (tdbh == NULL) { + MALLOC(tdbh, struct tdb **, + sizeof(struct tdb *) * (tdb_hashmask + 1), + M_TDB, M_WAITOK); + MALLOC(tdbaddr, struct tdb **, + sizeof(struct tdb *) * (tdb_hashmask + 1), + M_TDB, M_WAITOK); + MALLOC(tdbsrc, struct tdb **, + sizeof(struct tdb *) * (tdb_hashmask + 1), + M_TDB, M_WAITOK); + + bzero(tdbh, sizeof(struct tdb *) * (tdb_hashmask + 1)); + bzero(tdbaddr, sizeof(struct tdb *) * (tdb_hashmask + 1)); + bzero(tdbsrc, sizeof(struct tdb *) * (tdb_hashmask + 1)); + } + hashval = tdb_hash(tdbp->tdb_spi, &tdbp->tdb_dst, tdbp->tdb_sproto); - } - tdbp->tdb_hnext = tdbh[hashval]; - tdbh[hashval] = tdbp; + /* + * Rehash if this tdb would cause a bucket to have more than two items + * and if the number of tdbs exceed 10% of the bucket count. This + * number is arbitratily chosen and is just a measure to not keep rehashing + * when adding and removing tdbs which happens to always end up in the + * same bucket, which is not uncommon when doing manual keying. + */ + if (tdbh[hashval] != NULL && tdbh[hashval]->tdb_hnext != NULL && + tdb_count * 10 > tdb_hashmask + 1) { + tdb_rehash(); + hashval = tdb_hash(tdbp->tdb_spi, &tdbp->tdb_dst, + tdbp->tdb_sproto); + } + + tdbp->tdb_hnext = tdbh[hashval]; + tdbh[hashval] = tdbp; - hashval = tdb_hash(0, &tdbp->tdb_dst, tdbp->tdb_sproto); - tdbp->tdb_anext = tdbaddr[hashval]; - tdbaddr[hashval] = tdbp; + hashval = tdb_hash(0, &tdbp->tdb_dst, tdbp->tdb_sproto); + tdbp->tdb_anext = tdbaddr[hashval]; + tdbaddr[hashval] = tdbp; - hashval = tdb_hash(0, &tdbp->tdb_src, tdbp->tdb_sproto); - tdbp->tdb_snext = tdbsrc[hashval]; - tdbsrc[hashval] = tdbp; + hashval = tdb_hash(0, &tdbp->tdb_src, tdbp->tdb_sproto); + tdbp->tdb_snext = tdbsrc[hashval]; + tdbsrc[hashval] = tdbp; - tdb_count++; + tdb_count++; - ipsec_last_added = time.tv_sec; + ipsec_last_added = time.tv_sec; - splx(s); + splx(s); } /* @@ -655,152 +622,143 @@ puttdb(struct tdb *tdbp) void tdb_delete(struct tdb *tdbp) { - struct ipsec_policy *ipo; - struct tdb *tdbpp; - struct inpcb *inp; - u_int32_t hashval; - int s; - - if (tdbh == NULL) - return; - - hashval = tdb_hash(tdbp->tdb_spi, &tdbp->tdb_dst, tdbp->tdb_sproto); - - s = spltdb(); - if (tdbh[hashval] == tdbp) - { - tdbpp = tdbp; - tdbh[hashval] = tdbp->tdb_hnext; - } - else - for (tdbpp = tdbh[hashval]; tdbpp != NULL; tdbpp = tdbpp->tdb_hnext) - if (tdbpp->tdb_hnext == tdbp) - { - tdbpp->tdb_hnext = tdbp->tdb_hnext; - tdbpp = tdbp; - break; + struct ipsec_policy *ipo; + struct tdb *tdbpp; + struct inpcb *inp; + u_int32_t hashval; + int s; + + if (tdbh == NULL) + return; + + hashval = tdb_hash(tdbp->tdb_spi, &tdbp->tdb_dst, tdbp->tdb_sproto); + + s = spltdb(); + if (tdbh[hashval] == tdbp) { + tdbpp = tdbp; + tdbh[hashval] = tdbp->tdb_hnext; + } else { + for (tdbpp = tdbh[hashval]; tdbpp != NULL; + tdbpp = tdbpp->tdb_hnext) { + if (tdbpp->tdb_hnext == tdbp) { + tdbpp->tdb_hnext = tdbp->tdb_hnext; + tdbpp = tdbp; + break; + } + } } - tdbp->tdb_hnext = NULL; - - hashval = tdb_hash(0, &tdbp->tdb_dst, tdbp->tdb_sproto); - - if (tdbaddr[hashval] == tdbp) - { - tdbpp = tdbp; - tdbaddr[hashval] = tdbp->tdb_anext; - } - else - for (tdbpp = tdbaddr[hashval]; tdbpp != NULL; tdbpp = tdbpp->tdb_anext) - if (tdbpp->tdb_anext == tdbp) - { - tdbpp->tdb_anext = tdbp->tdb_anext; - tdbpp = tdbp; - break; + tdbp->tdb_hnext = NULL; + + hashval = tdb_hash(0, &tdbp->tdb_dst, tdbp->tdb_sproto); + + if (tdbaddr[hashval] == tdbp) { + tdbpp = tdbp; + tdbaddr[hashval] = tdbp->tdb_anext; + } else { + for (tdbpp = tdbaddr[hashval]; tdbpp != NULL; + tdbpp = tdbpp->tdb_anext) { + if (tdbpp->tdb_anext == tdbp) { + tdbpp->tdb_anext = tdbp->tdb_anext; + tdbpp = tdbp; + break; + } + } } - hashval = tdb_hash(0, &tdbp->tdb_src, tdbp->tdb_sproto); - - if (tdbsrc[hashval] == tdbp) - { - tdbpp = tdbp; - tdbsrc[hashval] = tdbp->tdb_snext; - } - else - for (tdbpp = tdbsrc[hashval]; tdbpp != NULL; tdbpp = tdbpp->tdb_snext) - if (tdbpp->tdb_snext == tdbp) - { - tdbpp->tdb_snext = tdbp->tdb_snext; - tdbpp = tdbp; - break; + hashval = tdb_hash(0, &tdbp->tdb_src, tdbp->tdb_sproto); + + if (tdbsrc[hashval] == tdbp) { + tdbpp = tdbp; + tdbsrc[hashval] = tdbp->tdb_snext; } + else { + for (tdbpp = tdbsrc[hashval]; tdbpp != NULL; + tdbpp = tdbpp->tdb_snext) { + if (tdbpp->tdb_snext == tdbp) { + tdbpp->tdb_snext = tdbp->tdb_snext; + tdbpp = tdbp; + break; + } + } + } + + tdbp->tdb_snext = NULL; - tdbp->tdb_snext = NULL; - - if (tdbp->tdb_xform) - { - (*(tdbp->tdb_xform->xf_zeroize))(tdbp); - tdbp->tdb_xform = NULL; - } - - /* Cleanup inp references */ - for (inp = TAILQ_FIRST(&tdbp->tdb_inp_in); inp; - inp = TAILQ_FIRST(&tdbp->tdb_inp_in)) - { - TAILQ_REMOVE(&tdbp->tdb_inp_in, inp, inp_tdb_in_next); - inp->inp_tdb_in = NULL; - } - - for (inp = TAILQ_FIRST(&tdbp->tdb_inp_out); inp; - inp = TAILQ_FIRST(&tdbp->tdb_inp_out)) - { - TAILQ_REMOVE(&tdbp->tdb_inp_out, inp, inp_tdb_out_next); - inp->inp_tdb_out = NULL; - } - - /* Cleanup SPD references */ - for (ipo = TAILQ_FIRST(&tdbp->tdb_policy_head); ipo; - ipo = TAILQ_FIRST(&tdbp->tdb_policy_head)) - { - TAILQ_REMOVE(&tdbp->tdb_policy_head, ipo, ipo_tdb_next); - ipo->ipo_tdb = NULL; - ipo->ipo_last_searched = 0; /* Force a re-search */ - } - - /* Remove expiration timeouts. */ - tdbp->tdb_flags &= ~(TDBF_FIRSTUSE | TDBF_SOFT_FIRSTUSE | TDBF_TIMER | - TDBF_SOFT_TIMER); - timeout_del(&tdbp->tdb_timer_tmo); - timeout_del(&tdbp->tdb_first_tmo); - timeout_del(&tdbp->tdb_stimer_tmo); - timeout_del(&tdbp->tdb_sfirst_tmo); - - if (tdbp->tdb_local_auth) - { - ipsp_reffree(tdbp->tdb_local_auth); - tdbp->tdb_local_auth = NULL; - } - - if (tdbp->tdb_remote_auth) - { - ipsp_reffree(tdbp->tdb_remote_auth); - tdbp->tdb_remote_auth = NULL; - } - - if (tdbp->tdb_srcid) - { - ipsp_reffree(tdbp->tdb_srcid); - tdbp->tdb_srcid = NULL; - } - - if (tdbp->tdb_dstid) - { - ipsp_reffree(tdbp->tdb_dstid); - tdbp->tdb_dstid = NULL; - } - - if (tdbp->tdb_local_cred) - { - ipsp_reffree(tdbp->tdb_local_cred); - tdbp->tdb_local_cred = NULL; - } - - if (tdbp->tdb_remote_cred) - { - ipsp_reffree(tdbp->tdb_remote_cred); - tdbp->tdb_local_cred = NULL; - } - - if ((tdbp->tdb_onext) && (tdbp->tdb_onext->tdb_inext == tdbp)) - tdbp->tdb_onext->tdb_inext = NULL; - - if ((tdbp->tdb_inext) && (tdbp->tdb_inext->tdb_onext == tdbp)) - tdbp->tdb_inext->tdb_onext = NULL; - - FREE(tdbp, M_TDB); - tdb_count--; - - splx(s); + if (tdbp->tdb_xform) { + (*(tdbp->tdb_xform->xf_zeroize))(tdbp); + tdbp->tdb_xform = NULL; + } + + /* Cleanup inp references */ + for (inp = TAILQ_FIRST(&tdbp->tdb_inp_in); inp; + inp = TAILQ_FIRST(&tdbp->tdb_inp_in)) { + TAILQ_REMOVE(&tdbp->tdb_inp_in, inp, inp_tdb_in_next); + inp->inp_tdb_in = NULL; + } + + for (inp = TAILQ_FIRST(&tdbp->tdb_inp_out); inp; + inp = TAILQ_FIRST(&tdbp->tdb_inp_out)) { + TAILQ_REMOVE(&tdbp->tdb_inp_out, inp, inp_tdb_out_next); + inp->inp_tdb_out = NULL; + } + + /* Cleanup SPD references */ + for (ipo = TAILQ_FIRST(&tdbp->tdb_policy_head); ipo; + ipo = TAILQ_FIRST(&tdbp->tdb_policy_head)) { + TAILQ_REMOVE(&tdbp->tdb_policy_head, ipo, ipo_tdb_next); + ipo->ipo_tdb = NULL; + ipo->ipo_last_searched = 0; /* Force a re-search */ + } + + /* Remove expiration timeouts. */ + tdbp->tdb_flags &= ~(TDBF_FIRSTUSE | TDBF_SOFT_FIRSTUSE | TDBF_TIMER | + TDBF_SOFT_TIMER); + timeout_del(&tdbp->tdb_timer_tmo); + timeout_del(&tdbp->tdb_first_tmo); + timeout_del(&tdbp->tdb_stimer_tmo); + timeout_del(&tdbp->tdb_sfirst_tmo); + + if (tdbp->tdb_local_auth) { + ipsp_reffree(tdbp->tdb_local_auth); + tdbp->tdb_local_auth = NULL; + } + + if (tdbp->tdb_remote_auth) { + ipsp_reffree(tdbp->tdb_remote_auth); + tdbp->tdb_remote_auth = NULL; + } + + if (tdbp->tdb_srcid) { + ipsp_reffree(tdbp->tdb_srcid); + tdbp->tdb_srcid = NULL; + } + + if (tdbp->tdb_dstid) { + ipsp_reffree(tdbp->tdb_dstid); + tdbp->tdb_dstid = NULL; + } + + if (tdbp->tdb_local_cred) { + ipsp_reffree(tdbp->tdb_local_cred); + tdbp->tdb_local_cred = NULL; + } + + if (tdbp->tdb_remote_cred) { + ipsp_reffree(tdbp->tdb_remote_cred); + tdbp->tdb_local_cred = NULL; + } + + if ((tdbp->tdb_onext) && (tdbp->tdb_onext->tdb_inext == tdbp)) + tdbp->tdb_onext->tdb_inext = NULL; + + if ((tdbp->tdb_inext) && (tdbp->tdb_inext->tdb_onext == tdbp)) + tdbp->tdb_inext->tdb_onext = NULL; + + FREE(tdbp, M_TDB); + tdb_count--; + + splx(s); } /* @@ -839,252 +797,253 @@ tdb_alloc(void) int tdb_init(struct tdb *tdbp, u_int16_t alg, struct ipsecinit *ii) { - struct xformsw *xsp; - int err; + struct xformsw *xsp; + int err; - for (xsp = xformsw; xsp < xformswNXFORMSW; xsp++) - if (xsp->xf_type == alg) - { - err = (*(xsp->xf_init))(tdbp, xsp, ii); + for (xsp = xformsw; xsp < xformswNXFORMSW; xsp++) { + if (xsp->xf_type == alg) { + err = (*(xsp->xf_init))(tdbp, xsp, ii); - /* Clear possible pending acquires */ - if (!err) - ipsp_clear_acquire(tdbp); + /* Clear possible pending acquires */ + if (!err) + ipsp_clear_acquire(tdbp); - return err; - } + return err; + } + } - DPRINTF(("tdb_init(): no alg %d for spi %08x, addr %s, proto %d\n", - alg, ntohl(tdbp->tdb_spi), ipsp_address(tdbp->tdb_dst), - tdbp->tdb_sproto)); + DPRINTF(("tdb_init(): no alg %d for spi %08x, addr %s, proto %d\n", + alg, ntohl(tdbp->tdb_spi), ipsp_address(tdbp->tdb_dst), + tdbp->tdb_sproto)); - return EINVAL; + return EINVAL; } #ifdef KERNFS /* - * Used by kernfs. + * Print TDB information on a buffer. */ int -ipsp_kern(int off, char **bufp, int len) +ipsp_print_tdb(struct tdb *tdb, char *buffer) { - static char buffer[IPSEC_KERNFS_BUFSIZE]; - struct tdb *tdb; - int l, i, s, k; - - struct ctlname ipspflags[] = { \ - { "unique", TDBF_UNIQUE }, \ - { "invalid", TDBF_INVALID }, \ - { "halfiv", TDBF_HALFIV }, \ - { "pfs", TDBF_PFS }, \ - { "tunneling", TDBF_TUNNELING }, \ - { "noreplay", TDBF_NOREPLAY }, \ - { "random padding", TDBF_RANDOMPADDING }, \ - { "skipcrypto", TDBF_SKIPCRYPTO }, \ - { "usedtunnel", TDBF_USEDTUNNEL }, \ - }; - - if (bufp == NULL) - return 0; - - bzero(buffer, IPSEC_KERNFS_BUFSIZE); - *bufp = buffer; - - if (off == 0) - { - kernfs_epoch++; - l = sprintf(buffer, "Hashmask: %d, policy entries: %d\n", tdb_hashmask, - ipsec_in_use); - return l; - } - - if (tdbh == NULL) - return 0; - - for (i = 0; i <= tdb_hashmask; i++) - { - s = spltdb(); - for (tdb = tdbh[i]; tdb; tdb = tdb->tdb_hnext) - if (tdb->tdb_epoch != kernfs_epoch) - { - tdb->tdb_epoch = kernfs_epoch; - - l = sprintf(buffer, - "SPI = %08x, Destination = %s, Sproto = %u\n", - ntohl(tdb->tdb_spi), - ipsp_address(tdb->tdb_dst), tdb->tdb_sproto); - - l += sprintf(buffer + l, "\tEstablished %d seconds ago\n", - time.tv_sec - tdb->tdb_established); - - l += sprintf(buffer + l, "\tSource = %s", - ipsp_address(tdb->tdb_src)); - - if (tdb->tdb_proxy.sa.sa_family) + int l, i, k; + + struct ctlname ipspflags[] = { \ + { "unique", TDBF_UNIQUE }, \ + { "invalid", TDBF_INVALID }, \ + { "halfiv", TDBF_HALFIV }, \ + { "pfs", TDBF_PFS }, \ + { "tunneling", TDBF_TUNNELING }, \ + { "noreplay", TDBF_NOREPLAY }, \ + { "random padding", TDBF_RANDOMPADDING }, \ + { "skipcrypto", TDBF_SKIPCRYPTO }, \ + { "usedtunnel", TDBF_USEDTUNNEL }, \ + }; + + l = sprintf(buffer, "SPI = %08x, Destination = %s, Sproto = %u\n", + ntohl(tdb->tdb_spi), ipsp_address(tdb->tdb_dst), tdb->tdb_sproto); + + l += sprintf(buffer + l, "\tEstablished %d seconds ago\n", + time.tv_sec - tdb->tdb_established); + + l += sprintf(buffer + l, "\tSource = %s", ipsp_address(tdb->tdb_src)); + + if (tdb->tdb_proxy.sa.sa_family) l += sprintf(buffer + l, ", Proxy = %s\n", - ipsp_address(tdb->tdb_proxy)); - else + ipsp_address(tdb->tdb_proxy)); + else l += sprintf(buffer + l, "\n"); - if (tdb->tdb_mtu && tdb->tdb_mtutimeout > time.tv_sec) - l += sprintf(buffer + l, - "\tMTU: %d, expires in %qu seconds\n", - tdb->tdb_mtu, tdb->tdb_mtutimeout - time.tv_sec); + if (tdb->tdb_mtu && tdb->tdb_mtutimeout > time.tv_sec) + l += sprintf(buffer + l, "\tMTU: %d, expires in %qu seconds\n", + tdb->tdb_mtu, tdb->tdb_mtutimeout - time.tv_sec); - if (tdb->tdb_local_cred) - l += sprintf(buffer + l, "\tLocal credential type %d\n", ((struct ipsec_ref *) tdb->tdb_local_cred)->ref_type); + if (tdb->tdb_local_cred) + l += sprintf(buffer + l, "\tLocal credential type %d\n", + ((struct ipsec_ref *) tdb->tdb_local_cred)->ref_type); - if (tdb->tdb_remote_cred) - l += sprintf(buffer + l, "\tRemote credential type %d\n", ((struct ipsec_ref *) tdb->tdb_remote_cred)->ref_type); + if (tdb->tdb_remote_cred) + l += sprintf(buffer + l, "\tRemote credential type %d\n", + ((struct ipsec_ref *) tdb->tdb_remote_cred)->ref_type); - if (tdb->tdb_local_auth) - l += sprintf(buffer + l, "\tLocal auth type %d\n", ((struct ipsec_ref *) tdb->tdb_local_auth)->ref_type); + if (tdb->tdb_local_auth) + l += sprintf(buffer + l, "\tLocal auth type %d\n", + ((struct ipsec_ref *) tdb->tdb_local_auth)->ref_type); - if (tdb->tdb_remote_auth) - l += sprintf(buffer + l, "\tRemote auth type %d\n", ((struct ipsec_ref *) tdb->tdb_remote_auth)->ref_type); + if (tdb->tdb_remote_auth) + l += sprintf(buffer + l, "\tRemote auth type %d\n", + ((struct ipsec_ref *) tdb->tdb_remote_auth)->ref_type); - l += sprintf(buffer + l, "\tFlags (%08x) = <", tdb->tdb_flags); + l += sprintf(buffer + l, "\tFlags (%08x) = <", tdb->tdb_flags); - if ((tdb->tdb_flags & ~(TDBF_TIMER | TDBF_BYTES | - TDBF_ALLOCATIONS | TDBF_FIRSTUSE | - TDBF_SOFT_TIMER | TDBF_SOFT_BYTES | - TDBF_SOFT_FIRSTUSE | - TDBF_SOFT_ALLOCATIONS)) == 0) + if ((tdb->tdb_flags & ~(TDBF_TIMER | TDBF_BYTES | TDBF_ALLOCATIONS | + TDBF_FIRSTUSE | TDBF_SOFT_TIMER | TDBF_SOFT_BYTES | + TDBF_SOFT_FIRSTUSE | TDBF_SOFT_ALLOCATIONS)) == 0) l += sprintf(buffer + l, "none>\n"); - else - { - /* We can reuse variable 'i' here, since we're not looping */ + else { for (k = 0, i = 0; - k < sizeof(ipspflags) / sizeof(struct ctlname); k++) - if (tdb->tdb_flags & ipspflags[k].ctl_type) - { - l += sprintf(buffer + l, "%s,", ipspflags[k].ctl_name); - i = 1; - } + k < sizeof(ipspflags) / sizeof(struct ctlname); k++) { + if (tdb->tdb_flags & ipspflags[k].ctl_type) { + l += sprintf(buffer + l, "%s,", + ipspflags[k].ctl_name); + i = 1; + } + } - if (i) /* If we added flags, remove trailing comma */ - l--; - l += sprintf(buffer + l, ">\n"); - } + /* If we added flags, remove trailing comma. */ + if (i) + l--; + l += sprintf(buffer + l, ">\n"); + } - l += sprintf(buffer + l, "\tCrypto ID: %qu\n", tdb->tdb_cryptoid); + l += sprintf(buffer + l, "\tCrypto ID: %qu\n", tdb->tdb_cryptoid); - if (tdb->tdb_xform) + if (tdb->tdb_xform) l += sprintf(buffer + l, "\txform = <%s>\n", - tdb->tdb_xform->xf_name); + tdb->tdb_xform->xf_name); - if (tdb->tdb_encalgxform) + if (tdb->tdb_encalgxform) l += sprintf(buffer + l, "\t\tEncryption = <%s>\n", - tdb->tdb_encalgxform->name); + tdb->tdb_encalgxform->name); - if (tdb->tdb_authalgxform) + if (tdb->tdb_authalgxform) l += sprintf(buffer + l, "\t\tAuthentication = <%s>\n", - tdb->tdb_authalgxform->name); - - if (tdb->tdb_onext) - l += sprintf(buffer + l, - "\tNext SA: SPI = %08x, " - "Destination = %s, Sproto = %u\n", - ntohl(tdb->tdb_onext->tdb_spi), - ipsp_address(tdb->tdb_onext->tdb_dst), - tdb->tdb_onext->tdb_sproto); + tdb->tdb_authalgxform->name); - if (tdb->tdb_inext) + if (tdb->tdb_onext) l += sprintf(buffer + l, - "\tPrevious SA: SPI = %08x, " - "Destination = %s, Sproto = %u\n", - ntohl(tdb->tdb_inext->tdb_spi), - ipsp_address(tdb->tdb_inext->tdb_dst), - tdb->tdb_inext->tdb_sproto); - - l += sprintf(buffer + l, "\t%qu bytes processed by this SA\n", - tdb->tdb_cur_bytes); - - if (tdb->tdb_last_used) + "\tNext SA: SPI = %08x, Destination = %s, Sproto = %u\n", + ntohl(tdb->tdb_onext->tdb_spi), + ipsp_address(tdb->tdb_onext->tdb_dst), + tdb->tdb_onext->tdb_sproto); + + if (tdb->tdb_inext) + l += sprintf(buffer + l, "\tPrevious SA: SPI = %08x, " + "Destination = %s, Sproto = %u\n", + ntohl(tdb->tdb_inext->tdb_spi), + ipsp_address(tdb->tdb_inext->tdb_dst), + tdb->tdb_inext->tdb_sproto); + + l += sprintf(buffer + l, "\t%qu bytes processed by this SA\n", + tdb->tdb_cur_bytes); + + if (tdb->tdb_last_used) l += sprintf(buffer + l, "\tLast used %qu seconds ago\n", - time.tv_sec - tdb->tdb_last_used); + time.tv_sec - tdb->tdb_last_used); - if (tdb->tdb_last_marked) - l += sprintf(buffer + l, - "\tLast marked/unmarked %qu seconds ago\n", - time.tv_sec - tdb->tdb_last_marked); + if (tdb->tdb_last_marked) + l += sprintf(buffer + l, + "\tLast marked/unmarked %qu seconds ago\n", + time.tv_sec - tdb->tdb_last_marked); - l += sprintf(buffer + l, "\tExpirations:\n"); + l += sprintf(buffer + l, "\tExpirations:\n"); - if (tdb->tdb_flags & TDBF_TIMER) + if (tdb->tdb_flags & TDBF_TIMER) l += sprintf(buffer + l, - "\t\tHard expiration(1) in %qu seconds\n", - tdb->tdb_established + tdb->tdb_exp_timeout - - time.tv_sec); + "\t\tHard expiration(1) in %qu seconds\n", + tdb->tdb_established + tdb->tdb_exp_timeout - time.tv_sec); - if (tdb->tdb_flags & TDBF_SOFT_TIMER) + if (tdb->tdb_flags & TDBF_SOFT_TIMER) l += sprintf(buffer + l, - "\t\tSoft expiration(1) in %qu seconds\n", - tdb->tdb_established + tdb->tdb_soft_timeout - - time.tv_sec); + "\t\tSoft expiration(1) in %qu seconds\n", + tdb->tdb_established + tdb->tdb_soft_timeout - + time.tv_sec); - if (tdb->tdb_flags & TDBF_BYTES) + if (tdb->tdb_flags & TDBF_BYTES) l += sprintf(buffer + l, - "\t\tHard expiration after %qu bytes\n", - tdb->tdb_exp_bytes); + "\t\tHard expiration after %qu bytes\n", + tdb->tdb_exp_bytes); - if (tdb->tdb_flags & TDBF_SOFT_BYTES) + if (tdb->tdb_flags & TDBF_SOFT_BYTES) l += sprintf(buffer + l, - "\t\tSoft expiration after %qu bytes\n", - tdb->tdb_soft_bytes); + "\t\tSoft expiration after %qu bytes\n", + tdb->tdb_soft_bytes); - if (tdb->tdb_flags & TDBF_ALLOCATIONS) + if (tdb->tdb_flags & TDBF_ALLOCATIONS) l += sprintf(buffer + l, - "\t\tHard expiration after %u flows\n", - tdb->tdb_exp_allocations); + "\t\tHard expiration after %u flows\n", + tdb->tdb_exp_allocations); - if (tdb->tdb_flags & TDBF_SOFT_ALLOCATIONS) + if (tdb->tdb_flags & TDBF_SOFT_ALLOCATIONS) l += sprintf(buffer + l, - "\t\tSoft expiration after %u flows\n", - tdb->tdb_soft_allocations); - - if (tdb->tdb_flags & TDBF_FIRSTUSE) - { - if (tdb->tdb_first_use) - l += sprintf(buffer + l, - "\t\tHard expiration(2) in %qu seconds\n", - (tdb->tdb_first_use + - tdb->tdb_exp_first_use) - time.tv_sec); - else - l += sprintf(buffer + l, - "\t\tHard expiration in %qu seconds " - "after first use\n", - tdb->tdb_exp_first_use); - } - - if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE) - { - if (tdb->tdb_first_use) - l += sprintf(buffer + l, - "\t\tSoft expiration(2) in %qu seconds\n", - (tdb->tdb_first_use + - tdb->tdb_soft_first_use) - time.tv_sec); - else - l += sprintf(buffer + l, - "\t\tSoft expiration in %qu seconds " - "after first use\n", - tdb->tdb_soft_first_use); - } - - if (!(tdb->tdb_flags & - (TDBF_TIMER | TDBF_SOFT_TIMER | TDBF_BYTES | - TDBF_SOFT_ALLOCATIONS | TDBF_ALLOCATIONS | - TDBF_SOFT_BYTES | TDBF_FIRSTUSE | TDBF_SOFT_FIRSTUSE))) + "\t\tSoft expiration after %u flows\n", + tdb->tdb_soft_allocations); + + if (tdb->tdb_flags & TDBF_FIRSTUSE) { + if (tdb->tdb_first_use) + l += sprintf(buffer + l, + "\t\tHard expiration(2) in %qu seconds\n", + (tdb->tdb_first_use + tdb->tdb_exp_first_use) - + time.tv_sec); + else + l += sprintf(buffer + l, + "\t\tHard expiration in %qu seconds " + "after first use\n", + tdb->tdb_exp_first_use); + } + + if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE) { + if (tdb->tdb_first_use) + l += sprintf(buffer + l, + "\t\tSoft expiration(2) in %qu seconds\n", + (tdb->tdb_first_use + tdb->tdb_soft_first_use) - + time.tv_sec); + else + l += sprintf(buffer + l, + "\t\tSoft expiration in %qu seconds " + "after first use\n", tdb->tdb_soft_first_use); + } + + if (!(tdb->tdb_flags & + (TDBF_TIMER | TDBF_SOFT_TIMER | TDBF_BYTES | + TDBF_SOFT_ALLOCATIONS | TDBF_ALLOCATIONS | + TDBF_SOFT_BYTES | TDBF_FIRSTUSE | TDBF_SOFT_FIRSTUSE))) l += sprintf(buffer + l, "\t\t(none)\n"); - l += sprintf(buffer + l, "\n"); + l += sprintf(buffer + l, "\n"); - splx(s); - return l; - } - splx(s); - } - return 0; + return l; +} + +/* + * Used by kernfs. + */ +int +ipsp_kern(int off, char **bufp, int len) +{ + static char buffer[IPSEC_KERNFS_BUFSIZE]; + struct tdb *tdb; + int i, s, l; + + if (bufp == NULL) + return 0; + + bzero(buffer, IPSEC_KERNFS_BUFSIZE); + *bufp = buffer; + + if (off == 0) { + kernfs_epoch++; + l = sprintf(buffer, "Hashmask: %d, policy entries: %d\n", + tdb_hashmask, ipsec_in_use); + return l; + } + + if (tdbh == NULL) + return 0; + + for (i = 0; i <= tdb_hashmask; i++) { + s = spltdb(); + for (tdb = tdbh[i]; tdb; tdb = tdb->tdb_hnext) { + if (tdb->tdb_epoch != kernfs_epoch) { + tdb->tdb_epoch = kernfs_epoch; + l = ipsp_print_tdb(tdb, buffer); + splx(s); + return l; + } + } + splx(s); + } + return 0; } #endif /* KERNFS */ @@ -1094,28 +1053,25 @@ ipsp_kern(int off, char **bufp, int len) u_int8_t get_sa_require(struct inpcb *inp) { - u_int8_t sareq = 0; - - if (inp != NULL) - { - sareq |= inp->inp_seclevel[SL_AUTH] >= IPSEC_LEVEL_USE ? - NOTIFY_SATYPE_AUTH : 0; - sareq |= inp->inp_seclevel[SL_ESP_TRANS] >= IPSEC_LEVEL_USE ? - NOTIFY_SATYPE_CONF : 0; - sareq |= inp->inp_seclevel[SL_ESP_NETWORK] >= IPSEC_LEVEL_USE ? - NOTIFY_SATYPE_TUNNEL : 0; - } - else - { - sareq |= ipsec_auth_default_level >= IPSEC_LEVEL_USE ? - NOTIFY_SATYPE_AUTH : 0; - sareq |= ipsec_esp_trans_default_level >= IPSEC_LEVEL_USE ? - NOTIFY_SATYPE_CONF : 0; - sareq |= ipsec_esp_network_default_level >= IPSEC_LEVEL_USE ? - NOTIFY_SATYPE_TUNNEL : 0; - } - - return (sareq); + u_int8_t sareq = 0; + + if (inp != NULL) { + sareq |= inp->inp_seclevel[SL_AUTH] >= IPSEC_LEVEL_USE ? + NOTIFY_SATYPE_AUTH : 0; + sareq |= inp->inp_seclevel[SL_ESP_TRANS] >= IPSEC_LEVEL_USE ? + NOTIFY_SATYPE_CONF : 0; + sareq |= inp->inp_seclevel[SL_ESP_NETWORK] >= IPSEC_LEVEL_USE ? + NOTIFY_SATYPE_TUNNEL : 0; + } else { + sareq |= ipsec_auth_default_level >= IPSEC_LEVEL_USE ? + NOTIFY_SATYPE_AUTH : 0; + sareq |= ipsec_esp_trans_default_level >= IPSEC_LEVEL_USE ? + NOTIFY_SATYPE_CONF : 0; + sareq |= ipsec_esp_network_default_level >= IPSEC_LEVEL_USE ? + NOTIFY_SATYPE_TUNNEL : 0; + } + + return (sareq); } /* @@ -1124,96 +1080,90 @@ get_sa_require(struct inpcb *inp) void tdb_add_inp(struct tdb *tdb, struct inpcb *inp, int inout) { - if (inout) - { - if (inp->inp_tdb_in) - { - if (inp->inp_tdb_in == tdb) - return; - - TAILQ_REMOVE(&inp->inp_tdb_in->tdb_inp_in, inp, inp_tdb_in_next); - } - - inp->inp_tdb_in = tdb; - TAILQ_INSERT_TAIL(&tdb->tdb_inp_in, inp, inp_tdb_in_next); - } - else - { - if (inp->inp_tdb_out) - { - if (inp->inp_tdb_out == tdb) - return; - - TAILQ_REMOVE(&inp->inp_tdb_out->tdb_inp_out, inp, - inp_tdb_out_next); - } - - inp->inp_tdb_out = tdb; - TAILQ_INSERT_TAIL(&tdb->tdb_inp_out, inp, inp_tdb_out_next); - } + if (inout) { + if (inp->inp_tdb_in) { + if (inp->inp_tdb_in == tdb) + return; + + TAILQ_REMOVE(&inp->inp_tdb_in->tdb_inp_in, inp, + inp_tdb_in_next); + } + + inp->inp_tdb_in = tdb; + TAILQ_INSERT_TAIL(&tdb->tdb_inp_in, inp, inp_tdb_in_next); + } else { + if (inp->inp_tdb_out) { + if (inp->inp_tdb_out == tdb) + return; + + TAILQ_REMOVE(&inp->inp_tdb_out->tdb_inp_out, inp, + inp_tdb_out_next); + } + + inp->inp_tdb_out = tdb; + TAILQ_INSERT_TAIL(&tdb->tdb_inp_out, inp, inp_tdb_out_next); + } } /* Return a printable string for the IPv4 address. */ char * inet_ntoa4(struct in_addr ina) { - static char buf[4][4 * sizeof "123" + 4]; - unsigned char *ucp = (unsigned char *) &ina; - static int i = 3; + static char buf[4][4 * sizeof "123" + 4]; + unsigned char *ucp = (unsigned char *) &ina; + static int i = 3; - i = (i + 1) % 4; - sprintf(buf[i], "%d.%d.%d.%d", ucp[0] & 0xff, ucp[1] & 0xff, + i = (i + 1) % 4; + sprintf(buf[i], "%d.%d.%d.%d", ucp[0] & 0xff, ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff); - return (buf[i]); + return (buf[i]); } /* Return a printable string for the address. */ char * ipsp_address(union sockaddr_union sa) { - switch (sa.sa.sa_family) - { + switch (sa.sa.sa_family) { #if INET case AF_INET: - return inet_ntoa4(sa.sin.sin_addr); + return inet_ntoa4(sa.sin.sin_addr); #endif /* INET */ #if INET6 case AF_INET6: - return ip6_sprintf(&sa.sin6.sin6_addr); + return ip6_sprintf(&sa.sin6.sin6_addr); #endif /* INET6 */ default: - return "(unknown address family)"; - } + return "(unknown address family)"; + } } /* Check whether an IP{4,6} address is unspecified. */ int ipsp_is_unspecified(union sockaddr_union addr) { - switch (addr.sa.sa_family) - { + switch (addr.sa.sa_family) { #ifdef INET case AF_INET: - if (addr.sin.sin_addr.s_addr == INADDR_ANY) - return 1; - else - return 0; + if (addr.sin.sin_addr.s_addr == INADDR_ANY) + return 1; + else + return 0; #endif /* INET */ #ifdef INET6 case AF_INET6: - if (IN6_IS_ADDR_UNSPECIFIED(&addr.sin6.sin6_addr)) - return 1; - else - return 0; + if (IN6_IS_ADDR_UNSPECIFIED(&addr.sin6.sin6_addr)) + return 1; + else + return 0; #endif /* INET6 */ case 0: /* No family set */ default: - return 1; - } + return 1; + } } /* Free reference-counted structure. */ @@ -1221,43 +1171,43 @@ void ipsp_reffree(struct ipsec_ref *ipr) { #ifdef DIAGNOSTIC - if (ipr->ref_count <= 0) - printf("ipsp_reffree: illegal reference count %d for object %p (len = %d, malloctype = %d)\n", ipr->ref_count, ipr, ipr->ref_len, ipr->ref_malloctype); + if (ipr->ref_count <= 0) + printf("ipsp_reffree: illegal reference count %d for " + "object %p (len = %d, malloctype = %d)\n", + ipr->ref_count, ipr, ipr->ref_len, ipr->ref_malloctype); #endif - if (--ipr->ref_count <= 0) - FREE(ipr, ipr->ref_malloctype); + if (--ipr->ref_count <= 0) + FREE(ipr, ipr->ref_malloctype); } /* Mark a TDB as TDBF_SKIPCRYPTO. */ void ipsp_skipcrypto_mark(struct tdb_ident *tdbi) { - struct tdb *tdb; - int s = spltdb(); + struct tdb *tdb; + int s = spltdb(); - tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto); - if (tdb != NULL) - { - tdb->tdb_flags |= TDBF_SKIPCRYPTO; - tdb->tdb_last_marked = time.tv_sec; - } - splx(s); + tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto); + if (tdb != NULL) { + tdb->tdb_flags |= TDBF_SKIPCRYPTO; + tdb->tdb_last_marked = time.tv_sec; + } + splx(s); } /* Unmark a TDB as TDBF_SKIPCRYPTO. */ void ipsp_skipcrypto_unmark(struct tdb_ident *tdbi) { - struct tdb *tdb; - int s = spltdb(); + struct tdb *tdb; + int s = spltdb(); - tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto); - if (tdb != NULL) - { - tdb->tdb_flags &= ~TDBF_SKIPCRYPTO; - tdb->tdb_last_marked = time.tv_sec; - } - splx(s); + tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto); + if (tdb != NULL) { + tdb->tdb_flags &= ~TDBF_SKIPCRYPTO; + tdb->tdb_last_marked = time.tv_sec; + } + splx(s); } /* @@ -1268,236 +1218,242 @@ ipsp_skipcrypto_unmark(struct tdb_ident *tdbi) struct m_tag * ipsp_parse_headers(struct mbuf *m, int off, u_int8_t proto) { - int ipv4sa = 0, s, esphlen = 0, trail = 0, i; - SLIST_HEAD(packet_tags, m_tag) tags; - unsigned char lasteight[8]; - struct tdb_ident *tdbi; - struct m_tag *mtag; - struct tdb *tdb; + int ipv4sa = 0, s, esphlen = 0, trail = 0, i; + SLIST_HEAD(packet_tags, m_tag) tags; + unsigned char lasteight[8]; + struct tdb_ident *tdbi; + struct m_tag *mtag; + struct tdb *tdb; #ifdef INET - struct ip iph; + struct ip iph; #endif /* INET */ #ifdef INET6 - struct in6_addr ip6_dst; + struct in6_addr ip6_dst; #endif /* INET6 */ - /* We have to start with a known network protocol */ - if (proto != IPPROTO_IPV4 && proto != IPPROTO_IPV6) - return NULL; + /* We have to start with a known network protocol */ + if (proto != IPPROTO_IPV4 && proto != IPPROTO_IPV6) + return NULL; - SLIST_INIT(&tags); + SLIST_INIT(&tags); - while (1) - { - switch (proto) - { + while (1) { + switch (proto) { #ifdef INET - case IPPROTO_IPV4: /* Also IPPROTO_IPIP */ - { - /* Save the IP header (we need both the address and ip_hl) */ - m_copydata(m, off, sizeof(struct ip), (caddr_t) &iph); - ipv4sa = 1; - proto = iph.ip_p; - off += iph.ip_hl << 2; - break; - } + case IPPROTO_IPV4: /* Also IPPROTO_IPIP */ + { + /* + * Save the IP header (we need both the + * address and ip_hl). + */ + m_copydata(m, off, sizeof(struct ip), (caddr_t) &iph); + ipv4sa = 1; + proto = iph.ip_p; + off += iph.ip_hl << 2; + break; + } #endif /* INET */ #ifdef INET6 - case IPPROTO_IPV6: - { - int nxtp, l; - - /* Copy the IPv6 address */ - m_copydata(m, off + offsetof(struct ip6_hdr, ip6_dst), - sizeof(struct ip6_hdr), (caddr_t) &ip6_dst); - ipv4sa = 0; - - /* - * Go down the chain of headers until we encounter a - * non-option. - */ - for (l = ip6_nexthdr(m, off, proto, &nxtp); l != -1; - l = ip6_nexthdr(m, off, proto, &nxtp)) + case IPPROTO_IPV6: { - off += l; - proto = nxtp; - - /* Construct a tag */ - if (nxtp == IPPROTO_AH) - { - mtag = m_tag_get(PACKET_TAG_IPSEC_IN_CRYPTO_DONE, - sizeof(struct tdb_ident), M_NOWAIT); - if (mtag == NULL) - return tags.slh_first; + int nxtp, l; - tdbi = (struct tdb_ident *) (mtag + 1); - bzero(tdbi, sizeof(struct tdb_ident)); - m_copydata(m, off + sizeof(u_int32_t), - sizeof(u_int32_t), (caddr_t) &tdbi->spi); - tdbi->proto = IPPROTO_AH; - tdbi->dst.sin6.sin6_family = AF_INET6; - tdbi->dst.sin6.sin6_len = sizeof(struct sockaddr_in6); - tdbi->dst.sin6.sin6_addr = ip6_dst; - SLIST_INSERT_HEAD(&tags, mtag, m_tag_link); - } - else - if (nxtp == IPPROTO_IPV6) + /* Copy the IPv6 address. */ m_copydata(m, off + offsetof(struct ip6_hdr, ip6_dst), - sizeof(struct ip6_hdr), (caddr_t) &ip6_dst); + sizeof(struct ip6_hdr), (caddr_t) &ip6_dst); + ipv4sa = 0; + + /* + * Go down the chain of headers until we encounter a + * non-option. + */ + for (l = ip6_nexthdr(m, off, proto, &nxtp); l != -1; + l = ip6_nexthdr(m, off, proto, &nxtp)) { + off += l; + proto = nxtp; + + /* Construct a tag */ + if (nxtp == IPPROTO_AH) { + mtag = m_tag_get(PACKET_TAG_IPSEC_IN_CRYPTO_DONE, + sizeof(struct tdb_ident), + M_NOWAIT); + + if (mtag == NULL) + return tags.slh_first; + + tdbi = (struct tdb_ident *) (mtag + 1); + bzero(tdbi, sizeof(struct tdb_ident)); + + m_copydata(m, off + sizeof(u_int32_t), + sizeof(u_int32_t), + (caddr_t) &tdbi->spi); + + tdbi->proto = IPPROTO_AH; + tdbi->dst.sin6.sin6_family = AF_INET6; + tdbi->dst.sin6.sin6_len = + sizeof(struct sockaddr_in6); + tdbi->dst.sin6.sin6_addr = ip6_dst; + SLIST_INSERT_HEAD(&tags, + mtag, m_tag_link); + } + else + if (nxtp == IPPROTO_IPV6) + m_copydata(m, off + + offsetof(struct ip6_hdr, + ip6_dst), + sizeof(struct ip6_hdr), + (caddr_t) &ip6_dst); + } + break; } - break; - } #endif /* INET6 */ - case IPPROTO_ESP: + case IPPROTO_ESP: /* Verify that this has been decrypted */ { - union sockaddr_union su; - u_int32_t spi; + union sockaddr_union su; + u_int32_t spi; - m_copydata(m, off, sizeof(u_int32_t), (caddr_t) &spi); - bzero(&su, sizeof(union sockaddr_union)); + m_copydata(m, off, sizeof(u_int32_t), (caddr_t) &spi); + bzero(&su, sizeof(union sockaddr_union)); - s = spltdb(); + s = spltdb(); #ifdef INET - if (ipv4sa) - { - su.sin.sin_family = AF_INET; - su.sin.sin_len = sizeof(struct sockaddr_in); - su.sin.sin_addr = iph.ip_dst; - } + if (ipv4sa) { + su.sin.sin_family = AF_INET; + su.sin.sin_len = sizeof(struct sockaddr_in); + su.sin.sin_addr = iph.ip_dst; + } #endif /* INET */ #ifdef INET6 - if (!ipv4sa) - { - su.sin6.sin6_family = AF_INET6; - su.sin6.sin6_len = sizeof(struct sockaddr_in6); - su.sin6.sin6_addr = ip6_dst; - } + if (!ipv4sa) { + su.sin6.sin6_family = AF_INET6; + su.sin6.sin6_len = sizeof(struct sockaddr_in6); + su.sin6.sin6_addr = ip6_dst; + } #endif /* INET6 */ - tdb = gettdb(spi, &su, IPPROTO_ESP); - if (tdb == NULL) - { - splx(s); - return tags.slh_first; - } - - /* How large is the ESP header ? We use this later */ - if (tdb->tdb_flags & TDBF_NOREPLAY) - esphlen = sizeof(u_int32_t) + tdb->tdb_ivlen; - else - esphlen = 2 * sizeof(u_int32_t) + tdb->tdb_ivlen; - - /* - * Verify decryption. If the SA is using random padding - * (as the "old" ESP SAs were bound to do, there's nothing - * we can do to see if the payload has been decrypted. - */ - if (tdb->tdb_flags & TDBF_RANDOMPADDING) - { - splx(s); - return tags.slh_first; - } - - /* Update the length of trailing ESP authenticators */ - if (tdb->tdb_authalgxform) - trail += AH_HMAC_HASHLEN; - - splx(s); + tdb = gettdb(spi, &su, IPPROTO_ESP); + if (tdb == NULL) { + splx(s); + return tags.slh_first; + } + + /* How large is the ESP header ? We use this later. */ + if (tdb->tdb_flags & TDBF_NOREPLAY) + esphlen = sizeof(u_int32_t) + tdb->tdb_ivlen; + else + esphlen = 2 * sizeof(u_int32_t) + + tdb->tdb_ivlen; + + /* + * Verify decryption. If the SA is using + * random padding (as the "old" ESP SAs were + * bound to do, there's nothing we can do to + * see if the payload has been decrypted. + */ + if (tdb->tdb_flags & TDBF_RANDOMPADDING) { + splx(s); + return tags.slh_first; + } - /* Copy the last 10 bytes */ - m_copydata(m, m->m_pkthdr.len - trail - 8, 8, lasteight); + /* Update the length of trailing ESP authenticators. */ + if (tdb->tdb_authalgxform) + trail += AH_HMAC_HASHLEN; - /* Verify the self-describing padding values */ - if (lasteight[6] != 0) - { - if (lasteight[6] != lasteight[5]) - return tags.slh_first; + splx(s); - for (i = 4; lasteight[i + 1] != 1 && i >= 0; i--) - if (lasteight[i + 1] != lasteight[i] + 1) - return tags.slh_first; - } + /* Copy the last 10 bytes. */ + m_copydata(m, m->m_pkthdr.len - trail - 8, 8, + lasteight); + + /* Verify the self-describing padding values */ + if (lasteight[6] != 0) { + if (lasteight[6] != lasteight[5]) + return tags.slh_first; + + for (i = 4; lasteight[i + 1] != 1 && i >= 0; + i--) + if (lasteight[i + 1] != + lasteight[i] + 1) + return tags.slh_first; + } } /* Fall through */ - case IPPROTO_AH: - mtag = m_tag_get(PACKET_TAG_IPSEC_IN_CRYPTO_DONE, - sizeof(struct tdb_ident), M_NOWAIT); - if (mtag == NULL) - return tags.slh_first; + case IPPROTO_AH: + mtag = m_tag_get(PACKET_TAG_IPSEC_IN_CRYPTO_DONE, + sizeof(struct tdb_ident), M_NOWAIT); + if (mtag == NULL) + return tags.slh_first; - tdbi = (struct tdb_ident *) (mtag + 1); - bzero(tdbi, sizeof(struct tdb_ident)); + tdbi = (struct tdb_ident *) (mtag + 1); + bzero(tdbi, sizeof(struct tdb_ident)); - /* Get SPI off the relevant header */ - if (proto == IPPROTO_AH) - m_copydata(m, off + sizeof(u_int32_t), sizeof(u_int32_t), - (caddr_t) &tdbi->spi); - else /* IPPROTO_ESP */ - m_copydata(m, off, sizeof(u_int32_t), (caddr_t) &tdbi->spi); + /* Get SPI off the relevant header */ + if (proto == IPPROTO_AH) + m_copydata(m, off + sizeof(u_int32_t), + sizeof(u_int32_t), (caddr_t) &tdbi->spi); + else /* IPPROTO_ESP */ + m_copydata(m, off, sizeof(u_int32_t), + (caddr_t) &tdbi->spi); - tdbi->proto = proto; /* We can get here for AH or ESP */ + tdbi->proto = proto; /* AH or ESP */ #ifdef INET - /* Last network header was IPv4 */ - if (ipv4sa) - { - tdbi->dst.sin.sin_family = AF_INET; - tdbi->dst.sin.sin_len = sizeof(struct sockaddr_in); - tdbi->dst.sin.sin_addr = iph.ip_dst; - } + /* Last network header was IPv4. */ + if (ipv4sa) { + tdbi->dst.sin.sin_family = AF_INET; + tdbi->dst.sin.sin_len = + sizeof(struct sockaddr_in); + tdbi->dst.sin.sin_addr = iph.ip_dst; + } #endif /* INET */ #ifdef INET6 - /* Last network header was IPv6 */ - if (!ipv4sa) - { - tdbi->dst.sin6.sin6_family = AF_INET6; - tdbi->dst.sin6.sin6_len = sizeof(struct sockaddr_in6); - tdbi->dst.sin6.sin6_addr = ip6_dst; - } + /* Last network header was IPv6 */ + if (!ipv4sa) { + tdbi->dst.sin6.sin6_family = AF_INET6; + tdbi->dst.sin6.sin6_len = + sizeof(struct sockaddr_in6); + tdbi->dst.sin6.sin6_addr = ip6_dst; + } #endif /* INET6 */ - SLIST_INSERT_HEAD(&tags, mtag, m_tag_link); - - /* Update next protocol/header and header offset */ - if (proto == IPPROTO_AH) - { - u_int8_t foo[2]; + SLIST_INSERT_HEAD(&tags, mtag, m_tag_link); - m_copydata(m, off, 2 * sizeof(u_int8_t), foo); - proto = foo[0]; - off += (foo[1] + 2) << 2; - } - else /* IPPROTO_ESP */ - { - /* Initialized in IPPROTO_ESP case */ - off += esphlen; - proto = lasteight[7]; + /* Update next protocol/header and header offset. */ + if (proto == IPPROTO_AH) { + u_int8_t foo[2]; + + m_copydata(m, off, 2 * sizeof(u_int8_t), foo); + proto = foo[0]; + off += (foo[1] + 2) << 2; + } else {/* IPPROTO_ESP */ + /* Initialized in IPPROTO_ESP case */ + off += esphlen; + proto = lasteight[7]; + } + break; + + default: + return tags.slh_first; /* done */ } - break; - - default: - return tags.slh_first; /* done */ } - } } /* Return true if the two structures match. */ int ipsp_ref_match(struct ipsec_ref *ref1, struct ipsec_ref *ref2) { - if (ref1->ref_type != ref2->ref_type || - ref1->ref_len != ref2->ref_len || - bcmp(ref1 + 1, ref2 + 1, ref1->ref_len)) - return 0; + if (ref1->ref_type != ref2->ref_type || + ref1->ref_len != ref2->ref_len || + bcmp(ref1 + 1, ref2 + 1, ref1->ref_len)) + return 0; - return 1; + return 1; } - diff --git a/sys/netinet/ip_ipsp.h b/sys/netinet/ip_ipsp.h index 9e05c303244..82e7ba9008d 100644 --- a/sys/netinet/ip_ipsp.h +++ b/sys/netinet/ip_ipsp.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_ipsp.h,v 1.109 2001/06/25 23:18:08 beck Exp $ */ +/* $OpenBSD: ip_ipsp.h,v 1.110 2001/06/26 03:52:42 angelos Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), * Angelos D. Keromytis (kermit@csd.uch.gr), @@ -613,5 +613,6 @@ extern struct m_tag *ipsp_parse_headers(struct mbuf *, int, u_int8_t); extern int ipsp_ref_match(struct ipsec_ref *, struct ipsec_ref *); extern ssize_t ipsec_hdrsz(struct tdb *); extern void ipsec_adjust_mtu(struct mbuf *, u_int32_t); +extern int ipsp_print_tdb(struct tdb *, char *); #endif /* _KERNEL */ #endif /* _NETINET_IPSP_H_ */ diff --git a/sys/netinet/ip_spd.c b/sys/netinet/ip_spd.c index d85134ae4da..c02709425f2 100644 --- a/sys/netinet/ip_spd.c +++ b/sys/netinet/ip_spd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_spd.c,v 1.25 2001/06/25 05:11:59 angelos Exp $ */ +/* $OpenBSD: ip_spd.c,v 1.26 2001/06/26 03:52:42 angelos Exp $ */ /* * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu) * @@ -49,9 +49,9 @@ #include <net/pfkeyv2.h> #ifdef ENCDEBUG -#define DPRINTF(x) if (encdebug) printf x +#define DPRINTF(x) if (encdebug) printf x #else -#define DPRINTF(x) +#define DPRINTF(x) #endif /* @@ -71,491 +71,481 @@ */ struct tdb * ipsp_spd_lookup(struct mbuf *m, int af, int hlen, int *error, int direction, - struct tdb *tdbp, struct inpcb *inp) + struct tdb *tdbp, struct inpcb *inp) { - struct route_enc re0, *re = &re0; - union sockaddr_union sdst, ssrc; - struct sockaddr_encap *ddst; - struct ipsec_policy *ipo; - int signore = 0, dignore = 0; - - /* - * If there are no flows in place, there's no point - * continuing with the SPD lookup. - */ - if (!ipsec_in_use && inp == NULL) - { - *error = 0; - return NULL; - } - - /* If an input packet is destined to a BYPASS socket, just accept it */ - if ((inp != NULL) && (direction == IPSP_DIRECTION_IN) && - (inp->inp_seclevel[SL_ESP_TRANS] == IPSEC_LEVEL_BYPASS) && - (inp->inp_seclevel[SL_ESP_NETWORK] == IPSEC_LEVEL_BYPASS) && - (inp->inp_seclevel[SL_AUTH] == IPSEC_LEVEL_BYPASS)) - { - *error = 0; - return NULL; - } + struct route_enc re0, *re = &re0; + union sockaddr_union sdst, ssrc; + struct sockaddr_encap *ddst; + struct ipsec_policy *ipo; + int signore = 0, dignore = 0; + + /* + * If there are no flows in place, there's no point + * continuing with the SPD lookup. + */ + if (!ipsec_in_use && inp == NULL) { + *error = 0; + return NULL; + } + + /* If an input packet is destined to a BYPASS socket, just accept it. */ + if ((inp != NULL) && (direction == IPSP_DIRECTION_IN) && + (inp->inp_seclevel[SL_ESP_TRANS] == IPSEC_LEVEL_BYPASS) && + (inp->inp_seclevel[SL_ESP_NETWORK] == IPSEC_LEVEL_BYPASS) && + (inp->inp_seclevel[SL_AUTH] == IPSEC_LEVEL_BYPASS)) { + *error = 0; + return NULL; + } - bzero((caddr_t) re, sizeof(struct route_enc)); - bzero((caddr_t) &sdst, sizeof(union sockaddr_union)); - bzero((caddr_t) &ssrc, sizeof(union sockaddr_union)); - ddst = (struct sockaddr_encap *) &re->re_dst; - ddst->sen_family = PF_KEY; - ddst->sen_len = SENT_LEN; + bzero((caddr_t) re, sizeof(struct route_enc)); + bzero((caddr_t) &sdst, sizeof(union sockaddr_union)); + bzero((caddr_t) &ssrc, sizeof(union sockaddr_union)); + ddst = (struct sockaddr_encap *) &re->re_dst; + ddst->sen_family = PF_KEY; + ddst->sen_len = SENT_LEN; - switch (af) - { + switch (af) { #ifdef INET case AF_INET: - ddst->sen_direction = direction; - ddst->sen_type = SENT_IP4; - - m_copydata(m, offsetof(struct ip, ip_src), - sizeof(struct in_addr), (caddr_t) &(ddst->sen_ip_src)); - m_copydata(m, offsetof(struct ip, ip_dst), - sizeof(struct in_addr), (caddr_t) &(ddst->sen_ip_dst)); - m_copydata(m, offsetof(struct ip, ip_p), sizeof(u_int8_t), - (caddr_t) &(ddst->sen_proto)); - - sdst.sin.sin_family = ssrc.sin.sin_family = AF_INET; - sdst.sin.sin_len = ssrc.sin.sin_len = sizeof(struct sockaddr_in); - ssrc.sin.sin_addr = ddst->sen_ip_src; - sdst.sin.sin_addr = ddst->sen_ip_dst; - - /* If TCP/UDP, extract the port numbers to use in the lookup */ - switch (ddst->sen_proto) - { + ddst->sen_direction = direction; + ddst->sen_type = SENT_IP4; + + m_copydata(m, offsetof(struct ip, ip_src), + sizeof(struct in_addr), (caddr_t) &(ddst->sen_ip_src)); + m_copydata(m, offsetof(struct ip, ip_dst), + sizeof(struct in_addr), (caddr_t) &(ddst->sen_ip_dst)); + m_copydata(m, offsetof(struct ip, ip_p), sizeof(u_int8_t), + (caddr_t) &(ddst->sen_proto)); + + sdst.sin.sin_family = ssrc.sin.sin_family = AF_INET; + sdst.sin.sin_len = ssrc.sin.sin_len = + sizeof(struct sockaddr_in); + ssrc.sin.sin_addr = ddst->sen_ip_src; + sdst.sin.sin_addr = ddst->sen_ip_dst; + + /* If TCP/UDP, extract the port numbers to use in the lookup */ + switch (ddst->sen_proto) { case IPPROTO_UDP: case IPPROTO_TCP: - /* Make sure there's enough data in the packet */ - if (m->m_pkthdr.len < hlen + 2 * sizeof(u_int16_t)) - { - *error = EINVAL; - return NULL; - } - - /* - * Luckily, the offset of the src/dst ports in both the UDP - * and TCP headers is the same (first two 16-bit values - * in the respective headers), so we can just copy them. - */ - m_copydata(m, hlen, sizeof(u_int16_t), - (caddr_t) &(ddst->sen_sport)); - m_copydata(m, hlen + sizeof(u_int16_t), sizeof(u_int16_t), - (caddr_t) &(ddst->sen_dport)); - break; + /* Make sure there's enough data in the packet */ + if (m->m_pkthdr.len < hlen + 2 * sizeof(u_int16_t)) { + *error = EINVAL; + return NULL; + } + + /* + * Luckily, the offset of the src/dst ports in + * both the UDP and TCP headers is the same (first + * two 16-bit values in the respective headers), + * so we can just copy them. + */ + m_copydata(m, hlen, sizeof(u_int16_t), + (caddr_t) &(ddst->sen_sport)); + m_copydata(m, hlen + sizeof(u_int16_t), sizeof(u_int16_t), + (caddr_t) &(ddst->sen_dport)); + break; default: - ddst->sen_sport = 0; - ddst->sen_dport = 0; - } + ddst->sen_sport = 0; + ddst->sen_dport = 0; + } - break; + break; #endif /* INET */ #ifdef INET6 case AF_INET6: - ddst->sen_type = SENT_IP6; - ddst->sen_ip6_direction = direction; - - m_copydata(m, offsetof(struct ip6_hdr, ip6_src), - sizeof(struct in6_addr), - (caddr_t) &(ddst->sen_ip6_src)); - m_copydata(m, offsetof(struct ip6_hdr, ip6_dst), - sizeof(struct in6_addr), - (caddr_t) &(ddst->sen_ip6_dst)); - m_copydata(m, offsetof(struct ip6_hdr, ip6_nxt), sizeof(u_int8_t), - (caddr_t) &(ddst->sen_ip6_proto)); - - sdst.sin6.sin6_family = ssrc.sin6.sin6_family = AF_INET6; - sdst.sin6.sin6_len = ssrc.sin6.sin6_family = - sizeof(struct sockaddr_in6); - ssrc.sin6.sin6_addr = ddst->sen_ip6_src; - sdst.sin6.sin6_addr = ddst->sen_ip6_dst; - - /* If TCP/UDP, extract the port numbers to use in the lookup */ - switch (ddst->sen_ip6_proto) - { + ddst->sen_type = SENT_IP6; + ddst->sen_ip6_direction = direction; + + m_copydata(m, offsetof(struct ip6_hdr, ip6_src), + sizeof(struct in6_addr), + (caddr_t) &(ddst->sen_ip6_src)); + m_copydata(m, offsetof(struct ip6_hdr, ip6_dst), + sizeof(struct in6_addr), + (caddr_t) &(ddst->sen_ip6_dst)); + m_copydata(m, offsetof(struct ip6_hdr, ip6_nxt), + sizeof(u_int8_t), + (caddr_t) &(ddst->sen_ip6_proto)); + + sdst.sin6.sin6_family = ssrc.sin6.sin6_family = AF_INET6; + sdst.sin6.sin6_len = ssrc.sin6.sin6_family = + sizeof(struct sockaddr_in6); + ssrc.sin6.sin6_addr = ddst->sen_ip6_src; + sdst.sin6.sin6_addr = ddst->sen_ip6_dst; + + /* If TCP/UDP, extract the port numbers to use in the lookup */ + switch (ddst->sen_ip6_proto) { case IPPROTO_UDP: case IPPROTO_TCP: - /* Make sure there's enough data in the packet */ - if (m->m_pkthdr.len < hlen + 2 * sizeof(u_int16_t)) - { - *error = EINVAL; - return NULL; - } - - /* - * Luckily, the offset of the src/dst ports in both the UDP - * and TCP headers is the same (first two 16-bit values - * in the respective headers), so we can just copy them. - */ - m_copydata(m, hlen, sizeof(u_int16_t), - (caddr_t) &(ddst->sen_ip6_sport)); - m_copydata(m, hlen + sizeof(u_int16_t), sizeof(u_int16_t), - (caddr_t) &(ddst->sen_ip6_dport)); - break; + /* Make sure there's enough data in the packet */ + if (m->m_pkthdr.len < hlen + 2 * sizeof(u_int16_t)) { + *error = EINVAL; + return NULL; + } + + /* + * Luckily, the offset of the src/dst ports in + * both the UDP and TCP headers is the same + * (first two 16-bit values in the respective + * headers), so we can just copy them. + */ + m_copydata(m, hlen, sizeof(u_int16_t), + (caddr_t) &(ddst->sen_ip6_sport)); + m_copydata(m, hlen + sizeof(u_int16_t), sizeof(u_int16_t), + (caddr_t) &(ddst->sen_ip6_dport)); + break; default: - ddst->sen_ip6_sport = 0; - ddst->sen_ip6_dport = 0; - } + ddst->sen_ip6_sport = 0; + ddst->sen_ip6_dport = 0; + } - break; + break; #endif /* INET6 */ default: - *error = EAFNOSUPPORT; - return NULL; - } - - /* Actual SPD lookup */ - rtalloc((struct route *) re); - if (re->re_rt == NULL) - { - *error = 0; - return NULL; /* Nothing found -- means no IPsec needed */ - } - - /* Sanity check */ - if ((re->re_rt->rt_gateway == NULL) || - (((struct sockaddr_encap *) re->re_rt->rt_gateway)->sen_type != - SENT_IPSP)) - { - RTFREE(re->re_rt); - *error = EHOSTUNREACH; - return NULL; - } + *error = EAFNOSUPPORT; + return NULL; + } - ipo = ((struct sockaddr_encap *) (re->re_rt->rt_gateway))->sen_ipsp; - RTFREE(re->re_rt); - if (ipo == NULL) - { - *error = EHOSTUNREACH; - return NULL; - } + /* Actual SPD lookup */ + rtalloc((struct route *) re); + if (re->re_rt == NULL) { + /* + * Return whatever the socket requirements are, there are no + * system-wide policies. + */ + *error = 0; + return ipsp_spd_inp(m, af, hlen, error, direction, + tdbp, inp, NULL); + } + + /* Sanity check */ + if ((re->re_rt->rt_gateway == NULL) || + (((struct sockaddr_encap *) re->re_rt->rt_gateway)->sen_type != + SENT_IPSP)) { + RTFREE(re->re_rt); + *error = EHOSTUNREACH; + return NULL; + } + + ipo = ((struct sockaddr_encap *) (re->re_rt->rt_gateway))->sen_ipsp; + RTFREE(re->re_rt); + if (ipo == NULL) { + *error = EHOSTUNREACH; + return NULL; + } - switch (ipo->ipo_type) - { + switch (ipo->ipo_type) { case IPSP_PERMIT: - *error = 0; - return NULL; + *error = 0; + return ipsp_spd_inp(m, af, hlen, error, direction, tdbp, + inp, ipo); case IPSP_DENY: - *error = EHOSTUNREACH; - return NULL; + *error = EHOSTUNREACH; + return NULL; case IPSP_IPSEC_USE: case IPSP_IPSEC_ACQUIRE: case IPSP_IPSEC_REQUIRE: case IPSP_IPSEC_DONTACQ: - /* Nothing more needed here */ - break; + /* Nothing more needed here */ + break; default: - *error = EINVAL; - return NULL; - } + *error = EINVAL; + return NULL; + } - /* Check for non-specific destination in the policy. */ - switch (ipo->ipo_dst.sa.sa_family) - { + /* Check for non-specific destination in the policy. */ + switch (ipo->ipo_dst.sa.sa_family) { #ifdef INET case AF_INET: - if ((ipo->ipo_dst.sin.sin_addr.s_addr == INADDR_ANY) || - (ipo->ipo_dst.sin.sin_addr.s_addr == INADDR_BROADCAST)) - dignore = 1; - break; + if ((ipo->ipo_dst.sin.sin_addr.s_addr == INADDR_ANY) || + (ipo->ipo_dst.sin.sin_addr.s_addr == INADDR_BROADCAST)) + dignore = 1; + break; #endif /* INET */ #ifdef INET6 case AF_INET6: - if ((IN6_IS_ADDR_UNSPECIFIED(&ipo->ipo_dst.sin6.sin6_addr)) || - (bcmp(&ipo->ipo_dst.sin6.sin6_addr, &in6mask128, - sizeof(in6mask128)))) - dignore = 1; - break; + if ((IN6_IS_ADDR_UNSPECIFIED(&ipo->ipo_dst.sin6.sin6_addr)) || + (bcmp(&ipo->ipo_dst.sin6.sin6_addr, &in6mask128, + sizeof(in6mask128)))) + dignore = 1; + break; #endif /* INET6 */ - } + } - /* Likewise for source. */ - switch (ipo->ipo_src.sa.sa_family) - { + /* Likewise for source. */ + switch (ipo->ipo_src.sa.sa_family) { #ifdef INET case AF_INET: - if (ipo->ipo_src.sin.sin_addr.s_addr == INADDR_ANY) - signore = 1; - break; + if (ipo->ipo_src.sin.sin_addr.s_addr == INADDR_ANY) + signore = 1; + break; #endif /* INET */ #ifdef INET6 case AF_INET6: - if (IN6_IS_ADDR_UNSPECIFIED(&ipo->ipo_src.sin6.sin6_addr)) - signore = 1; - break; + if (IN6_IS_ADDR_UNSPECIFIED(&ipo->ipo_src.sin6.sin6_addr)) + signore = 1; + break; #endif /* INET6 */ - } - - /* Do we have a cached entry ? If so, check if it's still valid. */ - if ((ipo->ipo_tdb) && (ipo->ipo_tdb->tdb_flags & TDBF_INVALID)) - { - TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo, ipo_tdb_next); - ipo->ipo_tdb = NULL; - } - - /* Outgoing packet SPD lookup */ - if (direction == IPSP_DIRECTION_OUT) - { - /* - * If the packet is destined for the policy-specified gateway/endhost, - * and the socket has the BYPASS option set, skip IPsec processing. - */ - if ((inp != NULL) && - (inp->inp_seclevel[SL_ESP_TRANS] == IPSEC_LEVEL_BYPASS) && - (inp->inp_seclevel[SL_ESP_NETWORK] == IPSEC_LEVEL_BYPASS) && - (inp->inp_seclevel[SL_AUTH] == IPSEC_LEVEL_BYPASS)) - { - /* Direct match */ - if (!bcmp(&sdst, &ipo->ipo_dst, sdst.sa.sa_len) || dignore) - { - *error = 0; - return NULL; - } } - /* Check that the cached TDB (if present), is appropriate */ - if (ipo->ipo_tdb) - { - if ((ipo->ipo_last_searched <= ipsec_last_added) || - (ipo->ipo_sproto != ipo->ipo_tdb->tdb_sproto) || - bcmp(dignore ? &sdst : &ipo->ipo_dst, &ipo->ipo_tdb->tdb_dst, - ipo->ipo_tdb->tdb_dst.sa.sa_len)) - goto nomatchout; - - /* Match source ID */ - if (ipo->ipo_srcid) - { - if (ipo->ipo_tdb->tdb_srcid == NULL || - !ipsp_ref_match(ipo->ipo_srcid, ipo->ipo_tdb->tdb_srcid)) - goto nomatchout; - } - - /* Match destination ID */ - if (ipo->ipo_dstid) - { - if (ipo->ipo_tdb->tdb_dstid == NULL || - !ipsp_ref_match(ipo->ipo_dstid, ipo->ipo_tdb->tdb_dstid)) - goto nomatchout; - } - - /* Match local credentials used */ - if (ipo->ipo_local_cred) - { - if (ipo->ipo_tdb->tdb_local_cred == NULL || - !ipsp_ref_match(ipo->ipo_local_cred, - ipo->ipo_tdb->tdb_local_cred)) - goto nomatchout; - } - - return ipo->ipo_tdb; /* Cached entry is good, we're done */ - - nomatchout: - /* Cached TDB was not good */ - TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo, ipo_tdb_next); - ipo->ipo_tdb = NULL; - ipo->ipo_last_searched = 0; + /* Do we have a cached entry ? If so, check if it's still valid. */ + if ((ipo->ipo_tdb) && (ipo->ipo_tdb->tdb_flags & TDBF_INVALID)) { + TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo, + ipo_tdb_next); + ipo->ipo_tdb = NULL; } - /* - * If no SA has been added since the last time we did a - * lookup, there's no point searching for one. However, if the - * destination gateway is left unspecified (or is all-1's), - * always lookup since this is a generic-match rule - * (otherwise, we can have situations where SAs to some - * destinations exist but are not used, possibly leading to an - * explosion in the number of acquired SAs). - */ - if (ipo->ipo_last_searched <= ipsec_last_added) - { - ipo->ipo_last_searched = time.tv_sec; /* "touch" the entry */ - - /* Find an appropriate SA from among the existing SAs */ - ipo->ipo_tdb = gettdbbyaddr(dignore ? &sdst : &ipo->ipo_dst, - ipo, m, af); - if (ipo->ipo_tdb) - { - TAILQ_INSERT_TAIL(&ipo->ipo_tdb->tdb_policy_head, ipo, - ipo_tdb_next); - *error = 0; - return ipo->ipo_tdb; - } - } + /* Outgoing packet SPD lookup. */ + if (direction == IPSP_DIRECTION_OUT) { + /* + * If the packet is destined for the policy-specified + * gateway/endhost, and the socket has the BYPASS + * option set, skip IPsec processing. + */ + if ((inp != NULL) && + (inp->inp_seclevel[SL_ESP_TRANS] == IPSEC_LEVEL_BYPASS) && + (inp->inp_seclevel[SL_ESP_NETWORK] == + IPSEC_LEVEL_BYPASS) && + (inp->inp_seclevel[SL_AUTH] == IPSEC_LEVEL_BYPASS)) { + /* Direct match */ + if (!bcmp(&sdst, &ipo->ipo_dst, sdst.sa.sa_len) || + dignore) { + *error = 0; + return ipsp_spd_inp(m, af, hlen, error, + direction, tdbp, inp, ipo); + } + } - /* So, we don't have an SA -- just a policy */ - switch (ipo->ipo_type) - { - case IPSP_IPSEC_REQUIRE: - /* Acquire SA through key management */ - if (ipsp_acquire_sa(ipo, dignore ? &sdst : &ipo->ipo_dst, - signore ? NULL : &ipo->ipo_src, - ddst, m) != 0) - { - *error = EACCES; - return NULL; - } - - /* Fall through */ - case IPSP_IPSEC_DONTACQ: - *error = -EINVAL; /* Silently drop packet */ - return NULL; + /* Check that the cached TDB (if present), is appropriate. */ + if (ipo->ipo_tdb) { + if ((ipo->ipo_last_searched <= ipsec_last_added) || + (ipo->ipo_sproto != ipo->ipo_tdb->tdb_sproto) || + bcmp(dignore ? &sdst : &ipo->ipo_dst, + &ipo->ipo_tdb->tdb_dst, + ipo->ipo_tdb->tdb_dst.sa.sa_len)) + goto nomatchout; + + /* Match source ID. */ + if (ipo->ipo_srcid) { + if (ipo->ipo_tdb->tdb_srcid == NULL || + !ipsp_ref_match(ipo->ipo_srcid, + ipo->ipo_tdb->tdb_srcid)) + goto nomatchout; + } + + /* Match destination ID. */ + if (ipo->ipo_dstid) { + if (ipo->ipo_tdb->tdb_dstid == NULL || + !ipsp_ref_match(ipo->ipo_dstid, + ipo->ipo_tdb->tdb_dstid)) + goto nomatchout; + } + + /* Match local credentials used */ + if (ipo->ipo_local_cred) { + if (ipo->ipo_tdb->tdb_local_cred == NULL || + !ipsp_ref_match(ipo->ipo_local_cred, + ipo->ipo_tdb->tdb_local_cred)) + goto nomatchout; + } + + /* Cached entry is good */ + return ipsp_spd_inp(m, af, hlen, error, direction, + tdbp, inp, ipo); - case IPSP_IPSEC_ACQUIRE: - /* Acquire SA through key management */ - if (ipsp_acquire_sa(ipo, dignore ? &sdst : &ipo->ipo_dst, - signore ? NULL : &ipo->ipo_src, - ddst, NULL) != 0) - { - *error = EACCES; - return NULL; - } - - /* Fall through */ - case IPSP_IPSEC_USE: - *error = 0; /* Let packet through */ - return NULL; - } - } - else /* IPSP_DIRECTION_IN */ - { - if (tdbp != NULL) - { - if (ipo->ipo_tdb == tdbp) - { - *error = 0; /* Accept packet */ - return NULL; - } - - if (bcmp(dignore ? &ssrc : &ipo->ipo_dst, &tdbp->tdb_src, - tdbp->tdb_src.sa.sa_len) || - (ipo->ipo_sproto != tdbp->tdb_sproto)) - goto nomatchin; - - /* Match source ID */ - if (ipo->ipo_srcid) - { - if (tdbp->tdb_dstid == NULL || - !ipsp_ref_match(ipo->ipo_srcid, tdbp->tdb_dstid)) - goto nomatchin; - } - - /* Match destination ID */ - if (ipo->ipo_dstid) - { - if (tdbp->tdb_srcid == NULL || - !ipsp_ref_match(ipo->ipo_dstid, tdbp->tdb_srcid)) - goto nomatchin; - } - - /* Add it to the cache */ - if (ipo->ipo_tdb) - TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo, ipo_tdb_next); - ipo->ipo_tdb = tdbp; - TAILQ_INSERT_TAIL(&tdbp->tdb_policy_head, ipo, ipo_tdb_next); - *error = 0; - return NULL; + nomatchout: + /* Cached TDB was not good */ + TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo, + ipo_tdb_next); + ipo->ipo_tdb = NULL; + ipo->ipo_last_searched = 0; + } - nomatchin: /* Nothing needed here, falling through */ - } + /* + * If no SA has been added since the last time we did a + * lookup, there's no point searching for one. However, if the + * destination gateway is left unspecified (or is all-1's), + * always lookup since this is a generic-match rule + * (otherwise, we can have situations where SAs to some + * destinations exist but are not used, possibly leading to an + * explosion in the number of acquired SAs). + */ + if (ipo->ipo_last_searched <= ipsec_last_added) { + /* "Touch" the entry. */ + ipo->ipo_last_searched = time.tv_sec; + + /* Find an appropriate SA from the existing ones. */ + ipo->ipo_tdb = + gettdbbyaddr(dignore ? &sdst : &ipo->ipo_dst, + ipo, m, af); + if (ipo->ipo_tdb) { + TAILQ_INSERT_TAIL(&ipo->ipo_tdb->tdb_policy_head, + ipo, ipo_tdb_next); + *error = 0; + return ipsp_spd_inp(m, af, hlen, error, + direction, tdbp, inp, ipo); + } + } - /* Check whether cached entry applies */ - if (ipo->ipo_tdb) - { - /* - * We only need to check that the correct security protocol and - * security gateway are set; credentials/IDs will be the same, - * since the cached entry is linked on this policy. - */ - if (ipo->ipo_sproto == ipo->ipo_tdb->tdb_sproto && - !bcmp(&ipo->ipo_tdb->tdb_src, dignore ? &ssrc : &ipo->ipo_dst, - ipo->ipo_tdb->tdb_src.sa.sa_len)) - goto skipinputsearch; - - /* Not applicable, unlink */ - TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo, ipo_tdb_next); - ipo->ipo_tdb = NULL; - } + /* So, we don't have an SA -- just a policy. */ + switch (ipo->ipo_type) { + case IPSP_IPSEC_REQUIRE: + /* Acquire SA through key management. */ + if (ipsp_acquire_sa(ipo, dignore ? &sdst : &ipo->ipo_dst, + signore ? NULL : &ipo->ipo_src, ddst, m) != 0) { + *error = EACCES; + return NULL; + } + + /* Fall through */ + case IPSP_IPSEC_DONTACQ: + *error = -EINVAL; /* Silently drop packet. */ + return NULL; - /* Find whether there exists an appropriate SA */ - if (ipo->ipo_last_searched <= ipsec_last_added) - { - ipo->ipo_last_searched = time.tv_sec; /* "touch" */ + case IPSP_IPSEC_ACQUIRE: + /* Acquire SA through key management. */ + if (ipsp_acquire_sa(ipo, dignore ? &sdst : &ipo->ipo_dst, + signore ? NULL : &ipo->ipo_src, ddst, NULL) != 0) { + *error = EACCES; + return NULL; + } + + /* Fall through */ + case IPSP_IPSEC_USE: + *error = 0; + return ipsp_spd_inp(m, af, hlen, error, direction, + tdbp, inp, ipo); + } + } else { /* IPSP_DIRECTION_IN */ + if (tdbp != NULL) { + /* Direct match in the cache. */ + if (ipo->ipo_tdb == tdbp) { + *error = 0; + return ipsp_spd_inp(m, af, hlen, error, + direction, tdbp, inp, ipo); + } + + if (bcmp(dignore ? &ssrc : &ipo->ipo_dst, + &tdbp->tdb_src, tdbp->tdb_src.sa.sa_len) || + (ipo->ipo_sproto != tdbp->tdb_sproto)) + goto nomatchin; + + /* Match source ID. */ + if (ipo->ipo_srcid) { + if (tdbp->tdb_dstid == NULL || + !ipsp_ref_match(ipo->ipo_srcid, + tdbp->tdb_dstid)) + goto nomatchin; + } + + /* Match destination ID. */ + if (ipo->ipo_dstid) { + if (tdbp->tdb_srcid == NULL || + !ipsp_ref_match(ipo->ipo_dstid, + tdbp->tdb_srcid)) + goto nomatchin; + } + + /* Add it to the cache. */ + if (ipo->ipo_tdb) + TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, + ipo, ipo_tdb_next); + ipo->ipo_tdb = tdbp; + TAILQ_INSERT_TAIL(&tdbp->tdb_policy_head, ipo, + ipo_tdb_next); + *error = 0; + return ipsp_spd_inp(m, af, hlen, error, direction, + tdbp, inp, ipo); - ipo->ipo_tdb = gettdbbysrc(dignore ? &ssrc : &ipo->ipo_dst, - ipo, m, af); - if (ipo->ipo_tdb) - TAILQ_INSERT_TAIL(&ipo->ipo_tdb->tdb_policy_head, ipo, - ipo_tdb_next); - } - skipinputsearch: + nomatchin: /* Nothing needed here, falling through */ + } - switch (ipo->ipo_type) - { - case IPSP_IPSEC_REQUIRE: - /* If an appropriate SA exists, don't acquire another */ - if (ipo->ipo_tdb) - { - *error = -EINVAL; - return NULL; + /* Check whether cached entry applies. */ + if (ipo->ipo_tdb) { + /* + * We only need to check that the correct + * security protocol and security gateway are + * set; credentials/IDs will be the same, + * since the cached entry is linked on this + * policy. + */ + if (ipo->ipo_sproto == ipo->ipo_tdb->tdb_sproto && + !bcmp(&ipo->ipo_tdb->tdb_src, dignore ? &ssrc : &ipo->ipo_dst, + ipo->ipo_tdb->tdb_src.sa.sa_len)) + goto skipinputsearch; + + /* Not applicable, unlink. */ + TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo, + ipo_tdb_next); + ipo->ipo_tdb = NULL; } - /* Acquire SA through key management */ - if ((*error = ipsp_acquire_sa(ipo, - dignore ? &ssrc : &ipo->ipo_dst, - signore ? NULL : &ipo->ipo_src, - ddst, m)) != 0) - return NULL; - - /* Fall through */ - case IPSP_IPSEC_DONTACQ: - /* Drop packet */ - *error = -EINVAL; - return NULL; + /* Find whether there exists an appropriate SA. */ + if (ipo->ipo_last_searched <= ipsec_last_added) { + ipo->ipo_last_searched = time.tv_sec; /* "touch" */ - case IPSP_IPSEC_ACQUIRE: - /* If an appropriate SA exists, don't acquire another */ - if (ipo->ipo_tdb) - { - *error = 0; - return NULL; + ipo->ipo_tdb = + gettdbbysrc(dignore ? &ssrc : &ipo->ipo_dst, + ipo, m, af); + if (ipo->ipo_tdb) + TAILQ_INSERT_TAIL(&ipo->ipo_tdb->tdb_policy_head, + ipo, ipo_tdb_next); } + skipinputsearch: - /* Acquire SA through key management */ - if ((*error = ipsp_acquire_sa(ipo, - dignore ? &ssrc : &ipo->ipo_dst, - signore ? NULL : &ipo->ipo_src, - ddst, NULL)) != 0) - return NULL; + switch (ipo->ipo_type) { + case IPSP_IPSEC_REQUIRE: + /* If appropriate SA exists, don't acquire another. */ + if (ipo->ipo_tdb) { + *error = -EINVAL; + return NULL; + } + + /* Acquire SA through key management. */ + if ((*error = ipsp_acquire_sa(ipo, + dignore ? &ssrc : &ipo->ipo_dst, + signore ? NULL : &ipo->ipo_src, ddst, m)) != 0) + return NULL; + + /* Fall through */ + case IPSP_IPSEC_DONTACQ: + /* Drop packet. */ + *error = -EINVAL; + return NULL; - /* Fall through */ - case IPSP_IPSEC_USE: - /* - * It doesn't matter what protection it had (if any), - * just accept it -- equivalent to PERMIT for input. - * This means we can't say that we want in incoming - * packet to be unprotected -- at least not directly; - * we can always have a DENY policy for ESP/AH packets. - */ - *error = 0; - return NULL; + case IPSP_IPSEC_ACQUIRE: + /* If appropriate SA exists, don't acquire another. */ + if (ipo->ipo_tdb) { + *error = 0; + return ipsp_spd_inp(m, af, hlen, error, + direction, tdbp, inp, ipo); + } + + /* Acquire SA through key management. */ + if ((*error = ipsp_acquire_sa(ipo, + dignore ? &ssrc : &ipo->ipo_dst, + signore ? NULL : &ipo->ipo_src, ddst, NULL)) != 0) + return NULL; + + /* Fall through */ + case IPSP_IPSEC_USE: + *error = 0; + return ipsp_spd_inp(m, af, hlen, error, direction, + tdbp, inp, ipo); + } } - } - /* Shouldn't ever get this far */ - *error = EINVAL; - return NULL; + /* Shouldn't ever get this far. */ + *error = EINVAL; + return NULL; } /* @@ -564,34 +554,34 @@ ipsp_spd_lookup(struct mbuf *m, int af, int hlen, int *error, int direction, int ipsec_delete_policy(struct ipsec_policy *ipo) { - int err = 0; + int err = 0; - /* Delete */ - if (!(ipo->ipo_flags & IPSP_POLICY_SOCKET)) - err = rtrequest(RTM_DELETE, (struct sockaddr *) &ipo->ipo_addr, - (struct sockaddr *) 0, - (struct sockaddr *) &ipo->ipo_mask, - 0, (struct rtentry **) 0); + /* Delete */ + if (!(ipo->ipo_flags & IPSP_POLICY_SOCKET)) + err = rtrequest(RTM_DELETE, (struct sockaddr *) &ipo->ipo_addr, + (struct sockaddr *) 0, + (struct sockaddr *) &ipo->ipo_mask, + 0, (struct rtentry **) 0); - if (ipo->ipo_tdb) - TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo, ipo_tdb_next); + if (ipo->ipo_tdb) + TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo, ipo_tdb_next); - TAILQ_REMOVE(&ipsec_policy_head, ipo, ipo_list); + TAILQ_REMOVE(&ipsec_policy_head, ipo, ipo_list); - if (ipo->ipo_srcid) - ipsp_reffree(ipo->ipo_srcid); - if (ipo->ipo_dstid) - ipsp_reffree(ipo->ipo_dstid); - if (ipo->ipo_local_cred) - ipsp_reffree(ipo->ipo_local_cred); - if (ipo->ipo_local_auth) - ipsp_reffree(ipo->ipo_local_cred); + if (ipo->ipo_srcid) + ipsp_reffree(ipo->ipo_srcid); + if (ipo->ipo_dstid) + ipsp_reffree(ipo->ipo_dstid); + if (ipo->ipo_local_cred) + ipsp_reffree(ipo->ipo_local_cred); + if (ipo->ipo_local_auth) + ipsp_reffree(ipo->ipo_local_cred); - FREE(ipo, M_IPSEC_POLICY); + FREE(ipo, M_IPSEC_POLICY); - ipsec_in_use--; + ipsec_in_use--; - return err; + return err; } /* @@ -601,43 +591,42 @@ struct ipsec_policy * ipsec_add_policy(struct sockaddr_encap *dst, struct sockaddr_encap *mask, union sockaddr_union *sdst, int type, int sproto) { - struct sockaddr_encap encapgw; - struct ipsec_policy *ipon; - - MALLOC(ipon, struct ipsec_policy *, sizeof(struct ipsec_policy), - M_IPSEC_POLICY, M_NOWAIT); - if (ipon == NULL) - return NULL; - - bzero(ipon, sizeof(struct ipsec_policy)); - bzero((caddr_t) &encapgw, sizeof(struct sockaddr_encap)); - - encapgw.sen_len = SENT_LEN; - encapgw.sen_family = PF_KEY; - encapgw.sen_type = SENT_IPSP; - encapgw.sen_ipsp = ipon; - - if (rtrequest(RTM_ADD, (struct sockaddr *) dst, - (struct sockaddr *) &encapgw, (struct sockaddr *) mask, - RTF_UP | RTF_GATEWAY | RTF_STATIC, - (struct rtentry **) 0) != 0) - { - DPRINTF(("ipsec_add_policy: failed to add policy\n")); - FREE(ipon, M_IPSEC_POLICY); - return NULL; - } + struct sockaddr_encap encapgw; + struct ipsec_policy *ipon; + + MALLOC(ipon, struct ipsec_policy *, sizeof(struct ipsec_policy), + M_IPSEC_POLICY, M_NOWAIT); + if (ipon == NULL) + return NULL; - ipsec_in_use++; + bzero(ipon, sizeof(struct ipsec_policy)); + bzero((caddr_t) &encapgw, sizeof(struct sockaddr_encap)); + + encapgw.sen_len = SENT_LEN; + encapgw.sen_family = PF_KEY; + encapgw.sen_type = SENT_IPSP; + encapgw.sen_ipsp = ipon; + + if (rtrequest(RTM_ADD, (struct sockaddr *) dst, + (struct sockaddr *) &encapgw, (struct sockaddr *) mask, + RTF_UP | RTF_GATEWAY | RTF_STATIC, + (struct rtentry **) 0) != 0) { + DPRINTF(("ipsec_add_policy: failed to add policy\n")); + FREE(ipon, M_IPSEC_POLICY); + return NULL; + } - bcopy(dst, &ipon->ipo_addr, sizeof(struct sockaddr_encap)); - bcopy(mask, &ipon->ipo_mask, sizeof(struct sockaddr_encap)); - bcopy(sdst, &ipon->ipo_dst, sizeof(union sockaddr_union)); - ipon->ipo_sproto = sproto; - ipon->ipo_type = type; + ipsec_in_use++; - TAILQ_INSERT_HEAD(&ipsec_policy_head, ipon, ipo_list); + bcopy(dst, &ipon->ipo_addr, sizeof(struct sockaddr_encap)); + bcopy(mask, &ipon->ipo_mask, sizeof(struct sockaddr_encap)); + bcopy(sdst, &ipon->ipo_dst, sizeof(union sockaddr_union)); + ipon->ipo_sproto = sproto; + ipon->ipo_type = type; - return ipon; + TAILQ_INSERT_HEAD(&ipsec_policy_head, ipon, ipo_list); + + return ipon; } /* @@ -646,13 +635,13 @@ ipsec_add_policy(struct sockaddr_encap *dst, struct sockaddr_encap *mask, void ipsp_delete_acquire(void *v) { - struct ipsec_acquire *ipa = v; + struct ipsec_acquire *ipa = v; - timeout_del(&ipa->ipa_timeout); - TAILQ_REMOVE(&ipsec_acquire_head, ipa, ipa_next); - if (ipa->ipa_packet) - m_freem(ipa->ipa_packet); - FREE(ipa, M_IPSEC_POLICY); + timeout_del(&ipa->ipa_timeout); + TAILQ_REMOVE(&ipsec_acquire_head, ipa, ipa_next); + if (ipa->ipa_packet) + m_freem(ipa->ipa_packet); + FREE(ipa, M_IPSEC_POLICY); } /* @@ -661,92 +650,94 @@ ipsp_delete_acquire(void *v) void ipsp_clear_acquire(struct tdb *tdb) { - struct ipsec_acquire *ipa; - struct ifqueue *ifq; - int s; - - while ((ipa = ipsp_pending_acquire(&tdb->tdb_dst)) != NULL) - { - - /* Retransmit */ - if (ipa->ipa_packet) - { - switch (ipa->ipa_info.sen_type) - { + struct ipsec_acquire *ipa; + struct ifqueue *ifq; + int s; + + while ((ipa = ipsp_pending_acquire(&tdb->tdb_dst)) != NULL) { + /* Retransmit */ + if (ipa->ipa_packet) { + switch (ipa->ipa_info.sen_type) { #ifdef INET - case SENT_IP4: - { - struct ip *ip; - - switch (ipa->ipa_info.sen_direction) - { - case IPSP_DIRECTION_OUT: - ip = mtod(ipa->ipa_packet, struct ip *); - if (ipa->ipa_packet->m_len < sizeof(struct ip)) - break; - - /* Same as in ip_output() -- massage the header */ - ip->ip_len = htons((u_short) ip->ip_len); - ip->ip_off = htons((u_short) ip->ip_off); - ipa->ipa_packet->m_flags &= ~(M_MCAST | M_BCAST); - - ipsp_process_packet(ipa->ipa_packet, tdb, - AF_INET, 0); - ipa->ipa_packet = NULL; - break; - - case IPSP_DIRECTION_IN: - ifq = &ipintrq; - s = splimp(); - if (IF_QFULL(ifq)) - { - IF_DROP(ifq); - splx(s); - break; - } - IF_ENQUEUE(ifq, ipa->ipa_packet); - ipa->ipa_packet = NULL; - schednetisr(NETISR_IP); - splx(s); - break; - } - } - break; + case SENT_IP4: + { + struct ip *ip; + + switch (ipa->ipa_info.sen_direction) { + case IPSP_DIRECTION_OUT: + ip = mtod(ipa->ipa_packet, + struct ip *); + + if (ipa->ipa_packet->m_len < + sizeof(struct ip)) + break; + + /* Same as in ip_output() -- + * massage the header. + */ + + ip->ip_len = + htons((u_short) ip->ip_len); + ip->ip_off = + htons((u_short) ip->ip_off); + ipa->ipa_packet->m_flags &= + ~(M_MCAST | M_BCAST); + + ipsp_process_packet(ipa->ipa_packet, + tdb, AF_INET, 0); + ipa->ipa_packet = NULL; + break; + + case IPSP_DIRECTION_IN: + ifq = &ipintrq; + s = splimp(); + if (IF_QFULL(ifq)) { + IF_DROP(ifq); + splx(s); + break; + } + IF_ENQUEUE(ifq, ipa->ipa_packet); + ipa->ipa_packet = NULL; + schednetisr(NETISR_IP); + splx(s); + break; + } + } + break; #endif /* INET */ #ifdef INET6 - case SENT_IP6: - switch (ipa->ipa_info.sen_ip6_direction) - { - case IPSP_DIRECTION_OUT: - ipa->ipa_packet->m_flags &= ~(M_BCAST | M_MCAST); - ipsp_process_packet(ipa->ipa_packet, tdb, - AF_INET6, 0); - ipa->ipa_packet = NULL; - break; - - case IPSP_DIRECTION_IN: - ifq = &ip6intrq; - s = splimp(); - if (IF_QFULL(ifq)) - { - IF_DROP(ifq); - splx(s); + case SENT_IP6: + switch (ipa->ipa_info.sen_ip6_direction) { + case IPSP_DIRECTION_OUT: + ipa->ipa_packet->m_flags &= + ~(M_BCAST | M_MCAST); + ipsp_process_packet(ipa->ipa_packet, + tdb, AF_INET6, 0); + ipa->ipa_packet = NULL; + break; + + case IPSP_DIRECTION_IN: + ifq = &ip6intrq; + s = splimp(); + if (IF_QFULL(ifq)) { + IF_DROP(ifq); + splx(s); + break; + } + IF_ENQUEUE(ifq, ipa->ipa_packet); + ipa->ipa_packet = NULL; + schednetisr(NETISR_IPV6); + splx(s); + break; + } break; - } - IF_ENQUEUE(ifq, ipa->ipa_packet); - ipa->ipa_packet = NULL; - schednetisr(NETISR_IPV6); - splx(s); - break; - } - break; #endif /* INET6 */ - } - } + } + } - ipsp_delete_acquire(ipa); - } + ipsp_delete_acquire(ipa); + } } /* @@ -756,17 +747,15 @@ ipsp_clear_acquire(struct tdb *tdb) struct ipsec_acquire * ipsp_pending_acquire(union sockaddr_union *gw) { - struct ipsec_acquire *ipa; + struct ipsec_acquire *ipa; - for (ipa = TAILQ_FIRST(&ipsec_acquire_head); - ipa; - ipa = TAILQ_NEXT(ipa, ipa_next)) - { - if (!bcmp(gw, &ipa->ipa_addr, gw->sa.sa_len)) - return ipa; - } + for (ipa = TAILQ_FIRST(&ipsec_acquire_head); ipa; + ipa = TAILQ_NEXT(ipa, ipa_next)) { + if (!bcmp(gw, &ipa->ipa_addr, gw->sa.sa_len)) + return ipa; + } - return NULL; + return NULL; } /* @@ -778,149 +767,139 @@ ipsp_acquire_sa(struct ipsec_policy *ipo, union sockaddr_union *gw, union sockaddr_union *laddr, struct sockaddr_encap *ddst, struct mbuf *m) { - struct ipsec_acquire *ipa; + struct ipsec_acquire *ipa; #ifdef INET6 - int i; + int i; #endif - /* Check whether request has been made already. */ - if ((ipa = ipsp_pending_acquire(gw)) != NULL) - { - if (ipa->ipa_packet && m) - { - m_freem(ipa->ipa_packet); - ipa->ipa_packet = m_copym2(m, 0, M_COPYALL, M_DONTWAIT); - } + /* Check whether request has been made already. */ + if ((ipa = ipsp_pending_acquire(gw)) != NULL) { + if (ipa->ipa_packet && m) { + m_freem(ipa->ipa_packet); + ipa->ipa_packet = m_copym2(m, 0, M_COPYALL, + M_DONTWAIT); + } - return 0; - } + return 0; + } - /* Add request in cache and proceed */ - MALLOC(ipa, struct ipsec_acquire *, sizeof(struct ipsec_acquire), - M_IPSEC_POLICY, M_DONTWAIT); - if (ipa == NULL) - return ENOMEM; + /* Add request in cache and proceed */ + MALLOC(ipa, struct ipsec_acquire *, sizeof(struct ipsec_acquire), + M_IPSEC_POLICY, M_DONTWAIT); + if (ipa == NULL) + return ENOMEM; - bzero(ipa, sizeof(struct ipsec_acquire)); - bcopy(gw, &ipa->ipa_addr, sizeof(union sockaddr_union)); - timeout_set(&ipa->ipa_timeout, ipsp_delete_acquire, ipa); + bzero(ipa, sizeof(struct ipsec_acquire)); + bcopy(gw, &ipa->ipa_addr, sizeof(union sockaddr_union)); + timeout_set(&ipa->ipa_timeout, ipsp_delete_acquire, ipa); - ipa->ipa_info.sen_len = ipa->ipa_mask.sen_len = SENT_LEN; - ipa->ipa_info.sen_family = ipa->ipa_mask.sen_family = PF_KEY; + ipa->ipa_info.sen_len = ipa->ipa_mask.sen_len = SENT_LEN; + ipa->ipa_info.sen_family = ipa->ipa_mask.sen_family = PF_KEY; - /* Just copy the right information */ - switch (ipo->ipo_addr.sen_type) - { + /* Just copy the right information */ + switch (ipo->ipo_addr.sen_type) { #ifdef INET case SENT_IP4: - ipa->ipa_info.sen_type = ipa->ipa_mask.sen_type = SENT_IP4; - ipa->ipa_info.sen_direction = ipo->ipo_addr.sen_direction; - ipa->ipa_mask.sen_direction = ipo->ipo_mask.sen_direction; - - if (ipo->ipo_mask.sen_ip_src.s_addr == INADDR_ANY || - ipo->ipo_addr.sen_ip_src.s_addr == INADDR_ANY || - ipsp_is_unspecified(ipo->ipo_dst)) - { - ipa->ipa_info.sen_ip_src = ddst->sen_ip_src; - ipa->ipa_mask.sen_ip_src.s_addr = INADDR_BROADCAST; - } - else - { - ipa->ipa_info.sen_ip_src = ipo->ipo_addr.sen_ip_src; - ipa->ipa_mask.sen_ip_src = ipo->ipo_mask.sen_ip_src; - } - - if (ipo->ipo_mask.sen_ip_dst.s_addr == INADDR_ANY || - ipo->ipo_addr.sen_ip_dst.s_addr == INADDR_ANY || - ipsp_is_unspecified(ipo->ipo_dst)) - { - ipa->ipa_info.sen_ip_dst = ddst->sen_ip_dst; - ipa->ipa_mask.sen_ip_dst.s_addr = INADDR_BROADCAST; - } - else - { - ipa->ipa_info.sen_ip_dst = ipo->ipo_addr.sen_ip_dst; - ipa->ipa_mask.sen_ip_dst = ipo->ipo_mask.sen_ip_dst; - } - - ipa->ipa_info.sen_proto = ipo->ipo_addr.sen_proto; - ipa->ipa_mask.sen_proto = ipo->ipo_mask.sen_proto; - - if (ipo->ipo_addr.sen_proto) - { - ipa->ipa_info.sen_sport = ipo->ipo_addr.sen_sport; - ipa->ipa_mask.sen_sport = ipo->ipo_mask.sen_sport; - - ipa->ipa_info.sen_dport = ipo->ipo_addr.sen_dport; - ipa->ipa_mask.sen_dport = ipo->ipo_mask.sen_dport; - } - break; + ipa->ipa_info.sen_type = ipa->ipa_mask.sen_type = SENT_IP4; + ipa->ipa_info.sen_direction = ipo->ipo_addr.sen_direction; + ipa->ipa_mask.sen_direction = ipo->ipo_mask.sen_direction; + + if (ipo->ipo_mask.sen_ip_src.s_addr == INADDR_ANY || + ipo->ipo_addr.sen_ip_src.s_addr == INADDR_ANY || + ipsp_is_unspecified(ipo->ipo_dst)) { + ipa->ipa_info.sen_ip_src = ddst->sen_ip_src; + ipa->ipa_mask.sen_ip_src.s_addr = INADDR_BROADCAST; + } else { + ipa->ipa_info.sen_ip_src = ipo->ipo_addr.sen_ip_src; + ipa->ipa_mask.sen_ip_src = ipo->ipo_mask.sen_ip_src; + } + + if (ipo->ipo_mask.sen_ip_dst.s_addr == INADDR_ANY || + ipo->ipo_addr.sen_ip_dst.s_addr == INADDR_ANY || + ipsp_is_unspecified(ipo->ipo_dst)) { + ipa->ipa_info.sen_ip_dst = ddst->sen_ip_dst; + ipa->ipa_mask.sen_ip_dst.s_addr = INADDR_BROADCAST; + } else { + ipa->ipa_info.sen_ip_dst = ipo->ipo_addr.sen_ip_dst; + ipa->ipa_mask.sen_ip_dst = ipo->ipo_mask.sen_ip_dst; + } + + ipa->ipa_info.sen_proto = ipo->ipo_addr.sen_proto; + ipa->ipa_mask.sen_proto = ipo->ipo_mask.sen_proto; + + if (ipo->ipo_addr.sen_proto) { + ipa->ipa_info.sen_sport = ipo->ipo_addr.sen_sport; + ipa->ipa_mask.sen_sport = ipo->ipo_mask.sen_sport; + + ipa->ipa_info.sen_dport = ipo->ipo_addr.sen_dport; + ipa->ipa_mask.sen_dport = ipo->ipo_mask.sen_dport; + } + break; #endif /* INET */ #ifdef INET6 case SENT_IP6: - ipa->ipa_info.sen_type = ipa->ipa_mask.sen_type = SENT_IP6; - ipa->ipa_info.sen_ip6_direction = ipo->ipo_addr.sen_ip6_direction; - ipa->ipa_mask.sen_ip6_direction = ipo->ipo_mask.sen_ip6_direction; - - if (IN6_IS_ADDR_UNSPECIFIED(&ipo->ipo_mask.sen_ip6_src) || - IN6_IS_ADDR_UNSPECIFIED(&ipo->ipo_addr.sen_ip6_src) || - ipsp_is_unspecified(ipo->ipo_dst)) - { - ipa->ipa_info.sen_ip6_src = ddst->sen_ip6_src; - for (i = 0; i < 16; i++) - ipa->ipa_mask.sen_ip6_src.s6_addr8[i] = 0xff; - } - else - { - ipa->ipa_info.sen_ip6_src = ipo->ipo_addr.sen_ip6_src; - ipa->ipa_mask.sen_ip6_src = ipo->ipo_mask.sen_ip6_src; - } - - if (IN6_IS_ADDR_UNSPECIFIED(&ipo->ipo_mask.sen_ip6_dst) || - IN6_IS_ADDR_UNSPECIFIED(&ipo->ipo_addr.sen_ip6_dst) || - ipsp_is_unspecified(ipo->ipo_dst)) - { - ipa->ipa_info.sen_ip6_dst = ddst->sen_ip6_dst; - for (i = 0; i < 16; i++) - ipa->ipa_mask.sen_ip6_dst.s6_addr8[i] = 0xff; - } - else - { - ipa->ipa_info.sen_ip6_dst = ipo->ipo_addr.sen_ip6_dst; - ipa->ipa_mask.sen_ip6_dst = ipo->ipo_mask.sen_ip6_dst; - } - - ipa->ipa_info.sen_ip6_proto = ipo->ipo_addr.sen_ip6_proto; - ipa->ipa_mask.sen_ip6_proto = ipo->ipo_mask.sen_ip6_proto; - - if (ipo->ipo_mask.sen_ip6_proto) - { - ipa->ipa_info.sen_ip6_sport = ipo->ipo_addr.sen_ip6_sport; - ipa->ipa_mask.sen_ip6_sport = ipo->ipo_mask.sen_ip6_sport; - ipa->ipa_info.sen_ip6_dport = ipo->ipo_addr.sen_ip6_dport; - ipa->ipa_mask.sen_ip6_dport = ipo->ipo_mask.sen_ip6_dport; - } - break; + ipa->ipa_info.sen_type = ipa->ipa_mask.sen_type = SENT_IP6; + ipa->ipa_info.sen_ip6_direction = + ipo->ipo_addr.sen_ip6_direction; + ipa->ipa_mask.sen_ip6_direction = + ipo->ipo_mask.sen_ip6_direction; + + if (IN6_IS_ADDR_UNSPECIFIED(&ipo->ipo_mask.sen_ip6_src) || + IN6_IS_ADDR_UNSPECIFIED(&ipo->ipo_addr.sen_ip6_src) || + ipsp_is_unspecified(ipo->ipo_dst)) { + ipa->ipa_info.sen_ip6_src = ddst->sen_ip6_src; + for (i = 0; i < 16; i++) + ipa->ipa_mask.sen_ip6_src.s6_addr8[i] = 0xff; + } else { + ipa->ipa_info.sen_ip6_src = ipo->ipo_addr.sen_ip6_src; + ipa->ipa_mask.sen_ip6_src = ipo->ipo_mask.sen_ip6_src; + } + + if (IN6_IS_ADDR_UNSPECIFIED(&ipo->ipo_mask.sen_ip6_dst) || + IN6_IS_ADDR_UNSPECIFIED(&ipo->ipo_addr.sen_ip6_dst) || + ipsp_is_unspecified(ipo->ipo_dst)) { + ipa->ipa_info.sen_ip6_dst = ddst->sen_ip6_dst; + for (i = 0; i < 16; i++) + ipa->ipa_mask.sen_ip6_dst.s6_addr8[i] = 0xff; + } else { + ipa->ipa_info.sen_ip6_dst = ipo->ipo_addr.sen_ip6_dst; + ipa->ipa_mask.sen_ip6_dst = ipo->ipo_mask.sen_ip6_dst; + } + + ipa->ipa_info.sen_ip6_proto = ipo->ipo_addr.sen_ip6_proto; + ipa->ipa_mask.sen_ip6_proto = ipo->ipo_mask.sen_ip6_proto; + + if (ipo->ipo_mask.sen_ip6_proto) { + ipa->ipa_info.sen_ip6_sport = + ipo->ipo_addr.sen_ip6_sport; + ipa->ipa_mask.sen_ip6_sport = + ipo->ipo_mask.sen_ip6_sport; + ipa->ipa_info.sen_ip6_dport = + ipo->ipo_addr.sen_ip6_dport; + ipa->ipa_mask.sen_ip6_dport = + ipo->ipo_mask.sen_ip6_dport; + } + break; #endif /* INET6 */ default: - FREE(ipa, M_IPSEC_POLICY); - return 0; - } - - /* - * Store the packet for eventual retransmission -- failure is not - * catastrophic. - */ - if (m) - ipa->ipa_packet = m_copym2(m, 0, M_COPYALL, M_DONTWAIT); - - timeout_add(&ipa->ipa_timeout, ipsec_expire_acquire * hz); - TAILQ_INSERT_TAIL(&ipsec_acquire_head, ipa, ipa_next); - - /* PF_KEYv2 notification message */ - return pfkeyv2_acquire(ipo, gw, laddr, &ipa->ipa_seq, ddst); + FREE(ipa, M_IPSEC_POLICY); + return 0; + } + + /* + * Store the packet for eventual retransmission -- failure is not + * catastrophic. + */ + if (m) + ipa->ipa_packet = m_copym2(m, 0, M_COPYALL, M_DONTWAIT); + + timeout_add(&ipa->ipa_timeout, ipsec_expire_acquire * hz); + TAILQ_INSERT_TAIL(&ipsec_acquire_head, ipa, ipa_next); + + /* PF_KEYv2 notification message */ + return pfkeyv2_acquire(ipo, gw, laddr, &ipa->ipa_seq, ddst); } /* @@ -930,13 +909,26 @@ ipsp_acquire_sa(struct ipsec_policy *ipo, union sockaddr_union *gw, struct ipsec_acquire * ipsec_get_acquire(u_int32_t seq) { - struct ipsec_acquire *ipa; + struct ipsec_acquire *ipa; - for (ipa = TAILQ_FIRST(&ipsec_acquire_head); - ipa; - ipa = TAILQ_NEXT(ipa, ipa_next)) - if (ipa->ipa_seq == seq) - return ipa; + for (ipa = TAILQ_FIRST(&ipsec_acquire_head); ipa; + ipa = TAILQ_NEXT(ipa, ipa_next)) + if (ipa->ipa_seq == seq) + return ipa; - return NULL; + return NULL; +} + +/* + * Deal with PCB security requirements. + */ +struct tdb * +ipsp_spd_inp(struct mbuf *m, int af, int hlen, int *error, int direction, + struct tdb *tdbp, struct inpcb *inp, struct ipsec_policy *ipo) +{ + /* XXX */ + if (ipo) + return ipo->ipo_tdb; + else + return NULL; } |