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.13 2006/12/22 23:57:53 swildner 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>
56 #include <machine/stdarg.h>
58 #include <netinet/in.h>
59 #include <netinet/in_systm.h>
60 #include <netinet/in_var.h>
61 #include <netinet/ip.h>
62 #include <netinet/ip_var.h>
63 #include <netinet/ip_ecn.h>
65 #include <netinet6/ip6_ecn.h>
69 #include <netinet/ip6.h>
70 #include <netinet6/ip6_var.h>
71 #include <netinet6/in6_pcb.h>
72 #include <netinet/icmp6.h>
73 #include <netinet6/ip6protosw.h>
76 #include <netinet6/ipsec.h>
78 #include <netinet6/ipsec6.h>
80 #include <netinet6/ah.h>
82 #include <netinet6/ah6.h>
84 #include <netproto/key/key.h>
85 #include <netproto/key/keydb.h>
87 #include <netproto/key/key_debug.h>
89 #define KEYDEBUG(lev,arg)
92 #include <machine/stdarg.h>
94 #include <net/net_osdep.h>
99 extern struct protosw inetsw
[];
102 ah4_input(struct mbuf
*m
, ...)
108 const struct ah_algorithm
*algo
;
112 struct secasvar
*sav
= NULL
;
119 off
= __va_arg(ap
, int);
120 proto
= __va_arg(ap
, int);
123 #ifndef PULLDOWN_TEST
124 if (m
->m_len
< off
+ sizeof(struct newah
)) {
125 m
= m_pullup(m
, off
+ sizeof(struct newah
));
127 ipseclog((LOG_DEBUG
, "IPv4 AH input: can't pullup;"
128 "dropping the packet for simplicity\n"));
129 ipsecstat
.in_inval
++;
134 ip
= mtod(m
, struct ip
*);
135 ah
= (struct ah
*)(((caddr_t
)ip
) + off
);
137 ip
= mtod(m
, struct ip
*);
138 IP6_EXTHDR_GET(ah
, struct ah
*, m
, off
, sizeof(struct newah
));
140 ipseclog((LOG_DEBUG
, "IPv4 AH input: can't pullup;"
141 "dropping the packet for simplicity\n"));
142 ipsecstat
.in_inval
++;
148 hlen
= IP_VHL_HL(ip
->ip_vhl
) << 2;
150 hlen
= ip
->ip_hl
<< 2;
153 /* find the sassoc. */
156 if ((sav
= key_allocsa(AF_INET
,
157 (caddr_t
)&ip
->ip_src
, (caddr_t
)&ip
->ip_dst
,
158 IPPROTO_AH
, spi
)) == 0) {
159 ipseclog((LOG_WARNING
,
160 "IPv4 AH input: no key association found for spi %u\n",
161 (u_int32_t
)ntohl(spi
)));
165 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
166 kprintf("DP ah4_input called to allocate SA:%p\n", sav
));
167 if (sav
->state
!= SADB_SASTATE_MATURE
168 && sav
->state
!= SADB_SASTATE_DYING
) {
170 "IPv4 AH input: non-mature/dying SA found for spi %u\n",
171 (u_int32_t
)ntohl(spi
)));
172 ipsecstat
.in_badspi
++;
176 algo
= ah_algorithm_lookup(sav
->alg_auth
);
178 ipseclog((LOG_DEBUG
, "IPv4 AH input: "
179 "unsupported authentication algorithm for spi %u\n",
180 (u_int32_t
)ntohl(spi
)));
181 ipsecstat
.in_badspi
++;
185 siz
= (*algo
->sumsiz
)(sav
);
186 siz1
= ((siz
+ 3) & ~(4 - 1));
189 * sanity checks for header, 1.
194 sizoff
= (sav
->flags
& SADB_X_EXT_OLD
) ? 0 : 4;
197 * Here, we do not do "siz1 == siz". This is because the way
198 * RFC240[34] section 2 is written. They do not require truncation
200 * For example, Microsoft IPsec stack attaches 160 bits of
201 * authentication data for both hmac-md5 and hmac-sha1. For hmac-sha1,
202 * 32 bits of padding is attached.
204 * There are two downsides to this specification.
205 * They have no real harm, however, they leave us fuzzy feeling.
206 * - if we attach more than 96 bits of authentication data onto AH,
207 * we will never notice about possible modification by rogue
208 * intermediate nodes.
209 * Since extra bits in AH checksum is never used, this constitutes
210 * no real issue, however, it is wacky.
211 * - even if the peer attaches big authentication data, we will never
212 * notice the difference, since longer authentication data will just
215 * We may need some clarification in the spec.
218 ipseclog((LOG_NOTICE
, "sum length too short in IPv4 AH input "
219 "(%lu, should be at least %lu): %s\n",
220 (u_long
)siz1
, (u_long
)siz
,
221 ipsec4_logpacketstr(ip
, spi
)));
222 ipsecstat
.in_inval
++;
225 if ((ah
->ah_len
<< 2) - sizoff
!= siz1
) {
226 ipseclog((LOG_NOTICE
, "sum length mismatch in IPv4 AH input "
227 "(%d should be %lu): %s\n",
228 (ah
->ah_len
<< 2) - sizoff
, (u_long
)siz1
,
229 ipsec4_logpacketstr(ip
, spi
)));
230 ipsecstat
.in_inval
++;
234 #ifndef PULLDOWN_TEST
235 if (m
->m_len
< off
+ sizeof(struct ah
) + sizoff
+ siz1
) {
236 m
= m_pullup(m
, off
+ sizeof(struct ah
) + sizoff
+ siz1
);
238 ipseclog((LOG_DEBUG
, "IPv4 AH input: can't pullup\n"));
239 ipsecstat
.in_inval
++;
243 ip
= mtod(m
, struct ip
*);
244 ah
= (struct ah
*)(((caddr_t
)ip
) + off
);
247 IP6_EXTHDR_GET(ah
, struct ah
*, m
, off
,
248 sizeof(struct ah
) + sizoff
+ siz1
);
250 ipseclog((LOG_DEBUG
, "IPv4 AH input: can't pullup\n"));
251 ipsecstat
.in_inval
++;
258 * check for sequence number.
260 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0 && sav
->replay
) {
261 if (ipsec_chkreplay(ntohl(((struct newah
*)ah
)->ah_seq
), sav
))
264 ipsecstat
.in_ahreplay
++;
265 ipseclog((LOG_WARNING
,
266 "replay packet in IPv4 AH input: %s %s\n",
267 ipsec4_logpacketstr(ip
, spi
), ipsec_logsastr(sav
)));
273 * alright, it seems sane. now we are going to check the
274 * cryptographic checksum.
276 cksum
= kmalloc(siz1
, M_TEMP
, M_NOWAIT
);
278 ipseclog((LOG_DEBUG
, "IPv4 AH input: "
279 "couldn't alloc temporary region for cksum\n"));
280 ipsecstat
.in_inval
++;
285 * some of IP header fields are flipped to the host endian.
286 * convert them back to network endian. VERY stupid.
288 ip
->ip_len
= htons(ip
->ip_len
+ hlen
);
289 ip
->ip_off
= htons(ip
->ip_off
);
290 if (ah4_calccksum(m
, (caddr_t
)cksum
, siz1
, algo
, sav
)) {
291 kfree(cksum
, M_TEMP
);
292 ipsecstat
.in_inval
++;
295 ipsecstat
.in_ahhist
[sav
->alg_auth
]++;
299 ip
->ip_len
= ntohs(ip
->ip_len
) - hlen
;
300 ip
->ip_off
= ntohs(ip
->ip_off
);
303 caddr_t sumpos
= NULL
;
305 if (sav
->flags
& SADB_X_EXT_OLD
) {
307 sumpos
= (caddr_t
)(ah
+ 1);
310 sumpos
= (caddr_t
)(((struct newah
*)ah
) + 1);
313 if (bcmp(sumpos
, cksum
, siz
) != 0) {
314 ipseclog((LOG_WARNING
,
315 "checksum mismatch in IPv4 AH input: %s %s\n",
316 ipsec4_logpacketstr(ip
, spi
), ipsec_logsastr(sav
)));
317 kfree(cksum
, M_TEMP
);
318 ipsecstat
.in_ahauthfail
++;
323 kfree(cksum
, M_TEMP
);
325 m
->m_flags
|= M_AUTHIPHDR
;
326 m
->m_flags
|= M_AUTHIPDGM
;
330 * looks okey, but we need more sanity check.
331 * XXX should elaborate.
333 if (ah
->ah_nxt
== IPPROTO_IPIP
|| ah
->ah_nxt
== IPPROTO_IP
) {
337 sizoff
= (sav
->flags
& SADB_X_EXT_OLD
) ? 0 : 4;
339 if (m
->m_len
< off
+ sizeof(struct ah
) + sizoff
+ siz1
+ hlen
) {
340 m
= m_pullup(m
, off
+ sizeof(struct ah
)
341 + sizoff
+ siz1
+ hlen
);
344 "IPv4 AH input: can't pullup\n"));
345 ipsecstat
.in_inval
++;
350 nip
= (struct ip
*)((u_char
*)(ah
+ 1) + sizoff
+ siz1
);
351 if (nip
->ip_src
.s_addr
!= ip
->ip_src
.s_addr
352 || nip
->ip_dst
.s_addr
!= ip
->ip_dst
.s_addr
) {
353 m
->m_flags
&= ~M_AUTHIPHDR
;
354 m
->m_flags
&= ~M_AUTHIPDGM
;
358 else if (ah
->ah_nxt
== IPPROTO_IPV6
) {
359 m
->m_flags
&= ~M_AUTHIPHDR
;
360 m
->m_flags
&= ~M_AUTHIPDGM
;
365 if (m
->m_flags
& M_AUTHIPHDR
366 && m
->m_flags
& M_AUTHIPDGM
) {
369 "IPv4 AH input: authentication succeess\n"));
371 ipsecstat
.in_ahauthsucc
++;
373 ipseclog((LOG_WARNING
,
374 "authentication failed in IPv4 AH input: %s %s\n",
375 ipsec4_logpacketstr(ip
, spi
), ipsec_logsastr(sav
)));
376 ipsecstat
.in_ahauthfail
++;
381 * update sequence number.
383 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0 && sav
->replay
) {
384 if (ipsec_updatereplay(ntohl(((struct newah
*)ah
)->ah_seq
), sav
)) {
385 ipsecstat
.in_ahreplay
++;
390 /* was it transmitted over the IPsec tunnel SA? */
391 if (sav
->flags
& SADB_X_EXT_OLD
) {
393 stripsiz
= sizeof(struct ah
) + siz1
;
396 stripsiz
= sizeof(struct newah
) + siz1
;
398 if (ipsec4_tunnel_validate(m
, off
+ stripsiz
, nxt
, sav
)) {
400 * strip off all the headers that precedes AH.
401 * IP xx AH IP' payload -> IP' payload
403 * XXX more sanity checks
404 * XXX relationship with gif?
409 m_adj(m
, off
+ stripsiz
);
410 if (m
->m_len
< sizeof(*ip
)) {
411 m
= m_pullup(m
, sizeof(*ip
));
413 ipsecstat
.in_inval
++;
417 ip
= mtod(m
, struct ip
*);
418 /* ECN consideration. */
419 ip_ecn_egress(ip4_ipsec_ecn
, &tos
, &ip
->ip_tos
);
420 if (!key_checktunnelsanity(sav
, AF_INET
,
421 (caddr_t
)&ip
->ip_src
, (caddr_t
)&ip
->ip_dst
)) {
422 ipseclog((LOG_NOTICE
, "ipsec tunnel address mismatch "
423 "in IPv4 AH input: %s %s\n",
424 ipsec4_logpacketstr(ip
, spi
), ipsec_logsastr(sav
)));
425 ipsecstat
.in_inval
++;
431 * Should the inner packet be considered authentic?
432 * My current answer is: NO.
434 * host1 -- gw1 === gw2 -- host2
435 * In this case, gw2 can trust the authenticity of the
436 * outer packet, but NOT inner. Packet may be altered
437 * between host1 and gw1.
439 * host1 -- gw1 === host2
440 * This case falls into the same scenario as above.
443 * This case is the only case when we may be able to leave
444 * M_AUTHIPHDR and M_AUTHIPDGM set.
445 * However, if host1 is wrongly configured, and allows
446 * attacker to inject some packet with src=host1 and
447 * dst=host2, you are in risk.
449 m
->m_flags
&= ~M_AUTHIPHDR
;
450 m
->m_flags
&= ~M_AUTHIPDGM
;
453 key_sa_recordxfer(sav
, m
);
454 if (ipsec_addhist(m
, IPPROTO_AH
, spi
) != 0 ||
455 ipsec_addhist(m
, IPPROTO_IPV4
, 0) != 0) {
456 ipsecstat
.in_nomem
++;
460 if (netisr_queue(NETISR_IP
, m
)) {
461 ipsecstat
.in_inval
++;
472 ip
= mtod(m
, struct ip
*);
473 #ifndef PULLDOWN_TEST
475 * We do deep-copy since KAME requires that
476 * the packet is placed in a single external mbuf.
478 ovbcopy((caddr_t
)ip
, (caddr_t
)(((u_char
*)ip
) + stripsiz
), off
);
479 m
->m_data
+= stripsiz
;
480 m
->m_len
-= stripsiz
;
481 m
->m_pkthdr
.len
-= stripsiz
;
484 * even in m_pulldown case, we need to strip off AH so that
485 * we can compute checksum for multiple AH correctly.
487 if (m
->m_len
>= stripsiz
+ off
) {
488 ovbcopy((caddr_t
)ip
, ((caddr_t
)ip
) + stripsiz
, off
);
489 m
->m_data
+= stripsiz
;
490 m
->m_len
-= stripsiz
;
491 m
->m_pkthdr
.len
-= stripsiz
;
494 * this comes with no copy if the boundary is on
499 n
= m_split(m
, off
, MB_DONTWAIT
);
501 /* m is retained by m_split */
505 /* m_cat does not update m_pkthdr.len */
506 m
->m_pkthdr
.len
+= n
->m_pkthdr
.len
;
511 if (m
->m_len
< sizeof(*ip
)) {
512 m
= m_pullup(m
, sizeof(*ip
));
514 ipsecstat
.in_inval
++;
518 ip
= mtod(m
, struct ip
*);
520 ip
->ip_len
= ip
->ip_len
- stripsiz
;
522 ip
->ip_len
= htons(ntohs(ip
->ip_len
) - stripsiz
);
525 /* forget about IP hdr checksum, the check has already been passed */
527 key_sa_recordxfer(sav
, m
);
528 if (ipsec_addhist(m
, IPPROTO_AH
, spi
) != 0) {
529 ipsecstat
.in_nomem
++;
533 if (nxt
!= IPPROTO_DONE
) {
534 if ((inetsw
[ip_protox
[nxt
]].pr_flags
& PR_LASTHDR
) &&
535 ipsec4_in_reject(m
, NULL
)) {
536 ipsecstat
.in_polvio
++;
539 if (!ip_lengthcheck(&m
)) {
540 m
= NULL
; /* freed in ip_lengthcheck() */
543 (*inetsw
[ip_protox
[nxt
]].pr_input
)(m
, off
, nxt
);
550 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
551 kprintf("DP ah4_input call free SA:%p\n", sav
));
554 ipsecstat
.in_success
++;
559 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
560 kprintf("DP ah4_input call free SA:%p\n", sav
));
571 ah6_input(struct mbuf
**mp
, int *offp
, int proto
)
573 struct mbuf
*m
= *mp
;
578 const struct ah_algorithm
*algo
;
582 struct secasvar
*sav
= NULL
;
586 #ifndef PULLDOWN_TEST
587 IP6_EXTHDR_CHECK(m
, off
, sizeof(struct ah
), IPPROTO_DONE
);
588 ah
= (struct ah
*)(mtod(m
, caddr_t
) + off
);
590 IP6_EXTHDR_GET(ah
, struct ah
*, m
, off
, sizeof(struct newah
));
592 ipseclog((LOG_DEBUG
, "IPv6 AH input: can't pullup\n"));
593 ipsec6stat
.in_inval
++;
597 ip6
= mtod(m
, struct ip6_hdr
*);
600 /* find the sassoc. */
603 if (ntohs(ip6
->ip6_plen
) == 0) {
604 ipseclog((LOG_ERR
, "IPv6 AH input: "
605 "AH with IPv6 jumbogram is not supported.\n"));
606 ipsec6stat
.in_inval
++;
610 if ((sav
= key_allocsa(AF_INET6
,
611 (caddr_t
)&ip6
->ip6_src
, (caddr_t
)&ip6
->ip6_dst
,
612 IPPROTO_AH
, spi
)) == 0) {
613 ipseclog((LOG_WARNING
,
614 "IPv6 AH input: no key association found for spi %u\n",
615 (u_int32_t
)ntohl(spi
)));
616 ipsec6stat
.in_nosa
++;
619 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
620 kprintf("DP ah6_input called to allocate SA:%p\n", sav
));
621 if (sav
->state
!= SADB_SASTATE_MATURE
622 && sav
->state
!= SADB_SASTATE_DYING
) {
624 "IPv6 AH input: non-mature/dying SA found for spi %u; ",
625 (u_int32_t
)ntohl(spi
)));
626 ipsec6stat
.in_badspi
++;
630 algo
= ah_algorithm_lookup(sav
->alg_auth
);
632 ipseclog((LOG_DEBUG
, "IPv6 AH input: "
633 "unsupported authentication algorithm for spi %u\n",
634 (u_int32_t
)ntohl(spi
)));
635 ipsec6stat
.in_badspi
++;
639 siz
= (*algo
->sumsiz
)(sav
);
640 siz1
= ((siz
+ 3) & ~(4 - 1));
643 * sanity checks for header, 1.
648 sizoff
= (sav
->flags
& SADB_X_EXT_OLD
) ? 0 : 4;
651 * Here, we do not do "siz1 == siz". See ah4_input() for complete
655 ipseclog((LOG_NOTICE
, "sum length too short in IPv6 AH input "
656 "(%lu, should be at least %lu): %s\n",
657 (u_long
)siz1
, (u_long
)siz
,
658 ipsec6_logpacketstr(ip6
, spi
)));
659 ipsec6stat
.in_inval
++;
662 if ((ah
->ah_len
<< 2) - sizoff
!= siz1
) {
663 ipseclog((LOG_NOTICE
, "sum length mismatch in IPv6 AH input "
664 "(%d should be %lu): %s\n",
665 (ah
->ah_len
<< 2) - sizoff
, (u_long
)siz1
,
666 ipsec6_logpacketstr(ip6
, spi
)));
667 ipsec6stat
.in_inval
++;
670 #ifndef PULLDOWN_TEST
671 IP6_EXTHDR_CHECK(m
, off
, sizeof(struct ah
) + sizoff
+ siz1
, IPPROTO_DONE
);
673 IP6_EXTHDR_GET(ah
, struct ah
*, m
, off
,
674 sizeof(struct ah
) + sizoff
+ siz1
);
676 ipseclog((LOG_NOTICE
, "couldn't pullup gather IPv6 AH checksum part"));
677 ipsec6stat
.in_inval
++;
685 * check for sequence number.
687 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0 && sav
->replay
) {
688 if (ipsec_chkreplay(ntohl(((struct newah
*)ah
)->ah_seq
), sav
))
691 ipsec6stat
.in_ahreplay
++;
692 ipseclog((LOG_WARNING
,
693 "replay packet in IPv6 AH input: %s %s\n",
694 ipsec6_logpacketstr(ip6
, spi
),
695 ipsec_logsastr(sav
)));
701 * alright, it seems sane. now we are going to check the
702 * cryptographic checksum.
704 cksum
= kmalloc(siz1
, M_TEMP
, M_NOWAIT
);
706 ipseclog((LOG_DEBUG
, "IPv6 AH input: "
707 "couldn't alloc temporary region for cksum\n"));
708 ipsec6stat
.in_inval
++;
712 if (ah6_calccksum(m
, (caddr_t
)cksum
, siz1
, algo
, sav
)) {
713 kfree(cksum
, M_TEMP
);
714 ipsec6stat
.in_inval
++;
717 ipsec6stat
.in_ahhist
[sav
->alg_auth
]++;
720 caddr_t sumpos
= NULL
;
722 if (sav
->flags
& SADB_X_EXT_OLD
) {
724 sumpos
= (caddr_t
)(ah
+ 1);
727 sumpos
= (caddr_t
)(((struct newah
*)ah
) + 1);
730 if (bcmp(sumpos
, cksum
, siz
) != 0) {
731 ipseclog((LOG_WARNING
,
732 "checksum mismatch in IPv6 AH input: %s %s\n",
733 ipsec6_logpacketstr(ip6
, spi
), ipsec_logsastr(sav
)));
734 kfree(cksum
, M_TEMP
);
735 ipsec6stat
.in_ahauthfail
++;
740 kfree(cksum
, M_TEMP
);
742 m
->m_flags
|= M_AUTHIPHDR
;
743 m
->m_flags
|= M_AUTHIPDGM
;
747 * looks okey, but we need more sanity check.
748 * XXX should elaborate.
750 if (ah
->ah_nxt
== IPPROTO_IPV6
) {
751 struct ip6_hdr
*nip6
;
754 sizoff
= (sav
->flags
& SADB_X_EXT_OLD
) ? 0 : 4;
756 IP6_EXTHDR_CHECK(m
, off
, sizeof(struct ah
) + sizoff
+ siz1
757 + sizeof(struct ip6_hdr
), IPPROTO_DONE
);
759 nip6
= (struct ip6_hdr
*)((u_char
*)(ah
+ 1) + sizoff
+ siz1
);
760 if (!IN6_ARE_ADDR_EQUAL(&nip6
->ip6_src
, &ip6
->ip6_src
)
761 || !IN6_ARE_ADDR_EQUAL(&nip6
->ip6_dst
, &ip6
->ip6_dst
)) {
762 m
->m_flags
&= ~M_AUTHIPHDR
;
763 m
->m_flags
&= ~M_AUTHIPDGM
;
765 } else if (ah
->ah_nxt
== IPPROTO_IPIP
) {
766 m
->m_flags
&= ~M_AUTHIPHDR
;
767 m
->m_flags
&= ~M_AUTHIPDGM
;
768 } else if (ah
->ah_nxt
== IPPROTO_IP
) {
769 m
->m_flags
&= ~M_AUTHIPHDR
;
770 m
->m_flags
&= ~M_AUTHIPDGM
;
774 if (m
->m_flags
& M_AUTHIPHDR
775 && m
->m_flags
& M_AUTHIPDGM
) {
778 "IPv6 AH input: authentication succeess\n"));
780 ipsec6stat
.in_ahauthsucc
++;
782 ipseclog((LOG_WARNING
,
783 "authentication failed in IPv6 AH input: %s %s\n",
784 ipsec6_logpacketstr(ip6
, spi
), ipsec_logsastr(sav
)));
785 ipsec6stat
.in_ahauthfail
++;
790 * update sequence number.
792 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0 && sav
->replay
) {
793 if (ipsec_updatereplay(ntohl(((struct newah
*)ah
)->ah_seq
), sav
)) {
794 ipsec6stat
.in_ahreplay
++;
799 /* was it transmitted over the IPsec tunnel SA? */
800 if (sav
->flags
& SADB_X_EXT_OLD
) {
802 stripsiz
= sizeof(struct ah
) + siz1
;
805 stripsiz
= sizeof(struct newah
) + siz1
;
807 if (ipsec6_tunnel_validate(m
, off
+ stripsiz
, nxt
, sav
)) {
809 * strip off all the headers that precedes AH.
810 * IP6 xx AH IP6' payload -> IP6' payload
812 * XXX more sanity checks
813 * XXX relationship with gif?
815 u_int32_t flowinfo
; /* net endian */
817 flowinfo
= ip6
->ip6_flow
;
818 m_adj(m
, off
+ stripsiz
);
819 if (m
->m_len
< sizeof(*ip6
)) {
821 * m_pullup is prohibited in KAME IPv6 input processing
822 * but there's no other way!
824 m
= m_pullup(m
, sizeof(*ip6
));
826 ipsec6stat
.in_inval
++;
830 ip6
= mtod(m
, struct ip6_hdr
*);
831 /* ECN consideration. */
832 ip6_ecn_egress(ip6_ipsec_ecn
, &flowinfo
, &ip6
->ip6_flow
);
833 if (!key_checktunnelsanity(sav
, AF_INET6
,
834 (caddr_t
)&ip6
->ip6_src
, (caddr_t
)&ip6
->ip6_dst
)) {
835 ipseclog((LOG_NOTICE
, "ipsec tunnel address mismatch "
836 "in IPv6 AH input: %s %s\n",
837 ipsec6_logpacketstr(ip6
, spi
),
838 ipsec_logsastr(sav
)));
839 ipsec6stat
.in_inval
++;
845 * should the inner packet be considered authentic?
846 * see comment in ah4_input().
848 m
->m_flags
&= ~M_AUTHIPHDR
;
849 m
->m_flags
&= ~M_AUTHIPDGM
;
852 key_sa_recordxfer(sav
, m
);
853 if (ipsec_addhist(m
, IPPROTO_AH
, spi
) != 0 ||
854 ipsec_addhist(m
, IPPROTO_IPV6
, 0) != 0) {
855 ipsec6stat
.in_nomem
++;
859 if (netisr_queue(NETISR_IPV6
, m
)) {
860 ipsec6stat
.in_inval
++;
873 * Copy the value of the next header field of AH to the
874 * next header field of the previous header.
875 * This is necessary because AH will be stripped off below.
877 prvnxtp
= ip6_get_prevhdr(m
, off
); /* XXX */
880 ip6
= mtod(m
, struct ip6_hdr
*);
881 #ifndef PULLDOWN_TEST
883 * We do deep-copy since KAME requires that
884 * the packet is placed in a single mbuf.
886 ovbcopy((caddr_t
)ip6
, ((caddr_t
)ip6
) + stripsiz
, off
);
887 m
->m_data
+= stripsiz
;
888 m
->m_len
-= stripsiz
;
889 m
->m_pkthdr
.len
-= stripsiz
;
892 * even in m_pulldown case, we need to strip off AH so that
893 * we can compute checksum for multiple AH correctly.
895 if (m
->m_len
>= stripsiz
+ off
) {
896 ovbcopy((caddr_t
)ip6
, ((caddr_t
)ip6
) + stripsiz
, off
);
897 m
->m_data
+= stripsiz
;
898 m
->m_len
-= stripsiz
;
899 m
->m_pkthdr
.len
-= stripsiz
;
902 * this comes with no copy if the boundary is on
907 n
= m_split(m
, off
, MB_DONTWAIT
);
909 /* m is retained by m_split */
913 /* m_cat does not update m_pkthdr.len */
914 m
->m_pkthdr
.len
+= n
->m_pkthdr
.len
;
918 ip6
= mtod(m
, struct ip6_hdr
*);
920 ip6
->ip6_plen
= htons(ntohs(ip6
->ip6_plen
) - stripsiz
);
922 key_sa_recordxfer(sav
, m
);
923 if (ipsec_addhist(m
, IPPROTO_AH
, spi
) != 0) {
924 ipsec6stat
.in_nomem
++;
933 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
934 kprintf("DP ah6_input call free SA:%p\n", sav
));
937 ipsec6stat
.in_success
++;
942 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
943 kprintf("DP ah6_input call free SA:%p\n", sav
));
952 ah6_ctlinput(int cmd
, struct sockaddr
*sa
, void *d
)
954 const struct newah
*ahp
;
956 struct secasvar
*sav
;
959 struct ip6ctlparam
*ip6cp
= NULL
;
961 struct sockaddr_in6
*sa6_src
, *sa6_dst
;
963 if (sa
->sa_family
!= AF_INET6
||
964 sa
->sa_len
!= sizeof(struct sockaddr_in6
))
966 if ((unsigned)cmd
>= PRC_NCMDS
)
969 /* if the parameter is from icmp6, decode it. */
971 ip6cp
= (struct ip6ctlparam
*)d
;
973 ip6
= ip6cp
->ip6c_ip6
;
974 off
= ip6cp
->ip6c_off
;
978 off
= 0; /* fix warning */
983 * XXX: We assume that when ip6 is non NULL,
984 * M and OFF are valid.
987 /* check if we can safely examine src and dst ports */
988 if (m
->m_pkthdr
.len
< off
+ sizeof(ah
))
991 if (m
->m_len
< off
+ sizeof(ah
)) {
993 * this should be rare case,
994 * so we compromise on this copy...
996 m_copydata(m
, off
, sizeof(ah
), (caddr_t
)&ah
);
999 ahp
= (struct newah
*)(mtod(m
, caddr_t
) + off
);
1001 if (cmd
== PRC_MSGSIZE
) {
1005 * Check to see if we have a valid SA corresponding to
1006 * the address in the ICMP message payload.
1008 sa6_src
= ip6cp
->ip6c_src
;
1009 sa6_dst
= (struct sockaddr_in6
*)sa
;
1010 sav
= key_allocsa(AF_INET6
,
1011 (caddr_t
)&sa6_src
->sin6_addr
,
1012 (caddr_t
)&sa6_dst
->sin6_addr
,
1013 IPPROTO_AH
, ahp
->ah_spi
);
1015 if (sav
->state
== SADB_SASTATE_MATURE
||
1016 sav
->state
== SADB_SASTATE_DYING
)
1021 /* XXX Further validation? */
1024 * Depending on the value of "valid" and routing table
1025 * size (mtudisc_{hi,lo}wat), we will:
1026 * - recalcurate the new MTU and create the
1027 * corresponding routing entry, or
1028 * - ignore the MTU change notification.
1030 icmp6_mtudisc_update((struct ip6ctlparam
*)d
, valid
);
1033 /* we normally notify single pcb here */
1035 /* we normally notify any pcb here */