diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2010-07-09 16:58:07 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2010-07-09 16:58:07 +0000 |
commit | 9b4939a135e7439d02025abc3fae443f6b34a436 (patch) | |
tree | 4d6d474863598a533548ed438df229f82ffd9a59 /sys/netinet/ip_ipsp.c | |
parent | 74c8e65b12d50b84bca2cad414861a6a3de2ec89 (diff) |
Add support for using IPsec in multiple rdomains.
This allows to run isakmpd/iked/ipsecctl in multiple rdomains
independently (with "route exec"); the kernel will pickup the rdomain
from the process context of the pfkey socket and load the flows and
SAs into the matching rdomain encap routing table. The network stack
also needs to pass the rdomain to the ipsec stack to lookup the
correct rdomain that belongs to an interface/mbuf/... You can now run
individual IPsec configs per rdomain or create IPsec VPNs between
multiple rdomains on the same machine ;). Note that a primary enc(4)
in addition to enc0 interface is required per rdomain, eg. enc1 rdomain 1.
Test by some people, mostly on existing "rdomain 0" setups. Was in
snaps for some days and people didn't complain.
ok claudio@ naddy@
Diffstat (limited to 'sys/netinet/ip_ipsp.c')
-rw-r--r-- | sys/netinet/ip_ipsp.c | 90 |
1 files changed, 58 insertions, 32 deletions
diff --git a/sys/netinet/ip_ipsp.c b/sys/netinet/ip_ipsp.c index 40df7b69f7b..93c18ee3a5d 100644 --- a/sys/netinet/ip_ipsp.c +++ b/sys/netinet/ip_ipsp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_ipsp.c,v 1.180 2010/04/20 22:05:43 tedu Exp $ */ +/* $OpenBSD: ip_ipsp.c,v 1.181 2010/07/09 16:58:06 reyk Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), * Angelos D. Keromytis (kermit@csd.uch.gr), @@ -94,7 +94,7 @@ void tdb_timeout(void *v); void tdb_firstuse(void *v); void tdb_soft_timeout(void *v); void tdb_soft_firstuse(void *v); -int tdb_hash(u_int32_t, union sockaddr_union *, u_int8_t); +int tdb_hash(u_int, u_int32_t, union sockaddr_union *, u_int8_t); extern int ipsec_auth_default_level; extern int ipsec_esp_trans_default_level; @@ -155,7 +155,8 @@ static int tdb_count; * so we cannot be DoS-attacked via choosing of the data to hash. */ int -tdb_hash(u_int32_t spi, union sockaddr_union *dst, u_int8_t proto) +tdb_hash(u_int rdomain, 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; @@ -168,7 +169,7 @@ tdb_hash(u_int32_t spi, union sockaddr_union *dst, u_int8_t proto) while (mult2 == 0) mult2 = arc4random(); - hash = (spi ^ proto) * mult1; + hash = (spi ^ proto ^ rdomain) * mult1; for (i = 0; i < SA_LEN(&dst->sa); i++) { val32 = (val32 << 8) | ptr[i]; if (i % 4 == 3) { @@ -192,8 +193,9 @@ tdb_hash(u_int32_t spi, union sockaddr_union *dst, u_int8_t proto) * an error return value. */ 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) +reserve_spi(u_int rdomain, u_int32_t sspi, u_int32_t tspi, + union sockaddr_union *src, union sockaddr_union *dst, + u_int8_t sproto, int *errval) { struct tdb *tdbp; u_int32_t spi; @@ -248,13 +250,13 @@ reserve_spi(u_int32_t sspi, u_int32_t tspi, union sockaddr_union *src, /* Check whether we're using this SPI already. */ s = spltdb(); - tdbp = gettdb(spi, dst, sproto); + tdbp = gettdb(rdomain, spi, dst, sproto); splx(s); if (tdbp != (struct tdb *) NULL) continue; - tdbp = tdb_alloc(); + tdbp = tdb_alloc(rdomain); tdbp->tdb_spi = spi; bcopy(&dst->sa, &tdbp->tdb_dst.sa, SA_LEN(&dst->sa)); @@ -289,7 +291,7 @@ reserve_spi(u_int32_t sspi, u_int32_t tspi, union sockaddr_union *src, * Caller is responsible for setting at least spltdb(). */ struct tdb * -gettdb(u_int32_t spi, union sockaddr_union *dst, u_int8_t proto) +gettdb(u_int rdomain, u_int32_t spi, union sockaddr_union *dst, u_int8_t proto) { u_int32_t hashval; struct tdb *tdbp; @@ -297,10 +299,11 @@ gettdb(u_int32_t spi, union sockaddr_union *dst, u_int8_t proto) if (tdbh == NULL) return (struct tdb *) NULL; - hashval = tdb_hash(spi, dst, proto); + hashval = tdb_hash(rdomain, spi, dst, proto); for (tdbp = tdbh[hashval]; tdbp != NULL; tdbp = tdbp->tdb_hnext) if ((tdbp->tdb_spi == spi) && (tdbp->tdb_sproto == proto) && + (tdbp->tdb_rdomain == rdomain) && !bcmp(&tdbp->tdb_dst, dst, SA_LEN(&dst->sa))) break; @@ -313,7 +316,7 @@ gettdb(u_int32_t spi, union sockaddr_union *dst, u_int8_t proto) * matches all SPIs. */ struct tdb * -gettdbbysrcdst(u_int32_t spi, union sockaddr_union *src, +gettdbbysrcdst(u_int rdomain, u_int32_t spi, union sockaddr_union *src, union sockaddr_union *dst, u_int8_t proto) { u_int32_t hashval; @@ -323,11 +326,12 @@ gettdbbysrcdst(u_int32_t spi, union sockaddr_union *src, if (tdbsrc == NULL) return (struct tdb *) NULL; - hashval = tdb_hash(0, src, proto); + hashval = tdb_hash(rdomain, 0, src, proto); for (tdbp = tdbsrc[hashval]; tdbp != NULL; tdbp = tdbp->tdb_snext) if (tdbp->tdb_sproto == proto && (spi == 0 || tdbp->tdb_spi == spi) && + (tdbp->tdb_rdomain == rdomain) && ((tdbp->tdb_flags & TDBF_INVALID) == 0) && (tdbp->tdb_dst.sa.sa_family == AF_UNSPEC || !bcmp(&tdbp->tdb_dst, dst, SA_LEN(&dst->sa))) && @@ -339,11 +343,12 @@ gettdbbysrcdst(u_int32_t spi, union sockaddr_union *src, bzero(&su_null, sizeof(su_null)); su_null.sa.sa_len = sizeof(struct sockaddr); - hashval = tdb_hash(0, &su_null, proto); + hashval = tdb_hash(rdomain, 0, &su_null, proto); for (tdbp = tdbsrc[hashval]; tdbp != NULL; tdbp = tdbp->tdb_snext) if (tdbp->tdb_sproto == proto && (spi == 0 || tdbp->tdb_spi == spi) && + (tdbp->tdb_rdomain == rdomain) && ((tdbp->tdb_flags & TDBF_INVALID) == 0) && (tdbp->tdb_dst.sa.sa_family == AF_UNSPEC || !bcmp(&tdbp->tdb_dst, dst, SA_LEN(&dst->sa))) && @@ -412,7 +417,7 @@ ipsp_aux_match(struct tdb *tdb, * the desired IDs. */ struct tdb * -gettdbbyaddr(union sockaddr_union *dst, u_int8_t sproto, +gettdbbyaddr(u_int rdomain, union sockaddr_union *dst, u_int8_t sproto, struct ipsec_ref *srcid, struct ipsec_ref *dstid, struct ipsec_ref *local_cred, struct mbuf *m, int af, struct sockaddr_encap *filter, struct sockaddr_encap *filtermask) @@ -423,10 +428,11 @@ gettdbbyaddr(union sockaddr_union *dst, u_int8_t sproto, if (tdbaddr == NULL) return (struct tdb *) NULL; - hashval = tdb_hash(0, dst, sproto); + hashval = tdb_hash(rdomain, 0, dst, sproto); for (tdbp = tdbaddr[hashval]; tdbp != NULL; tdbp = tdbp->tdb_anext) if ((tdbp->tdb_sproto == sproto) && + (tdbp->tdb_rdomain == rdomain) && ((tdbp->tdb_flags & TDBF_INVALID) == 0) && (!bcmp(&tdbp->tdb_dst, dst, SA_LEN(&dst->sa)))) { /* Do IDs and local credentials match ? */ @@ -444,7 +450,7 @@ gettdbbyaddr(union sockaddr_union *dst, u_int8_t sproto, * the desired IDs. */ struct tdb * -gettdbbysrc(union sockaddr_union *src, u_int8_t sproto, +gettdbbysrc(u_int rdomain, union sockaddr_union *src, u_int8_t sproto, struct ipsec_ref *srcid, struct ipsec_ref *dstid, struct mbuf *m, int af, struct sockaddr_encap *filter, struct sockaddr_encap *filtermask) @@ -455,10 +461,11 @@ gettdbbysrc(union sockaddr_union *src, u_int8_t sproto, if (tdbsrc == NULL) return (struct tdb *) NULL; - hashval = tdb_hash(0, src, sproto); + hashval = tdb_hash(rdomain, 0, src, sproto); for (tdbp = tdbsrc[hashval]; tdbp != NULL; tdbp = tdbp->tdb_snext) if ((tdbp->tdb_sproto == sproto) && + (tdbp->tdb_rdomain == rdomain) && ((tdbp->tdb_flags & TDBF_INVALID) == 0) && (!bcmp(&tdbp->tdb_src, src, SA_LEN(&src->sa)))) { /* Check whether IDs match */ @@ -506,7 +513,7 @@ tdb_hashstats(void) * Caller is responsible for setting at least spltdb(). */ int -tdb_walk(int (*walker)(struct tdb *, void *, int), void *arg) +tdb_walk(u_int rdomain, int (*walker)(struct tdb *, void *, int), void *arg) { int i, rval = 0; struct tdb *tdbp, *next; @@ -517,6 +524,10 @@ tdb_walk(int (*walker)(struct tdb *, void *, int), void *arg) for (i = 0; i <= tdb_hashmask; i++) for (tdbp = tdbh[i]; rval == 0 && tdbp != NULL; tdbp = next) { next = tdbp->tdb_hnext; + + if (rdomain != tdbp->tdb_rdomain) + continue; + if (i == tdb_hashmask && next == NULL) rval = walker(tdbp, (void *)arg, 1); else @@ -606,7 +617,8 @@ tdb_rehash(void) 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, + hashval = tdb_hash(tdbp->tdb_rdomain, + tdbp->tdb_spi, &tdbp->tdb_dst, tdbp->tdb_sproto); tdbp->tdb_hnext = new_tdbh[hashval]; new_tdbh[hashval] = tdbp; @@ -614,7 +626,8 @@ tdb_rehash(void) for (tdbp = tdbaddr[i]; tdbp != NULL; tdbp = tdbnp) { tdbnp = tdbp->tdb_anext; - hashval = tdb_hash(0, &tdbp->tdb_dst, + hashval = tdb_hash(tdbp->tdb_rdomain, + 0, &tdbp->tdb_dst, tdbp->tdb_sproto); tdbp->tdb_anext = new_tdbaddr[hashval]; new_tdbaddr[hashval] = tdbp; @@ -622,7 +635,8 @@ tdb_rehash(void) for (tdbp = tdbsrc[i]; tdbp != NULL; tdbp = tdbnp) { tdbnp = tdbp->tdb_snext; - hashval = tdb_hash(0, &tdbp->tdb_src, + hashval = tdb_hash(tdbp->tdb_rdomain, + 0, &tdbp->tdb_src, tdbp->tdb_sproto); tdbp->tdb_snext = new_srcaddr[hashval]; new_srcaddr[hashval] = tdbp; @@ -657,7 +671,8 @@ puttdb(struct tdb *tdbp) M_TDB, M_WAITOK | M_ZERO); } - hashval = tdb_hash(tdbp->tdb_spi, &tdbp->tdb_dst, tdbp->tdb_sproto); + hashval = tdb_hash(tdbp->tdb_rdomain, tdbp->tdb_spi, + &tdbp->tdb_dst, tdbp->tdb_sproto); /* * Rehash if this tdb would cause a bucket to have more than @@ -670,18 +685,20 @@ puttdb(struct tdb *tdbp) 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); + hashval = tdb_hash(tdbp->tdb_rdomain, 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); + hashval = tdb_hash(tdbp->tdb_rdomain, 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); + hashval = tdb_hash(tdbp->tdb_rdomain, 0, &tdbp->tdb_src, + tdbp->tdb_sproto); tdbp->tdb_snext = tdbsrc[hashval]; tdbsrc[hashval] = tdbp; @@ -705,7 +722,8 @@ tdb_delete(struct tdb *tdbp) if (tdbh == NULL) return; - hashval = tdb_hash(tdbp->tdb_spi, &tdbp->tdb_dst, tdbp->tdb_sproto); + hashval = tdb_hash(tdbp->tdb_rdomain, tdbp->tdb_spi, + &tdbp->tdb_dst, tdbp->tdb_sproto); s = spltdb(); if (tdbh[hashval] == tdbp) { @@ -722,7 +740,8 @@ tdb_delete(struct tdb *tdbp) tdbp->tdb_hnext = NULL; - hashval = tdb_hash(0, &tdbp->tdb_dst, tdbp->tdb_sproto); + hashval = tdb_hash(tdbp->tdb_rdomain, 0, &tdbp->tdb_dst, + tdbp->tdb_sproto); if (tdbaddr[hashval] == tdbp) { tdbaddr[hashval] = tdbp->tdb_anext; @@ -736,7 +755,8 @@ tdb_delete(struct tdb *tdbp) } } - hashval = tdb_hash(0, &tdbp->tdb_src, tdbp->tdb_sproto); + hashval = tdb_hash(tdbp->tdb_rdomain, 0, &tdbp->tdb_src, + tdbp->tdb_sproto); if (tdbsrc[hashval] == tdbp) { tdbsrc[hashval] = tdbp->tdb_snext; @@ -762,7 +782,7 @@ tdb_delete(struct tdb *tdbp) * Allocate a TDB and initialize a few basic fields. */ struct tdb * -tdb_alloc(void) +tdb_alloc(u_int rdomain) { struct tdb *tdbp; @@ -777,6 +797,9 @@ tdb_alloc(void) /* Record establishment time. */ tdbp->tdb_established = time_second; + /* Save routing domain */ + tdbp->tdb_rdomain = rdomain; + /* Initialize timeouts. */ timeout_set(&tdbp->tdb_timer_tmo, tdb_timeout, tdbp); timeout_set(&tdbp->tdb_first_tmo, tdb_firstuse, tdbp); @@ -1041,7 +1064,7 @@ ipsp_skipcrypto_mark(struct tdb_ident *tdbi) struct tdb *tdb; int s = spltdb(); - tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto); + tdb = gettdb(tdbi->rdomain, tdbi->spi, &tdbi->dst, tdbi->proto); if (tdb != NULL) { tdb->tdb_flags |= TDBF_SKIPCRYPTO; tdb->tdb_last_marked = time_second; @@ -1056,7 +1079,7 @@ ipsp_skipcrypto_unmark(struct tdb_ident *tdbi) struct tdb *tdb; int s = spltdb(); - tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto); + tdb = gettdb(tdbi->rdomain, tdbi->spi, &tdbi->dst, tdbi->proto); if (tdb != NULL) { tdb->tdb_flags &= ~TDBF_SKIPCRYPTO; tdb->tdb_last_marked = time_second; @@ -1163,6 +1186,8 @@ ipsp_parse_headers(struct mbuf *m, int off, u_int8_t proto) tdbi->dst.sin6.sin6_len = sizeof(struct sockaddr_in6); tdbi->dst.sin6.sin6_addr = ip6_dst; + tdbi->rdomain = + rtable_l2(m->m_pkthdr.rdomain); SLIST_INSERT_HEAD(&tags, mtag, m_tag_link); } @@ -1270,6 +1295,7 @@ ipsp_parse_headers(struct mbuf *m, int off, u_int8_t proto) (caddr_t) &tdbi->spi); tdbi->proto = proto; /* AH or ESP */ + tdbi->rdomain = rtable_l2(m->m_pkthdr.rdomain); #ifdef INET /* Last network header was IPv4. */ |