1 /* $NetBSD: ah_input.c,v 1.57 2008/04/24 11:38:38 ad Exp $ */
2 /* $KAME: ah_input.c,v 1.64 2001/09/04 08:43:19 itojun 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/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: ah_input.c,v 1.57 2008/04/24 11:38:38 ad Exp $");
41 #include "opt_ipsec.h"
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/malloc.h>
47 #include <sys/domain.h>
48 #include <sys/protosw.h>
49 #include <sys/socket.h>
50 #include <sys/errno.h>
52 #include <sys/kernel.h>
53 #include <sys/syslog.h>
56 #include <net/route.h>
57 #include <net/netisr.h>
60 #include <netinet/in.h>
61 #include <netinet/in_systm.h>
62 #include <netinet/in_var.h>
63 #include <netinet/in_proto.h>
64 #include <netinet/ip.h>
65 #include <netinet/ip_var.h>
66 #include <netinet/ip_ecn.h>
67 #include <netinet/ip_icmp.h>
69 #include <netinet/ip6.h>
72 #include <netinet6/ip6_var.h>
73 #include <netinet/icmp6.h>
74 #include <netinet6/ip6protosw.h>
77 #include <netinet6/ipsec.h>
78 #include <netinet6/ipsec_private.h>
79 #include <netinet6/ah.h>
80 #include <netkey/key.h>
81 #include <netkey/keydb.h>
82 #include <netkey/key_debug.h>
84 #include <machine/stdarg.h>
86 #include <net/net_osdep.h>
88 /*#define IPLEN_FLIPPED*/
100 ah4_input(struct mbuf
*m
, ...)
102 ah4_input(struct mbuf
*m
, va_alist
)
110 const struct ah_algorithm
*algo
;
113 u_int8_t cksum
[AH_MAXSUMSIZE
];
114 struct secasvar
*sav
= NULL
;
124 struct m_tag
*tag
= NULL
;
128 off
= va_arg(ap
, int);
129 proto
= va_arg(ap
, int);
133 /* find the source port for NAT-T */
134 if ((tag
= m_tag_find(m
, PACKET_TAG_IPSEC_NAT_T_PORTS
, NULL
)) != NULL
) {
135 sport
= ((u_int16_t
*)(tag
+ 1))[0];
136 dport
= ((u_int16_t
*)(tag
+ 1))[1];
140 ip
= mtod(m
, struct ip
*);
141 IP6_EXTHDR_GET(ah
, struct ah
*, m
, off
, sizeof(struct newah
));
143 ipseclog((LOG_DEBUG
, "IPv4 AH input: can't pullup;"
144 "dropping the packet for simplicity\n"));
145 IPSEC_STATINC(IPSEC_STAT_IN_INVAL
);
149 hlen
= ip
->ip_hl
<< 2;
151 /* find the sassoc. */
154 if ((sav
= key_allocsa(AF_INET
,
155 (const void *)&ip
->ip_src
,
156 (const void *)&ip
->ip_dst
,
157 IPPROTO_AH
, spi
, sport
, dport
)) == 0) {
158 ipseclog((LOG_WARNING
,
159 "IPv4 AH input: no key association found for spi %u\n",
160 (u_int32_t
)ntohl(spi
)));
161 IPSEC_STATINC(IPSEC_STAT_IN_NOSA
);
164 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
165 printf("DP ah4_input called to allocate SA:%p\n", sav
));
166 if (sav
->state
!= SADB_SASTATE_MATURE
&&
167 sav
->state
!= SADB_SASTATE_DYING
) {
169 "IPv4 AH input: non-mature/dying SA found for spi %u\n",
170 (u_int32_t
)ntohl(spi
)));
171 IPSEC_STATINC(IPSEC_STAT_IN_BADSPI
);
175 algo
= ah_algorithm_lookup(sav
->alg_auth
);
177 ipseclog((LOG_DEBUG
, "IPv4 AH input: "
178 "unsupported authentication algorithm for spi %u\n",
179 (u_int32_t
)ntohl(spi
)));
180 IPSEC_STATINC(IPSEC_STAT_IN_BADSPI
);
184 siz
= (*algo
->sumsiz
)(sav
);
185 siz1
= ((siz
+ 3) & ~(4 - 1));
188 * sanity checks for header, 1.
193 sizoff
= (sav
->flags
& SADB_X_EXT_OLD
) ? 0 : 4;
196 * Here, we do not do "siz1 == siz". This is because the way
197 * RFC240[34] section 2 is written. They do not require truncation
199 * For example, Microsoft IPsec stack attaches 160 bits of
200 * authentication data for both hmac-md5 and hmac-sha1. For hmac-sha1,
201 * 32 bits of padding is attached.
203 * There are two downsides to this specification.
204 * They have no real harm, however, they leave us fuzzy feeling.
205 * - if we attach more than 96 bits of authentication data onto AH,
206 * we will never notice about possible modification by rogue
207 * intermediate nodes.
208 * Since extra bits in AH checksum is never used, this constitutes
209 * no real issue, however, it is wacky.
210 * - even if the peer attaches big authentication data, we will never
211 * notice the difference, since longer authentication data will just
214 * We may need some clarification in the spec.
217 ipseclog((LOG_NOTICE
, "sum length too short in IPv4 AH input "
218 "(%lu, should be at least %lu): %s\n",
219 (u_long
)siz1
, (u_long
)siz
,
220 ipsec4_logpacketstr(ip
, spi
)));
221 IPSEC_STATINC(IPSEC_STAT_IN_INVAL
);
224 if ((ah
->ah_len
<< 2) - sizoff
!= siz1
) {
225 ipseclog((LOG_NOTICE
, "sum length mismatch in IPv4 AH input "
226 "(%d should be %lu): %s\n",
227 (ah
->ah_len
<< 2) - sizoff
, (u_long
)siz1
,
228 ipsec4_logpacketstr(ip
, spi
)));
229 IPSEC_STATINC(IPSEC_STAT_IN_INVAL
);
232 if (siz1
> sizeof(cksum
)) {
233 ipseclog((LOG_NOTICE
, "sum length too large: %s\n",
234 ipsec4_logpacketstr(ip
, spi
)));
235 IPSEC_STATINC(IPSEC_STAT_IN_INVAL
);
239 IP6_EXTHDR_GET(ah
, struct ah
*, m
, off
,
240 sizeof(struct ah
) + sizoff
+ siz1
);
242 ipseclog((LOG_DEBUG
, "IPv4 AH input: can't pullup\n"));
243 IPSEC_STATINC(IPSEC_STAT_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 IPSEC_STATINC(IPSEC_STAT_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.
271 * some of IP header fields are flipped to the host endian.
272 * convert them back to network endian. VERY stupid.
274 ip
->ip_len
= htons(ip
->ip_len
);
275 ip
->ip_off
= htons(ip
->ip_off
);
277 if (ah4_calccksum(m
, cksum
, siz1
, algo
, sav
)) {
278 IPSEC_STATINC(IPSEC_STAT_IN_INVAL
);
281 IPSEC_STATINC(IPSEC_STAT_IN_AHHIST
+ sav
->alg_auth
);
286 ip
->ip_len
= ntohs(ip
->ip_len
);
287 ip
->ip_off
= ntohs(ip
->ip_off
);
294 if (sav
->flags
& SADB_X_EXT_OLD
) {
296 sumpos
= (void *)(ah
+ 1);
299 sumpos
= (void *)(((struct newah
*)ah
) + 1);
302 if (memcmp(sumpos
, cksum
, siz
) != 0) {
303 ipseclog((LOG_WARNING
,
304 "checksum mismatch in IPv4 AH input: %s %s\n",
305 ipsec4_logpacketstr(ip
, spi
), ipsec_logsastr(sav
)));
306 IPSEC_STATINC(IPSEC_STAT_IN_AHAUTHFAIL
);
311 m
->m_flags
|= M_AUTHIPHDR
;
312 m
->m_flags
|= M_AUTHIPDGM
;
316 * looks okey, but we need more sanity check.
317 * XXX should elaborate.
319 if (ah
->ah_nxt
== IPPROTO_IPIP
|| ah
->ah_nxt
== IPPROTO_IP
) {
323 sizoff
= (sav
->flags
& SADB_X_EXT_OLD
) ? 0 : 4;
325 if (m
->m_len
< off
+ sizeof(struct ah
) + sizoff
+ siz1
+ hlen
) {
326 m
= m_pullup(m
, off
+ sizeof(struct ah
)
327 + sizoff
+ siz1
+ hlen
);
330 "IPv4 AH input: can't pullup\n"));
331 IPSEC_STATINC(IPSEC_STAT_IN_INVAL
);
336 nip
= (struct ip
*)((u_char
*)(ah
+ 1) + sizoff
+ siz1
);
337 if (nip
->ip_src
.s_addr
!= ip
->ip_src
.s_addr
338 || nip
->ip_dst
.s_addr
!= ip
->ip_dst
.s_addr
) {
339 m
->m_flags
&= ~M_AUTHIPHDR
;
340 m
->m_flags
&= ~M_AUTHIPDGM
;
344 else if (ah
->ah_nxt
== IPPROTO_IPV6
) {
345 m
->m_flags
&= ~M_AUTHIPHDR
;
346 m
->m_flags
&= ~M_AUTHIPDGM
;
351 if (m
->m_flags
& M_AUTHIPHDR
&& m
->m_flags
& M_AUTHIPDGM
) {
354 "IPv4 AH input: authentication succeess\n"));
356 IPSEC_STATINC(IPSEC_STAT_IN_AHAUTHSUCC
);
358 ipseclog((LOG_WARNING
,
359 "authentication failed in IPv4 AH input: %s %s\n",
360 ipsec4_logpacketstr(ip
, spi
), ipsec_logsastr(sav
)));
361 IPSEC_STATINC(IPSEC_STAT_IN_AHAUTHFAIL
);
366 * update sequence number.
368 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0 && sav
->replay
) {
369 if (ipsec_updatereplay(ntohl(((struct newah
*)ah
)->ah_seq
), sav
)) {
370 IPSEC_STATINC(IPSEC_STAT_IN_AHREPLAY
);
375 /* was it transmitted over the IPsec tunnel SA? */
376 if (sav
->flags
& SADB_X_EXT_OLD
) {
378 stripsiz
= sizeof(struct ah
) + siz1
;
381 stripsiz
= sizeof(struct newah
) + siz1
;
383 if (ipsec4_tunnel_validate(ip
, nxt
, sav
)) {
385 * strip off all the headers that precedes AH.
386 * IP xx AH IP' payload -> IP' payload
388 * XXX more sanity checks
389 * XXX relationship with gif?
394 m_adj(m
, off
+ stripsiz
);
395 if (m
->m_len
< sizeof(*ip
)) {
396 m
= m_pullup(m
, sizeof(*ip
));
398 IPSEC_STATINC(IPSEC_STAT_IN_INVAL
);
402 ip
= mtod(m
, struct ip
*);
403 /* ECN consideration. */
404 ip_ecn_egress(ip4_ipsec_ecn
, &tos
, &ip
->ip_tos
);
405 if (!key_checktunnelsanity(sav
, AF_INET
,
406 (void *)&ip
->ip_src
, (void *)&ip
->ip_dst
)) {
407 ipseclog((LOG_NOTICE
, "ipsec tunnel address mismatch "
408 "in IPv4 AH input: %s %s\n",
409 ipsec4_logpacketstr(ip
, spi
), ipsec_logsastr(sav
)));
410 IPSEC_STATINC(IPSEC_STAT_IN_INVAL
);
414 key_sa_recordxfer(sav
, m
);
415 if (ipsec_addhist(m
, IPPROTO_AH
, spi
) != 0 ||
416 ipsec_addhist(m
, IPPROTO_IPV4
, 0) != 0) {
417 IPSEC_STATINC(IPSEC_STAT_IN_NOMEM
);
422 if (IF_QFULL(&ipintrq
)) {
423 IPSEC_STATINC(IPSEC_STAT_IN_INVAL
);
427 IF_ENQUEUE(&ipintrq
, m
);
429 schednetisr(NETISR_IP
); /* can be skipped but to make sure */
437 ip
= mtod(m
, struct ip
*);
439 * even in m_pulldown case, we need to strip off AH so that
440 * we can compute checksum for multiple AH correctly.
442 if (m
->m_len
>= stripsiz
+ off
) {
443 (void)memmove((char *)ip
+ stripsiz
, ip
, off
);
444 m
->m_data
+= stripsiz
;
445 m
->m_len
-= stripsiz
;
446 m
->m_pkthdr
.len
-= stripsiz
;
449 * this comes with no copy if the boundary is on
454 n
= m_split(m
, off
, M_DONTWAIT
);
456 /* m is retained by m_split */
460 /* m_cat does not update m_pkthdr.len */
461 m
->m_pkthdr
.len
+= n
->m_pkthdr
.len
;
465 if (m
->m_len
< sizeof(*ip
)) {
466 m
= m_pullup(m
, sizeof(*ip
));
468 IPSEC_STATINC(IPSEC_STAT_IN_INVAL
);
472 ip
= mtod(m
, struct ip
*);
474 ip
->ip_len
= ip
->ip_len
- stripsiz
;
476 ip
->ip_len
= htons(ntohs(ip
->ip_len
) - stripsiz
);
479 /* forget about IP hdr checksum, the check has already been passed */
481 key_sa_recordxfer(sav
, m
);
482 if (ipsec_addhist(m
, IPPROTO_AH
, spi
) != 0) {
483 IPSEC_STATINC(IPSEC_STAT_IN_NOMEM
);
487 if (nxt
!= IPPROTO_DONE
) {
488 if ((inetsw
[ip_protox
[nxt
]].pr_flags
& PR_LASTHDR
) != 0 &&
489 ipsec4_in_reject(m
, NULL
)) {
490 IPSEC_STATINC(IPSEC_STAT_IN_POLVIO
);
493 (*inetsw
[ip_protox
[nxt
]].pr_input
)(m
, off
, nxt
);
500 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
501 printf("DP ah4_input call free SA:%p\n", sav
));
504 IPSEC_STATINC(IPSEC_STAT_IN_SUCCESS
);
509 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
510 printf("DP ah4_input call free SA:%p\n", sav
));
518 /* assumes that ip header and ah header are contiguous on mbuf */
520 ah4_ctlinput(int cmd
, const struct sockaddr
*sa
, void *v
)
525 struct secasvar
*sav
;
527 if (sa
->sa_family
!= AF_INET
||
528 sa
->sa_len
!= sizeof(struct sockaddr_in
))
530 if ((unsigned)cmd
>= PRC_NCMDS
)
532 if (cmd
== PRC_MSGSIZE
&& ip_mtudisc
&& ip
&& ip
->ip_v
== 4) {
534 * Check to see if we have a valid SA corresponding to
535 * the address in the ICMP message payload.
537 ah
= (struct ah
*)((char *)ip
+ (ip
->ip_hl
<< 2));
538 if ((sav
= key_allocsa(AF_INET
,
539 (void *) &ip
->ip_src
,
540 (void *) &ip
->ip_dst
,
541 IPPROTO_AH
, ah
->ah_spi
, 0, 0)) == NULL
)
543 if (sav
->state
!= SADB_SASTATE_MATURE
&&
544 sav
->state
!= SADB_SASTATE_DYING
) {
549 /* XXX Further validation? */
554 * Now that we've validated that we are actually communicating
555 * with the host indicated in the ICMP message, locate the
556 * ICMP header, recalculate the new MTU, and create the
557 * corresponding routing entry.
559 icp
= (struct icmp
*)((char *)ip
-
560 offsetof(struct icmp
, icmp_ip
));
561 icmp_mtudisc(icp
, ip
->ip_dst
);
579 ah6_input(struct mbuf
**mp
, int *offp
, int proto
)
581 struct mbuf
*m
= *mp
;
586 const struct ah_algorithm
*algo
;
589 u_int8_t cksum
[AH_MAXSUMSIZE
];
590 struct secasvar
*sav
= NULL
;
595 IP6_EXTHDR_GET(ah
, struct ah
*, m
, off
, sizeof(struct newah
));
597 ipseclog((LOG_DEBUG
, "IPv6 AH input: can't pullup\n"));
598 IPSEC6_STATINC(IPSEC_STAT_IN_INVAL
);
601 ip6
= mtod(m
, struct ip6_hdr
*);
604 /* find the sassoc. */
607 if (ntohs(ip6
->ip6_plen
) == 0) {
608 ipseclog((LOG_ERR
, "IPv6 AH input: "
609 "AH with IPv6 jumbogram is not supported.\n"));
610 IPSEC6_STATINC(IPSEC_STAT_IN_INVAL
);
614 if ((sav
= key_allocsa(AF_INET6
,
615 (void *)&ip6
->ip6_src
, (void *)&ip6
->ip6_dst
,
616 IPPROTO_AH
, spi
, 0, 0)) == 0) {
617 ipseclog((LOG_WARNING
,
618 "IPv6 AH input: no key association found for spi %u\n",
619 (u_int32_t
)ntohl(spi
)));
620 IPSEC6_STATINC(IPSEC_STAT_IN_NOSA
);
623 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
624 printf("DP ah6_input called to allocate SA:%p\n", sav
));
625 if (sav
->state
!= SADB_SASTATE_MATURE
&&
626 sav
->state
!= SADB_SASTATE_DYING
) {
628 "IPv6 AH input: non-mature/dying SA found for spi %u; ",
629 (u_int32_t
)ntohl(spi
)));
630 IPSEC6_STATINC(IPSEC_STAT_IN_BADSPI
);
634 algo
= ah_algorithm_lookup(sav
->alg_auth
);
636 ipseclog((LOG_DEBUG
, "IPv6 AH input: "
637 "unsupported authentication algorithm for spi %u\n",
638 (u_int32_t
)ntohl(spi
)));
639 IPSEC6_STATINC(IPSEC_STAT_IN_BADSPI
);
643 siz
= (*algo
->sumsiz
)(sav
);
644 siz1
= ((siz
+ 3) & ~(4 - 1));
647 * sanity checks for header, 1.
652 sizoff
= (sav
->flags
& SADB_X_EXT_OLD
) ? 0 : 4;
655 * Here, we do not do "siz1 == siz". See ah4_input() for complete
659 ipseclog((LOG_NOTICE
, "sum length too short in IPv6 AH input "
660 "(%lu, should be at least %lu): %s\n",
661 (u_long
)siz1
, (u_long
)siz
,
662 ipsec6_logpacketstr(ip6
, spi
)));
663 IPSEC6_STATINC(IPSEC_STAT_IN_INVAL
);
666 if ((ah
->ah_len
<< 2) - sizoff
!= siz1
) {
667 ipseclog((LOG_NOTICE
, "sum length mismatch in IPv6 AH input "
668 "(%d should be %lu): %s\n",
669 (ah
->ah_len
<< 2) - sizoff
, (u_long
)siz1
,
670 ipsec6_logpacketstr(ip6
, spi
)));
671 IPSEC6_STATINC(IPSEC_STAT_IN_INVAL
);
674 if (siz1
> sizeof(cksum
)) {
675 ipseclog((LOG_NOTICE
, "sum length too large: %s\n",
676 ipsec6_logpacketstr(ip6
, spi
)));
677 IPSEC6_STATINC(IPSEC_STAT_IN_INVAL
);
681 IP6_EXTHDR_GET(ah
, struct ah
*, m
, off
,
682 sizeof(struct ah
) + sizoff
+ siz1
);
684 ipseclog((LOG_NOTICE
, "couldn't pullup gather IPv6 AH checksum part"));
685 IPSEC6_STATINC(IPSEC_STAT_IN_INVAL
);
692 * check for sequence number.
694 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0 && sav
->replay
) {
695 if (ipsec_chkreplay(ntohl(((struct newah
*)ah
)->ah_seq
), sav
))
698 IPSEC6_STATINC(IPSEC_STAT_IN_AHREPLAY
);
699 ipseclog((LOG_WARNING
,
700 "replay packet in IPv6 AH input: %s %s\n",
701 ipsec6_logpacketstr(ip6
, spi
),
702 ipsec_logsastr(sav
)));
708 * alright, it seems sane. now we are going to check the
709 * cryptographic checksum.
712 if (ah6_calccksum(m
, cksum
, siz1
, algo
, sav
)) {
713 IPSEC6_STATINC(IPSEC_STAT_IN_INVAL
);
716 IPSEC6_STATINC(IPSEC_STAT_IN_AHHIST
+ sav
->alg_auth
);
721 if (sav
->flags
& SADB_X_EXT_OLD
) {
723 sumpos
= (void *)(ah
+ 1);
726 sumpos
= (void *)(((struct newah
*)ah
) + 1);
729 if (memcmp(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 IPSEC6_STATINC(IPSEC_STAT_IN_AHAUTHFAIL
);
738 m
->m_flags
|= M_AUTHIPHDR
;
739 m
->m_flags
|= M_AUTHIPDGM
;
743 * looks okey, but we need more sanity check.
744 * XXX should elaborate.
746 if (ah
->ah_nxt
== IPPROTO_IPV6
) {
747 struct ip6_hdr
*nip6
;
750 sizoff
= (sav
->flags
& SADB_X_EXT_OLD
) ? 0 : 4;
752 IP6_EXTHDR_CHECK(m
, off
, sizeof(struct ah
) + sizoff
+ siz1
753 + sizeof(struct ip6_hdr
), IPPROTO_DONE
);
755 nip6
= (struct ip6_hdr
*)((u_char
*)(ah
+ 1) + sizoff
+ siz1
);
756 if (!IN6_ARE_ADDR_EQUAL(&nip6
->ip6_src
, &ip6
->ip6_src
)
757 || !IN6_ARE_ADDR_EQUAL(&nip6
->ip6_dst
, &ip6
->ip6_dst
)) {
758 m
->m_flags
&= ~M_AUTHIPHDR
;
759 m
->m_flags
&= ~M_AUTHIPDGM
;
761 } else if (ah
->ah_nxt
== IPPROTO_IPIP
) {
762 m
->m_flags
&= ~M_AUTHIPHDR
;
763 m
->m_flags
&= ~M_AUTHIPDGM
;
764 } else if (ah
->ah_nxt
== IPPROTO_IP
) {
765 m
->m_flags
&= ~M_AUTHIPHDR
;
766 m
->m_flags
&= ~M_AUTHIPDGM
;
770 if (m
->m_flags
& M_AUTHIPHDR
&& m
->m_flags
& M_AUTHIPDGM
) {
773 "IPv6 AH input: authentication succeess\n"));
775 IPSEC6_STATINC(IPSEC_STAT_IN_AHAUTHSUCC
);
777 ipseclog((LOG_WARNING
,
778 "authentication failed in IPv6 AH input: %s %s\n",
779 ipsec6_logpacketstr(ip6
, spi
), ipsec_logsastr(sav
)));
780 IPSEC6_STATINC(IPSEC_STAT_IN_AHAUTHFAIL
);
785 * update sequence number.
787 if ((sav
->flags
& SADB_X_EXT_OLD
) == 0 && sav
->replay
) {
788 if (ipsec_updatereplay(ntohl(((struct newah
*)ah
)->ah_seq
), sav
)) {
789 IPSEC6_STATINC(IPSEC_STAT_IN_AHREPLAY
);
794 /* was it transmitted over the IPsec tunnel SA? */
795 if (sav
->flags
& SADB_X_EXT_OLD
) {
797 stripsiz
= sizeof(struct ah
) + siz1
;
800 stripsiz
= sizeof(struct newah
) + siz1
;
802 if (ipsec6_tunnel_validate(ip6
, nxt
, sav
)) {
804 * strip off all the headers that precedes AH.
805 * IP6 xx AH IP6' payload -> IP6' payload
807 * XXX more sanity checks
808 * XXX relationship with gif?
810 u_int32_t flowinfo
; /* net endian */
812 flowinfo
= ip6
->ip6_flow
;
813 m_adj(m
, off
+ stripsiz
);
814 if (m
->m_len
< sizeof(*ip6
)) {
815 m
= m_pullup(m
, sizeof(*ip6
));
817 IPSEC6_STATINC(IPSEC_STAT_IN_INVAL
);
821 ip6
= mtod(m
, struct ip6_hdr
*);
822 /* ECN consideration. */
823 ip6_ecn_egress(ip6_ipsec_ecn
, &flowinfo
, &ip6
->ip6_flow
);
824 if (!key_checktunnelsanity(sav
, AF_INET6
,
825 (void *)&ip6
->ip6_src
, (void *)&ip6
->ip6_dst
)) {
826 ipseclog((LOG_NOTICE
, "ipsec tunnel address mismatch "
827 "in IPv6 AH input: %s %s\n",
828 ipsec6_logpacketstr(ip6
, spi
),
829 ipsec_logsastr(sav
)));
830 IPSEC6_STATINC(IPSEC_STAT_IN_INVAL
);
834 key_sa_recordxfer(sav
, m
);
835 if (ipsec_addhist(m
, IPPROTO_AH
, spi
) != 0 ||
836 ipsec_addhist(m
, IPPROTO_IPV6
, 0) != 0) {
837 IPSEC6_STATINC(IPSEC_STAT_IN_NOMEM
);
842 if (IF_QFULL(&ip6intrq
)) {
843 IPSEC6_STATINC(IPSEC_STAT_IN_INVAL
);
847 IF_ENQUEUE(&ip6intrq
, m
);
849 schednetisr(NETISR_IPV6
); /* can be skipped but to make sure */
859 * Copy the value of the next header field of AH to the
860 * next header field of the previous header.
861 * This is necessary because AH will be stripped off below.
863 prvnxtp
= ip6_get_prevhdr(m
, off
); /* XXX */
866 ip6
= mtod(m
, struct ip6_hdr
*);
868 * even in m_pulldown case, we need to strip off AH so that
869 * we can compute checksum for multiple AH correctly.
871 if (m
->m_len
>= stripsiz
+ off
) {
872 (void)memmove((char *)ip6
+ stripsiz
, ip6
, off
);
873 m
->m_data
+= stripsiz
;
874 m
->m_len
-= stripsiz
;
875 m
->m_pkthdr
.len
-= stripsiz
;
878 * this comes with no copy if the boundary is on
883 n
= m_split(m
, off
, M_DONTWAIT
);
885 /* m is retained by m_split */
889 /* m_cat does not update m_pkthdr.len */
890 m
->m_pkthdr
.len
+= n
->m_pkthdr
.len
;
893 ip6
= mtod(m
, struct ip6_hdr
*);
895 ip6
->ip6_plen
= htons(ntohs(ip6
->ip6_plen
) - stripsiz
);
897 key_sa_recordxfer(sav
, m
);
898 if (ipsec_addhist(m
, IPPROTO_AH
, spi
) != 0) {
899 IPSEC6_STATINC(IPSEC_STAT_IN_NOMEM
);
908 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
909 printf("DP ah6_input call free SA:%p\n", sav
));
912 IPSEC6_STATINC(IPSEC_STAT_IN_SUCCESS
);
917 KEYDEBUG(KEYDEBUG_IPSEC_STAMP
,
918 printf("DP ah6_input call free SA:%p\n", sav
));
927 ah6_ctlinput(int cmd
, const struct sockaddr
*sa
, void *d
)
929 const struct newah
*ahp
;
931 struct secasvar
*sav
;
934 struct ip6ctlparam
*ip6cp
= NULL
;
936 const struct sockaddr_in6
*sa6_src
, *sa6_dst
;
938 if (sa
->sa_family
!= AF_INET6
||
939 sa
->sa_len
!= sizeof(struct sockaddr_in6
))
941 if ((unsigned)cmd
>= PRC_NCMDS
)
944 /* if the parameter is from icmp6, decode it. */
946 ip6cp
= (struct ip6ctlparam
*)d
;
948 ip6
= ip6cp
->ip6c_ip6
;
949 off
= ip6cp
->ip6c_off
;
958 * XXX: We assume that when ip6 is non NULL,
959 * M and OFF are valid.
962 /* check if we can safely examine src and dst ports */
963 if (m
->m_pkthdr
.len
< off
+ sizeof(ah
))
966 if (m
->m_len
< off
+ sizeof(ah
)) {
968 * this should be rare case,
969 * so we compromise on this copy...
971 m_copydata(m
, off
, sizeof(ah
), &ah
);
974 ahp
= (struct newah
*)(mtod(m
, char *) + off
);
976 if (cmd
== PRC_MSGSIZE
) {
980 * Check to see if we have a valid SA corresponding to
981 * the address in the ICMP message payload.
983 sa6_src
= ip6cp
->ip6c_src
;
984 sa6_dst
= (const struct sockaddr_in6
*)sa
;
985 sav
= key_allocsa(AF_INET6
,
986 (const void *)&sa6_src
->sin6_addr
,
987 (const void *)&sa6_dst
->sin6_addr
,
988 IPPROTO_AH
, ahp
->ah_spi
, 0, 0);
990 if (sav
->state
== SADB_SASTATE_MATURE
||
991 sav
->state
== SADB_SASTATE_DYING
)
996 /* XXX Further validation? */
999 * Depending on the value of "valid" and routing table
1000 * size (mtudisc_{hi,lo}wat), we will:
1001 * - recalcurate the new MTU and create the
1002 * corresponding routing entry, or
1003 * - ignore the MTU change notification.
1005 icmp6_mtudisc_update((struct ip6ctlparam
*)d
, valid
);
1008 /* we normally notify single pcb here */
1010 /* we normally notify any pcb here */