]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/ah_input.c
1 /* $FreeBSD: src/sys/netinet6/ah_input.c,v 1.1.2.4 2001/07/03 11:01:49 ume Exp $ */
2 /* $KAME: ah_input.c,v 1.59 2001/05/16 04:01:27 jinmei Exp $ */
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * RFC1826/2402 authentication header.
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/malloc.h>
41 #include <sys/domain.h>
42 #include <sys/protosw.h>
43 #include <sys/socket.h>
44 #include <sys/errno.h>
46 #include <sys/kernel.h>
47 #include <sys/syslog.h>
50 #include <net/route.h>
51 #include <net/netisr.h>
52 #include <kern/cpu_number.h>
54 #include <netinet/in.h>
55 #include <netinet/in_systm.h>
56 #include <netinet/in_var.h>
57 #include <netinet/ip.h>
58 #include <netinet/ip_var.h>
59 #include <netinet/ip_ecn.h>
60 #include <netinet/in_pcb.h>
62 #include <netinet6/ip6_ecn.h>
66 #include <netinet/ip6.h>
67 #include <netinet6/ip6_var.h>
68 #include <netinet6/in6_pcb.h>
69 #include <netinet/icmp6.h>
70 #include <netinet6/ip6protosw.h>
73 #include <netinet6/ipsec.h>
75 #include <netinet6/ipsec6.h>
77 #include <netinet6/ah.h>
79 #include <netinet6/ah6.h>
81 #include <netkey/key.h>
82 #include <netkey/keydb.h>
84 #include <netkey/key_debug.h>
86 #define KEYDEBUG(lev,arg)
90 #include <net/net_osdep.h>
95 extern struct protosw inetsw
[];
98 ah4_input(struct mbuf
*m
, int off
)
103 const struct ah_algorithm
*algo
;
107 struct secasvar
*sav
= NULL
;
114 #ifndef PULLDOWN_TEST
115 if (m
->m_len
< off
+ sizeof(struct newah
)) {
116 m
= m_pullup(m
, off
+ sizeof(struct newah
));
118 ipseclog((LOG_DEBUG
, "IPv4 AH input: can't pullup;"
119 "dropping the packet for simplicity\n"));
120 ipsecstat
.in_inval
++;
125 ip
= mtod(m
, struct ip
*);
126 ah
= (struct ah
*)(((caddr_t
)ip
) + off
);
128 ip
= mtod(m
, struct ip
*);
129 IP6_EXTHDR_GET(ah
, struct ah
*, m
, off
, sizeof(struct newah
));
131 ipseclog((LOG_DEBUG
, "IPv4 AH input: can't pullup;"
132 "dropping the packet for simplicity\n"));
133 ipsecstat
.in_inval
++;
139 hlen
= IP_VHL_HL(ip
->ip_vhl
) << 2;
141 hlen
= ip
->ip_hl
<< 2;
144 /* find the sassoc. */
147 if ((sav
= key_allocsa(AF_INET
,
148 (caddr_t
)&ip
->ip_src
, (caddr_t
)&ip
->ip_dst
,
149 IPPROTO_AH
, spi
)) == 0) {
150 ipseclog((LOG_WARNING
,
151 "IPv4 AH input: no key association found for spi %u\n",
152 (u_int32_t
)ntohl(spi
)));
156 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
157 printf("DP ah4_input called to allocate SA:%p\n", sav
));
158 if (sav
->state
!= SADB_SASTATE_MATURE
159 && sav
->state
!= SADB_SASTATE_DYING
) {
161 "IPv4 AH input: non-mature/dying SA found for spi %u\n",
162 (u_int32_t
)ntohl(spi
)));
163 ipsecstat
.in_badspi
++;
167 algo
= ah_algorithm_lookup(sav
->alg_auth
);
169 ipseclog((LOG_DEBUG
, "IPv4 AH input: "
170 "unsupported authentication algorithm for spi %u\n",
171 (u_int32_t
)ntohl(spi
)));
172 ipsecstat
.in_badspi
++;
176 siz
= (*algo
->sumsiz
)(sav
);
177 siz1
= ((siz
+ 3) & ~(4 - 1));
180 * sanity checks for header, 1.
185 sizoff
= (sav
->flags
& SADB_X_EXT_OLD
) ? 0 : 4;
188 * Here, we do not do "siz1 == siz". This is because the way
189 * RFC240[34] section 2 is written. They do not require truncation
191 * For example, Microsoft IPsec stack attaches 160 bits of
192 * authentication data for both hmac-md5 and hmac-sha1. For hmac-sha1,
193 * 32 bits of padding is attached.
195 * There are two downsides to this specification.
196 * They have no real harm, however, they leave us fuzzy feeling.
197 * - if we attach more than 96 bits of authentication data onto AH,
198 * we will never notice about possible modification by rogue
199 * intermediate nodes.
200 * Since extra bits in AH checksum is never used, this constitutes
201 * no real issue, however, it is wacky.
202 * - even if the peer attaches big authentication data, we will never
203 * notice the difference, since longer authentication data will just
206 * We may need some clarification in the spec.
209 ipseclog((LOG_NOTICE
, "sum length too short in IPv4 AH input "
210 "(%lu, should be at least %lu): %s\n",
211 (u_long
)siz1
, (u_long
)siz
,
212 ipsec4_logpacketstr(ip
, spi
)));
213 ipsecstat
.in_inval
++;
216 if ((ah
->ah_len
<< 2) - sizoff
!= siz1
) {
217 ipseclog((LOG_NOTICE
, "sum length mismatch in IPv4 AH input "
218 "(%d should be %lu): %s\n",
219 (ah
->ah_len
<< 2) - sizoff
, (u_long
)siz1
,
220 ipsec4_logpacketstr(ip
, spi
)));
221 ipsecstat
.in_inval
++;
225 #ifndef PULLDOWN_TEST
226 if (m
->m_len
< off
+ sizeof(struct ah
) + sizoff
+ siz1
) {
227 m
= m_pullup(m
, off
+ sizeof(struct ah
) + sizoff
+ siz1
);
229 ipseclog((LOG_DEBUG
, "IPv4 AH input: can't pullup\n"));
230 ipsecstat
.in_inval
++;
234 ip
= mtod(m
, struct ip
*);
235 ah
= (struct ah
*)(((caddr_t
)ip
) + off
);
238 IP6_EXTHDR_GET(ah
, struct ah
*, m
, off
,
239 sizeof(struct ah
) + sizoff
+ siz1
);
241 ipseclog((LOG_DEBUG
, "IPv4 AH input: can't pullup\n"));
242 ipsecstat
.in_inval
++;
249 * check for sequence number.
251 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0 && sav
->replay
) {
252 if (ipsec_chkreplay(ntohl(((struct newah
*)ah
)->ah_seq
), sav
))
255 ipsecstat
.in_ahreplay
++;
256 ipseclog((LOG_WARNING
,
257 "replay packet in IPv4 AH input: %s %s\n",
258 ipsec4_logpacketstr(ip
, spi
), ipsec_logsastr(sav
)));
264 * alright, it seems sane. now we are going to check the
265 * cryptographic checksum.
267 cksum
= _MALLOC(siz1
, M_TEMP
, M_NOWAIT
);
269 ipseclog((LOG_DEBUG
, "IPv4 AH input: "
270 "couldn't alloc temporary region for cksum\n"));
271 ipsecstat
.in_inval
++;
276 * some of IP header fields are flipped to the host endian.
277 * convert them back to network endian. VERY stupid.
279 ip
->ip_len
= htons(ip
->ip_len
+ hlen
);
280 ip
->ip_off
= htons(ip
->ip_off
);
281 if (ah4_calccksum(m
, (caddr_t
)cksum
, siz1
, algo
, sav
)) {
283 ipsecstat
.in_inval
++;
286 ipsecstat
.in_ahhist
[sav
->alg_auth
]++;
290 ip
->ip_len
= ntohs(ip
->ip_len
) - hlen
;
291 ip
->ip_off
= ntohs(ip
->ip_off
);
294 caddr_t sumpos
= NULL
;
296 if (sav
->flags
& SADB_X_EXT_OLD
) {
298 sumpos
= (caddr_t
)(ah
+ 1);
301 sumpos
= (caddr_t
)(((struct newah
*)ah
) + 1);
304 if (bcmp(sumpos
, cksum
, siz
) != 0) {
305 ipseclog((LOG_WARNING
,
306 "checksum mismatch in IPv4 AH input: %s %s\n",
307 ipsec4_logpacketstr(ip
, spi
), ipsec_logsastr(sav
)));
309 ipsecstat
.in_ahauthfail
++;
316 m
->m_flags
|= M_AUTHIPHDR
;
317 m
->m_flags
|= M_AUTHIPDGM
;
321 * looks okey, but we need more sanity check.
322 * XXX should elaborate.
324 if (ah
->ah_nxt
== IPPROTO_IPIP
|| ah
->ah_nxt
== IPPROTO_IP
) {
328 sizoff
= (sav
->flags
& SADB_X_EXT_OLD
) ? 0 : 4;
330 if (m
->m_len
< off
+ sizeof(struct ah
) + sizoff
+ siz1
+ hlen
) {
331 m
= m_pullup(m
, off
+ sizeof(struct ah
)
332 + sizoff
+ siz1
+ hlen
);
335 "IPv4 AH input: can't pullup\n"));
336 ipsecstat
.in_inval
++;
341 nip
= (struct ip
*)((u_char
*)(ah
+ 1) + sizoff
+ siz1
);
342 if (nip
->ip_src
.s_addr
!= ip
->ip_src
.s_addr
343 || nip
->ip_dst
.s_addr
!= ip
->ip_dst
.s_addr
) {
344 m
->m_flags
&= ~M_AUTHIPHDR
;
345 m
->m_flags
&= ~M_AUTHIPDGM
;
349 else if (ah
->ah_nxt
== IPPROTO_IPV6
) {
350 m
->m_flags
&= ~M_AUTHIPHDR
;
351 m
->m_flags
&= ~M_AUTHIPDGM
;
356 if (m
->m_flags
& M_AUTHIPHDR
357 && m
->m_flags
& M_AUTHIPDGM
) {
360 "IPv4 AH input: authentication succeess\n"));
362 ipsecstat
.in_ahauthsucc
++;
364 ipseclog((LOG_WARNING
,
365 "authentication failed in IPv4 AH input: %s %s\n",
366 ipsec4_logpacketstr(ip
, spi
), ipsec_logsastr(sav
)));
367 ipsecstat
.in_ahauthfail
++;
372 * update sequence number.
374 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0 && sav
->replay
) {
375 if (ipsec_updatereplay(ntohl(((struct newah
*)ah
)->ah_seq
), sav
)) {
376 ipsecstat
.in_ahreplay
++;
381 /* was it transmitted over the IPsec tunnel SA? */
382 if (sav
->flags
& SADB_X_EXT_OLD
) {
384 stripsiz
= sizeof(struct ah
) + siz1
;
387 stripsiz
= sizeof(struct newah
) + siz1
;
389 if (ipsec4_tunnel_validate(m
, off
+ stripsiz
, nxt
, sav
)) {
391 * strip off all the headers that precedes AH.
392 * IP xx AH IP' payload -> IP' payload
394 * XXX more sanity checks
395 * XXX relationship with gif?
400 m_adj(m
, off
+ stripsiz
);
401 if (m
->m_len
< sizeof(*ip
)) {
402 m
= m_pullup(m
, sizeof(*ip
));
404 ipsecstat
.in_inval
++;
408 ip
= mtod(m
, struct ip
*);
409 /* ECN consideration. */
410 ip_ecn_egress(ip4_ipsec_ecn
, &tos
, &ip
->ip_tos
);
411 if (!key_checktunnelsanity(sav
, AF_INET
,
412 (caddr_t
)&ip
->ip_src
, (caddr_t
)&ip
->ip_dst
)) {
413 ipseclog((LOG_NOTICE
, "ipsec tunnel address mismatch "
414 "in IPv4 AH input: %s %s\n",
415 ipsec4_logpacketstr(ip
, spi
), ipsec_logsastr(sav
)));
416 ipsecstat
.in_inval
++;
420 #if 0 /* XXX should we call ipfw rather than ipsec_in_reject? */
421 /* drop it if it does not match the default policy */
422 if (ipsec4_in_reject(m
, NULL
)) {
423 ipsecstat
.in_polvio
++;
430 * Should the inner packet be considered authentic?
431 * My current answer is: NO.
433 * host1 -- gw1 === gw2 -- host2
434 * In this case, gw2 can trust the authenticity of the
435 * outer packet, but NOT inner. Packet may be altered
436 * between host1 and gw1.
438 * host1 -- gw1 === host2
439 * This case falls into the same scenario as above.
442 * This case is the only case when we may be able to leave
443 * M_AUTHIPHDR and M_AUTHIPDGM set.
444 * However, if host1 is wrongly configured, and allows
445 * attacker to inject some packet with src=host1 and
446 * dst=host2, you are in risk.
448 m
->m_flags
&= ~M_AUTHIPHDR
;
449 m
->m_flags
&= ~M_AUTHIPDGM
;
452 key_sa_recordxfer(sav
, m
);
453 if (ipsec_addhist(m
, IPPROTO_AH
, spi
) != 0 ||
454 ipsec_addhist(m
, IPPROTO_IPV4
, 0) != 0) {
455 ipsecstat
.in_nomem
++;
460 if (IF_QFULL(&ipintrq
)) {
461 ipsecstat
.in_inval
++;
465 IF_ENQUEUE(&ipintrq
, m
);
467 schednetisr(NETISR_IP
); /*can be skipped but to make sure*/
475 ip
= mtod(m
, struct ip
*);
476 #ifndef PULLDOWN_TEST
478 * We do deep-copy since KAME requires that
479 * the packet is placed in a single external mbuf.
481 ovbcopy((caddr_t
)ip
, (caddr_t
)(((u_char
*)ip
) + stripsiz
), off
);
482 m
->m_data
+= stripsiz
;
483 m
->m_len
-= stripsiz
;
484 m
->m_pkthdr
.len
-= stripsiz
;
487 * even in m_pulldown case, we need to strip off AH so that
488 * we can compute checksum for multiple AH correctly.
490 if (m
->m_len
>= stripsiz
+ off
) {
491 ovbcopy((caddr_t
)ip
, ((caddr_t
)ip
) + stripsiz
, off
);
492 m
->m_data
+= stripsiz
;
493 m
->m_len
-= stripsiz
;
494 m
->m_pkthdr
.len
-= stripsiz
;
497 * this comes with no copy if the boundary is on
502 n
= m_split(m
, off
, M_DONTWAIT
);
504 /* m is retained by m_split */
509 /* m_cat does not update m_pkthdr.len */
510 m
->m_pkthdr
.len
+= n
->m_pkthdr
.len
;
514 if (m
->m_len
< sizeof(*ip
)) {
515 m
= m_pullup(m
, sizeof(*ip
));
517 ipsecstat
.in_inval
++;
521 ip
= mtod(m
, struct ip
*);
523 ip
->ip_len
= ip
->ip_len
- stripsiz
;
525 ip
->ip_len
= htons(ntohs(ip
->ip_len
) - stripsiz
);
528 /* forget about IP hdr checksum, the check has already been passed */
530 key_sa_recordxfer(sav
, m
);
531 if (ipsec_addhist(m
, IPPROTO_AH
, spi
) != 0) {
532 ipsecstat
.in_nomem
++;
536 if (nxt
!= IPPROTO_DONE
) {
537 if ((ip_protox
[nxt
]->pr_flags
& PR_LASTHDR
) != 0 &&
538 ipsec4_in_reject(m
, NULL
)) {
539 ipsecstat
.in_polvio
++;
542 (*ip_protox
[nxt
]->pr_input
)(m
, off
);
549 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
550 printf("DP ah4_input call free SA:%p\n", sav
));
553 ipsecstat
.in_success
++;
558 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
559 printf("DP ah4_input call free SA:%p\n", sav
));
570 ah6_input(mp
, offp
, proto
)
574 struct mbuf
*m
= *mp
;
579 const struct ah_algorithm
*algo
;
583 struct secasvar
*sav
= NULL
;
588 #ifndef PULLDOWN_TEST
589 IP6_EXTHDR_CHECK(m
, off
, sizeof(struct ah
), IPPROTO_DONE
);
590 ah
= (struct ah
*)(mtod(m
, caddr_t
) + off
);
592 IP6_EXTHDR_GET(ah
, struct ah
*, m
, off
, sizeof(struct newah
));
594 ipseclog((LOG_DEBUG
, "IPv6 AH input: can't pullup\n"));
595 ipsec6stat
.in_inval
++;
599 ip6
= mtod(m
, struct ip6_hdr
*);
602 /* find the sassoc. */
605 if (ntohs(ip6
->ip6_plen
) == 0) {
606 ipseclog((LOG_ERR
, "IPv6 AH input: "
607 "AH with IPv6 jumbogram is not supported.\n"));
608 ipsec6stat
.in_inval
++;
612 if ((sav
= key_allocsa(AF_INET6
,
613 (caddr_t
)&ip6
->ip6_src
, (caddr_t
)&ip6
->ip6_dst
,
614 IPPROTO_AH
, spi
)) == 0) {
615 ipseclog((LOG_WARNING
,
616 "IPv6 AH input: no key association found for spi %u\n",
617 (u_int32_t
)ntohl(spi
)));
618 ipsec6stat
.in_nosa
++;
621 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
622 printf("DP ah6_input called to allocate SA:%p\n", sav
));
623 if (sav
->state
!= SADB_SASTATE_MATURE
624 && sav
->state
!= SADB_SASTATE_DYING
) {
626 "IPv6 AH input: non-mature/dying SA found for spi %u; ",
627 (u_int32_t
)ntohl(spi
)));
628 ipsec6stat
.in_badspi
++;
632 algo
= ah_algorithm_lookup(sav
->alg_auth
);
634 ipseclog((LOG_DEBUG
, "IPv6 AH input: "
635 "unsupported authentication algorithm for spi %u\n",
636 (u_int32_t
)ntohl(spi
)));
637 ipsec6stat
.in_badspi
++;
641 siz
= (*algo
->sumsiz
)(sav
);
642 siz1
= ((siz
+ 3) & ~(4 - 1));
645 * sanity checks for header, 1.
650 sizoff
= (sav
->flags
& SADB_X_EXT_OLD
) ? 0 : 4;
653 * Here, we do not do "siz1 == siz". See ah4_input() for complete
657 ipseclog((LOG_NOTICE
, "sum length too short in IPv6 AH input "
658 "(%lu, should be at least %lu): %s\n",
659 (u_long
)siz1
, (u_long
)siz
,
660 ipsec6_logpacketstr(ip6
, spi
)));
661 ipsec6stat
.in_inval
++;
664 if ((ah
->ah_len
<< 2) - sizoff
!= siz1
) {
665 ipseclog((LOG_NOTICE
, "sum length mismatch in IPv6 AH input "
666 "(%d should be %lu): %s\n",
667 (ah
->ah_len
<< 2) - sizoff
, (u_long
)siz1
,
668 ipsec6_logpacketstr(ip6
, spi
)));
669 ipsec6stat
.in_inval
++;
672 #ifndef PULLDOWN_TEST
673 IP6_EXTHDR_CHECK(m
, off
, sizeof(struct ah
) + sizoff
+ siz1
, IPPROTO_DONE
);
675 IP6_EXTHDR_GET(ah
, struct ah
*, m
, off
,
676 sizeof(struct ah
) + sizoff
+ siz1
);
678 ipseclog((LOG_NOTICE
, "couldn't pullup gather IPv6 AH checksum part"));
679 ipsec6stat
.in_inval
++;
687 * check for sequence number.
689 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0 && sav
->replay
) {
690 if (ipsec_chkreplay(ntohl(((struct newah
*)ah
)->ah_seq
), sav
))
693 ipsec6stat
.in_ahreplay
++;
694 ipseclog((LOG_WARNING
,
695 "replay packet in IPv6 AH input: %s %s\n",
696 ipsec6_logpacketstr(ip6
, spi
),
697 ipsec_logsastr(sav
)));
703 * alright, it seems sane. now we are going to check the
704 * cryptographic checksum.
706 cksum
= _MALLOC(siz1
, M_TEMP
, M_NOWAIT
);
708 ipseclog((LOG_DEBUG
, "IPv6 AH input: "
709 "couldn't alloc temporary region for cksum\n"));
710 ipsec6stat
.in_inval
++;
714 if (ah6_calccksum(m
, (caddr_t
)cksum
, siz1
, algo
, sav
)) {
716 ipsec6stat
.in_inval
++;
719 ipsec6stat
.in_ahhist
[sav
->alg_auth
]++;
722 caddr_t sumpos
= NULL
;
724 if (sav
->flags
& SADB_X_EXT_OLD
) {
726 sumpos
= (caddr_t
)(ah
+ 1);
729 sumpos
= (caddr_t
)(((struct newah
*)ah
) + 1);
732 if (bcmp(sumpos
, cksum
, siz
) != 0) {
733 ipseclog((LOG_WARNING
,
734 "checksum mismatch in IPv6 AH input: %s %s\n",
735 ipsec6_logpacketstr(ip6
, spi
), ipsec_logsastr(sav
)));
737 ipsec6stat
.in_ahauthfail
++;
744 m
->m_flags
|= M_AUTHIPHDR
;
745 m
->m_flags
|= M_AUTHIPDGM
;
749 * looks okey, but we need more sanity check.
750 * XXX should elaborate.
752 if (ah
->ah_nxt
== IPPROTO_IPV6
) {
753 struct ip6_hdr
*nip6
;
756 sizoff
= (sav
->flags
& SADB_X_EXT_OLD
) ? 0 : 4;
758 IP6_EXTHDR_CHECK(m
, off
, sizeof(struct ah
) + sizoff
+ siz1
759 + sizeof(struct ip6_hdr
), IPPROTO_DONE
);
761 nip6
= (struct ip6_hdr
*)((u_char
*)(ah
+ 1) + sizoff
+ siz1
);
762 if (!IN6_ARE_ADDR_EQUAL(&nip6
->ip6_src
, &ip6
->ip6_src
)
763 || !IN6_ARE_ADDR_EQUAL(&nip6
->ip6_dst
, &ip6
->ip6_dst
)) {
764 m
->m_flags
&= ~M_AUTHIPHDR
;
765 m
->m_flags
&= ~M_AUTHIPDGM
;
767 } else if (ah
->ah_nxt
== IPPROTO_IPIP
) {
768 m
->m_flags
&= ~M_AUTHIPHDR
;
769 m
->m_flags
&= ~M_AUTHIPDGM
;
770 } else if (ah
->ah_nxt
== IPPROTO_IP
) {
771 m
->m_flags
&= ~M_AUTHIPHDR
;
772 m
->m_flags
&= ~M_AUTHIPDGM
;
776 if (m
->m_flags
& M_AUTHIPHDR
777 && m
->m_flags
& M_AUTHIPDGM
) {
780 "IPv6 AH input: authentication succeess\n"));
782 ipsec6stat
.in_ahauthsucc
++;
784 ipseclog((LOG_WARNING
,
785 "authentication failed in IPv6 AH input: %s %s\n",
786 ipsec6_logpacketstr(ip6
, spi
), ipsec_logsastr(sav
)));
787 ipsec6stat
.in_ahauthfail
++;
792 * update sequence number.
794 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0 && sav
->replay
) {
795 if (ipsec_updatereplay(ntohl(((struct newah
*)ah
)->ah_seq
), sav
)) {
796 ipsec6stat
.in_ahreplay
++;
801 /* was it transmitted over the IPsec tunnel SA? */
802 if (sav
->flags
& SADB_X_EXT_OLD
) {
804 stripsiz
= sizeof(struct ah
) + siz1
;
807 stripsiz
= sizeof(struct newah
) + siz1
;
809 if (ipsec6_tunnel_validate(m
, off
+ stripsiz
, nxt
, sav
)) {
811 * strip off all the headers that precedes AH.
812 * IP6 xx AH IP6' payload -> IP6' payload
814 * XXX more sanity checks
815 * XXX relationship with gif?
817 u_int32_t flowinfo
; /*net endian*/
819 flowinfo
= ip6
->ip6_flow
;
820 m_adj(m
, off
+ stripsiz
);
821 if (m
->m_len
< sizeof(*ip6
)) {
823 * m_pullup is prohibited in KAME IPv6 input processing
824 * but there's no other way!
826 m
= m_pullup(m
, sizeof(*ip6
));
828 ipsec6stat
.in_inval
++;
832 ip6
= mtod(m
, struct ip6_hdr
*);
833 /* ECN consideration. */
834 ip6_ecn_egress(ip6_ipsec_ecn
, &flowinfo
, &ip6
->ip6_flow
);
835 if (!key_checktunnelsanity(sav
, AF_INET6
,
836 (caddr_t
)&ip6
->ip6_src
, (caddr_t
)&ip6
->ip6_dst
)) {
837 ipseclog((LOG_NOTICE
, "ipsec tunnel address mismatch "
838 "in IPv6 AH input: %s %s\n",
839 ipsec6_logpacketstr(ip6
, spi
),
840 ipsec_logsastr(sav
)));
841 ipsec6stat
.in_inval
++;
845 #if 0 /* XXX should we call ipfw rather than ipsec_in_reject? */
846 /* drop it if it does not match the default policy */
847 if (ipsec6_in_reject(m
, NULL
)) {
848 ipsec6stat
.in_polvio
++;
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 sav
= key_allocsa(AF_INET6
,
1025 (caddr_t
)&sa6_src
.sin6_addr
,
1026 (caddr_t
)&sa6_dst
.sin6_addr
,
1027 IPPROTO_AH
, ahp
->ah_spi
);
1029 if (sav
->state
== SADB_SASTATE_MATURE
||
1030 sav
->state
== SADB_SASTATE_DYING
)
1035 /* XXX Further validation? */
1038 * Depending on the value of "valid" and routing table
1039 * size (mtudisc_{hi,lo}wat), we will:
1040 * - recalcurate the new MTU and create the
1041 * corresponding routing entry, or
1042 * - ignore the MTU change notification.
1044 icmp6_mtudisc_update((struct ip6ctlparam
*)d
, valid
);
1047 /* we normally notify single pcb here */
1049 /* we normally notify any pcb here */