summaryrefslogtreecommitdiff
path: root/sys/netinet6/ah_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet6/ah_output.c')
-rw-r--r--sys/netinet6/ah_output.c586
1 files changed, 0 insertions, 586 deletions
diff --git a/sys/netinet6/ah_output.c b/sys/netinet6/ah_output.c
deleted file mode 100644
index c58ca0ee75ea7..0000000000000
--- a/sys/netinet6/ah_output.c
+++ /dev/null
@@ -1,586 +0,0 @@
-/* $FreeBSD$ */
-/* $KAME: ah_output.c,v 1.38 2003/09/06 05:15:43 itojun Exp $ */
-
-/*-
- * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the project nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * RFC1826/2402 authentication header.
- */
-
-#include "opt_inet.h"
-#include "opt_inet6.h"
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/mbuf.h>
-#include <sys/domain.h>
-#include <sys/protosw.h>
-#include <sys/socket.h>
-#include <sys/socketvar.h>
-#include <sys/errno.h>
-#include <sys/time.h>
-#include <sys/syslog.h>
-
-#include <net/if.h>
-#include <net/route.h>
-
-#include <netinet/in.h>
-
-#include <netinet/in_systm.h>
-#include <netinet/ip.h>
-#include <netinet/in_var.h>
-
-#ifdef INET6
-#include <netinet/ip6.h>
-#include <netinet6/ip6_var.h>
-#include <netinet/icmp6.h>
-#endif
-
-#include <netinet6/ipsec.h>
-#ifdef INET6
-#include <netinet6/ipsec6.h>
-#endif
-#include <netinet6/ah.h>
-#ifdef INET6
-#include <netinet6/ah6.h>
-#endif
-#include <netkey/key.h>
-#include <netkey/keydb.h>
-
-#ifdef INET
-static struct in_addr *ah4_finaldst __P((struct mbuf *));
-#endif
-
-/*
- * compute AH header size.
- * transport mode only. for tunnel mode, we should implement
- * virtual interface, and control MTU/MSS by the interface MTU.
- */
-size_t
-ah_hdrsiz(isr)
- struct ipsecrequest *isr;
-{
- const struct ah_algorithm *algo;
- size_t hdrsiz;
-
- /* sanity check */
- if (isr == NULL)
- panic("ah_hdrsiz: NULL was passed.");
-
- if (isr->saidx.proto != IPPROTO_AH)
- panic("unsupported mode passed to ah_hdrsiz");
-
- if (isr->sav == NULL)
- goto estimate;
- if (isr->sav->state != SADB_SASTATE_MATURE
- && isr->sav->state != SADB_SASTATE_DYING)
- goto estimate;
-
- /* we need transport mode AH. */
- algo = ah_algorithm_lookup(isr->sav->alg_auth);
- if (!algo)
- goto estimate;
-
- /*
- * XXX
- * right now we don't calcurate the padding size. simply
- * treat the padding size as constant, for simplicity.
- *
- * XXX variable size padding support
- */
- hdrsiz = (((*algo->sumsiz)(isr->sav) + 3) & ~(4 - 1));
- if (isr->sav->flags & SADB_X_EXT_OLD)
- hdrsiz += sizeof(struct ah);
- else
- hdrsiz += sizeof(struct newah);
-
- return hdrsiz;
-
- estimate:
- /* ASSUMING:
- * sizeof(struct newah) > sizeof(struct ah).
- * AH_MAXSUMSIZE is multiple of 4.
- */
- return sizeof(struct newah) + AH_MAXSUMSIZE;
-}
-
-#ifdef INET
-/*
- * Modify the packet so that it includes the authentication data.
- * The mbuf passed must start with IPv4 header.
- *
- * assumes that the first mbuf contains IPv4 header + option only.
- * the function does not modify m.
- */
-int
-ah4_output(m, isr)
- struct mbuf *m;
- struct ipsecrequest *isr;
-{
- struct secasvar *sav = isr->sav;
- const struct ah_algorithm *algo;
- u_int32_t spi;
- u_char *ahdrpos;
- u_int8_t *ahsumpos = NULL;
- size_t hlen = 0; /* IP header+option in bytes */
- size_t plen = 0; /* AH payload size in bytes */
- size_t ahlen = 0; /* plen + sizeof(ah) */
- struct ip *ip;
- in_addr_t saveaddr = { 0 };
- struct in_addr *finaldst;
- int error;
-
- /* sanity checks */
- if ((sav->flags & SADB_X_EXT_OLD) == 0 && !sav->replay) {
- struct ip *ip;
-
- ip = mtod(m, struct ip *);
- ipseclog((LOG_DEBUG, "ah4_output: internal error: "
- "sav->replay is null: %x->%x, SPI=%u\n",
- (u_int32_t)ntohl(ip->ip_src.s_addr),
- (u_int32_t)ntohl(ip->ip_dst.s_addr),
- (u_int32_t)ntohl(sav->spi)));
- ipsecstat.out_inval++;
- m_freem(m);
- return EINVAL;
- }
-
- algo = ah_algorithm_lookup(sav->alg_auth);
- if (!algo) {
- ipseclog((LOG_ERR, "ah4_output: unsupported algorithm: "
- "SPI=%u\n", (u_int32_t)ntohl(sav->spi)));
- ipsecstat.out_inval++;
- m_freem(m);
- return EINVAL;
- }
- spi = sav->spi;
-
- /*
- * determine the size to grow.
- */
- if (sav->flags & SADB_X_EXT_OLD) {
- /* RFC 1826 */
- plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /* XXX pad to 8byte? */
- ahlen = plen + sizeof(struct ah);
- } else {
- /* RFC 2402 */
- plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /* XXX pad to 8byte? */
- ahlen = plen + sizeof(struct newah);
- }
-
- /*
- * grow the mbuf to accomodate AH.
- */
- ip = mtod(m, struct ip *);
-#ifdef _IP_VHL
- hlen = IP_VHL_HL(ip->ip_vhl) << 2;
-#else
- hlen = ip->ip_hl << 2;
-#endif
-
- if (m->m_len != hlen)
- panic("ah4_output: assumption failed (first mbuf length)");
- if (M_LEADINGSPACE(m->m_next) < ahlen) {
- struct mbuf *n;
- MGET(n, M_DONTWAIT, MT_DATA);
- if (!n) {
- ipseclog((LOG_DEBUG, "ENOBUFS in ah4_output %d\n",
- __LINE__));
- m_freem(m);
- return ENOBUFS;
- }
- n->m_len = ahlen;
- n->m_next = m->m_next;
- m->m_next = n;
- m->m_pkthdr.len += ahlen;
- ahdrpos = mtod(n, u_char *);
- } else {
- m->m_next->m_len += ahlen;
- m->m_next->m_data -= ahlen;
- m->m_pkthdr.len += ahlen;
- ahdrpos = mtod(m->m_next, u_char *);
- }
-
- ip = mtod(m, struct ip *); /* just to be sure */
-
- /*
- * initialize AH.
- */
- if (sav->flags & SADB_X_EXT_OLD) {
- struct ah *ahdr;
-
- ahdr = (struct ah *)ahdrpos;
- ahsumpos = (u_char *)(ahdr + 1);
- ahdr->ah_len = plen >> 2;
- ahdr->ah_nxt = ip->ip_p;
- ahdr->ah_reserve = htons(0);
- ahdr->ah_spi = spi;
- bzero(ahdr + 1, plen);
- } else {
- struct newah *ahdr;
-
- ahdr = (struct newah *)ahdrpos;
- ahsumpos = (u_char *)(ahdr + 1);
- ahdr->ah_len = (plen >> 2) + 1; /* plus one for seq# */
- ahdr->ah_nxt = ip->ip_p;
- ahdr->ah_reserve = htons(0);
- ahdr->ah_spi = spi;
- if (sav->replay->count == ~0) {
- if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) {
- /* XXX Is it noisy ? */
- ipseclog((LOG_WARNING,
- "replay counter overflowed. %s\n",
- ipsec_logsastr(sav)));
- ipsecstat.out_inval++;
- m_freem(m);
- return EINVAL;
- }
- }
- sav->replay->count++;
- /*
- * XXX sequence number must not be cycled, if the SA is
- * installed by IKE daemon.
- */
- ahdr->ah_seq = htonl(sav->replay->count & 0xffffffff);
- bzero(ahdr + 1, plen);
- }
-
- /*
- * modify IPv4 header.
- */
- ip->ip_p = IPPROTO_AH;
- if (ahlen < (IP_MAXPACKET - ntohs(ip->ip_len)))
- ip->ip_len = htons(ntohs(ip->ip_len) + ahlen);
- else {
- ipseclog((LOG_ERR, "IPv4 AH output: size exceeds limit\n"));
- ipsecstat.out_inval++;
- m_freem(m);
- return EMSGSIZE;
- }
-
- /*
- * If there is source routing option, update destination field in
- * the IPv4 header to the final destination.
- * Note that we do not need to update source routing option itself
- * (as done in IPv4 AH processing -- see ip6_output()), since
- * source routing option is not part of the ICV computation.
- */
- finaldst = ah4_finaldst(m);
- if (finaldst) {
- saveaddr = ip->ip_dst.s_addr;
- ip->ip_dst.s_addr = finaldst->s_addr;
- }
-
- /*
- * calcurate the checksum, based on security association
- * and the algorithm specified.
- */
- error = ah4_calccksum(m, ahsumpos, plen, algo, sav);
- if (error) {
- ipseclog((LOG_ERR,
- "error after ah4_calccksum, called from ah4_output"));
- m_freem(m);
- m = NULL;
- ipsecstat.out_inval++;
- return error;
- }
-
- if (finaldst) {
- ip = mtod(m, struct ip *); /* just to make sure */
- ip->ip_dst.s_addr = saveaddr;
- }
- ipsecstat.out_success++;
- ipsecstat.out_ahhist[sav->alg_auth]++;
- key_sa_recordxfer(sav, m);
-
- return 0;
-}
-#endif
-
-/* Calculate AH length */
-int
-ah_hdrlen(sav)
- struct secasvar *sav;
-{
- const struct ah_algorithm *algo;
- int plen, ahlen;
-
- algo = ah_algorithm_lookup(sav->alg_auth);
- if (!algo)
- return 0;
- if (sav->flags & SADB_X_EXT_OLD) {
- /* RFC 1826 */
- plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /* XXX pad to 8byte? */
- ahlen = plen + sizeof(struct ah);
- } else {
- /* RFC 2402 */
- plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /* XXX pad to 8byte? */
- ahlen = plen + sizeof(struct newah);
- }
-
- return (ahlen);
-}
-
-#ifdef INET6
-/*
- * Fill in the Authentication Header and calculate checksum.
- */
-int
-ah6_output(m, nexthdrp, md, isr)
- struct mbuf *m;
- u_char *nexthdrp;
- struct mbuf *md;
- struct ipsecrequest *isr;
-{
- struct mbuf *mprev;
- struct mbuf *mah;
- struct secasvar *sav = isr->sav;
- const struct ah_algorithm *algo;
- u_int32_t spi;
- u_int8_t *ahsumpos = NULL;
- size_t plen; /* AH payload size in bytes */
- int error = 0;
- int ahlen;
- struct ip6_hdr *ip6;
-
- if (m->m_len < sizeof(struct ip6_hdr)) {
- ipseclog((LOG_DEBUG, "ah6_output: first mbuf too short\n"));
- m_freem(m);
- return EINVAL;
- }
-
- ahlen = ah_hdrlen(sav);
- if (ahlen == 0)
- return 0;
-
- for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
- ;
- if (!mprev || mprev->m_next != md) {
- ipseclog((LOG_DEBUG, "ah6_output: md is not in chain\n"));
- m_freem(m);
- return EINVAL;
- }
-
- MGET(mah, M_DONTWAIT, MT_DATA);
- if (!mah) {
- m_freem(m);
- return ENOBUFS;
- }
- if (ahlen > MLEN) {
- MCLGET(mah, M_DONTWAIT);
- if ((mah->m_flags & M_EXT) == 0) {
- m_free(mah);
- m_freem(m);
- return ENOBUFS;
- }
- }
- mah->m_len = ahlen;
- mah->m_next = md;
- mprev->m_next = mah;
- m->m_pkthdr.len += ahlen;
-
- /* fix plen */
- if (m->m_pkthdr.len - sizeof(struct ip6_hdr) > IPV6_MAXPACKET) {
- ipseclog((LOG_ERR,
- "ah6_output: AH with IPv6 jumbogram is not supported\n"));
- m_freem(m);
- return EINVAL;
- }
- ip6 = mtod(m, struct ip6_hdr *);
- ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
-
- if ((sav->flags & SADB_X_EXT_OLD) == 0 && !sav->replay) {
- ipseclog((LOG_DEBUG, "ah6_output: internal error: "
- "sav->replay is null: SPI=%u\n",
- (u_int32_t)ntohl(sav->spi)));
- ipsec6stat.out_inval++;
- m_freem(m);
- return EINVAL;
- }
-
- algo = ah_algorithm_lookup(sav->alg_auth);
- if (!algo) {
- ipseclog((LOG_ERR, "ah6_output: unsupported algorithm: "
- "SPI=%u\n", (u_int32_t)ntohl(sav->spi)));
- ipsec6stat.out_inval++;
- m_freem(m);
- return EINVAL;
- }
- spi = sav->spi;
-
- /*
- * initialize AH.
- */
- if (sav->flags & SADB_X_EXT_OLD) {
- struct ah *ahdr = mtod(mah, struct ah *);
-
- plen = mah->m_len - sizeof(struct ah);
- ahsumpos = (u_char *)(ahdr + 1);
- ahdr->ah_nxt = *nexthdrp;
- *nexthdrp = IPPROTO_AH;
- ahdr->ah_len = plen >> 2;
- ahdr->ah_reserve = htons(0);
- ahdr->ah_spi = spi;
- bzero(ahdr + 1, plen);
- } else {
- struct newah *ahdr = mtod(mah, struct newah *);
-
- plen = mah->m_len - sizeof(struct newah);
- ahsumpos = (u_char *)(ahdr + 1);
- ahdr->ah_nxt = *nexthdrp;
- *nexthdrp = IPPROTO_AH;
- ahdr->ah_len = (plen >> 2) + 1; /* plus one for seq# */
- ahdr->ah_reserve = htons(0);
- ahdr->ah_spi = spi;
- if (sav->replay->count == ~0) {
- if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) {
- /* XXX Is it noisy ? */
- ipseclog((LOG_WARNING,
- "replay counter overflowed. %s\n",
- ipsec_logsastr(sav)));
- ipsec6stat.out_inval++;
- m_freem(m);
- return EINVAL;
- }
- }
- sav->replay->count++;
- /*
- * XXX sequence number must not be cycled, if the SA is
- * installed by IKE daemon.
- */
- ahdr->ah_seq = htonl(sav->replay->count);
- bzero(ahdr + 1, plen);
- }
-
- /*
- * calcurate the checksum, based on security association
- * and the algorithm specified.
- */
- error = ah6_calccksum(m, ahsumpos, plen, algo, sav);
- if (error) {
- ipsec6stat.out_inval++;
- m_freem(m);
- } else {
- ipsec6stat.out_success++;
- key_sa_recordxfer(sav, m);
- }
- ipsec6stat.out_ahhist[sav->alg_auth]++;
-
- return (error);
-}
-#endif
-
-#ifdef INET
-/*
- * Find the final destination if there is loose/strict source routing option.
- * Returns NULL if there's no source routing options.
- * Returns NULL on errors too.
- * Note that this function will return a pointer INTO the given parameter,
- * struct mbuf *m.
- * The mbuf must be pulled up toward, at least, ip option part.
- */
-static struct in_addr *
-ah4_finaldst(m)
- struct mbuf *m;
-{
- struct ip *ip;
- int optlen;
- u_char *q;
- int i;
- int hlen;
-
- if (!m)
- panic("ah4_finaldst: m == NULL");
- ip = mtod(m, struct ip *);
- hlen = (ip->ip_hl << 2);
-
- if (m->m_len < hlen) {
- ipseclog((LOG_DEBUG,
- "ah4_finaldst: parameter mbuf wrong (not pulled up)\n"));
- return NULL;
- }
-
- if (hlen == sizeof(struct ip))
- return NULL;
-
- optlen = hlen - sizeof(struct ip);
- if (optlen < 0) {
- ipseclog((LOG_DEBUG, "ah4_finaldst: wrong optlen %d\n",
- optlen));
- return NULL;
- }
-
- q = (u_char *)(ip + 1);
- i = 0;
- while (i < optlen) {
- if (i + IPOPT_OPTVAL >= optlen)
- return NULL;
- if (q[i + IPOPT_OPTVAL] == IPOPT_EOL ||
- q[i + IPOPT_OPTVAL] == IPOPT_NOP ||
- i + IPOPT_OLEN < optlen)
- ;
- else
- return NULL;
-
- switch (q[i + IPOPT_OPTVAL]) {
- case IPOPT_EOL:
- i = optlen; /* bye */
- break;
- case IPOPT_NOP:
- i++;
- break;
- case IPOPT_LSRR:
- case IPOPT_SSRR:
- if (q[i + IPOPT_OLEN] < 2 + sizeof(struct in_addr) ||
- optlen - i < q[i + IPOPT_OLEN]) {
- ipseclog((LOG_ERR,
- "ip_finaldst: invalid IP option "
- "(code=%02x len=%02x)\n",
- q[i + IPOPT_OPTVAL], q[i + IPOPT_OLEN]));
- return NULL;
- }
- i += q[i + IPOPT_OLEN] - sizeof(struct in_addr);
- return (struct in_addr *)(q + i);
- default:
- if (q[i + IPOPT_OLEN] < 2 ||
- optlen - i < q[i + IPOPT_OLEN]) {
- ipseclog((LOG_ERR,
- "ip_finaldst: invalid IP option "
- "(code=%02x len=%02x)\n",
- q[i + IPOPT_OPTVAL], q[i + IPOPT_OLEN]));
- return NULL;
- }
- i += q[i + IPOPT_OLEN];
- break;
- }
- }
- return NULL;
-}
-#endif