Date: Tue, 6 Dec 2016 12:52:20 +0000 (UTC) From: "Andrey V. Elsukov" <ae@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r309614 - projects/ipsec/sys/netipsec Message-ID: <201612061252.uB6CqKnH071526@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: ae Date: Tue Dec 6 12:52:20 2016 New Revision: 309614 URL: https://svnweb.freebsd.org/changeset/base/309614 Log: Due to the changes in SADB now each SA has unique SPI. Previously TCP-MD5 SAs have one magic SPI = 0x1000. This was used by some applications. E.g. bird uses SADB_ADD and SADB_DELETE PF_KEY messages to configure security key used by TCP_MD5SIG socket option. To support old applications and configs add the workaround. When SADB_ADD, SADB_GET and SADB_DELETE messages are used for IPPROTO_TCP, do lookup for needed SA using its secasindex, instead of SPI. When several TCP-MD5 SAs added with one SPI value, use key_do_getnewspi to allocate new SPI value in SADB_ADD. Modified: projects/ipsec/sys/netipsec/key.c Modified: projects/ipsec/sys/netipsec/key.c ============================================================================== --- projects/ipsec/sys/netipsec/key.c Tue Dec 6 12:43:07 2016 (r309613) +++ projects/ipsec/sys/netipsec/key.c Tue Dec 6 12:52:20 2016 (r309614) @@ -4732,6 +4732,58 @@ key_do_getnewspi(struct sadb_spirange *s } /* + * Find TCP-MD5 SA with corresponding secasindex. + * If not found, return NULL and fill SPI with usable value if needed. + */ +static struct secasvar * +key_getsav_tcpmd5(struct secasindex *saidx, uint32_t *spi) +{ + SAHTREE_RLOCK_TRACKER; + struct secashead *sah; + struct secasvar *sav; + + IPSEC_ASSERT(saidx->proto == IPPROTO_TCP, ("wrong proto")); + SAHTREE_RLOCK(); + LIST_FOREACH(sah, SAHADDRHASH_HASH(saidx), addrhash) { + if (sah->saidx.proto != IPPROTO_TCP) + continue; + if (!key_sockaddrcmp(&saidx->dst.sa, &sah->saidx.dst.sa, + key_portfromsaddr(&sah->saidx.dst.sa))) + break; + } + if (sah != NULL) { + if (V_key_preferred_oldsa) + sav = TAILQ_LAST(&sah->savtree_alive, secasvar_queue); + else + sav = TAILQ_FIRST(&sah->savtree_alive); + if (sav != NULL) { + SAV_ADDREF(sav); + SAHTREE_RUNLOCK(); + return (sav); + } + } + if (spi == NULL) { + /* No SPI required */ + SAHTREE_RUNLOCK(); + return (NULL); + } + /* Check that SPI is unique */ + LIST_FOREACH(sav, SAVHASH_HASH(*spi), spihash) { + if (sav->spi == *spi) + break; + } + if (sav == NULL) { + SAHTREE_RUNLOCK(); + /* SPI is already unique */ + return (NULL); + } + SAHTREE_RUNLOCK(); + /* XXX: not optimal */ + *spi = key_do_getnewspi(NULL, saidx); + return (NULL); +} + +/* * SADB_UPDATE processing * receive * <base, SA, (SA2), (lifetime(HSC),) address(SD), (address(P),) @@ -4965,7 +5017,7 @@ key_add(struct socket *so, struct mbuf * struct sadb_address *src0, *dst0; struct sadb_sa *sa0; struct secasvar *sav; - uint32_t reqid; + uint32_t reqid, spi; uint8_t mode, proto; int error; @@ -5046,19 +5098,36 @@ key_add(struct socket *so, struct mbuf * /* * Make sure the port numbers are zero. * In case of NAT-T we will update them later if needed. + * XXXAE: TCP-MD5 may set dst port. */ key_porttosaddr(&saidx.src.sa, 0); key_porttosaddr(&saidx.dst.sa, 0); - /* We can create new SA only if SPI is different. */ - sav = key_getsavbyspi(sa0->sadb_sa_spi); + spi = sa0->sadb_sa_spi; + /* + * XXX: For TCP-MD5 SAs we don't use SPI. + * Check the uniqueness using secasindex. + */ + if (proto == IPPROTO_TCP) { + sav = key_getsav_tcpmd5(&saidx, &spi); + if (sav == NULL && spi == 0) { + /* Failed to allocate SPI */ + ipseclog((LOG_DEBUG, "%s: SA already exists.\n", + __func__)); + return key_senderror(so, m, EEXIST); + } + /* XXX: SPI that we report back can have another value */ + } else { + /* We can create new SA only if SPI is different. */ + sav = key_getsavbyspi(spi); + } if (sav != NULL) { key_freesav(&sav); ipseclog((LOG_DEBUG, "%s: SA already exists.\n", __func__)); return key_senderror(so, m, EEXIST); } - sav = key_newsav(mhp, &saidx, sa0->sadb_sa_spi, &error); + sav = key_newsav(mhp, &saidx, spi, &error); if (sav == NULL) return key_senderror(so, m, error); KEYDBG(KEY_STAMP, @@ -5333,7 +5402,10 @@ key_delete(struct socket *so, struct mbu return (key_senderror(so, m, EINVAL)); } sa0 = (struct sadb_sa *)mhp->ext[SADB_EXT_SA]; - sav = key_getsavbyspi(sa0->sadb_sa_spi); + if (proto == IPPROTO_TCP) + sav = key_getsav_tcpmd5(&saidx, NULL); + else + sav = key_getsavbyspi(sa0->sadb_sa_spi); if (sav == NULL) { ipseclog((LOG_DEBUG, "%s: no SA found for SPI %u.\n", __func__, ntohl(sa0->sadb_sa_spi))); @@ -5504,14 +5576,17 @@ key_get(struct socket *so, struct mbuf * key_porttosaddr(&saidx.src.sa, 0); key_porttosaddr(&saidx.dst.sa, 0); - sav = key_getsavbyspi(sa0->sadb_sa_spi); + if (proto == IPPROTO_TCP) + sav = key_getsav_tcpmd5(&saidx, NULL); + else + sav = key_getsavbyspi(sa0->sadb_sa_spi); if (sav == NULL) { ipseclog((LOG_DEBUG, "%s: no SA found.\n", __func__)); return key_senderror(so, m, ESRCH); } if (key_cmpsaidx(&sav->sah->saidx, &saidx, CMP_HEAD) == 0) { ipseclog((LOG_DEBUG, "%s: saidx mismatched for SPI %u.\n", - __func__, ntohl(sav->spi))); + __func__, ntohl(sa0->sadb_sa_spi))); key_freesav(&sav); return (key_senderror(so, m, ESRCH)); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201612061252.uB6CqKnH071526>