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.
38 #include "opt_inet6.h"
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/malloc.h>
44 #include <sys/domain.h>
45 #include <sys/protosw.h>
46 #include <sys/socket.h>
47 #include <sys/errno.h>
49 #include <sys/syslog.h>
52 #include <net/route.h>
53 #include <net/netisr.h>
54 #include <machine/cpu.h>
55 #include <machine/stdarg.h>
57 #include <netinet/in.h>
58 #include <netinet/in_systm.h>
59 #include <netinet/in_var.h>
60 #include <netinet/ip.h>
61 #include <netinet/ip_var.h>
62 #include <netinet/ip_ecn.h>
64 #include <netinet6/ip6_ecn.h>
68 #include <netinet/ip6.h>
69 #include <netinet6/ip6_var.h>
70 #include <netinet6/in6_pcb.h>
71 #include <netinet/icmp6.h>
72 #include <netinet6/ip6protosw.h>
75 #include <netinet6/ipsec.h>
77 #include <netinet6/ipsec6.h>
79 #include <netinet6/ah.h>
81 #include <netinet6/ah6.h>
83 #include <netproto/key/key.h>
84 #include <netproto/key/keydb.h>
86 #include <netproto/key/key_debug.h>
88 #define KEYDEBUG(lev,arg)
91 #include <net/net_osdep.h>
96 extern struct protosw inetsw
[];
99 ah4_input(struct mbuf
**mp
, int *offp
, int proto
)
106 const struct ah_algorithm
*algo
;
110 struct secasvar
*sav
= NULL
;
119 #ifndef PULLDOWN_TEST
120 if (m
->m_len
< off
+ sizeof(struct newah
)) {
121 m
= m_pullup(m
, off
+ sizeof(struct newah
));
123 ipseclog((LOG_DEBUG
, "IPv4 AH input: can't pullup;"
124 "dropping the packet for simplicity\n"));
125 ipsecstat
.in_inval
++;
130 ip
= mtod(m
, struct ip
*);
131 ah
= (struct ah
*)(((caddr_t
)ip
) + off
);
133 ip
= mtod(m
, struct ip
*);
134 IP6_EXTHDR_GET(ah
, struct ah
*, m
, off
, sizeof(struct newah
));
136 ipseclog((LOG_DEBUG
, "IPv4 AH input: can't pullup;"
137 "dropping the packet for simplicity\n"));
138 ipsecstat
.in_inval
++;
144 hlen
= IP_VHL_HL(ip
->ip_vhl
) << 2;
146 hlen
= ip
->ip_hl
<< 2;
149 /* find the sassoc. */
152 if ((sav
= key_allocsa(AF_INET
,
153 (caddr_t
)&ip
->ip_src
, (caddr_t
)&ip
->ip_dst
,
154 IPPROTO_AH
, spi
)) == NULL
) {
155 ipseclog((LOG_WARNING
,
156 "IPv4 AH input: no key association found for spi %u\n",
157 (u_int32_t
)ntohl(spi
)));
161 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
162 kprintf("DP ah4_input called to allocate SA:%p\n", sav
));
163 if (sav
->state
!= SADB_SASTATE_MATURE
164 && sav
->state
!= SADB_SASTATE_DYING
) {
166 "IPv4 AH input: non-mature/dying SA found for spi %u\n",
167 (u_int32_t
)ntohl(spi
)));
168 ipsecstat
.in_badspi
++;
172 algo
= ah_algorithm_lookup(sav
->alg_auth
);
174 ipseclog((LOG_DEBUG
, "IPv4 AH input: "
175 "unsupported authentication algorithm for spi %u\n",
176 (u_int32_t
)ntohl(spi
)));
177 ipsecstat
.in_badspi
++;
181 siz
= (*algo
->sumsiz
)(sav
);
182 siz1
= ((siz
+ 3) & ~(4 - 1));
185 * sanity checks for header, 1.
190 sizoff
= (sav
->flags
& SADB_X_EXT_OLD
) ? 0 : 4;
193 * Here, we do not do "siz1 == siz". This is because the way
194 * RFC240[34] section 2 is written. They do not require truncation
196 * For example, Microsoft IPsec stack attaches 160 bits of
197 * authentication data for both hmac-md5 and hmac-sha1. For hmac-sha1,
198 * 32 bits of padding is attached.
200 * There are two downsides to this specification.
201 * They have no real harm, however, they leave us fuzzy feeling.
202 * - if we attach more than 96 bits of authentication data onto AH,
203 * we will never notice about possible modification by rogue
204 * intermediate nodes.
205 * Since extra bits in AH checksum is never used, this constitutes
206 * no real issue, however, it is wacky.
207 * - even if the peer attaches big authentication data, we will never
208 * notice the difference, since longer authentication data will just
211 * We may need some clarification in the spec.
214 ipseclog((LOG_NOTICE
, "sum length too short in IPv4 AH input "
215 "(%lu, should be at least %lu): %s\n",
216 (u_long
)siz1
, (u_long
)siz
,
217 ipsec4_logpacketstr(ip
, spi
)));
218 ipsecstat
.in_inval
++;
221 if ((ah
->ah_len
<< 2) - sizoff
!= siz1
) {
222 ipseclog((LOG_NOTICE
, "sum length mismatch in IPv4 AH input "
223 "(%d should be %lu): %s\n",
224 (ah
->ah_len
<< 2) - sizoff
, (u_long
)siz1
,
225 ipsec4_logpacketstr(ip
, spi
)));
226 ipsecstat
.in_inval
++;
230 #ifndef PULLDOWN_TEST
231 if (m
->m_len
< off
+ sizeof(struct ah
) + sizoff
+ siz1
) {
232 m
= m_pullup(m
, off
+ sizeof(struct ah
) + sizoff
+ siz1
);
234 ipseclog((LOG_DEBUG
, "IPv4 AH input: can't pullup\n"));
235 ipsecstat
.in_inval
++;
239 ip
= mtod(m
, struct ip
*);
240 ah
= (struct ah
*)(((caddr_t
)ip
) + off
);
243 IP6_EXTHDR_GET(ah
, struct ah
*, m
, off
,
244 sizeof(struct ah
) + sizoff
+ siz1
);
246 ipseclog((LOG_DEBUG
, "IPv4 AH input: can't pullup\n"));
247 ipsecstat
.in_inval
++;
254 * check for sequence number.
256 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0 && sav
->replay
) {
257 if (ipsec_chkreplay(ntohl(((struct newah
*)ah
)->ah_seq
), sav
))
260 ipsecstat
.in_ahreplay
++;
261 ipseclog((LOG_WARNING
,
262 "replay packet in IPv4 AH input: %s %s\n",
263 ipsec4_logpacketstr(ip
, spi
), ipsec_logsastr(sav
)));
269 * alright, it seems sane. now we are going to check the
270 * cryptographic checksum.
272 cksum
= kmalloc(siz1
, M_TEMP
, M_NOWAIT
);
274 ipseclog((LOG_DEBUG
, "IPv4 AH input: "
275 "couldn't alloc temporary region for cksum\n"));
276 ipsecstat
.in_inval
++;
281 * some of IP header fields are flipped to the host endian.
282 * convert them back to network endian. VERY stupid.
284 ip
->ip_len
= htons(ip
->ip_len
+ hlen
);
285 ip
->ip_off
= htons(ip
->ip_off
);
286 if (ah4_calccksum(m
, (caddr_t
)cksum
, siz1
, algo
, sav
)) {
287 kfree(cksum
, M_TEMP
);
288 ipsecstat
.in_inval
++;
291 ipsecstat
.in_ahhist
[sav
->alg_auth
]++;
295 ip
->ip_len
= ntohs(ip
->ip_len
) - hlen
;
296 ip
->ip_off
= ntohs(ip
->ip_off
);
299 caddr_t sumpos
= NULL
;
301 if (sav
->flags
& SADB_X_EXT_OLD
) {
303 sumpos
= (caddr_t
)(ah
+ 1);
306 sumpos
= (caddr_t
)(((struct newah
*)ah
) + 1);
309 if (bcmp(sumpos
, cksum
, siz
) != 0) {
310 ipseclog((LOG_WARNING
,
311 "checksum mismatch in IPv4 AH input: %s %s\n",
312 ipsec4_logpacketstr(ip
, spi
), ipsec_logsastr(sav
)));
313 kfree(cksum
, M_TEMP
);
314 ipsecstat
.in_ahauthfail
++;
319 kfree(cksum
, M_TEMP
);
321 m
->m_flags
|= M_AUTHIPHDR
;
322 m
->m_flags
|= M_AUTHIPDGM
;
326 * looks okey, but we need more sanity check.
327 * XXX should elaborate.
329 if (ah
->ah_nxt
== IPPROTO_IPIP
|| ah
->ah_nxt
== IPPROTO_IP
) {
333 sizoff
= (sav
->flags
& SADB_X_EXT_OLD
) ? 0 : 4;
335 if (m
->m_len
< off
+ sizeof(struct ah
) + sizoff
+ siz1
+ hlen
) {
336 m
= m_pullup(m
, off
+ sizeof(struct ah
)
337 + sizoff
+ siz1
+ hlen
);
340 "IPv4 AH input: can't pullup\n"));
341 ipsecstat
.in_inval
++;
346 nip
= (struct ip
*)((u_char
*)(ah
+ 1) + sizoff
+ siz1
);
347 if (nip
->ip_src
.s_addr
!= ip
->ip_src
.s_addr
348 || nip
->ip_dst
.s_addr
!= ip
->ip_dst
.s_addr
) {
349 m
->m_flags
&= ~M_AUTHIPHDR
;
350 m
->m_flags
&= ~M_AUTHIPDGM
;
354 else if (ah
->ah_nxt
== IPPROTO_IPV6
) {
355 m
->m_flags
&= ~M_AUTHIPHDR
;
356 m
->m_flags
&= ~M_AUTHIPDGM
;
361 if (m
->m_flags
& M_AUTHIPHDR
362 && m
->m_flags
& M_AUTHIPDGM
) {
365 "IPv4 AH input: authentication succeess\n"));
367 ipsecstat
.in_ahauthsucc
++;
369 ipseclog((LOG_WARNING
,
370 "authentication failed in IPv4 AH input: %s %s\n",
371 ipsec4_logpacketstr(ip
, spi
), ipsec_logsastr(sav
)));
372 ipsecstat
.in_ahauthfail
++;
377 * update sequence number.
379 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0 && sav
->replay
) {
380 if (ipsec_updatereplay(ntohl(((struct newah
*)ah
)->ah_seq
), sav
)) {
381 ipsecstat
.in_ahreplay
++;
386 /* was it transmitted over the IPsec tunnel SA? */
387 if (sav
->flags
& SADB_X_EXT_OLD
) {
389 stripsiz
= sizeof(struct ah
) + siz1
;
392 stripsiz
= sizeof(struct newah
) + siz1
;
394 if (ipsec4_tunnel_validate(m
, off
+ stripsiz
, nxt
, sav
)) {
396 * strip off all the headers that precedes AH.
397 * IP xx AH IP' payload -> IP' payload
399 * XXX more sanity checks
400 * XXX relationship with gif?
405 m_adj(m
, off
+ stripsiz
);
406 if (m
->m_len
< sizeof(*ip
)) {
407 m
= m_pullup(m
, sizeof(*ip
));
409 ipsecstat
.in_inval
++;
413 ip
= mtod(m
, struct ip
*);
414 /* ECN consideration. */
415 ip_ecn_egress(ip4_ipsec_ecn
, &tos
, &ip
->ip_tos
);
416 if (!key_checktunnelsanity(sav
, AF_INET
,
417 (caddr_t
)&ip
->ip_src
, (caddr_t
)&ip
->ip_dst
)) {
418 ipseclog((LOG_NOTICE
, "ipsec tunnel address mismatch "
419 "in IPv4 AH input: %s %s\n",
420 ipsec4_logpacketstr(ip
, spi
), ipsec_logsastr(sav
)));
421 ipsecstat
.in_inval
++;
427 * Should the inner packet be considered authentic?
428 * My current answer is: NO.
430 * host1 -- gw1 === gw2 -- host2
431 * In this case, gw2 can trust the authenticity of the
432 * outer packet, but NOT inner. Packet may be altered
433 * between host1 and gw1.
435 * host1 -- gw1 === host2
436 * This case falls into the same scenario as above.
439 * This case is the only case when we may be able to leave
440 * M_AUTHIPHDR and M_AUTHIPDGM set.
441 * However, if host1 is wrongly configured, and allows
442 * attacker to inject some packet with src=host1 and
443 * dst=host2, you are in risk.
445 m
->m_flags
&= ~M_AUTHIPHDR
;
446 m
->m_flags
&= ~M_AUTHIPDGM
;
449 key_sa_recordxfer(sav
, m
);
450 if (ipsec_addhist(m
, IPPROTO_AH
, spi
) != 0 ||
451 ipsec_addhist(m
, IPPROTO_IPV4
, 0) != 0) {
452 ipsecstat
.in_nomem
++;
456 if (netisr_queue(NETISR_IP
, m
)) {
457 ipsecstat
.in_inval
++;
468 ip
= mtod(m
, struct ip
*);
469 #ifndef PULLDOWN_TEST
471 * We do deep-copy since KAME requires that
472 * the packet is placed in a single external mbuf.
474 bcopy((caddr_t
)ip
, (caddr_t
)(((u_char
*)ip
) + stripsiz
), off
);
475 m
->m_data
+= stripsiz
;
476 m
->m_len
-= stripsiz
;
477 m
->m_pkthdr
.len
-= stripsiz
;
480 * even in m_pulldown case, we need to strip off AH so that
481 * we can compute checksum for multiple AH correctly.
483 if (m
->m_len
>= stripsiz
+ off
) {
484 bcopy((caddr_t
)ip
, ((caddr_t
)ip
) + stripsiz
, off
);
485 m
->m_data
+= stripsiz
;
486 m
->m_len
-= stripsiz
;
487 m
->m_pkthdr
.len
-= stripsiz
;
490 * this comes with no copy if the boundary is on
495 n
= m_split(m
, off
, M_NOWAIT
);
497 /* m is retained by m_split */
501 /* m_cat does not update m_pkthdr.len */
502 m
->m_pkthdr
.len
+= n
->m_pkthdr
.len
;
507 if (m
->m_len
< sizeof(*ip
)) {
508 m
= m_pullup(m
, sizeof(*ip
));
510 ipsecstat
.in_inval
++;
514 ip
= mtod(m
, struct ip
*);
516 ip
->ip_len
= ip
->ip_len
- stripsiz
;
518 ip
->ip_len
= htons(ntohs(ip
->ip_len
) - stripsiz
);
521 /* forget about IP hdr checksum, the check has already been passed */
523 key_sa_recordxfer(sav
, m
);
524 if (ipsec_addhist(m
, IPPROTO_AH
, spi
) != 0) {
525 ipsecstat
.in_nomem
++;
529 if (nxt
!= IPPROTO_DONE
) {
530 if ((inetsw
[ip_protox
[nxt
]].pr_flags
& PR_LASTHDR
) &&
531 ipsec4_in_reject(m
, NULL
)) {
532 ipsecstat
.in_polvio
++;
535 if (!ip_lengthcheck(&m
, 0)) {
536 /* freed in ip_lengthcheck() */
541 (*inetsw
[ip_protox
[nxt
]].pr_input
)(mp
, offp
, nxt
);
549 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
550 kprintf("DP ah4_input call free SA:%p\n", sav
));
553 ipsecstat
.in_success
++;
554 return(IPPROTO_DONE
);
558 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
559 kprintf("DP ah4_input call free SA:%p\n", sav
));
564 return(IPPROTO_DONE
);
570 ah6_input(struct mbuf
**mp
, int *offp
, int proto
)
572 struct mbuf
*m
= *mp
;
577 const struct ah_algorithm
*algo
;
581 struct secasvar
*sav
= NULL
;
585 #ifndef PULLDOWN_TEST
586 IP6_EXTHDR_CHECK(m
, off
, sizeof(struct ah
), IPPROTO_DONE
);
587 ah
= (struct ah
*)(mtod(m
, caddr_t
) + off
);
589 IP6_EXTHDR_GET(ah
, struct ah
*, m
, off
, sizeof(struct newah
));
591 ipseclog((LOG_DEBUG
, "IPv6 AH input: can't pullup\n"));
592 ipsec6stat
.in_inval
++;
596 ip6
= mtod(m
, struct ip6_hdr
*);
599 /* find the sassoc. */
602 if (ntohs(ip6
->ip6_plen
) == 0) {
603 ipseclog((LOG_ERR
, "IPv6 AH input: "
604 "AH with IPv6 jumbogram is not supported.\n"));
605 ipsec6stat
.in_inval
++;
609 if ((sav
= key_allocsa(AF_INET6
,
610 (caddr_t
)&ip6
->ip6_src
, (caddr_t
)&ip6
->ip6_dst
,
611 IPPROTO_AH
, spi
)) == NULL
) {
612 ipseclog((LOG_WARNING
,
613 "IPv6 AH input: no key association found for spi %u\n",
614 (u_int32_t
)ntohl(spi
)));
615 ipsec6stat
.in_nosa
++;
618 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
619 kprintf("DP ah6_input called to allocate SA:%p\n", sav
));
620 if (sav
->state
!= SADB_SASTATE_MATURE
621 && sav
->state
!= SADB_SASTATE_DYING
) {
623 "IPv6 AH input: non-mature/dying SA found for spi %u; ",
624 (u_int32_t
)ntohl(spi
)));
625 ipsec6stat
.in_badspi
++;
629 algo
= ah_algorithm_lookup(sav
->alg_auth
);
631 ipseclog((LOG_DEBUG
, "IPv6 AH input: "
632 "unsupported authentication algorithm for spi %u\n",
633 (u_int32_t
)ntohl(spi
)));
634 ipsec6stat
.in_badspi
++;
638 siz
= (*algo
->sumsiz
)(sav
);
639 siz1
= ((siz
+ 3) & ~(4 - 1));
642 * sanity checks for header, 1.
647 sizoff
= (sav
->flags
& SADB_X_EXT_OLD
) ? 0 : 4;
650 * Here, we do not do "siz1 == siz". See ah4_input() for complete
654 ipseclog((LOG_NOTICE
, "sum length too short in IPv6 AH input "
655 "(%lu, should be at least %lu): %s\n",
656 (u_long
)siz1
, (u_long
)siz
,
657 ipsec6_logpacketstr(ip6
, spi
)));
658 ipsec6stat
.in_inval
++;
661 if ((ah
->ah_len
<< 2) - sizoff
!= siz1
) {
662 ipseclog((LOG_NOTICE
, "sum length mismatch in IPv6 AH input "
663 "(%d should be %lu): %s\n",
664 (ah
->ah_len
<< 2) - sizoff
, (u_long
)siz1
,
665 ipsec6_logpacketstr(ip6
, spi
)));
666 ipsec6stat
.in_inval
++;
669 #ifndef PULLDOWN_TEST
670 IP6_EXTHDR_CHECK(m
, off
, sizeof(struct ah
) + sizoff
+ siz1
, IPPROTO_DONE
);
672 IP6_EXTHDR_GET(ah
, struct ah
*, m
, off
,
673 sizeof(struct ah
) + sizoff
+ siz1
);
675 ipseclog((LOG_NOTICE
, "couldn't pullup gather IPv6 AH checksum part"));
676 ipsec6stat
.in_inval
++;
684 * check for sequence number.
686 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0 && sav
->replay
) {
687 if (ipsec_chkreplay(ntohl(((struct newah
*)ah
)->ah_seq
), sav
))
690 ipsec6stat
.in_ahreplay
++;
691 ipseclog((LOG_WARNING
,
692 "replay packet in IPv6 AH input: %s %s\n",
693 ipsec6_logpacketstr(ip6
, spi
),
694 ipsec_logsastr(sav
)));
700 * alright, it seems sane. now we are going to check the
701 * cryptographic checksum.
703 cksum
= kmalloc(siz1
, M_TEMP
, M_NOWAIT
);
705 ipseclog((LOG_DEBUG
, "IPv6 AH input: "
706 "couldn't alloc temporary region for cksum\n"));
707 ipsec6stat
.in_inval
++;
711 if (ah6_calccksum(m
, (caddr_t
)cksum
, siz1
, algo
, sav
)) {
712 kfree(cksum
, M_TEMP
);
713 ipsec6stat
.in_inval
++;
716 ipsec6stat
.in_ahhist
[sav
->alg_auth
]++;
719 caddr_t sumpos
= NULL
;
721 if (sav
->flags
& SADB_X_EXT_OLD
) {
723 sumpos
= (caddr_t
)(ah
+ 1);
726 sumpos
= (caddr_t
)(((struct newah
*)ah
) + 1);
729 if (bcmp(sumpos
, cksum
, siz
) != 0) {
730 ipseclog((LOG_WARNING
,
731 "checksum mismatch in IPv6 AH input: %s %s\n",
732 ipsec6_logpacketstr(ip6
, spi
), ipsec_logsastr(sav
)));
733 kfree(cksum
, M_TEMP
);
734 ipsec6stat
.in_ahauthfail
++;
739 kfree(cksum
, M_TEMP
);
741 m
->m_flags
|= M_AUTHIPHDR
;
742 m
->m_flags
|= M_AUTHIPDGM
;
746 * looks okey, but we need more sanity check.
747 * XXX should elaborate.
749 if (ah
->ah_nxt
== IPPROTO_IPV6
) {
750 struct ip6_hdr
*nip6
;
753 sizoff
= (sav
->flags
& SADB_X_EXT_OLD
) ? 0 : 4;
755 IP6_EXTHDR_CHECK(m
, off
, sizeof(struct ah
) + sizoff
+ siz1
756 + sizeof(struct ip6_hdr
), IPPROTO_DONE
);
758 nip6
= (struct ip6_hdr
*)((u_char
*)(ah
+ 1) + sizoff
+ siz1
);
759 if (!IN6_ARE_ADDR_EQUAL(&nip6
->ip6_src
, &ip6
->ip6_src
)
760 || !IN6_ARE_ADDR_EQUAL(&nip6
->ip6_dst
, &ip6
->ip6_dst
)) {
761 m
->m_flags
&= ~M_AUTHIPHDR
;
762 m
->m_flags
&= ~M_AUTHIPDGM
;
764 } else if (ah
->ah_nxt
== IPPROTO_IPIP
) {
765 m
->m_flags
&= ~M_AUTHIPHDR
;
766 m
->m_flags
&= ~M_AUTHIPDGM
;
767 } else if (ah
->ah_nxt
== IPPROTO_IP
) {
768 m
->m_flags
&= ~M_AUTHIPHDR
;
769 m
->m_flags
&= ~M_AUTHIPDGM
;
773 if (m
->m_flags
& M_AUTHIPHDR
774 && m
->m_flags
& M_AUTHIPDGM
) {
777 "IPv6 AH input: authentication succeess\n"));
779 ipsec6stat
.in_ahauthsucc
++;
781 ipseclog((LOG_WARNING
,
782 "authentication failed in IPv6 AH input: %s %s\n",
783 ipsec6_logpacketstr(ip6
, spi
), ipsec_logsastr(sav
)));
784 ipsec6stat
.in_ahauthfail
++;
789 * update sequence number.
791 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0 && sav
->replay
) {
792 if (ipsec_updatereplay(ntohl(((struct newah
*)ah
)->ah_seq
), sav
)) {
793 ipsec6stat
.in_ahreplay
++;
798 /* was it transmitted over the IPsec tunnel SA? */
799 if (sav
->flags
& SADB_X_EXT_OLD
) {
801 stripsiz
= sizeof(struct ah
) + siz1
;
804 stripsiz
= sizeof(struct newah
) + siz1
;
806 if (ipsec6_tunnel_validate(m
, off
+ stripsiz
, nxt
, sav
)) {
808 * strip off all the headers that precedes AH.
809 * IP6 xx AH IP6' payload -> IP6' payload
811 * XXX more sanity checks
812 * XXX relationship with gif?
814 u_int32_t flowinfo
; /* net endian */
816 flowinfo
= ip6
->ip6_flow
;
817 m_adj(m
, off
+ stripsiz
);
818 if (m
->m_len
< sizeof(*ip6
)) {
820 * m_pullup is prohibited in KAME IPv6 input processing
821 * but there's no other way!
823 m
= m_pullup(m
, sizeof(*ip6
));
825 ipsec6stat
.in_inval
++;
829 ip6
= mtod(m
, struct ip6_hdr
*);
830 /* ECN consideration. */
831 ip6_ecn_egress(ip6_ipsec_ecn
, &flowinfo
, &ip6
->ip6_flow
);
832 if (!key_checktunnelsanity(sav
, AF_INET6
,
833 (caddr_t
)&ip6
->ip6_src
, (caddr_t
)&ip6
->ip6_dst
)) {
834 ipseclog((LOG_NOTICE
, "ipsec tunnel address mismatch "
835 "in IPv6 AH input: %s %s\n",
836 ipsec6_logpacketstr(ip6
, spi
),
837 ipsec_logsastr(sav
)));
838 ipsec6stat
.in_inval
++;
844 * should the inner packet be considered authentic?
845 * see comment in ah4_input().
847 m
->m_flags
&= ~M_AUTHIPHDR
;
848 m
->m_flags
&= ~M_AUTHIPDGM
;
851 key_sa_recordxfer(sav
, m
);
852 if (ipsec_addhist(m
, IPPROTO_AH
, spi
) != 0 ||
853 ipsec_addhist(m
, IPPROTO_IPV6
, 0) != 0) {
854 ipsec6stat
.in_nomem
++;
858 if (netisr_queue(NETISR_IPV6
, m
)) {
859 ipsec6stat
.in_inval
++;
872 * Copy the value of the next header field of AH to the
873 * next header field of the previous header.
874 * This is necessary because AH will be stripped off below.
876 prvnxtp
= ip6_get_prevhdr(m
, off
); /* XXX */
879 ip6
= mtod(m
, struct ip6_hdr
*);
880 #ifndef PULLDOWN_TEST
882 * We do deep-copy since KAME requires that
883 * the packet is placed in a single mbuf.
885 bcopy((caddr_t
)ip6
, ((caddr_t
)ip6
) + stripsiz
, off
);
886 m
->m_data
+= stripsiz
;
887 m
->m_len
-= stripsiz
;
888 m
->m_pkthdr
.len
-= stripsiz
;
891 * even in m_pulldown case, we need to strip off AH so that
892 * we can compute checksum for multiple AH correctly.
894 if (m
->m_len
>= stripsiz
+ off
) {
895 bcopy((caddr_t
)ip6
, ((caddr_t
)ip6
) + stripsiz
, off
);
896 m
->m_data
+= stripsiz
;
897 m
->m_len
-= stripsiz
;
898 m
->m_pkthdr
.len
-= stripsiz
;
901 * this comes with no copy if the boundary is on
906 n
= m_split(m
, off
, M_NOWAIT
);
908 /* m is retained by m_split */
912 /* m_cat does not update m_pkthdr.len */
913 m
->m_pkthdr
.len
+= n
->m_pkthdr
.len
;
917 ip6
= mtod(m
, struct ip6_hdr
*);
919 ip6
->ip6_plen
= htons(ntohs(ip6
->ip6_plen
) - stripsiz
);
921 key_sa_recordxfer(sav
, m
);
922 if (ipsec_addhist(m
, IPPROTO_AH
, spi
) != 0) {
923 ipsec6stat
.in_nomem
++;
932 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
933 kprintf("DP ah6_input call free SA:%p\n", sav
));
936 ipsec6stat
.in_success
++;
941 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
942 kprintf("DP ah6_input call free SA:%p\n", sav
));
951 ah6_ctlinput(int cmd
, struct sockaddr
*sa
, void *d
)
953 const struct newah
*ahp
;
955 struct secasvar
*sav
;
958 struct ip6ctlparam
*ip6cp
= NULL
;
960 struct sockaddr_in6
*sa6_src
, *sa6_dst
;
962 if (sa
->sa_family
!= AF_INET6
||
963 sa
->sa_len
!= sizeof(struct sockaddr_in6
))
965 if ((unsigned)cmd
>= PRC_NCMDS
)
968 /* if the parameter is from icmp6, decode it. */
970 ip6cp
= (struct ip6ctlparam
*)d
;
972 ip6
= ip6cp
->ip6c_ip6
;
973 off
= ip6cp
->ip6c_off
;
977 off
= 0; /* fix warning */
982 * XXX: We assume that when ip6 is non NULL,
983 * M and OFF are valid.
986 /* check if we can safely examine src and dst ports */
987 if (m
->m_pkthdr
.len
< off
+ sizeof(ah
))
990 if (m
->m_len
< off
+ sizeof(ah
)) {
992 * this should be rare case,
993 * so we compromise on this copy...
995 m_copydata(m
, off
, sizeof(ah
), (caddr_t
)&ah
);
998 ahp
= (struct newah
*)(mtod(m
, caddr_t
) + off
);
1000 if (cmd
== PRC_MSGSIZE
) {
1004 * Check to see if we have a valid SA corresponding to
1005 * the address in the ICMP message payload.
1007 sa6_src
= ip6cp
->ip6c_src
;
1008 sa6_dst
= (struct sockaddr_in6
*)sa
;
1009 sav
= key_allocsa(AF_INET6
,
1010 (caddr_t
)&sa6_src
->sin6_addr
,
1011 (caddr_t
)&sa6_dst
->sin6_addr
,
1012 IPPROTO_AH
, ahp
->ah_spi
);
1014 if (sav
->state
== SADB_SASTATE_MATURE
||
1015 sav
->state
== SADB_SASTATE_DYING
)
1020 /* XXX Further validation? */
1023 * Depending on the value of "valid" and routing table
1024 * size (mtudisc_{hi,lo}wat), we will:
1025 * - recalcurate the new MTU and create the
1026 * corresponding routing entry, or
1027 * - ignore the MTU change notification.
1029 icmp6_mtudisc_update((struct ip6ctlparam
*)d
, valid
);
1032 /* we normally notify single pcb here */
1034 /* we normally notify any pcb here */