1 /* $FreeBSD: src/sys/netinet6/ah_input.c,v 1.1.2.6 2002/04/28 05:40:26 suz Exp $ */
2 /* $DragonFly: src/sys/netinet6/ah_input.c,v 1.2 2003/06/17 04:28:51 dillon Exp $ */
3 /* $KAME: ah_input.c,v 1.67 2002/01/07 11:39:56 kjc Exp $ */
6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the project nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * RFC1826/2402 authentication header.
39 #include "opt_inet6.h"
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/malloc.h>
45 #include <sys/domain.h>
46 #include <sys/protosw.h>
47 #include <sys/socket.h>
48 #include <sys/errno.h>
50 #include <sys/syslog.h>
53 #include <net/route.h>
54 #include <net/netisr.h>
55 #include <machine/cpu.h>
57 #include <netinet/in.h>
58 #include <netinet/in_systm.h>
59 #include <netinet/in_var.h>
60 #include <netinet/ip.h>
61 #include <netinet/ip_var.h>
62 #include <netinet/ip_ecn.h>
64 #include <netinet6/ip6_ecn.h>
68 #include <netinet/ip6.h>
69 #include <netinet6/ip6_var.h>
70 #include <netinet6/in6_pcb.h>
71 #include <netinet/icmp6.h>
72 #include <netinet6/ip6protosw.h>
75 #include <netinet6/ipsec.h>
77 #include <netinet6/ipsec6.h>
79 #include <netinet6/ah.h>
81 #include <netinet6/ah6.h>
83 #include <netkey/key.h>
84 #include <netkey/keydb.h>
86 #include <netkey/key_debug.h>
88 #define KEYDEBUG(lev,arg)
91 #include <machine/stdarg.h>
93 #include <net/net_osdep.h>
98 #include <netinet/ipprotosw.h>
99 extern struct ipprotosw inetsw[];
103 ah4_input(struct mbuf *m, ...)
105 ah4_input(m, va_alist)
113 const struct ah_algorithm *algo;
117 struct secasvar *sav = NULL;
126 off = va_arg(ap, int);
127 proto = va_arg(ap, int);
130 #ifndef PULLDOWN_TEST
131 if (m->m_len < off + sizeof(struct newah)) {
132 m = m_pullup(m, off + sizeof(struct newah));
134 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;"
135 "dropping the packet for simplicity\n"));
136 ipsecstat.in_inval++;
141 ip = mtod(m, struct ip *);
142 ah = (struct ah *)(((caddr_t)ip) + off);
144 ip = mtod(m, struct ip *);
145 IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah));
147 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;"
148 "dropping the packet for simplicity\n"));
149 ipsecstat.in_inval++;
155 hlen = IP_VHL_HL(ip->ip_vhl) << 2;
157 hlen = ip->ip_hl << 2;
160 /* find the sassoc. */
163 if ((sav = key_allocsa(AF_INET,
164 (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst,
165 IPPROTO_AH, spi)) == 0) {
166 ipseclog((LOG_WARNING,
167 "IPv4 AH input: no key association found for spi %u\n",
168 (u_int32_t)ntohl(spi)));
172 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
173 printf("DP ah4_input called to allocate SA:%p\n", sav));
174 if (sav->state != SADB_SASTATE_MATURE
175 && sav->state != SADB_SASTATE_DYING) {
177 "IPv4 AH input: non-mature/dying SA found for spi %u\n",
178 (u_int32_t)ntohl(spi)));
179 ipsecstat.in_badspi++;
183 algo = ah_algorithm_lookup(sav->alg_auth);
185 ipseclog((LOG_DEBUG, "IPv4 AH input: "
186 "unsupported authentication algorithm for spi %u\n",
187 (u_int32_t)ntohl(spi)));
188 ipsecstat.in_badspi++;
192 siz = (*algo->sumsiz)(sav);
193 siz1 = ((siz + 3) & ~(4 - 1));
196 * sanity checks for header, 1.
201 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
204 * Here, we do not do "siz1 == siz". This is because the way
205 * RFC240[34] section 2 is written. They do not require truncation
207 * For example, Microsoft IPsec stack attaches 160 bits of
208 * authentication data for both hmac-md5 and hmac-sha1. For hmac-sha1,
209 * 32 bits of padding is attached.
211 * There are two downsides to this specification.
212 * They have no real harm, however, they leave us fuzzy feeling.
213 * - if we attach more than 96 bits of authentication data onto AH,
214 * we will never notice about possible modification by rogue
215 * intermediate nodes.
216 * Since extra bits in AH checksum is never used, this constitutes
217 * no real issue, however, it is wacky.
218 * - even if the peer attaches big authentication data, we will never
219 * notice the difference, since longer authentication data will just
222 * We may need some clarification in the spec.
225 ipseclog((LOG_NOTICE, "sum length too short in IPv4 AH input "
226 "(%lu, should be at least %lu): %s\n",
227 (u_long)siz1, (u_long)siz,
228 ipsec4_logpacketstr(ip, spi)));
229 ipsecstat.in_inval++;
232 if ((ah->ah_len << 2) - sizoff != siz1) {
233 ipseclog((LOG_NOTICE, "sum length mismatch in IPv4 AH input "
234 "(%d should be %lu): %s\n",
235 (ah->ah_len << 2) - sizoff, (u_long)siz1,
236 ipsec4_logpacketstr(ip, spi)));
237 ipsecstat.in_inval++;
241 #ifndef PULLDOWN_TEST
242 if (m->m_len < off + sizeof(struct ah) + sizoff + siz1) {
243 m = m_pullup(m, off + sizeof(struct ah) + sizoff + siz1);
245 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n"));
246 ipsecstat.in_inval++;
250 ip = mtod(m, struct ip *);
251 ah = (struct ah *)(((caddr_t)ip) + off);
254 IP6_EXTHDR_GET(ah, struct ah *, m, off,
255 sizeof(struct ah) + sizoff + siz1);
257 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n"));
258 ipsecstat.in_inval++;
265 * check for sequence number.
267 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
268 if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav))
271 ipsecstat.in_ahreplay++;
272 ipseclog((LOG_WARNING,
273 "replay packet in IPv4 AH input: %s %s\n",
274 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
280 * alright, it seems sane. now we are going to check the
281 * cryptographic checksum.
283 cksum = malloc(siz1, M_TEMP, M_NOWAIT);
285 ipseclog((LOG_DEBUG, "IPv4 AH input: "
286 "couldn't alloc temporary region for cksum\n"));
287 ipsecstat.in_inval++;
292 * some of IP header fields are flipped to the host endian.
293 * convert them back to network endian. VERY stupid.
295 ip->ip_len = htons(ip->ip_len + hlen);
296 ip->ip_off = htons(ip->ip_off);
297 if (ah4_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) {
299 ipsecstat.in_inval++;
302 ipsecstat.in_ahhist[sav->alg_auth]++;
306 ip->ip_len = ntohs(ip->ip_len) - hlen;
307 ip->ip_off = ntohs(ip->ip_off);
310 caddr_t sumpos = NULL;
312 if (sav->flags & SADB_X_EXT_OLD) {
314 sumpos = (caddr_t)(ah + 1);
317 sumpos = (caddr_t)(((struct newah *)ah) + 1);
320 if (bcmp(sumpos, cksum, siz) != 0) {
321 ipseclog((LOG_WARNING,
322 "checksum mismatch in IPv4 AH input: %s %s\n",
323 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
325 ipsecstat.in_ahauthfail++;
332 m->m_flags |= M_AUTHIPHDR;
333 m->m_flags |= M_AUTHIPDGM;
337 * looks okey, but we need more sanity check.
338 * XXX should elaborate.
340 if (ah->ah_nxt == IPPROTO_IPIP || ah->ah_nxt == IPPROTO_IP) {
344 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
346 if (m->m_len < off + sizeof(struct ah) + sizoff + siz1 + hlen) {
347 m = m_pullup(m, off + sizeof(struct ah)
348 + sizoff + siz1 + hlen);
351 "IPv4 AH input: can't pullup\n"));
352 ipsecstat.in_inval++;
357 nip = (struct ip *)((u_char *)(ah + 1) + sizoff + siz1);
358 if (nip->ip_src.s_addr != ip->ip_src.s_addr
359 || nip->ip_dst.s_addr != ip->ip_dst.s_addr) {
360 m->m_flags &= ~M_AUTHIPHDR;
361 m->m_flags &= ~M_AUTHIPDGM;
365 else if (ah->ah_nxt == IPPROTO_IPV6) {
366 m->m_flags &= ~M_AUTHIPHDR;
367 m->m_flags &= ~M_AUTHIPDGM;
372 if (m->m_flags & M_AUTHIPHDR
373 && m->m_flags & M_AUTHIPDGM) {
376 "IPv4 AH input: authentication succeess\n"));
378 ipsecstat.in_ahauthsucc++;
380 ipseclog((LOG_WARNING,
381 "authentication failed in IPv4 AH input: %s %s\n",
382 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
383 ipsecstat.in_ahauthfail++;
388 * update sequence number.
390 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
391 if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) {
392 ipsecstat.in_ahreplay++;
397 /* was it transmitted over the IPsec tunnel SA? */
398 if (sav->flags & SADB_X_EXT_OLD) {
400 stripsiz = sizeof(struct ah) + siz1;
403 stripsiz = sizeof(struct newah) + siz1;
405 if (ipsec4_tunnel_validate(m, off + stripsiz, nxt, sav)) {
407 * strip off all the headers that precedes AH.
408 * IP xx AH IP' payload -> IP' payload
410 * XXX more sanity checks
411 * XXX relationship with gif?
416 m_adj(m, off + stripsiz);
417 if (m->m_len < sizeof(*ip)) {
418 m = m_pullup(m, sizeof(*ip));
420 ipsecstat.in_inval++;
424 ip = mtod(m, struct ip *);
425 /* ECN consideration. */
426 ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos);
427 if (!key_checktunnelsanity(sav, AF_INET,
428 (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) {
429 ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
430 "in IPv4 AH input: %s %s\n",
431 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
432 ipsecstat.in_inval++;
438 * Should the inner packet be considered authentic?
439 * My current answer is: NO.
441 * host1 -- gw1 === gw2 -- host2
442 * In this case, gw2 can trust the authenticity of the
443 * outer packet, but NOT inner. Packet may be altered
444 * between host1 and gw1.
446 * host1 -- gw1 === host2
447 * This case falls into the same scenario as above.
450 * This case is the only case when we may be able to leave
451 * M_AUTHIPHDR and M_AUTHIPDGM set.
452 * However, if host1 is wrongly configured, and allows
453 * attacker to inject some packet with src=host1 and
454 * dst=host2, you are in risk.
456 m->m_flags &= ~M_AUTHIPHDR;
457 m->m_flags &= ~M_AUTHIPDGM;
460 key_sa_recordxfer(sav, m);
461 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
462 ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) {
463 ipsecstat.in_nomem++;
468 if (IF_QFULL(&ipintrq)) {
469 ipsecstat.in_inval++;
473 IF_ENQUEUE(&ipintrq, m);
475 schednetisr(NETISR_IP); /* can be skipped but to make sure */
483 ip = mtod(m, struct ip *);
484 #ifndef PULLDOWN_TEST
486 * We do deep-copy since KAME requires that
487 * the packet is placed in a single external mbuf.
489 ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), off);
490 m->m_data += stripsiz;
491 m->m_len -= stripsiz;
492 m->m_pkthdr.len -= stripsiz;
495 * even in m_pulldown case, we need to strip off AH so that
496 * we can compute checksum for multiple AH correctly.
498 if (m->m_len >= stripsiz + off) {
499 ovbcopy((caddr_t)ip, ((caddr_t)ip) + stripsiz, off);
500 m->m_data += stripsiz;
501 m->m_len -= stripsiz;
502 m->m_pkthdr.len -= stripsiz;
505 * this comes with no copy if the boundary is on
510 n = m_split(m, off, M_DONTWAIT);
512 /* m is retained by m_split */
517 /* m_cat does not update m_pkthdr.len */
518 m->m_pkthdr.len += n->m_pkthdr.len;
522 if (m->m_len < sizeof(*ip)) {
523 m = m_pullup(m, sizeof(*ip));
525 ipsecstat.in_inval++;
529 ip = mtod(m, struct ip *);
531 ip->ip_len = ip->ip_len - stripsiz;
533 ip->ip_len = htons(ntohs(ip->ip_len) - stripsiz);
536 /* forget about IP hdr checksum, the check has already been passed */
538 key_sa_recordxfer(sav, m);
539 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
540 ipsecstat.in_nomem++;
544 if (nxt != IPPROTO_DONE) {
545 if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
546 ipsec4_in_reject(m, NULL)) {
547 ipsecstat.in_polvio++;
550 (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt);
557 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
558 printf("DP ah4_input call free SA:%p\n", sav));
561 ipsecstat.in_success++;
566 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
567 printf("DP ah4_input call free SA:%p\n", sav));
578 ah6_input(mp, offp, proto)
582 struct mbuf *m = *mp;
587 const struct ah_algorithm *algo;
591 struct secasvar *sav = NULL;
596 #ifndef PULLDOWN_TEST
597 IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), IPPROTO_DONE);
598 ah = (struct ah *)(mtod(m, caddr_t) + off);
600 IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah));
602 ipseclog((LOG_DEBUG, "IPv6 AH input: can't pullup\n"));
603 ipsec6stat.in_inval++;
607 ip6 = mtod(m, struct ip6_hdr *);
610 /* find the sassoc. */
613 if (ntohs(ip6->ip6_plen) == 0) {
614 ipseclog((LOG_ERR, "IPv6 AH input: "
615 "AH with IPv6 jumbogram is not supported.\n"));
616 ipsec6stat.in_inval++;
620 if ((sav = key_allocsa(AF_INET6,
621 (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst,
622 IPPROTO_AH, spi)) == 0) {
623 ipseclog((LOG_WARNING,
624 "IPv6 AH input: no key association found for spi %u\n",
625 (u_int32_t)ntohl(spi)));
626 ipsec6stat.in_nosa++;
629 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
630 printf("DP ah6_input called to allocate SA:%p\n", sav));
631 if (sav->state != SADB_SASTATE_MATURE
632 && sav->state != SADB_SASTATE_DYING) {
634 "IPv6 AH input: non-mature/dying SA found for spi %u; ",
635 (u_int32_t)ntohl(spi)));
636 ipsec6stat.in_badspi++;
640 algo = ah_algorithm_lookup(sav->alg_auth);
642 ipseclog((LOG_DEBUG, "IPv6 AH input: "
643 "unsupported authentication algorithm for spi %u\n",
644 (u_int32_t)ntohl(spi)));
645 ipsec6stat.in_badspi++;
649 siz = (*algo->sumsiz)(sav);
650 siz1 = ((siz + 3) & ~(4 - 1));
653 * sanity checks for header, 1.
658 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
661 * Here, we do not do "siz1 == siz". See ah4_input() for complete
665 ipseclog((LOG_NOTICE, "sum length too short in IPv6 AH input "
666 "(%lu, should be at least %lu): %s\n",
667 (u_long)siz1, (u_long)siz,
668 ipsec6_logpacketstr(ip6, spi)));
669 ipsec6stat.in_inval++;
672 if ((ah->ah_len << 2) - sizoff != siz1) {
673 ipseclog((LOG_NOTICE, "sum length mismatch in IPv6 AH input "
674 "(%d should be %lu): %s\n",
675 (ah->ah_len << 2) - sizoff, (u_long)siz1,
676 ipsec6_logpacketstr(ip6, spi)));
677 ipsec6stat.in_inval++;
680 #ifndef PULLDOWN_TEST
681 IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1, IPPROTO_DONE);
683 IP6_EXTHDR_GET(ah, struct ah *, m, off,
684 sizeof(struct ah) + sizoff + siz1);
686 ipseclog((LOG_NOTICE, "couldn't pullup gather IPv6 AH checksum part"));
687 ipsec6stat.in_inval++;
695 * check for sequence number.
697 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
698 if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav))
701 ipsec6stat.in_ahreplay++;
702 ipseclog((LOG_WARNING,
703 "replay packet in IPv6 AH input: %s %s\n",
704 ipsec6_logpacketstr(ip6, spi),
705 ipsec_logsastr(sav)));
711 * alright, it seems sane. now we are going to check the
712 * cryptographic checksum.
714 cksum = malloc(siz1, M_TEMP, M_NOWAIT);
716 ipseclog((LOG_DEBUG, "IPv6 AH input: "
717 "couldn't alloc temporary region for cksum\n"));
718 ipsec6stat.in_inval++;
722 if (ah6_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) {
724 ipsec6stat.in_inval++;
727 ipsec6stat.in_ahhist[sav->alg_auth]++;
730 caddr_t sumpos = NULL;
732 if (sav->flags & SADB_X_EXT_OLD) {
734 sumpos = (caddr_t)(ah + 1);
737 sumpos = (caddr_t)(((struct newah *)ah) + 1);
740 if (bcmp(sumpos, cksum, siz) != 0) {
741 ipseclog((LOG_WARNING,
742 "checksum mismatch in IPv6 AH input: %s %s\n",
743 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
745 ipsec6stat.in_ahauthfail++;
752 m->m_flags |= M_AUTHIPHDR;
753 m->m_flags |= M_AUTHIPDGM;
757 * looks okey, but we need more sanity check.
758 * XXX should elaborate.
760 if (ah->ah_nxt == IPPROTO_IPV6) {
761 struct ip6_hdr *nip6;
764 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
766 IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1
767 + sizeof(struct ip6_hdr), IPPROTO_DONE);
769 nip6 = (struct ip6_hdr *)((u_char *)(ah + 1) + sizoff + siz1);
770 if (!IN6_ARE_ADDR_EQUAL(&nip6->ip6_src, &ip6->ip6_src)
771 || !IN6_ARE_ADDR_EQUAL(&nip6->ip6_dst, &ip6->ip6_dst)) {
772 m->m_flags &= ~M_AUTHIPHDR;
773 m->m_flags &= ~M_AUTHIPDGM;
775 } else if (ah->ah_nxt == IPPROTO_IPIP) {
776 m->m_flags &= ~M_AUTHIPHDR;
777 m->m_flags &= ~M_AUTHIPDGM;
778 } else if (ah->ah_nxt == IPPROTO_IP) {
779 m->m_flags &= ~M_AUTHIPHDR;
780 m->m_flags &= ~M_AUTHIPDGM;
784 if (m->m_flags & M_AUTHIPHDR
785 && m->m_flags & M_AUTHIPDGM) {
788 "IPv6 AH input: authentication succeess\n"));
790 ipsec6stat.in_ahauthsucc++;
792 ipseclog((LOG_WARNING,
793 "authentication failed in IPv6 AH input: %s %s\n",
794 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
795 ipsec6stat.in_ahauthfail++;
800 * update sequence number.
802 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
803 if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) {
804 ipsec6stat.in_ahreplay++;
809 /* was it transmitted over the IPsec tunnel SA? */
810 if (sav->flags & SADB_X_EXT_OLD) {
812 stripsiz = sizeof(struct ah) + siz1;
815 stripsiz = sizeof(struct newah) + siz1;
817 if (ipsec6_tunnel_validate(m, off + stripsiz, nxt, sav)) {
819 * strip off all the headers that precedes AH.
820 * IP6 xx AH IP6' payload -> IP6' payload
822 * XXX more sanity checks
823 * XXX relationship with gif?
825 u_int32_t flowinfo; /* net endian */
827 flowinfo = ip6->ip6_flow;
828 m_adj(m, off + stripsiz);
829 if (m->m_len < sizeof(*ip6)) {
831 * m_pullup is prohibited in KAME IPv6 input processing
832 * but there's no other way!
834 m = m_pullup(m, sizeof(*ip6));
836 ipsec6stat.in_inval++;
840 ip6 = mtod(m, struct ip6_hdr *);
841 /* ECN consideration. */
842 ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow);
843 if (!key_checktunnelsanity(sav, AF_INET6,
844 (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) {
845 ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
846 "in IPv6 AH input: %s %s\n",
847 ipsec6_logpacketstr(ip6, spi),
848 ipsec_logsastr(sav)));
849 ipsec6stat.in_inval++;
855 * should the inner packet be considered authentic?
856 * see comment in ah4_input().
858 m->m_flags &= ~M_AUTHIPHDR;
859 m->m_flags &= ~M_AUTHIPDGM;
862 key_sa_recordxfer(sav, m);
863 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
864 ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) {
865 ipsec6stat.in_nomem++;
870 if (IF_QFULL(&ip6intrq)) {
871 ipsec6stat.in_inval++;
875 IF_ENQUEUE(&ip6intrq, m);
877 schednetisr(NETISR_IPV6); /* can be skipped but to make sure */
887 * Copy the value of the next header field of AH to the
888 * next header field of the previous header.
889 * This is necessary because AH will be stripped off below.
891 prvnxtp = ip6_get_prevhdr(m, off); /* XXX */
894 ip6 = mtod(m, struct ip6_hdr *);
895 #ifndef PULLDOWN_TEST
897 * We do deep-copy since KAME requires that
898 * the packet is placed in a single mbuf.
900 ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
901 m->m_data += stripsiz;
902 m->m_len -= stripsiz;
903 m->m_pkthdr.len -= stripsiz;
906 * even in m_pulldown case, we need to strip off AH so that
907 * we can compute checksum for multiple AH correctly.
909 if (m->m_len >= stripsiz + off) {
910 ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
911 m->m_data += stripsiz;
912 m->m_len -= stripsiz;
913 m->m_pkthdr.len -= stripsiz;
916 * this comes with no copy if the boundary is on
921 n = m_split(m, off, M_DONTWAIT);
923 /* m is retained by m_split */
928 /* m_cat does not update m_pkthdr.len */
929 m->m_pkthdr.len += n->m_pkthdr.len;
932 ip6 = mtod(m, struct ip6_hdr *);
934 ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz);
936 key_sa_recordxfer(sav, m);
937 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
938 ipsec6stat.in_nomem++;
947 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
948 printf("DP ah6_input call free SA:%p\n", sav));
951 ipsec6stat.in_success++;
956 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
957 printf("DP ah6_input call free SA:%p\n", sav));
966 ah6_ctlinput(cmd, sa, d)
971 const struct newah *ahp;
973 struct secasvar *sav;
976 struct ip6ctlparam *ip6cp = NULL;
978 struct sockaddr_in6 *sa6_src, *sa6_dst;
980 if (sa->sa_family != AF_INET6 ||
981 sa->sa_len != sizeof(struct sockaddr_in6))
983 if ((unsigned)cmd >= PRC_NCMDS)
986 /* if the parameter is from icmp6, decode it. */
988 ip6cp = (struct ip6ctlparam *)d;
990 ip6 = ip6cp->ip6c_ip6;
991 off = ip6cp->ip6c_off;
999 * XXX: We assume that when ip6 is non NULL,
1000 * M and OFF are valid.
1003 /* check if we can safely examine src and dst ports */
1004 if (m->m_pkthdr.len < off + sizeof(ah))
1007 if (m->m_len < off + sizeof(ah)) {
1009 * this should be rare case,
1010 * so we compromise on this copy...
1012 m_copydata(m, off, sizeof(ah), (caddr_t)&ah);
1015 ahp = (struct newah *)(mtod(m, caddr_t) + off);
1017 if (cmd == PRC_MSGSIZE) {
1021 * Check to see if we have a valid SA corresponding to
1022 * the address in the ICMP message payload.
1024 sa6_src = ip6cp->ip6c_src;
1025 sa6_dst = (struct sockaddr_in6 *)sa;
1026 sav = key_allocsa(AF_INET6,
1027 (caddr_t)&sa6_src->sin6_addr,
1028 (caddr_t)&sa6_dst->sin6_addr,
1029 IPPROTO_AH, ahp->ah_spi);
1031 if (sav->state == SADB_SASTATE_MATURE ||
1032 sav->state == SADB_SASTATE_DYING)
1037 /* XXX Further validation? */
1040 * Depending on the value of "valid" and routing table
1041 * size (mtudisc_{hi,lo}wat), we will:
1042 * - recalcurate the new MTU and create the
1043 * corresponding routing entry, or
1044 * - ignore the MTU change notification.
1046 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
1049 /* we normally notify single pcb here */
1051 /* we normally notify any pcb here */