]>
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.6 2002/04/28 05:40:26 suz Exp $ */
2 /* $KAME: ah_input.c,v 1.67 2002/01/07 11:39:56 kjc 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
++;
422 * Should the inner packet be considered authentic?
423 * My current answer is: NO.
425 * host1 -- gw1 === gw2 -- host2
426 * In this case, gw2 can trust the authenticity of the
427 * outer packet, but NOT inner. Packet may be altered
428 * between host1 and gw1.
430 * host1 -- gw1 === host2
431 * This case falls into the same scenario as above.
434 * This case is the only case when we may be able to leave
435 * M_AUTHIPHDR and M_AUTHIPDGM set.
436 * However, if host1 is wrongly configured, and allows
437 * attacker to inject some packet with src=host1 and
438 * dst=host2, you are in risk.
440 m
->m_flags
&= ~M_AUTHIPHDR
;
441 m
->m_flags
&= ~M_AUTHIPDGM
;
444 key_sa_recordxfer(sav
, m
);
445 if (ipsec_addhist(m
, IPPROTO_AH
, spi
) != 0 ||
446 ipsec_addhist(m
, IPPROTO_IPV4
, 0) != 0) {
447 ipsecstat
.in_nomem
++;
452 if (IF_QFULL(&ipintrq
)) {
453 ipsecstat
.in_inval
++;
457 IF_ENQUEUE(&ipintrq
, m
);
459 schednetisr(NETISR_IP
); /*can be skipped but to make sure*/
467 ip
= mtod(m
, struct ip
*);
468 #ifndef PULLDOWN_TEST
470 * We do deep-copy since KAME requires that
471 * the packet is placed in a single external mbuf.
473 ovbcopy((caddr_t
)ip
, (caddr_t
)(((u_char
*)ip
) + stripsiz
), off
);
474 m
->m_data
+= stripsiz
;
475 m
->m_len
-= stripsiz
;
476 m
->m_pkthdr
.len
-= stripsiz
;
479 * even in m_pulldown case, we need to strip off AH so that
480 * we can compute checksum for multiple AH correctly.
482 if (m
->m_len
>= stripsiz
+ off
) {
483 ovbcopy((caddr_t
)ip
, ((caddr_t
)ip
) + stripsiz
, off
);
484 m
->m_data
+= stripsiz
;
485 m
->m_len
-= stripsiz
;
486 m
->m_pkthdr
.len
-= stripsiz
;
489 * this comes with no copy if the boundary is on
494 n
= m_split(m
, off
, M_DONTWAIT
);
496 /* m is retained by m_split */
500 /* m_cat does not update m_pkthdr.len */
501 m
->m_pkthdr
.len
+= n
->m_pkthdr
.len
;
506 if (m
->m_len
< sizeof(*ip
)) {
507 m
= m_pullup(m
, sizeof(*ip
));
509 ipsecstat
.in_inval
++;
513 ip
= mtod(m
, struct ip
*);
515 ip
->ip_len
= ip
->ip_len
- stripsiz
;
517 ip
->ip_len
= htons(ntohs(ip
->ip_len
) - stripsiz
);
520 /* forget about IP hdr checksum, the check has already been passed */
522 key_sa_recordxfer(sav
, m
);
523 if (ipsec_addhist(m
, IPPROTO_AH
, spi
) != 0) {
524 ipsecstat
.in_nomem
++;
528 if (nxt
!= IPPROTO_DONE
) {
529 if ((ip_protox
[nxt
]->pr_flags
& PR_LASTHDR
) != 0 &&
530 ipsec4_in_reject(m
, NULL
)) {
531 ipsecstat
.in_polvio
++;
534 (*ip_protox
[nxt
]->pr_input
)(m
, off
);
541 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
542 printf("DP ah4_input call free SA:%p\n", sav
));
545 ipsecstat
.in_success
++;
550 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
551 printf("DP ah4_input call free SA:%p\n", sav
));
566 struct mbuf
*m
= *mp
;
571 const struct ah_algorithm
*algo
;
575 struct secasvar
*sav
= NULL
;
580 #ifndef PULLDOWN_TEST
581 IP6_EXTHDR_CHECK(m
, off
, sizeof(struct ah
), IPPROTO_DONE
);
582 ah
= (struct ah
*)(mtod(m
, caddr_t
) + off
);
584 IP6_EXTHDR_GET(ah
, struct ah
*, m
, off
, sizeof(struct newah
));
586 ipseclog((LOG_DEBUG
, "IPv6 AH input: can't pullup\n"));
587 ipsec6stat
.in_inval
++;
591 ip6
= mtod(m
, struct ip6_hdr
*);
594 /* find the sassoc. */
597 if (ntohs(ip6
->ip6_plen
) == 0) {
598 ipseclog((LOG_ERR
, "IPv6 AH input: "
599 "AH with IPv6 jumbogram is not supported.\n"));
600 ipsec6stat
.in_inval
++;
604 if ((sav
= key_allocsa(AF_INET6
,
605 (caddr_t
)&ip6
->ip6_src
, (caddr_t
)&ip6
->ip6_dst
,
606 IPPROTO_AH
, spi
)) == 0) {
607 ipseclog((LOG_WARNING
,
608 "IPv6 AH input: no key association found for spi %u\n",
609 (u_int32_t
)ntohl(spi
)));
610 ipsec6stat
.in_nosa
++;
613 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
614 printf("DP ah6_input called to allocate SA:%p\n", sav
));
615 if (sav
->state
!= SADB_SASTATE_MATURE
616 && sav
->state
!= SADB_SASTATE_DYING
) {
618 "IPv6 AH input: non-mature/dying SA found for spi %u; ",
619 (u_int32_t
)ntohl(spi
)));
620 ipsec6stat
.in_badspi
++;
624 algo
= ah_algorithm_lookup(sav
->alg_auth
);
626 ipseclog((LOG_DEBUG
, "IPv6 AH input: "
627 "unsupported authentication algorithm for spi %u\n",
628 (u_int32_t
)ntohl(spi
)));
629 ipsec6stat
.in_badspi
++;
633 siz
= (*algo
->sumsiz
)(sav
);
634 siz1
= ((siz
+ 3) & ~(4 - 1));
637 * sanity checks for header, 1.
642 sizoff
= (sav
->flags
& SADB_X_EXT_OLD
) ? 0 : 4;
645 * Here, we do not do "siz1 == siz". See ah4_input() for complete
649 ipseclog((LOG_NOTICE
, "sum length too short in IPv6 AH input "
650 "(%lu, should be at least %lu): %s\n",
651 (u_long
)siz1
, (u_long
)siz
,
652 ipsec6_logpacketstr(ip6
, spi
)));
653 ipsec6stat
.in_inval
++;
656 if ((ah
->ah_len
<< 2) - sizoff
!= siz1
) {
657 ipseclog((LOG_NOTICE
, "sum length mismatch in IPv6 AH input "
658 "(%d should be %lu): %s\n",
659 (ah
->ah_len
<< 2) - sizoff
, (u_long
)siz1
,
660 ipsec6_logpacketstr(ip6
, spi
)));
661 ipsec6stat
.in_inval
++;
664 #ifndef PULLDOWN_TEST
665 IP6_EXTHDR_CHECK(m
, off
, sizeof(struct ah
) + sizoff
+ siz1
, IPPROTO_DONE
);
667 IP6_EXTHDR_GET(ah
, struct ah
*, m
, off
,
668 sizeof(struct ah
) + sizoff
+ siz1
);
670 ipseclog((LOG_NOTICE
, "couldn't pullup gather IPv6 AH checksum part"));
671 ipsec6stat
.in_inval
++;
679 * check for sequence number.
681 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0 && sav
->replay
) {
682 if (ipsec_chkreplay(ntohl(((struct newah
*)ah
)->ah_seq
), sav
))
685 ipsec6stat
.in_ahreplay
++;
686 ipseclog((LOG_WARNING
,
687 "replay packet in IPv6 AH input: %s %s\n",
688 ipsec6_logpacketstr(ip6
, spi
),
689 ipsec_logsastr(sav
)));
695 * alright, it seems sane. now we are going to check the
696 * cryptographic checksum.
698 cksum
= _MALLOC(siz1
, M_TEMP
, M_NOWAIT
);
700 ipseclog((LOG_DEBUG
, "IPv6 AH input: "
701 "couldn't alloc temporary region for cksum\n"));
702 ipsec6stat
.in_inval
++;
706 if (ah6_calccksum(m
, (caddr_t
)cksum
, siz1
, algo
, sav
)) {
708 ipsec6stat
.in_inval
++;
711 ipsec6stat
.in_ahhist
[sav
->alg_auth
]++;
714 caddr_t sumpos
= NULL
;
716 if (sav
->flags
& SADB_X_EXT_OLD
) {
718 sumpos
= (caddr_t
)(ah
+ 1);
721 sumpos
= (caddr_t
)(((struct newah
*)ah
) + 1);
724 if (bcmp(sumpos
, cksum
, siz
) != 0) {
725 ipseclog((LOG_WARNING
,
726 "checksum mismatch in IPv6 AH input: %s %s\n",
727 ipsec6_logpacketstr(ip6
, spi
), ipsec_logsastr(sav
)));
729 ipsec6stat
.in_ahauthfail
++;
736 m
->m_flags
|= M_AUTHIPHDR
;
737 m
->m_flags
|= M_AUTHIPDGM
;
741 * looks okey, but we need more sanity check.
742 * XXX should elaborate.
744 if (ah
->ah_nxt
== IPPROTO_IPV6
) {
745 struct ip6_hdr
*nip6
;
748 sizoff
= (sav
->flags
& SADB_X_EXT_OLD
) ? 0 : 4;
750 IP6_EXTHDR_CHECK(m
, off
, sizeof(struct ah
) + sizoff
+ siz1
751 + sizeof(struct ip6_hdr
), IPPROTO_DONE
);
753 nip6
= (struct ip6_hdr
*)((u_char
*)(ah
+ 1) + sizoff
+ siz1
);
754 if (!IN6_ARE_ADDR_EQUAL(&nip6
->ip6_src
, &ip6
->ip6_src
)
755 || !IN6_ARE_ADDR_EQUAL(&nip6
->ip6_dst
, &ip6
->ip6_dst
)) {
756 m
->m_flags
&= ~M_AUTHIPHDR
;
757 m
->m_flags
&= ~M_AUTHIPDGM
;
759 } else if (ah
->ah_nxt
== IPPROTO_IPIP
) {
760 m
->m_flags
&= ~M_AUTHIPHDR
;
761 m
->m_flags
&= ~M_AUTHIPDGM
;
762 } else if (ah
->ah_nxt
== IPPROTO_IP
) {
763 m
->m_flags
&= ~M_AUTHIPHDR
;
764 m
->m_flags
&= ~M_AUTHIPDGM
;
768 if (m
->m_flags
& M_AUTHIPHDR
769 && m
->m_flags
& M_AUTHIPDGM
) {
772 "IPv6 AH input: authentication succeess\n"));
774 ipsec6stat
.in_ahauthsucc
++;
776 ipseclog((LOG_WARNING
,
777 "authentication failed in IPv6 AH input: %s %s\n",
778 ipsec6_logpacketstr(ip6
, spi
), ipsec_logsastr(sav
)));
779 ipsec6stat
.in_ahauthfail
++;
784 * update sequence number.
786 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0 && sav
->replay
) {
787 if (ipsec_updatereplay(ntohl(((struct newah
*)ah
)->ah_seq
), sav
)) {
788 ipsec6stat
.in_ahreplay
++;
793 /* was it transmitted over the IPsec tunnel SA? */
794 if (sav
->flags
& SADB_X_EXT_OLD
) {
796 stripsiz
= sizeof(struct ah
) + siz1
;
799 stripsiz
= sizeof(struct newah
) + siz1
;
801 if (ipsec6_tunnel_validate(m
, off
+ stripsiz
, nxt
, sav
)) {
803 * strip off all the headers that precedes AH.
804 * IP6 xx AH IP6' payload -> IP6' payload
806 * XXX more sanity checks
807 * XXX relationship with gif?
809 u_int32_t flowinfo
; /*net endian*/
811 flowinfo
= ip6
->ip6_flow
;
812 m_adj(m
, off
+ stripsiz
);
813 if (m
->m_len
< sizeof(*ip6
)) {
815 * m_pullup is prohibited in KAME IPv6 input processing
816 * but there's no other way!
818 m
= m_pullup(m
, sizeof(*ip6
));
820 ipsec6stat
.in_inval
++;
824 ip6
= mtod(m
, struct ip6_hdr
*);
825 /* ECN consideration. */
826 ip6_ecn_egress(ip6_ipsec_ecn
, &flowinfo
, &ip6
->ip6_flow
);
827 if (!key_checktunnelsanity(sav
, AF_INET6
,
828 (caddr_t
)&ip6
->ip6_src
, (caddr_t
)&ip6
->ip6_dst
)) {
829 ipseclog((LOG_NOTICE
, "ipsec tunnel address mismatch "
830 "in IPv6 AH input: %s %s\n",
831 ipsec6_logpacketstr(ip6
, spi
),
832 ipsec_logsastr(sav
)));
833 ipsec6stat
.in_inval
++;
839 * should the inner packet be considered authentic?
840 * see comment in ah4_input().
842 m
->m_flags
&= ~M_AUTHIPHDR
;
843 m
->m_flags
&= ~M_AUTHIPDGM
;
846 key_sa_recordxfer(sav
, m
);
847 if (ipsec_addhist(m
, IPPROTO_AH
, spi
) != 0 ||
848 ipsec_addhist(m
, IPPROTO_IPV6
, 0) != 0) {
849 ipsec6stat
.in_nomem
++;
854 if (IF_QFULL(&ip6intrq
)) {
855 ipsec6stat
.in_inval
++;
859 IF_ENQUEUE(&ip6intrq
, m
);
861 schednetisr(NETISR_IPV6
); /* can be skipped but to make sure */
871 * Copy the value of the next header field of AH to the
872 * next header field of the previous header.
873 * This is necessary because AH will be stripped off below.
875 prvnxtp
= ip6_get_prevhdr(m
, off
); /* XXX */
878 ip6
= mtod(m
, struct ip6_hdr
*);
879 #ifndef PULLDOWN_TEST
881 * We do deep-copy since KAME requires that
882 * the packet is placed in a single mbuf.
884 ovbcopy((caddr_t
)ip6
, ((caddr_t
)ip6
) + stripsiz
, off
);
885 m
->m_data
+= stripsiz
;
886 m
->m_len
-= stripsiz
;
887 m
->m_pkthdr
.len
-= stripsiz
;
890 * even in m_pulldown case, we need to strip off AH so that
891 * we can compute checksum for multiple AH correctly.
893 if (m
->m_len
>= stripsiz
+ off
) {
894 ovbcopy((caddr_t
)ip6
, ((caddr_t
)ip6
) + stripsiz
, off
);
895 m
->m_data
+= stripsiz
;
896 m
->m_len
-= stripsiz
;
897 m
->m_pkthdr
.len
-= stripsiz
;
900 * this comes with no copy if the boundary is on
905 n
= m_split(m
, off
, M_DONTWAIT
);
907 /* m is retained by m_split */
911 /* m_cat does not update m_pkthdr.len */
912 m
->m_pkthdr
.len
+= n
->m_pkthdr
.len
;
916 ip6
= mtod(m
, struct ip6_hdr
*);
918 ip6
->ip6_plen
= htons(ntohs(ip6
->ip6_plen
) - stripsiz
);
920 key_sa_recordxfer(sav
, m
);
921 if (ipsec_addhist(m
, IPPROTO_AH
, spi
) != 0) {
922 ipsec6stat
.in_nomem
++;
931 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
932 printf("DP ah6_input call free SA:%p\n", sav
));
935 ipsec6stat
.in_success
++;
940 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
941 printf("DP ah6_input call free SA:%p\n", sav
));
950 ah6_ctlinput(cmd
, sa
, d
)
955 const struct newah
*ahp
;
957 struct secasvar
*sav
;
960 struct ip6ctlparam
*ip6cp
= NULL
;
962 struct sockaddr_in6
*sa6_src
, *sa6_dst
;
964 if (sa
->sa_family
!= AF_INET6
||
965 sa
->sa_len
!= sizeof(struct sockaddr_in6
))
967 if ((unsigned)cmd
>= PRC_NCMDS
)
970 /* if the parameter is from icmp6, decode it. */
972 ip6cp
= (struct ip6ctlparam
*)d
;
974 ip6
= ip6cp
->ip6c_ip6
;
975 off
= ip6cp
->ip6c_off
;
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 */