]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/ah_input.c
2 * Copyright (c) 2008 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 /* $FreeBSD: src/sys/netinet6/ah_input.c,v 1.1.2.6 2002/04/28 05:40:26 suz Exp $ */
30 /* $KAME: ah_input.c,v 1.67 2002/01/07 11:39:56 kjc Exp $ */
33 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the project nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * RFC1826/2402 authentication header.
65 #include <sys/param.h>
66 #include <sys/systm.h>
67 #include <sys/malloc.h>
69 #include <sys/domain.h>
70 #include <sys/protosw.h>
71 #include <sys/socket.h>
72 #include <sys/errno.h>
74 #include <sys/kernel.h>
75 #include <sys/syslog.h>
78 #include <net/route.h>
79 #include <kern/cpu_number.h>
80 #include <kern/locks.h>
82 #include <netinet/in.h>
83 #include <netinet/in_systm.h>
84 #include <netinet/in_var.h>
85 #include <netinet/ip.h>
86 #include <netinet/ip_var.h>
87 #include <netinet/ip_ecn.h>
88 #include <netinet/in_pcb.h>
90 #include <netinet6/ip6_ecn.h>
94 #include <netinet/ip6.h>
95 #include <netinet6/ip6_var.h>
96 #include <netinet6/in6_pcb.h>
97 #include <netinet/icmp6.h>
98 #include <netinet6/ip6protosw.h>
101 #include <netinet6/ipsec.h>
103 #include <netinet6/ipsec6.h>
105 #include <netinet6/ah.h>
107 #include <netinet6/ah6.h>
109 #include <netkey/key.h>
110 #include <netkey/keydb.h>
112 #include <netkey/key_debug.h>
114 #define KEYDEBUG(lev,arg)
117 #include <net/kpi_protocol.h>
118 #include <netinet/kpi_ipfilter_var.h>
120 #include <net/net_osdep.h>
122 #define IPLEN_FLIPPED
125 extern struct protosw inetsw
[];
128 ah4_input(struct mbuf
*m
, int off
)
133 const struct ah_algorithm
*algo
;
137 struct secasvar
*sav
= NULL
;
143 #ifndef PULLDOWN_TEST
144 if (m
->m_len
< off
+ sizeof(struct newah
)) {
145 m
= m_pullup(m
, off
+ sizeof(struct newah
));
147 ipseclog((LOG_DEBUG
, "IPv4 AH input: can't pullup;"
148 "dropping the packet for simplicity\n"));
149 IPSEC_STAT_INCREMENT(ipsecstat
.in_inval
);
154 ip
= mtod(m
, struct ip
*);
155 ah
= (struct ah
*)(((caddr_t
)ip
) + off
);
157 ip
= mtod(m
, struct ip
*);
158 IP6_EXTHDR_GET(ah
, struct ah
*, m
, off
, sizeof(struct newah
));
160 ipseclog((LOG_DEBUG
, "IPv4 AH input: can't pullup;"
161 "dropping the packet for simplicity\n"));
162 IPSEC_STAT_INCREMENT(ipsecstat
.in_inval
);
168 hlen
= IP_VHL_HL(ip
->ip_vhl
) << 2;
170 hlen
= ip
->ip_hl
<< 2;
173 /* find the sassoc. */
176 if ((sav
= key_allocsa(AF_INET
,
177 (caddr_t
)&ip
->ip_src
, (caddr_t
)&ip
->ip_dst
,
178 IPPROTO_AH
, spi
)) == 0) {
179 ipseclog((LOG_WARNING
,
180 "IPv4 AH input: no key association found for spi %u\n",
181 (u_int32_t
)ntohl(spi
)));
182 IPSEC_STAT_INCREMENT(ipsecstat
.in_nosa
);
185 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
186 printf("DP ah4_input called to allocate SA:%p\n", sav
));
187 if (sav
->state
!= SADB_SASTATE_MATURE
188 && sav
->state
!= SADB_SASTATE_DYING
) {
190 "IPv4 AH input: non-mature/dying SA found for spi %u\n",
191 (u_int32_t
)ntohl(spi
)));
192 IPSEC_STAT_INCREMENT(ipsecstat
.in_badspi
);
196 algo
= ah_algorithm_lookup(sav
->alg_auth
);
198 ipseclog((LOG_DEBUG
, "IPv4 AH input: "
199 "unsupported authentication algorithm for spi %u\n",
200 (u_int32_t
)ntohl(spi
)));
201 IPSEC_STAT_INCREMENT(ipsecstat
.in_badspi
);
205 siz
= (*algo
->sumsiz
)(sav
);
206 siz1
= ((siz
+ 3) & ~(4 - 1));
209 * sanity checks for header, 1.
214 sizoff
= (sav
->flags
& SADB_X_EXT_OLD
) ? 0 : 4;
217 * Here, we do not do "siz1 == siz". This is because the way
218 * RFC240[34] section 2 is written. They do not require truncation
220 * For example, Microsoft IPsec stack attaches 160 bits of
221 * authentication data for both hmac-md5 and hmac-sha1. For hmac-sha1,
222 * 32 bits of padding is attached.
224 * There are two downsides to this specification.
225 * They have no real harm, however, they leave us fuzzy feeling.
226 * - if we attach more than 96 bits of authentication data onto AH,
227 * we will never notice about possible modification by rogue
228 * intermediate nodes.
229 * Since extra bits in AH checksum is never used, this constitutes
230 * no real issue, however, it is wacky.
231 * - even if the peer attaches big authentication data, we will never
232 * notice the difference, since longer authentication data will just
235 * We may need some clarification in the spec.
238 ipseclog((LOG_NOTICE
, "sum length too short in IPv4 AH input "
239 "(%lu, should be at least %lu): %s\n",
240 (u_int32_t
)siz1
, (u_int32_t
)siz
,
241 ipsec4_logpacketstr(ip
, spi
)));
242 IPSEC_STAT_INCREMENT(ipsecstat
.in_inval
);
245 if ((ah
->ah_len
<< 2) - sizoff
!= siz1
) {
246 ipseclog((LOG_NOTICE
, "sum length mismatch in IPv4 AH input "
247 "(%d should be %lu): %s\n",
248 (ah
->ah_len
<< 2) - sizoff
, (u_int32_t
)siz1
,
249 ipsec4_logpacketstr(ip
, spi
)));
250 IPSEC_STAT_INCREMENT(ipsecstat
.in_inval
);
254 #ifndef PULLDOWN_TEST
255 if (m
->m_len
< off
+ sizeof(struct ah
) + sizoff
+ siz1
) {
256 m
= m_pullup(m
, off
+ sizeof(struct ah
) + sizoff
+ siz1
);
258 ipseclog((LOG_DEBUG
, "IPv4 AH input: can't pullup\n"));
259 IPSEC_STAT_INCREMENT(ipsecstat
.in_inval
);
263 ip
= mtod(m
, struct ip
*);
264 ah
= (struct ah
*)(((caddr_t
)ip
) + off
);
267 IP6_EXTHDR_GET(ah
, struct ah
*, m
, off
,
268 sizeof(struct ah
) + sizoff
+ siz1
);
270 ipseclog((LOG_DEBUG
, "IPv4 AH input: can't pullup\n"));
271 IPSEC_STAT_INCREMENT(ipsecstat
.in_inval
);
278 * check for sequence number.
280 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0 && sav
->replay
) {
281 if (ipsec_chkreplay(ntohl(((struct newah
*)ah
)->ah_seq
), sav
))
284 IPSEC_STAT_INCREMENT(ipsecstat
.in_ahreplay
);
285 ipseclog((LOG_WARNING
,
286 "replay packet in IPv4 AH input: %s %s\n",
287 ipsec4_logpacketstr(ip
, spi
), ipsec_logsastr(sav
)));
293 * alright, it seems sane. now we are going to check the
294 * cryptographic checksum.
296 cksum
= _MALLOC(siz1
, M_TEMP
, M_NOWAIT
);
298 ipseclog((LOG_DEBUG
, "IPv4 AH input: "
299 "couldn't alloc temporary region for cksum\n"));
300 IPSEC_STAT_INCREMENT(ipsecstat
.in_inval
);
305 * some of IP header fields are flipped to the host endian.
306 * convert them back to network endian. VERY stupid.
308 ip
->ip_len
= htons(ip
->ip_len
+ hlen
);
309 ip
->ip_off
= htons(ip
->ip_off
);
310 if (ah4_calccksum(m
, (caddr_t
)cksum
, siz1
, algo
, sav
)) {
312 IPSEC_STAT_INCREMENT(ipsecstat
.in_inval
);
315 IPSEC_STAT_INCREMENT(ipsecstat
.in_ahhist
[sav
->alg_auth
]);
319 ip
->ip_len
= ntohs(ip
->ip_len
) - hlen
;
320 ip
->ip_off
= ntohs(ip
->ip_off
);
323 caddr_t sumpos
= NULL
;
325 if (sav
->flags
& SADB_X_EXT_OLD
) {
327 sumpos
= (caddr_t
)(ah
+ 1);
330 sumpos
= (caddr_t
)(((struct newah
*)ah
) + 1);
333 if (bcmp(sumpos
, cksum
, siz
) != 0) {
334 ipseclog((LOG_WARNING
,
335 "checksum mismatch in IPv4 AH input: %s %s\n",
336 ipsec4_logpacketstr(ip
, spi
), ipsec_logsastr(sav
)));
338 IPSEC_STAT_INCREMENT(ipsecstat
.in_ahauthfail
);
345 m
->m_flags
|= M_AUTHIPHDR
;
346 m
->m_flags
|= M_AUTHIPDGM
;
350 * looks okey, but we need more sanity check.
351 * XXX should elaborate.
353 if (ah
->ah_nxt
== IPPROTO_IPIP
|| ah
->ah_nxt
== IPPROTO_IP
) {
357 sizoff
= (sav
->flags
& SADB_X_EXT_OLD
) ? 0 : 4;
359 if (m
->m_len
< off
+ sizeof(struct ah
) + sizoff
+ siz1
+ hlen
) {
360 m
= m_pullup(m
, off
+ sizeof(struct ah
)
361 + sizoff
+ siz1
+ hlen
);
364 "IPv4 AH input: can't pullup\n"));
365 IPSEC_STAT_INCREMENT(ipsecstat
.in_inval
);
370 nip
= (struct ip
*)((u_char
*)(ah
+ 1) + sizoff
+ siz1
);
371 if (nip
->ip_src
.s_addr
!= ip
->ip_src
.s_addr
372 || nip
->ip_dst
.s_addr
!= ip
->ip_dst
.s_addr
) {
373 m
->m_flags
&= ~M_AUTHIPHDR
;
374 m
->m_flags
&= ~M_AUTHIPDGM
;
378 else if (ah
->ah_nxt
== IPPROTO_IPV6
) {
379 m
->m_flags
&= ~M_AUTHIPHDR
;
380 m
->m_flags
&= ~M_AUTHIPDGM
;
385 if (m
->m_flags
& M_AUTHIPHDR
386 && m
->m_flags
& M_AUTHIPDGM
) {
389 "IPv4 AH input: authentication succeess\n"));
391 IPSEC_STAT_INCREMENT(ipsecstat
.in_ahauthsucc
);
393 ipseclog((LOG_WARNING
,
394 "authentication failed in IPv4 AH input: %s %s\n",
395 ipsec4_logpacketstr(ip
, spi
), ipsec_logsastr(sav
)));
396 IPSEC_STAT_INCREMENT(ipsecstat
.in_ahauthfail
);
401 * update sequence number.
403 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0 && sav
->replay
) {
404 if (ipsec_updatereplay(ntohl(((struct newah
*)ah
)->ah_seq
), sav
)) {
405 IPSEC_STAT_INCREMENT(ipsecstat
.in_ahreplay
);
410 /* was it transmitted over the IPsec tunnel SA? */
411 if (sav
->flags
& SADB_X_EXT_OLD
) {
413 stripsiz
= sizeof(struct ah
) + siz1
;
416 stripsiz
= sizeof(struct newah
) + siz1
;
418 if (ipsec4_tunnel_validate(m
, off
+ stripsiz
, nxt
, sav
, &ifamily
)) {
420 * strip off all the headers that precedes AH.
421 * IP xx AH IP' payload -> IP' payload
423 * XXX more sanity checks
424 * XXX relationship with gif?
428 if (ifamily
== AF_INET6
) {
429 ipseclog((LOG_NOTICE
, "ipsec tunnel protocol mismatch "
430 "in IPv4 AH input: %s\n", ipsec_logsastr(sav
)));
434 m_adj(m
, off
+ stripsiz
);
435 if (m
->m_len
< sizeof(*ip
)) {
436 m
= m_pullup(m
, sizeof(*ip
));
438 IPSEC_STAT_INCREMENT(ipsecstat
.in_inval
);
442 ip
= mtod(m
, struct ip
*);
443 /* ECN consideration. */
444 ip_ecn_egress(ip4_ipsec_ecn
, &tos
, &ip
->ip_tos
);
445 if (!key_checktunnelsanity(sav
, AF_INET
,
446 (caddr_t
)&ip
->ip_src
, (caddr_t
)&ip
->ip_dst
)) {
447 ipseclog((LOG_NOTICE
, "ipsec tunnel address mismatch "
448 "in IPv4 AH input: %s %s\n",
449 ipsec4_logpacketstr(ip
, spi
), ipsec_logsastr(sav
)));
450 IPSEC_STAT_INCREMENT(ipsecstat
.in_inval
);
456 * Should the inner packet be considered authentic?
457 * My current answer is: NO.
459 * host1 -- gw1 === gw2 -- host2
460 * In this case, gw2 can trust the authenticity of the
461 * outer packet, but NOT inner. Packet may be altered
462 * between host1 and gw1.
464 * host1 -- gw1 === host2
465 * This case falls into the same scenario as above.
468 * This case is the only case when we may be able to leave
469 * M_AUTHIPHDR and M_AUTHIPDGM set.
470 * However, if host1 is wrongly configured, and allows
471 * attacker to inject some packet with src=host1 and
472 * dst=host2, you are in risk.
474 m
->m_flags
&= ~M_AUTHIPHDR
;
475 m
->m_flags
&= ~M_AUTHIPDGM
;
478 key_sa_recordxfer(sav
, m
);
479 if (ipsec_addhist(m
, IPPROTO_AH
, spi
) != 0 ||
480 ipsec_addhist(m
, IPPROTO_IPV4
, 0) != 0) {
481 IPSEC_STAT_INCREMENT(ipsecstat
.in_nomem
);
484 proto_input(PF_INET
, m
);
491 ip
= mtod(m
, struct ip
*);
492 #ifndef PULLDOWN_TEST
494 * We do deep-copy since KAME requires that
495 * the packet is placed in a single external mbuf.
497 ovbcopy((caddr_t
)ip
, (caddr_t
)(((u_char
*)ip
) + stripsiz
), off
);
498 m
->m_data
+= stripsiz
;
499 m
->m_len
-= stripsiz
;
500 m
->m_pkthdr
.len
-= stripsiz
;
503 * even in m_pulldown case, we need to strip off AH so that
504 * we can compute checksum for multiple AH correctly.
506 if (m
->m_len
>= stripsiz
+ off
) {
507 ovbcopy((caddr_t
)ip
, ((caddr_t
)ip
) + stripsiz
, off
);
508 m
->m_data
+= stripsiz
;
509 m
->m_len
-= stripsiz
;
510 m
->m_pkthdr
.len
-= stripsiz
;
513 * this comes with no copy if the boundary is on
518 n
= m_split(m
, off
, M_DONTWAIT
);
520 /* m is retained by m_split */
524 /* m_cat does not update m_pkthdr.len */
525 m
->m_pkthdr
.len
+= n
->m_pkthdr
.len
;
530 if (m
->m_len
< sizeof(*ip
)) {
531 m
= m_pullup(m
, sizeof(*ip
));
533 IPSEC_STAT_INCREMENT(ipsecstat
.in_inval
);
537 ip
= mtod(m
, struct ip
*);
539 ip
->ip_len
= ip
->ip_len
- stripsiz
;
541 ip
->ip_len
= htons(ntohs(ip
->ip_len
) - stripsiz
);
544 /* forget about IP hdr checksum, the check has already been passed */
546 key_sa_recordxfer(sav
, m
);
547 if (ipsec_addhist(m
, IPPROTO_AH
, spi
) != 0) {
548 IPSEC_STAT_INCREMENT(ipsecstat
.in_nomem
);
552 if (nxt
!= IPPROTO_DONE
) {
553 if ((ip_protox
[nxt
]->pr_flags
& PR_LASTHDR
) != 0 &&
554 ipsec4_in_reject(m
, NULL
)) {
555 IPSEC_STAT_INCREMENT(ipsecstat
.in_polvio
);
558 ip_proto_dispatch_in(m
, off
, nxt
, 0);
565 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
566 printf("DP ah4_input call free SA:%p\n", sav
));
567 key_freesav(sav
, KEY_SADB_UNLOCKED
);
569 IPSEC_STAT_INCREMENT(ipsecstat
.in_success
);
574 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
575 printf("DP ah4_input call free SA:%p\n", sav
));
576 key_freesav(sav
, KEY_SADB_UNLOCKED
);
590 struct mbuf
*m
= *mp
;
595 const struct ah_algorithm
*algo
;
599 struct secasvar
*sav
= NULL
;
604 #ifndef PULLDOWN_TEST
605 IP6_EXTHDR_CHECK(m
, off
, sizeof(struct ah
), {return IPPROTO_DONE
;});
606 ah
= (struct ah
*)(mtod(m
, caddr_t
) + off
);
608 IP6_EXTHDR_GET(ah
, struct ah
*, m
, off
, sizeof(struct newah
));
610 ipseclog((LOG_DEBUG
, "IPv6 AH input: can't pullup\n"));
611 ipsec6stat
.in_inval
++;
615 ip6
= mtod(m
, struct ip6_hdr
*);
618 /* find the sassoc. */
621 if (ntohs(ip6
->ip6_plen
) == 0) {
622 ipseclog((LOG_ERR
, "IPv6 AH input: "
623 "AH with IPv6 jumbogram is not supported.\n"));
624 IPSEC_STAT_INCREMENT(ipsec6stat
.in_inval
);
628 if ((sav
= key_allocsa(AF_INET6
,
629 (caddr_t
)&ip6
->ip6_src
, (caddr_t
)&ip6
->ip6_dst
,
630 IPPROTO_AH
, spi
)) == 0) {
631 ipseclog((LOG_WARNING
,
632 "IPv6 AH input: no key association found for spi %u\n",
633 (u_int32_t
)ntohl(spi
)));
634 IPSEC_STAT_INCREMENT(ipsec6stat
.in_nosa
);
637 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
638 printf("DP ah6_input called to allocate SA:%p\n", sav
));
639 if (sav
->state
!= SADB_SASTATE_MATURE
640 && sav
->state
!= SADB_SASTATE_DYING
) {
642 "IPv6 AH input: non-mature/dying SA found for spi %u; ",
643 (u_int32_t
)ntohl(spi
)));
644 IPSEC_STAT_INCREMENT(ipsec6stat
.in_badspi
);
648 algo
= ah_algorithm_lookup(sav
->alg_auth
);
650 ipseclog((LOG_DEBUG
, "IPv6 AH input: "
651 "unsupported authentication algorithm for spi %u\n",
652 (u_int32_t
)ntohl(spi
)));
653 IPSEC_STAT_INCREMENT(ipsec6stat
.in_badspi
);
657 siz
= (*algo
->sumsiz
)(sav
);
658 siz1
= ((siz
+ 3) & ~(4 - 1));
661 * sanity checks for header, 1.
666 sizoff
= (sav
->flags
& SADB_X_EXT_OLD
) ? 0 : 4;
669 * Here, we do not do "siz1 == siz". See ah4_input() for complete
673 ipseclog((LOG_NOTICE
, "sum length too short in IPv6 AH input "
674 "(%lu, should be at least %lu): %s\n",
675 (u_int32_t
)siz1
, (u_int32_t
)siz
,
676 ipsec6_logpacketstr(ip6
, spi
)));
677 IPSEC_STAT_INCREMENT(ipsec6stat
.in_inval
);
680 if ((ah
->ah_len
<< 2) - sizoff
!= siz1
) {
681 ipseclog((LOG_NOTICE
, "sum length mismatch in IPv6 AH input "
682 "(%d should be %lu): %s\n",
683 (ah
->ah_len
<< 2) - sizoff
, (u_int32_t
)siz1
,
684 ipsec6_logpacketstr(ip6
, spi
)));
685 IPSEC_STAT_INCREMENT(ipsec6stat
.in_inval
);
688 #ifndef PULLDOWN_TEST
689 IP6_EXTHDR_CHECK(m
, off
, sizeof(struct ah
) + sizoff
+ siz1
,
690 {return IPPROTO_DONE
;});
692 IP6_EXTHDR_GET(ah
, struct ah
*, m
, off
,
693 sizeof(struct ah
) + sizoff
+ siz1
);
695 ipseclog((LOG_NOTICE
, "couldn't pullup gather IPv6 AH checksum part"));
696 IPSEC_STAT_INCREMENT(ipsec6stat
.in_inval
);
704 * check for sequence number.
706 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0 && sav
->replay
) {
707 if (ipsec_chkreplay(ntohl(((struct newah
*)ah
)->ah_seq
), sav
))
710 IPSEC_STAT_INCREMENT(ipsec6stat
.in_ahreplay
);
711 ipseclog((LOG_WARNING
,
712 "replay packet in IPv6 AH input: %s %s\n",
713 ipsec6_logpacketstr(ip6
, spi
),
714 ipsec_logsastr(sav
)));
720 * alright, it seems sane. now we are going to check the
721 * cryptographic checksum.
723 cksum
= _MALLOC(siz1
, M_TEMP
, M_NOWAIT
);
725 ipseclog((LOG_DEBUG
, "IPv6 AH input: "
726 "couldn't alloc temporary region for cksum\n"));
727 IPSEC_STAT_INCREMENT(ipsec6stat
.in_inval
);
731 if (ah6_calccksum(m
, (caddr_t
)cksum
, siz1
, algo
, sav
)) {
733 IPSEC_STAT_INCREMENT(ipsec6stat
.in_inval
);
736 IPSEC_STAT_INCREMENT(ipsec6stat
.in_ahhist
[sav
->alg_auth
]);
739 caddr_t sumpos
= NULL
;
741 if (sav
->flags
& SADB_X_EXT_OLD
) {
743 sumpos
= (caddr_t
)(ah
+ 1);
746 sumpos
= (caddr_t
)(((struct newah
*)ah
) + 1);
749 if (bcmp(sumpos
, cksum
, siz
) != 0) {
750 ipseclog((LOG_WARNING
,
751 "checksum mismatch in IPv6 AH input: %s %s\n",
752 ipsec6_logpacketstr(ip6
, spi
), ipsec_logsastr(sav
)));
754 IPSEC_STAT_INCREMENT(ipsec6stat
.in_ahauthfail
);
761 m
->m_flags
|= M_AUTHIPHDR
;
762 m
->m_flags
|= M_AUTHIPDGM
;
766 * looks okey, but we need more sanity check.
767 * XXX should elaborate.
769 if (ah
->ah_nxt
== IPPROTO_IPV6
) {
770 struct ip6_hdr
*nip6
;
773 sizoff
= (sav
->flags
& SADB_X_EXT_OLD
) ? 0 : 4;
775 IP6_EXTHDR_CHECK(m
, off
, sizeof(struct ah
) + sizoff
+ siz1
776 + sizeof(struct ip6_hdr
),
777 {return IPPROTO_DONE
;});
779 nip6
= (struct ip6_hdr
*)((u_char
*)(ah
+ 1) + sizoff
+ siz1
);
780 if (!IN6_ARE_ADDR_EQUAL(&nip6
->ip6_src
, &ip6
->ip6_src
)
781 || !IN6_ARE_ADDR_EQUAL(&nip6
->ip6_dst
, &ip6
->ip6_dst
)) {
782 m
->m_flags
&= ~M_AUTHIPHDR
;
783 m
->m_flags
&= ~M_AUTHIPDGM
;
785 } else if (ah
->ah_nxt
== IPPROTO_IPIP
) {
786 m
->m_flags
&= ~M_AUTHIPHDR
;
787 m
->m_flags
&= ~M_AUTHIPDGM
;
788 } else if (ah
->ah_nxt
== IPPROTO_IP
) {
789 m
->m_flags
&= ~M_AUTHIPHDR
;
790 m
->m_flags
&= ~M_AUTHIPDGM
;
794 if (m
->m_flags
& M_AUTHIPHDR
795 && m
->m_flags
& M_AUTHIPDGM
) {
798 "IPv6 AH input: authentication succeess\n"));
800 IPSEC_STAT_INCREMENT(ipsec6stat
.in_ahauthsucc
);
802 ipseclog((LOG_WARNING
,
803 "authentication failed in IPv6 AH input: %s %s\n",
804 ipsec6_logpacketstr(ip6
, spi
), ipsec_logsastr(sav
)));
805 IPSEC_STAT_INCREMENT(ipsec6stat
.in_ahauthfail
);
810 * update sequence number.
812 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0 && sav
->replay
) {
813 if (ipsec_updatereplay(ntohl(((struct newah
*)ah
)->ah_seq
), sav
)) {
814 IPSEC_STAT_INCREMENT(ipsec6stat
.in_ahreplay
);
819 /* was it transmitted over the IPsec tunnel SA? */
820 if (sav
->flags
& SADB_X_EXT_OLD
) {
822 stripsiz
= sizeof(struct ah
) + siz1
;
825 stripsiz
= sizeof(struct newah
) + siz1
;
827 if (ipsec6_tunnel_validate(m
, off
+ stripsiz
, nxt
, sav
)) {
829 * strip off all the headers that precedes AH.
830 * IP6 xx AH IP6' payload -> IP6' payload
832 * XXX more sanity checks
833 * XXX relationship with gif?
835 u_int32_t flowinfo
; /*net endian*/
837 flowinfo
= ip6
->ip6_flow
;
838 m_adj(m
, off
+ stripsiz
);
839 if (m
->m_len
< sizeof(*ip6
)) {
841 * m_pullup is prohibited in KAME IPv6 input processing
842 * but there's no other way!
844 m
= m_pullup(m
, sizeof(*ip6
));
846 IPSEC_STAT_INCREMENT(ipsec6stat
.in_inval
);
850 ip6
= mtod(m
, struct ip6_hdr
*);
851 /* ECN consideration. */
852 ip6_ecn_egress(ip6_ipsec_ecn
, &flowinfo
, &ip6
->ip6_flow
);
853 if (!key_checktunnelsanity(sav
, AF_INET6
,
854 (caddr_t
)&ip6
->ip6_src
, (caddr_t
)&ip6
->ip6_dst
)) {
855 ipseclog((LOG_NOTICE
, "ipsec tunnel address mismatch "
856 "in IPv6 AH input: %s %s\n",
857 ipsec6_logpacketstr(ip6
, spi
),
858 ipsec_logsastr(sav
)));
859 IPSEC_STAT_INCREMENT(ipsec6stat
.in_inval
);
865 * should the inner packet be considered authentic?
866 * see comment in ah4_input().
868 m
->m_flags
&= ~M_AUTHIPHDR
;
869 m
->m_flags
&= ~M_AUTHIPDGM
;
872 key_sa_recordxfer(sav
, m
);
873 if (ipsec_addhist(m
, IPPROTO_AH
, spi
) != 0 ||
874 ipsec_addhist(m
, IPPROTO_IPV6
, 0) != 0) {
875 IPSEC_STAT_INCREMENT(ipsec6stat
.in_nomem
);
878 proto_input(PF_INET6
, m
);
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 */
927 /* m_cat does not update m_pkthdr.len */
928 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 IPSEC_STAT_INCREMENT(ipsec6stat
.in_nomem
);
947 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
948 printf("DP ah6_input call free SA:%p\n", sav
));
949 key_freesav(sav
, KEY_SADB_UNLOCKED
);
951 IPSEC_STAT_INCREMENT(ipsec6stat
.in_success
);
956 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
957 printf("DP ah6_input call free SA:%p\n", sav
));
958 key_freesav(sav
, KEY_SADB_UNLOCKED
);
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
)
1034 key_freesav(sav
, KEY_SADB_UNLOCKED
);
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 */