]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet6/ah_input.c
xnu-2050.7.9.tar.gz
[apple/xnu.git] / bsd / netinet6 / ah_input.c
CommitLineData
b0d623f7 1/*
316670eb 2 * Copyright (c) 2008-2011 Apple Inc. All rights reserved.
b0d623f7
A
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
55e303ae
A
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 $ */
9bccf70c 31
1c79356b
A
32/*
33 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
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.
47 *
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
58 * SUCH DAMAGE.
59 */
60
61/*
62 * RFC1826/2402 authentication header.
63 */
64
1c79356b
A
65#include <sys/param.h>
66#include <sys/systm.h>
67#include <sys/malloc.h>
68#include <sys/mbuf.h>
316670eb 69#include <sys/mcache.h>
1c79356b
A
70#include <sys/domain.h>
71#include <sys/protosw.h>
72#include <sys/socket.h>
73#include <sys/errno.h>
74#include <sys/time.h>
75#include <sys/kernel.h>
76#include <sys/syslog.h>
77
78#include <net/if.h>
79#include <net/route.h>
1c79356b 80#include <kern/cpu_number.h>
91447636 81#include <kern/locks.h>
1c79356b
A
82
83#include <netinet/in.h>
84#include <netinet/in_systm.h>
85#include <netinet/in_var.h>
86#include <netinet/ip.h>
87#include <netinet/ip_var.h>
88#include <netinet/ip_ecn.h>
9bccf70c
A
89#include <netinet/in_pcb.h>
90#if INET6
91#include <netinet6/ip6_ecn.h>
92#endif
1c79356b
A
93
94#if INET6
95#include <netinet/ip6.h>
96#include <netinet6/ip6_var.h>
9bccf70c 97#include <netinet6/in6_pcb.h>
1c79356b 98#include <netinet/icmp6.h>
9bccf70c 99#include <netinet6/ip6protosw.h>
1c79356b
A
100#endif
101
102#include <netinet6/ipsec.h>
9bccf70c
A
103#if INET6
104#include <netinet6/ipsec6.h>
105#endif
1c79356b 106#include <netinet6/ah.h>
9bccf70c
A
107#if INET6
108#include <netinet6/ah6.h>
109#endif
1c79356b
A
110#include <netkey/key.h>
111#include <netkey/keydb.h>
9bccf70c 112#if IPSEC_DEBUG
1c79356b 113#include <netkey/key_debug.h>
9bccf70c
A
114#else
115#define KEYDEBUG(lev,arg)
116#endif
1c79356b 117
2d21ac55
A
118#include <net/kpi_protocol.h>
119#include <netinet/kpi_ipfilter_var.h>
6d2010ae 120#include <mach/sdt.h>
1c79356b
A
121
122#include <net/net_osdep.h>
123
124#define IPLEN_FLIPPED
125
126#if INET
127extern struct protosw inetsw[];
1c79356b
A
128
129void
130ah4_input(struct mbuf *m, int off)
131{
132 struct ip *ip;
133 struct ah *ah;
134 u_int32_t spi;
9bccf70c 135 const struct ah_algorithm *algo;
1c79356b
A
136 size_t siz;
137 size_t siz1;
138 u_char *cksum;
139 struct secasvar *sav = NULL;
140 u_int16_t nxt;
141 size_t hlen;
9bccf70c 142 size_t stripsiz = 0;
2d21ac55 143 sa_family_t ifamily;
1c79356b
A
144
145#ifndef PULLDOWN_TEST
146 if (m->m_len < off + sizeof(struct newah)) {
147 m = m_pullup(m, off + sizeof(struct newah));
148 if (!m) {
149 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;"
150 "dropping the packet for simplicity\n"));
2d21ac55 151 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
152 goto fail;
153 }
154 }
155
316670eb
A
156 /* Expect 32-bit aligned data pointer on strict-align platforms */
157 MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
158
1c79356b 159 ip = mtod(m, struct ip *);
316670eb 160 ah = (struct ah *)(void *)(((caddr_t)ip) + off);
1c79356b 161#else
316670eb
A
162 /* Expect 32-bit aligned data pointer on strict-align platforms */
163 MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
164
1c79356b
A
165 ip = mtod(m, struct ip *);
166 IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah));
167 if (ah == NULL) {
168 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;"
169 "dropping the packet for simplicity\n"));
2d21ac55 170 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
171 goto fail;
172 }
173#endif
174 nxt = ah->ah_nxt;
175#ifdef _IP_VHL
176 hlen = IP_VHL_HL(ip->ip_vhl) << 2;
177#else
178 hlen = ip->ip_hl << 2;
179#endif
180
181 /* find the sassoc. */
182 spi = ah->ah_spi;
183
184 if ((sav = key_allocsa(AF_INET,
185 (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst,
186 IPPROTO_AH, spi)) == 0) {
187 ipseclog((LOG_WARNING,
188 "IPv4 AH input: no key association found for spi %u\n",
189 (u_int32_t)ntohl(spi)));
2d21ac55 190 IPSEC_STAT_INCREMENT(ipsecstat.in_nosa);
1c79356b
A
191 goto fail;
192 }
193 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
194 printf("DP ah4_input called to allocate SA:%p\n", sav));
195 if (sav->state != SADB_SASTATE_MATURE
196 && sav->state != SADB_SASTATE_DYING) {
197 ipseclog((LOG_DEBUG,
198 "IPv4 AH input: non-mature/dying SA found for spi %u\n",
199 (u_int32_t)ntohl(spi)));
2d21ac55 200 IPSEC_STAT_INCREMENT(ipsecstat.in_badspi);
1c79356b
A
201 goto fail;
202 }
9bccf70c
A
203
204 algo = ah_algorithm_lookup(sav->alg_auth);
205 if (!algo) {
1c79356b 206 ipseclog((LOG_DEBUG, "IPv4 AH input: "
9bccf70c 207 "unsupported authentication algorithm for spi %u\n",
1c79356b 208 (u_int32_t)ntohl(spi)));
2d21ac55 209 IPSEC_STAT_INCREMENT(ipsecstat.in_badspi);
1c79356b
A
210 goto fail;
211 }
212
1c79356b
A
213 siz = (*algo->sumsiz)(sav);
214 siz1 = ((siz + 3) & ~(4 - 1));
215
216 /*
217 * sanity checks for header, 1.
218 */
219 {
220 int sizoff;
221
222 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
223
9bccf70c
A
224 /*
225 * Here, we do not do "siz1 == siz". This is because the way
226 * RFC240[34] section 2 is written. They do not require truncation
227 * to 96 bits.
228 * For example, Microsoft IPsec stack attaches 160 bits of
229 * authentication data for both hmac-md5 and hmac-sha1. For hmac-sha1,
230 * 32 bits of padding is attached.
231 *
232 * There are two downsides to this specification.
233 * They have no real harm, however, they leave us fuzzy feeling.
234 * - if we attach more than 96 bits of authentication data onto AH,
235 * we will never notice about possible modification by rogue
236 * intermediate nodes.
237 * Since extra bits in AH checksum is never used, this constitutes
238 * no real issue, however, it is wacky.
239 * - even if the peer attaches big authentication data, we will never
240 * notice the difference, since longer authentication data will just
241 * work.
242 *
243 * We may need some clarification in the spec.
244 */
245 if (siz1 < siz) {
246 ipseclog((LOG_NOTICE, "sum length too short in IPv4 AH input "
247 "(%lu, should be at least %lu): %s\n",
b0d623f7 248 (u_int32_t)siz1, (u_int32_t)siz,
9bccf70c 249 ipsec4_logpacketstr(ip, spi)));
2d21ac55 250 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
9bccf70c
A
251 goto fail;
252 }
1c79356b
A
253 if ((ah->ah_len << 2) - sizoff != siz1) {
254 ipseclog((LOG_NOTICE, "sum length mismatch in IPv4 AH input "
9bccf70c 255 "(%d should be %lu): %s\n",
b0d623f7 256 (ah->ah_len << 2) - sizoff, (u_int32_t)siz1,
9bccf70c 257 ipsec4_logpacketstr(ip, spi)));
2d21ac55 258 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
259 goto fail;
260 }
261
262#ifndef PULLDOWN_TEST
263 if (m->m_len < off + sizeof(struct ah) + sizoff + siz1) {
264 m = m_pullup(m, off + sizeof(struct ah) + sizoff + siz1);
265 if (!m) {
266 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n"));
2d21ac55 267 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
268 goto fail;
269 }
316670eb
A
270 /* Expect 32-bit aligned data ptr on strict-align platforms */
271 MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
1c79356b
A
272
273 ip = mtod(m, struct ip *);
316670eb 274 ah = (struct ah *)(void *)(((caddr_t)ip) + off);
1c79356b
A
275 }
276#else
277 IP6_EXTHDR_GET(ah, struct ah *, m, off,
278 sizeof(struct ah) + sizoff + siz1);
279 if (ah == NULL) {
280 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n"));
2d21ac55 281 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
282 goto fail;
283 }
284#endif
285 }
286
287 /*
288 * check for sequence number.
289 */
290 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
291 if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav))
292 ; /*okey*/
293 else {
2d21ac55 294 IPSEC_STAT_INCREMENT(ipsecstat.in_ahreplay);
1c79356b
A
295 ipseclog((LOG_WARNING,
296 "replay packet in IPv4 AH input: %s %s\n",
297 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
298 goto fail;
299 }
300 }
301
302 /*
303 * alright, it seems sane. now we are going to check the
304 * cryptographic checksum.
305 */
306 cksum = _MALLOC(siz1, M_TEMP, M_NOWAIT);
307 if (!cksum) {
308 ipseclog((LOG_DEBUG, "IPv4 AH input: "
309 "couldn't alloc temporary region for cksum\n"));
2d21ac55 310 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
311 goto fail;
312 }
313
1c79356b
A
314 /*
315 * some of IP header fields are flipped to the host endian.
316 * convert them back to network endian. VERY stupid.
317 */
1c79356b 318 ip->ip_len = htons(ip->ip_len + hlen);
1c79356b 319 ip->ip_off = htons(ip->ip_off);
9bccf70c
A
320 if (ah4_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) {
321 FREE(cksum, M_TEMP);
2d21ac55 322 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
323 goto fail;
324 }
2d21ac55 325 IPSEC_STAT_INCREMENT(ipsecstat.in_ahhist[sav->alg_auth]);
1c79356b
A
326 /*
327 * flip them back.
328 */
1c79356b 329 ip->ip_len = ntohs(ip->ip_len) - hlen;
1c79356b 330 ip->ip_off = ntohs(ip->ip_off);
1c79356b
A
331
332 {
333 caddr_t sumpos = NULL;
334
335 if (sav->flags & SADB_X_EXT_OLD) {
336 /* RFC 1826 */
337 sumpos = (caddr_t)(ah + 1);
338 } else {
339 /* RFC 2402 */
340 sumpos = (caddr_t)(((struct newah *)ah) + 1);
341 }
342
343 if (bcmp(sumpos, cksum, siz) != 0) {
344 ipseclog((LOG_WARNING,
345 "checksum mismatch in IPv4 AH input: %s %s\n",
346 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
9bccf70c 347 FREE(cksum, M_TEMP);
2d21ac55 348 IPSEC_STAT_INCREMENT(ipsecstat.in_ahauthfail);
1c79356b
A
349 goto fail;
350 }
351 }
352
9bccf70c 353 FREE(cksum, M_TEMP);
1c79356b
A
354
355 m->m_flags |= M_AUTHIPHDR;
356 m->m_flags |= M_AUTHIPDGM;
357
358#if 0
359 /*
360 * looks okey, but we need more sanity check.
361 * XXX should elaborate.
362 */
363 if (ah->ah_nxt == IPPROTO_IPIP || ah->ah_nxt == IPPROTO_IP) {
364 struct ip *nip;
365 size_t sizoff;
366
367 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
368
369 if (m->m_len < off + sizeof(struct ah) + sizoff + siz1 + hlen) {
370 m = m_pullup(m, off + sizeof(struct ah)
371 + sizoff + siz1 + hlen);
372 if (!m) {
373 ipseclog((LOG_DEBUG,
374 "IPv4 AH input: can't pullup\n"));
2d21ac55 375 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
376 goto fail;
377 }
378 }
379
380 nip = (struct ip *)((u_char *)(ah + 1) + sizoff + siz1);
381 if (nip->ip_src.s_addr != ip->ip_src.s_addr
382 || nip->ip_dst.s_addr != ip->ip_dst.s_addr) {
383 m->m_flags &= ~M_AUTHIPHDR;
384 m->m_flags &= ~M_AUTHIPDGM;
385 }
386 }
387#if INET6
388 else if (ah->ah_nxt == IPPROTO_IPV6) {
389 m->m_flags &= ~M_AUTHIPHDR;
390 m->m_flags &= ~M_AUTHIPDGM;
391 }
392#endif /*INET6*/
393#endif /*0*/
394
395 if (m->m_flags & M_AUTHIPHDR
396 && m->m_flags & M_AUTHIPDGM) {
397#if 0
398 ipseclog((LOG_DEBUG,
399 "IPv4 AH input: authentication succeess\n"));
400#endif
2d21ac55 401 IPSEC_STAT_INCREMENT(ipsecstat.in_ahauthsucc);
1c79356b
A
402 } else {
403 ipseclog((LOG_WARNING,
404 "authentication failed in IPv4 AH input: %s %s\n",
405 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
2d21ac55 406 IPSEC_STAT_INCREMENT(ipsecstat.in_ahauthfail);
1c79356b
A
407 goto fail;
408 }
409
410 /*
411 * update sequence number.
412 */
413 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
414 if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) {
2d21ac55 415 IPSEC_STAT_INCREMENT(ipsecstat.in_ahreplay);
1c79356b
A
416 goto fail;
417 }
418 }
419
420 /* was it transmitted over the IPsec tunnel SA? */
9bccf70c
A
421 if (sav->flags & SADB_X_EXT_OLD) {
422 /* RFC 1826 */
423 stripsiz = sizeof(struct ah) + siz1;
424 } else {
425 /* RFC 2402 */
426 stripsiz = sizeof(struct newah) + siz1;
427 }
2d21ac55 428 if (ipsec4_tunnel_validate(m, off + stripsiz, nxt, sav, &ifamily)) {
6d2010ae
A
429 ifaddr_t ifa;
430 struct sockaddr_storage addr;
431
1c79356b
A
432 /*
433 * strip off all the headers that precedes AH.
434 * IP xx AH IP' payload -> IP' payload
435 *
436 * XXX more sanity checks
437 * XXX relationship with gif?
438 */
1c79356b 439 u_int8_t tos;
2d21ac55
A
440
441 if (ifamily == AF_INET6) {
442 ipseclog((LOG_NOTICE, "ipsec tunnel protocol mismatch "
443 "in IPv4 AH input: %s\n", ipsec_logsastr(sav)));
444 goto fail;
445 }
1c79356b 446 tos = ip->ip_tos;
1c79356b
A
447 m_adj(m, off + stripsiz);
448 if (m->m_len < sizeof(*ip)) {
449 m = m_pullup(m, sizeof(*ip));
450 if (!m) {
2d21ac55 451 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
452 goto fail;
453 }
454 }
455 ip = mtod(m, struct ip *);
456 /* ECN consideration. */
457 ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos);
458 if (!key_checktunnelsanity(sav, AF_INET,
459 (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) {
460 ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
461 "in IPv4 AH input: %s %s\n",
462 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
2d21ac55 463 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
464 goto fail;
465 }
466
1c79356b
A
467#if 1
468 /*
469 * Should the inner packet be considered authentic?
470 * My current answer is: NO.
471 *
472 * host1 -- gw1 === gw2 -- host2
473 * In this case, gw2 can trust the authenticity of the
474 * outer packet, but NOT inner. Packet may be altered
475 * between host1 and gw1.
476 *
477 * host1 -- gw1 === host2
478 * This case falls into the same scenario as above.
479 *
480 * host1 === host2
481 * This case is the only case when we may be able to leave
482 * M_AUTHIPHDR and M_AUTHIPDGM set.
483 * However, if host1 is wrongly configured, and allows
484 * attacker to inject some packet with src=host1 and
485 * dst=host2, you are in risk.
486 */
487 m->m_flags &= ~M_AUTHIPHDR;
488 m->m_flags &= ~M_AUTHIPDGM;
489#endif
490
491 key_sa_recordxfer(sav, m);
9bccf70c
A
492 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
493 ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) {
2d21ac55 494 IPSEC_STAT_INCREMENT(ipsecstat.in_nomem);
9bccf70c
A
495 goto fail;
496 }
6d2010ae
A
497
498 if (ip_doscopedroute) {
499 struct sockaddr_in *ipaddr;
500
501 bzero(&addr, sizeof(addr));
502 ipaddr = (__typeof__(ipaddr))&addr;
503 ipaddr->sin_family = AF_INET;
504 ipaddr->sin_len = sizeof(*ipaddr);
505 ipaddr->sin_addr = ip->ip_dst;
506
507 // update the receiving interface address based on the inner address
508 ifa = ifa_ifwithaddr((struct sockaddr *)&addr);
509 if (ifa) {
510 m->m_pkthdr.rcvif = ifa->ifa_ifp;
511 IFA_REMREF(ifa);
512 }
513 }
514 if (proto_input(PF_INET, m) != 0)
515 goto fail;
1c79356b
A
516 nxt = IPPROTO_DONE;
517 } else {
518 /*
519 * strip off AH.
1c79356b 520 */
1c79356b
A
521
522 ip = mtod(m, struct ip *);
523#ifndef PULLDOWN_TEST
9bccf70c
A
524 /*
525 * We do deep-copy since KAME requires that
526 * the packet is placed in a single external mbuf.
527 */
1c79356b
A
528 ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), off);
529 m->m_data += stripsiz;
530 m->m_len -= stripsiz;
531 m->m_pkthdr.len -= stripsiz;
532#else
533 /*
534 * even in m_pulldown case, we need to strip off AH so that
535 * we can compute checksum for multiple AH correctly.
536 */
537 if (m->m_len >= stripsiz + off) {
538 ovbcopy((caddr_t)ip, ((caddr_t)ip) + stripsiz, off);
539 m->m_data += stripsiz;
540 m->m_len -= stripsiz;
541 m->m_pkthdr.len -= stripsiz;
542 } else {
543 /*
544 * this comes with no copy if the boundary is on
545 * cluster
546 */
547 struct mbuf *n;
548
549 n = m_split(m, off, M_DONTWAIT);
550 if (n == NULL) {
551 /* m is retained by m_split */
552 goto fail;
553 }
554 m_adj(n, stripsiz);
1c79356b
A
555 /* m_cat does not update m_pkthdr.len */
556 m->m_pkthdr.len += n->m_pkthdr.len;
55e303ae 557 m_cat(m, n);
1c79356b
A
558 }
559#endif
560
561 if (m->m_len < sizeof(*ip)) {
562 m = m_pullup(m, sizeof(*ip));
563 if (m == NULL) {
2d21ac55 564 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
565 goto fail;
566 }
567 }
568 ip = mtod(m, struct ip *);
569#ifdef IPLEN_FLIPPED
570 ip->ip_len = ip->ip_len - stripsiz;
571#else
572 ip->ip_len = htons(ntohs(ip->ip_len) - stripsiz);
573#endif
574 ip->ip_p = nxt;
575 /* forget about IP hdr checksum, the check has already been passed */
576
577 key_sa_recordxfer(sav, m);
9bccf70c 578 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
2d21ac55 579 IPSEC_STAT_INCREMENT(ipsecstat.in_nomem);
9bccf70c
A
580 goto fail;
581 }
1c79356b 582
6d2010ae
A
583 DTRACE_IP6(receive, struct mbuf *, m, struct inpcb *, NULL,
584 struct ip *, ip, struct ifnet *, m->m_pkthdr.rcvif,
585 struct ip *, ip, struct ip6_hdr *, NULL);
586
9bccf70c
A
587 if (nxt != IPPROTO_DONE) {
588 if ((ip_protox[nxt]->pr_flags & PR_LASTHDR) != 0 &&
589 ipsec4_in_reject(m, NULL)) {
2d21ac55 590 IPSEC_STAT_INCREMENT(ipsecstat.in_polvio);
9bccf70c
A
591 goto fail;
592 }
91447636 593 ip_proto_dispatch_in(m, off, nxt, 0);
9bccf70c 594 } else
1c79356b
A
595 m_freem(m);
596 m = NULL;
597 }
598
599 if (sav) {
600 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
601 printf("DP ah4_input call free SA:%p\n", sav));
2d21ac55 602 key_freesav(sav, KEY_SADB_UNLOCKED);
1c79356b 603 }
2d21ac55 604 IPSEC_STAT_INCREMENT(ipsecstat.in_success);
1c79356b
A
605 return;
606
607fail:
608 if (sav) {
609 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
610 printf("DP ah4_input call free SA:%p\n", sav));
2d21ac55 611 key_freesav(sav, KEY_SADB_UNLOCKED);
1c79356b
A
612 }
613 if (m)
614 m_freem(m);
615 return;
616}
617#endif /* INET */
618
619#if INET6
620int
6d2010ae 621ah6_input(struct mbuf **mp, int *offp, int proto)
1c79356b 622{
6d2010ae 623#pragma unused(proto)
1c79356b
A
624 struct mbuf *m = *mp;
625 int off = *offp;
626 struct ip6_hdr *ip6;
627 struct ah *ah;
628 u_int32_t spi;
9bccf70c 629 const struct ah_algorithm *algo;
1c79356b
A
630 size_t siz;
631 size_t siz1;
632 u_char *cksum;
633 struct secasvar *sav = NULL;
634 u_int16_t nxt;
9bccf70c 635 size_t stripsiz = 0;
1c79356b 636
91447636 637
1c79356b 638#ifndef PULLDOWN_TEST
2d21ac55 639 IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), {return IPPROTO_DONE;});
316670eb 640 ah = (struct ah *)(void *)(mtod(m, caddr_t) + off);
1c79356b
A
641#else
642 IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah));
643 if (ah == NULL) {
644 ipseclog((LOG_DEBUG, "IPv6 AH input: can't pullup\n"));
9bccf70c 645 ipsec6stat.in_inval++;
1c79356b
A
646 return IPPROTO_DONE;
647 }
648#endif
316670eb
A
649 /* Expect 32-bit aligned data pointer on strict-align platforms */
650 MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
651
1c79356b
A
652 ip6 = mtod(m, struct ip6_hdr *);
653 nxt = ah->ah_nxt;
654
655 /* find the sassoc. */
656 spi = ah->ah_spi;
657
658 if (ntohs(ip6->ip6_plen) == 0) {
659 ipseclog((LOG_ERR, "IPv6 AH input: "
660 "AH with IPv6 jumbogram is not supported.\n"));
2d21ac55 661 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
1c79356b
A
662 goto fail;
663 }
664
665 if ((sav = key_allocsa(AF_INET6,
666 (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst,
667 IPPROTO_AH, spi)) == 0) {
668 ipseclog((LOG_WARNING,
669 "IPv6 AH input: no key association found for spi %u\n",
670 (u_int32_t)ntohl(spi)));
2d21ac55 671 IPSEC_STAT_INCREMENT(ipsec6stat.in_nosa);
1c79356b
A
672 goto fail;
673 }
674 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
675 printf("DP ah6_input called to allocate SA:%p\n", sav));
676 if (sav->state != SADB_SASTATE_MATURE
677 && sav->state != SADB_SASTATE_DYING) {
678 ipseclog((LOG_DEBUG,
679 "IPv6 AH input: non-mature/dying SA found for spi %u; ",
680 (u_int32_t)ntohl(spi)));
2d21ac55 681 IPSEC_STAT_INCREMENT(ipsec6stat.in_badspi);
1c79356b
A
682 goto fail;
683 }
9bccf70c
A
684
685 algo = ah_algorithm_lookup(sav->alg_auth);
686 if (!algo) {
1c79356b 687 ipseclog((LOG_DEBUG, "IPv6 AH input: "
9bccf70c 688 "unsupported authentication algorithm for spi %u\n",
1c79356b 689 (u_int32_t)ntohl(spi)));
2d21ac55 690 IPSEC_STAT_INCREMENT(ipsec6stat.in_badspi);
1c79356b
A
691 goto fail;
692 }
693
1c79356b
A
694 siz = (*algo->sumsiz)(sav);
695 siz1 = ((siz + 3) & ~(4 - 1));
696
697 /*
698 * sanity checks for header, 1.
699 */
700 {
701 int sizoff;
702
703 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
704
9bccf70c
A
705 /*
706 * Here, we do not do "siz1 == siz". See ah4_input() for complete
707 * description.
708 */
709 if (siz1 < siz) {
710 ipseclog((LOG_NOTICE, "sum length too short in IPv6 AH input "
711 "(%lu, should be at least %lu): %s\n",
b0d623f7 712 (u_int32_t)siz1, (u_int32_t)siz,
9bccf70c 713 ipsec6_logpacketstr(ip6, spi)));
2d21ac55 714 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
9bccf70c
A
715 goto fail;
716 }
1c79356b
A
717 if ((ah->ah_len << 2) - sizoff != siz1) {
718 ipseclog((LOG_NOTICE, "sum length mismatch in IPv6 AH input "
9bccf70c 719 "(%d should be %lu): %s\n",
b0d623f7 720 (ah->ah_len << 2) - sizoff, (u_int32_t)siz1,
9bccf70c 721 ipsec6_logpacketstr(ip6, spi)));
2d21ac55 722 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
1c79356b
A
723 goto fail;
724 }
725#ifndef PULLDOWN_TEST
91447636 726 IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1,
2d21ac55 727 {return IPPROTO_DONE;});
1c79356b
A
728#else
729 IP6_EXTHDR_GET(ah, struct ah *, m, off,
730 sizeof(struct ah) + sizoff + siz1);
731 if (ah == NULL) {
732 ipseclog((LOG_NOTICE, "couldn't pullup gather IPv6 AH checksum part"));
2d21ac55 733 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
1c79356b
A
734 m = NULL;
735 goto fail;
736 }
737#endif
738 }
739
740 /*
741 * check for sequence number.
742 */
743 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
744 if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav))
745 ; /*okey*/
746 else {
2d21ac55 747 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahreplay);
1c79356b
A
748 ipseclog((LOG_WARNING,
749 "replay packet in IPv6 AH input: %s %s\n",
750 ipsec6_logpacketstr(ip6, spi),
751 ipsec_logsastr(sav)));
752 goto fail;
753 }
754 }
755
756 /*
757 * alright, it seems sane. now we are going to check the
758 * cryptographic checksum.
759 */
760 cksum = _MALLOC(siz1, M_TEMP, M_NOWAIT);
761 if (!cksum) {
762 ipseclog((LOG_DEBUG, "IPv6 AH input: "
763 "couldn't alloc temporary region for cksum\n"));
2d21ac55 764 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
1c79356b
A
765 goto fail;
766 }
767
9bccf70c
A
768 if (ah6_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) {
769 FREE(cksum, M_TEMP);
2d21ac55 770 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
1c79356b
A
771 goto fail;
772 }
2d21ac55 773 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahhist[sav->alg_auth]);
1c79356b
A
774
775 {
776 caddr_t sumpos = NULL;
777
778 if (sav->flags & SADB_X_EXT_OLD) {
779 /* RFC 1826 */
780 sumpos = (caddr_t)(ah + 1);
781 } else {
782 /* RFC 2402 */
783 sumpos = (caddr_t)(((struct newah *)ah) + 1);
784 }
785
786 if (bcmp(sumpos, cksum, siz) != 0) {
787 ipseclog((LOG_WARNING,
788 "checksum mismatch in IPv6 AH input: %s %s\n",
789 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
9bccf70c 790 FREE(cksum, M_TEMP);
2d21ac55 791 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahauthfail);
1c79356b
A
792 goto fail;
793 }
794 }
795
9bccf70c 796 FREE(cksum, M_TEMP);
1c79356b
A
797
798 m->m_flags |= M_AUTHIPHDR;
799 m->m_flags |= M_AUTHIPDGM;
800
801#if 0
802 /*
803 * looks okey, but we need more sanity check.
804 * XXX should elaborate.
805 */
806 if (ah->ah_nxt == IPPROTO_IPV6) {
807 struct ip6_hdr *nip6;
808 size_t sizoff;
809
810 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
811
812 IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1
91447636 813 + sizeof(struct ip6_hdr),
2d21ac55 814 {return IPPROTO_DONE;});
1c79356b
A
815
816 nip6 = (struct ip6_hdr *)((u_char *)(ah + 1) + sizoff + siz1);
817 if (!IN6_ARE_ADDR_EQUAL(&nip6->ip6_src, &ip6->ip6_src)
818 || !IN6_ARE_ADDR_EQUAL(&nip6->ip6_dst, &ip6->ip6_dst)) {
819 m->m_flags &= ~M_AUTHIPHDR;
820 m->m_flags &= ~M_AUTHIPDGM;
821 }
822 } else if (ah->ah_nxt == IPPROTO_IPIP) {
823 m->m_flags &= ~M_AUTHIPHDR;
824 m->m_flags &= ~M_AUTHIPDGM;
825 } else if (ah->ah_nxt == IPPROTO_IP) {
826 m->m_flags &= ~M_AUTHIPHDR;
827 m->m_flags &= ~M_AUTHIPDGM;
828 }
829#endif
830
831 if (m->m_flags & M_AUTHIPHDR
832 && m->m_flags & M_AUTHIPDGM) {
833#if 0
834 ipseclog((LOG_DEBUG,
835 "IPv6 AH input: authentication succeess\n"));
836#endif
2d21ac55 837 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahauthsucc);
1c79356b
A
838 } else {
839 ipseclog((LOG_WARNING,
840 "authentication failed in IPv6 AH input: %s %s\n",
841 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
2d21ac55 842 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahauthfail);
1c79356b
A
843 goto fail;
844 }
845
846 /*
847 * update sequence number.
848 */
849 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
850 if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) {
2d21ac55 851 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahreplay);
1c79356b
A
852 goto fail;
853 }
854 }
855
856 /* was it transmitted over the IPsec tunnel SA? */
9bccf70c
A
857 if (sav->flags & SADB_X_EXT_OLD) {
858 /* RFC 1826 */
859 stripsiz = sizeof(struct ah) + siz1;
860 } else {
861 /* RFC 2402 */
862 stripsiz = sizeof(struct newah) + siz1;
863 }
864 if (ipsec6_tunnel_validate(m, off + stripsiz, nxt, sav)) {
6d2010ae
A
865 ifaddr_t ifa;
866 struct sockaddr_storage addr;
867
1c79356b
A
868 /*
869 * strip off all the headers that precedes AH.
870 * IP6 xx AH IP6' payload -> IP6' payload
871 *
872 * XXX more sanity checks
873 * XXX relationship with gif?
874 */
1c79356b
A
875 u_int32_t flowinfo; /*net endian*/
876
877 flowinfo = ip6->ip6_flow;
1c79356b
A
878 m_adj(m, off + stripsiz);
879 if (m->m_len < sizeof(*ip6)) {
880 /*
881 * m_pullup is prohibited in KAME IPv6 input processing
882 * but there's no other way!
883 */
884 m = m_pullup(m, sizeof(*ip6));
885 if (!m) {
2d21ac55 886 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
1c79356b
A
887 goto fail;
888 }
889 }
890 ip6 = mtod(m, struct ip6_hdr *);
891 /* ECN consideration. */
892 ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow);
893 if (!key_checktunnelsanity(sav, AF_INET6,
894 (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) {
895 ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
896 "in IPv6 AH input: %s %s\n",
897 ipsec6_logpacketstr(ip6, spi),
898 ipsec_logsastr(sav)));
2d21ac55 899 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
1c79356b
A
900 goto fail;
901 }
902
1c79356b
A
903#if 1
904 /*
905 * should the inner packet be considered authentic?
906 * see comment in ah4_input().
907 */
908 m->m_flags &= ~M_AUTHIPHDR;
909 m->m_flags &= ~M_AUTHIPDGM;
910#endif
911
912 key_sa_recordxfer(sav, m);
9bccf70c
A
913 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
914 ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) {
2d21ac55 915 IPSEC_STAT_INCREMENT(ipsec6stat.in_nomem);
9bccf70c
A
916 goto fail;
917 }
6d2010ae
A
918
919 if (ip6_doscopedroute) {
920 struct sockaddr_in6 *ip6addr;
921
922 bzero(&addr, sizeof(addr));
923 ip6addr = (__typeof__(ip6addr))&addr;
924 ip6addr->sin6_family = AF_INET6;
925 ip6addr->sin6_len = sizeof(*ip6addr);
926 ip6addr->sin6_addr = ip6->ip6_dst;
927
928 // update the receiving interface address based on the inner address
929 ifa = ifa_ifwithaddr((struct sockaddr *)&addr);
930 if (ifa) {
931 m->m_pkthdr.rcvif = ifa->ifa_ifp;
932 IFA_REMREF(ifa);
933 }
934 }
935
936 if (proto_input(PF_INET6, m) != 0)
937 goto fail;
1c79356b
A
938 nxt = IPPROTO_DONE;
939 } else {
940 /*
941 * strip off AH.
1c79356b 942 */
1c79356b
A
943 char *prvnxtp;
944
945 /*
946 * Copy the value of the next header field of AH to the
947 * next header field of the previous header.
948 * This is necessary because AH will be stripped off below.
949 */
950 prvnxtp = ip6_get_prevhdr(m, off); /* XXX */
951 *prvnxtp = nxt;
952
1c79356b
A
953 ip6 = mtod(m, struct ip6_hdr *);
954#ifndef PULLDOWN_TEST
9bccf70c
A
955 /*
956 * We do deep-copy since KAME requires that
957 * the packet is placed in a single mbuf.
958 */
1c79356b
A
959 ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
960 m->m_data += stripsiz;
961 m->m_len -= stripsiz;
962 m->m_pkthdr.len -= stripsiz;
963#else
964 /*
965 * even in m_pulldown case, we need to strip off AH so that
966 * we can compute checksum for multiple AH correctly.
967 */
968 if (m->m_len >= stripsiz + off) {
969 ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
970 m->m_data += stripsiz;
971 m->m_len -= stripsiz;
972 m->m_pkthdr.len -= stripsiz;
973 } else {
974 /*
975 * this comes with no copy if the boundary is on
976 * cluster
977 */
978 struct mbuf *n;
979
980 n = m_split(m, off, M_DONTWAIT);
981 if (n == NULL) {
982 /* m is retained by m_split */
983 goto fail;
984 }
985 m_adj(n, stripsiz);
1c79356b
A
986 /* m_cat does not update m_pkthdr.len */
987 m->m_pkthdr.len += n->m_pkthdr.len;
55e303ae 988 m_cat(m, n);
1c79356b
A
989 }
990#endif
991 ip6 = mtod(m, struct ip6_hdr *);
992 /* XXX jumbogram */
993 ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz);
994
995 key_sa_recordxfer(sav, m);
9bccf70c 996 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
2d21ac55 997 IPSEC_STAT_INCREMENT(ipsec6stat.in_nomem);
9bccf70c
A
998 goto fail;
999 }
1c79356b
A
1000 }
1001
1002 *offp = off;
1003 *mp = m;
1004
1005 if (sav) {
1006 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
1007 printf("DP ah6_input call free SA:%p\n", sav));
2d21ac55 1008 key_freesav(sav, KEY_SADB_UNLOCKED);
1c79356b 1009 }
2d21ac55 1010 IPSEC_STAT_INCREMENT(ipsec6stat.in_success);
1c79356b
A
1011 return nxt;
1012
1013fail:
1014 if (sav) {
1015 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
1016 printf("DP ah6_input call free SA:%p\n", sav));
2d21ac55 1017 key_freesav(sav, KEY_SADB_UNLOCKED);
1c79356b
A
1018 }
1019 if (m)
1020 m_freem(m);
1021 return IPPROTO_DONE;
1022}
9bccf70c
A
1023
1024void
1025ah6_ctlinput(cmd, sa, d)
1026 int cmd;
1027 struct sockaddr *sa;
1028 void *d;
1029{
1030 const struct newah *ahp;
1031 struct newah ah;
1032 struct secasvar *sav;
1033 struct ip6_hdr *ip6;
1034 struct mbuf *m;
1035 struct ip6ctlparam *ip6cp = NULL;
1036 int off;
55e303ae 1037 struct sockaddr_in6 *sa6_src, *sa6_dst;
9bccf70c
A
1038
1039 if (sa->sa_family != AF_INET6 ||
1040 sa->sa_len != sizeof(struct sockaddr_in6))
1041 return;
1042 if ((unsigned)cmd >= PRC_NCMDS)
1043 return;
1044
1045 /* if the parameter is from icmp6, decode it. */
1046 if (d != NULL) {
1047 ip6cp = (struct ip6ctlparam *)d;
1048 m = ip6cp->ip6c_m;
1049 ip6 = ip6cp->ip6c_ip6;
1050 off = ip6cp->ip6c_off;
1051 } else {
1052 m = NULL;
1053 ip6 = NULL;
1054 }
1055
1056 if (ip6) {
1057 /*
1058 * XXX: We assume that when ip6 is non NULL,
1059 * M and OFF are valid.
1060 */
1061
1062 /* check if we can safely examine src and dst ports */
1063 if (m->m_pkthdr.len < off + sizeof(ah))
1064 return;
1065
1066 if (m->m_len < off + sizeof(ah)) {
1067 /*
1068 * this should be rare case,
1069 * so we compromise on this copy...
1070 */
1071 m_copydata(m, off, sizeof(ah), (caddr_t)&ah);
1072 ahp = &ah;
1073 } else
316670eb 1074 ahp = (struct newah *)(void *)(mtod(m, caddr_t) + off);
9bccf70c
A
1075
1076 if (cmd == PRC_MSGSIZE) {
1077 int valid = 0;
1078
1079 /*
1080 * Check to see if we have a valid SA corresponding to
1081 * the address in the ICMP message payload.
1082 */
55e303ae 1083 sa6_src = ip6cp->ip6c_src;
316670eb 1084 sa6_dst = (struct sockaddr_in6 *)(void *)sa;
9bccf70c 1085 sav = key_allocsa(AF_INET6,
55e303ae
A
1086 (caddr_t)&sa6_src->sin6_addr,
1087 (caddr_t)&sa6_dst->sin6_addr,
9bccf70c
A
1088 IPPROTO_AH, ahp->ah_spi);
1089 if (sav) {
1090 if (sav->state == SADB_SASTATE_MATURE ||
1091 sav->state == SADB_SASTATE_DYING)
1092 valid++;
2d21ac55 1093 key_freesav(sav, KEY_SADB_UNLOCKED);
9bccf70c
A
1094 }
1095
1096 /* XXX Further validation? */
1097
1098 /*
1099 * Depending on the value of "valid" and routing table
1100 * size (mtudisc_{hi,lo}wat), we will:
1101 * - recalcurate the new MTU and create the
1102 * corresponding routing entry, or
1103 * - ignore the MTU change notification.
1104 */
1105 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
1106 }
1107
1108 /* we normally notify single pcb here */
1109 } else {
1110 /* we normally notify any pcb here */
1111 }
1112}
1c79356b 1113#endif /* INET6 */