summaryrefslogtreecommitdiff
path: root/sys/netinet/ipsec_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/ipsec_output.c')
-rw-r--r--sys/netinet/ipsec_output.c512
1 files changed, 254 insertions, 258 deletions
diff --git a/sys/netinet/ipsec_output.c b/sys/netinet/ipsec_output.c
index 62c20fb3a2a..7821bc1d3bd 100644
--- a/sys/netinet/ipsec_output.c
+++ b/sys/netinet/ipsec_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ipsec_output.c,v 1.16 2001/06/25 05:11:59 angelos Exp $ */
+/* $OpenBSD: ipsec_output.c,v 1.17 2001/06/26 04:17:57 angelos Exp $ */
/*
* The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
*
@@ -63,233 +63,235 @@
int
ipsp_process_packet(struct mbuf *m, struct tdb *tdb, int af, int tunalready)
{
- int i, off, error;
- struct mbuf *mp;
+ int i, off, error;
+ struct mbuf *mp;
#ifdef INET
- int setdf = 0;
- struct ip *ip;
+ int setdf = 0;
+ struct ip *ip;
#endif /* INET */
#ifdef INET6
- struct ip6_hdr *ip6;
+ struct ip6_hdr *ip6;
#endif /* INET6 */
- /* Check that the transform is allowed by the administrator */
- if ((tdb->tdb_sproto == IPPROTO_ESP && !esp_enable) ||
- (tdb->tdb_sproto == IPPROTO_AH && !ah_enable))
- {
- DPRINTF(("ipsp_process_packet(): IPSec outbound packet dropped due to policy (check your sysctls)\n"));
- m_freem(m);
- return EHOSTUNREACH;
- }
-
- /* Sanity check */
- if (!tdb->tdb_xform)
- {
- DPRINTF(("ipsp_process_packet(): uninitialized TDB\n"));
- m_freem(m);
- return EHOSTUNREACH;
- }
-
- /* Check if the SPI is invalid */
- if (tdb->tdb_flags & TDBF_INVALID)
- {
- DPRINTF(("ipsp_process_packet(): attempt to use invalid SA %s/%08x/%u\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi), tdb->tdb_sproto));
- m_freem(m);
- return ENXIO;
- }
-
- /* Check that the network protocol is supported */
- switch (tdb->tdb_dst.sa.sa_family)
- {
+ /* Check that the transform is allowed by the administrator. */
+ if ((tdb->tdb_sproto == IPPROTO_ESP && !esp_enable) ||
+ (tdb->tdb_sproto == IPPROTO_AH && !ah_enable)) {
+ DPRINTF(("ipsp_process_packet(): IPSec outbound packet "
+ "dropped due to policy (check your sysctls)\n"));
+ m_freem(m);
+ return EHOSTUNREACH;
+ }
+
+ /* Sanity check. */
+ if (!tdb->tdb_xform) {
+ DPRINTF(("ipsp_process_packet(): uninitialized TDB\n"));
+ m_freem(m);
+ return EHOSTUNREACH;
+ }
+
+ /* Check if the SPI is invalid. */
+ if (tdb->tdb_flags & TDBF_INVALID) {
+ DPRINTF(("ipsp_process_packet(): attempt to use invalid "
+ "SA %s/%08x/%u\n", ipsp_address(tdb->tdb_dst),
+ ntohl(tdb->tdb_spi), tdb->tdb_sproto));
+ m_freem(m);
+ return ENXIO;
+ }
+
+ /* Check that the network protocol is supported */
+ switch (tdb->tdb_dst.sa.sa_family) {
#ifdef INET
case AF_INET:
- break;
+ break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
- break;
+ break;
#endif /* INET6 */
default:
- DPRINTF(("ipsp_process_packet(): attempt to use SA %s/%08x/%u for protocol family %d\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi), tdb->tdb_sproto, tdb->tdb_dst.sa.sa_family));
- m_freem(m);
- return ENXIO;
- }
-
- /* Register first use if applicable, setup relevant expiration timer */
- if (tdb->tdb_first_use == 0)
- {
- tdb->tdb_first_use = time.tv_sec;
- if (tdb->tdb_flags & TDBF_FIRSTUSE)
- timeout_add(&tdb->tdb_first_tmo, hz * tdb->tdb_exp_first_use);
- if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE)
- timeout_add(&tdb->tdb_sfirst_tmo, hz * tdb->tdb_soft_first_use);
- }
-
- /*
- * Check for tunneling if we don't have the first header in place.
- * When doing Ethernet-over-IP, we are handed an already-encapsulated
- * frame, so we don't need to re-encapsulate.
- */
- if (tunalready == 0)
- {
+ DPRINTF(("ipsp_process_packet(): attempt to use "
+ "SA %s/%08x/%u for protocol family %d\n",
+ ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi),
+ tdb->tdb_sproto, tdb->tdb_dst.sa.sa_family));
+ m_freem(m);
+ return ENXIO;
+ }
+
+ /*
+ * Register first use if applicable, setup relevant expiration timer.
+ */
+ if (tdb->tdb_first_use == 0) {
+ tdb->tdb_first_use = time.tv_sec;
+ if (tdb->tdb_flags & TDBF_FIRSTUSE)
+ timeout_add(&tdb->tdb_first_tmo,
+ hz * tdb->tdb_exp_first_use);
+ if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE)
+ timeout_add(&tdb->tdb_sfirst_tmo,
+ hz * tdb->tdb_soft_first_use);
+ }
+
/*
- * If the target protocol family is different, we know we'll be
- * doing tunneling.
+ * Check for tunneling if we don't have the first header in place.
+ * When doing Ethernet-over-IP, we are handed an already-encapsulated
+ * frame, so we don't need to re-encapsulate.
*/
- if (af == tdb->tdb_dst.sa.sa_family)
- {
+ if (tunalready == 0) {
+ /*
+ * If the target protocol family is different, we know we'll be
+ * doing tunneling.
+ */
+ if (af == tdb->tdb_dst.sa.sa_family) {
#ifdef INET
- if (af == AF_INET)
- i = sizeof(struct ip);
+ if (af == AF_INET)
+ i = sizeof(struct ip);
#endif /* INET */
#ifdef INET6
- if (af == AF_INET6)
- i = sizeof(struct ip6_hdr);
+ if (af == AF_INET6)
+ i = sizeof(struct ip6_hdr);
#endif /* INET6 */
- /* Bring the network header in the first mbuf */
- if (m->m_len < i)
- {
- if ((m = m_pullup(m, i)) == NULL)
- return ENOBUFS;
- }
+ /* Bring the network header in the first mbuf. */
+ if (m->m_len < i) {
+ if ((m = m_pullup(m, i)) == NULL)
+ return ENOBUFS;
+ }
#ifdef INET
- ip = mtod(m, struct ip *);
- /* This is not a bridge packet, remember if we had IP_DF */
- setdf = ntohs(ip->ip_off) & IP_DF;
+ ip = mtod(m, struct ip *);
+
+ /*
+ * This is not a bridge packet, remember if we
+ * had IP_DF.
+ */
+ setdf = ntohs(ip->ip_off) & IP_DF;
#endif /* INET */
#ifdef INET6
- ip6 = mtod(m, struct ip6_hdr *);
+ ip6 = mtod(m, struct ip6_hdr *);
#endif /* INET6 */
- }
+ }
- /* Do the appropriate encapsulation, if necessary */
- if ((tdb->tdb_dst.sa.sa_family != af) || /* PF mismatch */
- (tdb->tdb_flags & TDBF_TUNNELING) || /* Tunneling requested */
- (tdb->tdb_xform->xf_type == XF_IP4) || /* ditto */
+ /* Do the appropriate encapsulation, if necessary. */
+ if ((tdb->tdb_dst.sa.sa_family != af) || /* PF mismatch */
+ (tdb->tdb_flags & TDBF_TUNNELING) || /* Tunneling needed */
+ (tdb->tdb_xform->xf_type == XF_IP4) || /* ditto */
#ifdef INET
- ((tdb->tdb_dst.sa.sa_family == AF_INET) &&
- (tdb->tdb_dst.sin.sin_addr.s_addr != INADDR_ANY) &&
- (tdb->tdb_dst.sin.sin_addr.s_addr != ip->ip_dst.s_addr)) ||
+ ((tdb->tdb_dst.sa.sa_family == AF_INET) &&
+ (tdb->tdb_dst.sin.sin_addr.s_addr != INADDR_ANY) &&
+ (tdb->tdb_dst.sin.sin_addr.s_addr != ip->ip_dst.s_addr)) ||
#endif /* INET */
#ifdef INET6
- ((tdb->tdb_dst.sa.sa_family == AF_INET6) &&
- (!IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_dst.sin6.sin6_addr)) &&
- (!IN6_ARE_ADDR_EQUAL(&tdb->tdb_dst.sin6.sin6_addr,
- &ip6->ip6_dst))) ||
+ ((tdb->tdb_dst.sa.sa_family == AF_INET6) &&
+ (!IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_dst.sin6.sin6_addr)) &&
+ (!IN6_ARE_ADDR_EQUAL(&tdb->tdb_dst.sin6.sin6_addr,
+ &ip6->ip6_dst))) ||
#endif /* INET6 */
- 0)
- {
+ 0) {
#ifdef INET
- /* Fix IPv4 header checksum and length */
- if (af == AF_INET)
- {
- if (m->m_len < sizeof(struct ip))
- if ((m = m_pullup(m, sizeof(struct ip))) == NULL)
- return ENOBUFS;
-
- ip = mtod(m, struct ip *);
- ip->ip_len = htons(m->m_pkthdr.len);
- ip->ip_sum = 0;
- ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
- }
+ /* Fix IPv4 header checksum and length. */
+ if (af == AF_INET) {
+ if (m->m_len < sizeof(struct ip))
+ if ((m = m_pullup(m,
+ sizeof(struct ip))) == NULL)
+ return ENOBUFS;
+
+ ip = mtod(m, struct ip *);
+ ip->ip_len = htons(m->m_pkthdr.len);
+ ip->ip_sum = 0;
+ ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
+ }
#endif /* INET */
#ifdef INET6
- /* Fix IPv6 header payload length */
- if (af == AF_INET6)
- {
- if (m->m_len < sizeof(struct ip6_hdr))
- if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL)
- return ENOBUFS;
-
- if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) {
- /* no jumbogram support */
- m_freem(m);
- return ENXIO; /*?*/
- }
- ip6 = mtod(m, struct ip6_hdr *);
- ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
- }
+ /* Fix IPv6 header payload length. */
+ if (af == AF_INET6) {
+ if (m->m_len < sizeof(struct ip6_hdr))
+ if ((m = m_pullup(m,
+ sizeof(struct ip6_hdr))) == NULL)
+ return ENOBUFS;
+
+ if (m->m_pkthdr.len - sizeof(*ip6) >
+ IPV6_MAXPACKET) {
+ /* No jumbogram support. */
+ m_freem(m);
+ return ENXIO; /*?*/
+ }
+ ip6 = mtod(m, struct ip6_hdr *);
+ ip6->ip6_plen = htons(m->m_pkthdr.len
+ - sizeof(*ip6));
+ }
#endif /* INET6 */
- /* Encapsulate -- the last two arguments are unused */
- error = ipip_output(m, tdb, &mp, 0, 0);
- if ((mp == NULL) && (!error))
- error = EFAULT;
- if (error)
- {
- if (mp)
- {
- m_freem(mp);
- mp = NULL;
- }
-
- return error;
- }
-
- m = mp;
- mp = NULL;
+ /* Encapsulate -- the last two arguments are unused. */
+ error = ipip_output(m, tdb, &mp, 0, 0);
+ if ((mp == NULL) && (!error))
+ error = EFAULT;
+ if (error) {
+ if (mp) {
+ m_freem(mp);
+ mp = NULL;
+ }
+ return error;
+ }
+
+ m = mp;
+ mp = NULL;
#ifdef INET
- if (tdb->tdb_dst.sa.sa_family == AF_INET && setdf) {
- ip = mtod(m, struct ip *);
- if (m->m_len < sizeof(struct ip))
- if ((m = m_pullup(m, sizeof(struct ip))) == NULL)
- return ENOBUFS;
+ if (tdb->tdb_dst.sa.sa_family == AF_INET && setdf) {
+ ip = mtod(m, struct ip *);
+ if (m->m_len < sizeof(struct ip))
+ if ((m = m_pullup(m,
+ sizeof(struct ip))) == NULL)
+ return ENOBUFS;
- NTOHS(ip->ip_off);
- ip->ip_off |= IP_DF;
- HTONS(ip->ip_off);
- }
+ NTOHS(ip->ip_off);
+ ip->ip_off |= IP_DF;
+ HTONS(ip->ip_off);
+ }
- /* Remember that we appended a tunnel header */
- tdb->tdb_flags |= TDBF_USEDTUNNEL;
+ /* Remember that we appended a tunnel header. */
+ tdb->tdb_flags |= TDBF_USEDTUNNEL;
#endif
- }
+ }
- /* We may be done with this TDB */
- if (tdb->tdb_xform->xf_type == XF_IP4)
- return ipsp_process_done(m, tdb);
- }
- else
- {
- /*
- * If this is just an IP-IP TDB and we're told there's already an
- * encapsulation header, move on.
- */
- if (tdb->tdb_xform->xf_type == XF_IP4)
- return ipsp_process_done(m, tdb);
- }
+ /* We may be done with this TDB */
+ if (tdb->tdb_xform->xf_type == XF_IP4)
+ return ipsp_process_done(m, tdb);
+ } else {
+ /*
+ * If this is just an IP-IP TDB and we're told there's
+ * already an encapsulation header, move on.
+ */
+ if (tdb->tdb_xform->xf_type == XF_IP4)
+ return ipsp_process_done(m, tdb);
+ }
- /* Extract some information off the headers */
- switch (tdb->tdb_dst.sa.sa_family)
- {
+ /* Extract some information off the headers. */
+ switch (tdb->tdb_dst.sa.sa_family) {
#ifdef INET
case AF_INET:
- ip = mtod(m, struct ip *);
- i = ip->ip_hl << 2;
- off = offsetof(struct ip, ip_p);
- break;
+ ip = mtod(m, struct ip *);
+ i = ip->ip_hl << 2;
+ off = offsetof(struct ip, ip_p);
+ break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
- ip6 = mtod(m, struct ip6_hdr *);
- i = sizeof(struct ip6_hdr);
- off = offsetof(struct ip6_hdr, ip6_nxt);
- break;
+ ip6 = mtod(m, struct ip6_hdr *);
+ i = sizeof(struct ip6_hdr);
+ off = offsetof(struct ip6_hdr, ip6_nxt);
+ break;
#endif /* INET6 */
- }
+ }
- /* Invoke the IPsec transform */
- return (*(tdb->tdb_xform->xf_output))(m, tdb, NULL, i, off);
+ /* Invoke the IPsec transform. */
+ return (*(tdb->tdb_xform->xf_output))(m, tdb, NULL, i, off);
}
/*
@@ -300,116 +302,110 @@ int
ipsp_process_done(struct mbuf *m, struct tdb *tdb)
{
#ifdef INET
- struct ip *ip;
+ struct ip *ip;
#endif /* INET */
#ifdef INET6
- struct ip6_hdr *ip6;
+ struct ip6_hdr *ip6;
#endif /* INET6 */
- struct tdb_ident *tdbi;
- struct m_tag *mtag;
+ struct tdb_ident *tdbi;
+ struct m_tag *mtag;
- tdb->tdb_last_used = time.tv_sec;
+ tdb->tdb_last_used = time.tv_sec;
- switch (tdb->tdb_dst.sa.sa_family)
- {
+ switch (tdb->tdb_dst.sa.sa_family) {
#ifdef INET
case AF_INET:
- /* Fix the header length, for AH processing */
- if (tdb->tdb_dst.sa.sa_family == AF_INET)
- {
- ip = mtod(m, struct ip *);
- ip->ip_len = htons(m->m_pkthdr.len);
- }
- break;
+ /* Fix the header length, for AH processing. */
+ if (tdb->tdb_dst.sa.sa_family == AF_INET) {
+ ip = mtod(m, struct ip *);
+ ip->ip_len = htons(m->m_pkthdr.len);
+ }
+ break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
- /* Fix the header length, for AH processing */
- if (tdb->tdb_dst.sa.sa_family == AF_INET6)
- {
- if (m->m_pkthdr.len < sizeof(*ip6)) {
- m_freem(m);
- return ENXIO;
+ /* Fix the header length, for AH processing. */
+ if (tdb->tdb_dst.sa.sa_family == AF_INET6) {
+ if (m->m_pkthdr.len < sizeof(*ip6)) {
+ m_freem(m);
+ return ENXIO;
+ }
+ if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) {
+ /* No jumbogram support. */
+ m_freem(m);
+ return ENXIO; /*?*/
+ }
+ ip6 = mtod(m, struct ip6_hdr *);
+ ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
}
- if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) {
- /* no jumbogram support */
- m_freem(m);
- return ENXIO; /*?*/
- }
-
- ip6 = mtod(m, struct ip6_hdr *);
- ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
- }
- break;
+ break;
#endif /* INET6 */
default:
- m_freem(m);
- DPRINTF(("ipsp_process_done(): unknown protocol family (%d)\n",
- tdb->tdb_dst.sa.sa_family));
- return ENXIO;
- }
-
- /*
- * Add a record of what we've done or what needs to be done to the
- * packet.
- */
- if ((tdb->tdb_flags & TDBF_SKIPCRYPTO) == 0)
- mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE, sizeof(struct tdb_ident),
- M_NOWAIT);
- else
- mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED,
- sizeof(struct tdb_ident), M_NOWAIT);
-
- if (mtag == NULL)
- {
- m_freem(m);
- DPRINTF(("ipsp_process_done(): could not allocate packet tag\n"));
- return ENOMEM;
- }
-
- tdbi = (struct tdb_ident *)(mtag + 1);
- bcopy(&tdb->tdb_dst, &tdbi->dst, sizeof(union sockaddr_union));
- tdbi->proto = tdb->tdb_sproto;
- tdbi->spi = tdb->tdb_spi;
-
- m_tag_prepend(m, mtag);
-
- /* If there's another (bundled) TDB to apply, do so */
- if (tdb->tdb_onext)
- return ipsp_process_packet(m, tdb->tdb_onext, tdb->tdb_dst.sa.sa_family,
- 0);
-
- /*
- * We're done with IPsec processing, transmit the packet using the
- * appropriate network protocol (IP or IPv6). SPD lookup will be
- * performed again there.
- */
- switch (tdb->tdb_dst.sa.sa_family)
- {
+ m_freem(m);
+ DPRINTF(("ipsp_process_done(): unknown protocol family (%d)\n",
+ tdb->tdb_dst.sa.sa_family));
+ return ENXIO;
+ }
+
+ /*
+ * Add a record of what we've done or what needs to be done to the
+ * packet.
+ */
+ if ((tdb->tdb_flags & TDBF_SKIPCRYPTO) == 0)
+ mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE,
+ sizeof(struct tdb_ident),
+ M_NOWAIT);
+ else
+ mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED,
+ sizeof(struct tdb_ident), M_NOWAIT);
+
+ if (mtag == NULL) {
+ m_freem(m);
+ DPRINTF(("ipsp_process_done(): could not allocate packet "
+ "tag\n"));
+ return ENOMEM;
+ }
+
+ tdbi = (struct tdb_ident *)(mtag + 1);
+ bcopy(&tdb->tdb_dst, &tdbi->dst, sizeof(union sockaddr_union));
+ tdbi->proto = tdb->tdb_sproto;
+ tdbi->spi = tdb->tdb_spi;
+
+ m_tag_prepend(m, mtag);
+
+ /* If there's another (bundled) TDB to apply, do so. */
+ if (tdb->tdb_onext)
+ return ipsp_process_packet(m, tdb->tdb_onext,
+ tdb->tdb_dst.sa.sa_family, 0);
+
+ /*
+ * We're done with IPsec processing, transmit the packet using the
+ * appropriate network protocol (IP or IPv6). SPD lookup will be
+ * performed again there.
+ */
+ switch (tdb->tdb_dst.sa.sa_family) {
#ifdef INET
case AF_INET:
- NTOHS(ip->ip_len);
- NTOHS(ip->ip_off);
+ NTOHS(ip->ip_len);
+ NTOHS(ip->ip_off);
- return ip_output(m, NULL, NULL, IP_RAWOUTPUT, NULL, NULL);
+ return ip_output(m, NULL, NULL, IP_RAWOUTPUT, NULL, NULL);
#endif /* INET */
#ifdef INET6
case AF_INET6:
- /*
- * We don't need massage, IPv6 header fields are always in
- * net endian
- */
- return ip6_output(m, NULL, NULL, 0, NULL, NULL);
+ /*
+ * We don't need massage, IPv6 header fields are always in
+ * net endian.
+ */
+ return ip6_output(m, NULL, NULL, 0, NULL, NULL);
#endif /* INET6 */
- }
-
- /* Not reached */
- return EINVAL;
+ }
+ return EINVAL; /* Not reached. */
}
ssize_t