1 /* $NetBSD: ah_input.c,v 1.44 2004/02/11 10:47:28 itojun Exp $ */
2 /* $KAME: ah_input.c,v 1.64 2001/09/04 08:43:19 itojun Exp $ */
3
4 /*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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.
19 *
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
30 * SUCH DAMAGE.
31 */
32
33 /*
34 * RFC1826/2402 authentication header.
35 */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: ah_input.c,v 1.44 2004/02/11 10:47:28 itojun Exp $");
39
40 #include "opt_inet.h"
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/malloc.h>
45 #include <sys/mbuf.h>
46 #include <sys/domain.h>
47 #include <sys/protosw.h>
48 #include <sys/socket.h>
49 #include <sys/errno.h>
50 #include <sys/time.h>
51 #include <sys/kernel.h>
52 #include <sys/syslog.h>
53
54 #include <net/if.h>
55 #include <net/route.h>
56 #include <net/netisr.h>
57 #include <machine/cpu.h>
58
59 #include <netinet/in.h>
60 #include <netinet/in_systm.h>
61 #include <netinet/in_var.h>
62 #include <netinet/ip.h>
63 #include <netinet/ip_var.h>
64 #include <netinet/ip_ecn.h>
65 #include <netinet/ip_icmp.h>
66
67 #include <netinet/ip6.h>
68
69 #ifdef INET6
70 #include <netinet6/ip6_var.h>
71 #include <netinet/icmp6.h>
72 #include <netinet6/ip6protosw.h>
73 #endif
74
75 #include <netinet6/ipsec.h>
76 #include <netinet6/ah.h>
77 #include <netkey/key.h>
78 #include <netkey/keydb.h>
79 #include <netkey/key_debug.h>
80
81 #include <machine/stdarg.h>
82
83 #include <net/net_osdep.h>
84
85 /*#define IPLEN_FLIPPED*/
86
87 #ifdef INET
88 void
89 #if __STDC__
90 ah4_input(struct mbuf *m, ...)
91 #else
92 ah4_input(m, va_alist)
93 struct mbuf *m;
94 va_dcl
95 #endif
96 {
97 struct ip *ip;
98 struct ah *ah;
99 u_int32_t spi;
100 const struct ah_algorithm *algo;
101 size_t siz;
102 size_t siz1;
103 u_int8_t cksum[AH_MAXSUMSIZE];
104 struct secasvar *sav = NULL;
105 u_int16_t nxt;
106 size_t hlen;
107 int s;
108 int off, proto;
109 va_list ap;
110 size_t stripsiz = 0;
111
112 va_start(ap, m);
113 off = va_arg(ap, int);
114 proto = va_arg(ap, int);
115 va_end(ap);
116
117 ip = mtod(m, struct ip *);
118 IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah));
119 if (ah == NULL) {
120 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;"
121 "dropping the packet for simplicity\n"));
122 ipsecstat.in_inval++;
123 goto fail;
124 }
125 nxt = ah->ah_nxt;
126 hlen = ip->ip_hl << 2;
127
128 /* find the sassoc. */
129 spi = ah->ah_spi;
130
131 if ((sav = key_allocsa(AF_INET,
132 (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst,
133 IPPROTO_AH, spi)) == 0) {
134 ipseclog((LOG_WARNING,
135 "IPv4 AH input: no key association found for spi %u\n",
136 (u_int32_t)ntohl(spi)));
137 ipsecstat.in_nosa++;
138 goto fail;
139 }
140 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
141 printf("DP ah4_input called to allocate SA:%p\n", sav));
142 if (sav->state != SADB_SASTATE_MATURE &&
143 sav->state != SADB_SASTATE_DYING) {
144 ipseclog((LOG_DEBUG,
145 "IPv4 AH input: non-mature/dying SA found for spi %u\n",
146 (u_int32_t)ntohl(spi)));
147 ipsecstat.in_badspi++;
148 goto fail;
149 }
150
151 algo = ah_algorithm_lookup(sav->alg_auth);
152 if (!algo) {
153 ipseclog((LOG_DEBUG, "IPv4 AH input: "
154 "unsupported authentication algorithm for spi %u\n",
155 (u_int32_t)ntohl(spi)));
156 ipsecstat.in_badspi++;
157 goto fail;
158 }
159
160 siz = (*algo->sumsiz)(sav);
161 siz1 = ((siz + 3) & ~(4 - 1));
162
163 /*
164 * sanity checks for header, 1.
165 */
166 {
167 int sizoff;
168
169 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
170
171 /*
172 * Here, we do not do "siz1 == siz". This is because the way
173 * RFC240[34] section 2 is written. They do not require truncation
174 * to 96 bits.
175 * For example, Microsoft IPsec stack attaches 160 bits of
176 * authentication data for both hmac-md5 and hmac-sha1. For hmac-sha1,
177 * 32 bits of padding is attached.
178 *
179 * There are two downsides to this specification.
180 * They have no real harm, however, they leave us fuzzy feeling.
181 * - if we attach more than 96 bits of authentication data onto AH,
182 * we will never notice about possible modification by rogue
183 * intermediate nodes.
184 * Since extra bits in AH checksum is never used, this constitutes
185 * no real issue, however, it is wacky.
186 * - even if the peer attaches big authentication data, we will never
187 * notice the difference, since longer authentication data will just
188 * work.
189 *
190 * We may need some clarification in the spec.
191 */
192 if (siz1 < siz) {
193 ipseclog((LOG_NOTICE, "sum length too short in IPv4 AH input "
194 "(%lu, should be at least %lu): %s\n",
195 (u_long)siz1, (u_long)siz,
196 ipsec4_logpacketstr(ip, spi)));
197 ipsecstat.in_inval++;
198 goto fail;
199 }
200 if ((ah->ah_len << 2) - sizoff != siz1) {
201 ipseclog((LOG_NOTICE, "sum length mismatch in IPv4 AH input "
202 "(%d should be %lu): %s\n",
203 (ah->ah_len << 2) - sizoff, (u_long)siz1,
204 ipsec4_logpacketstr(ip, spi)));
205 ipsecstat.in_inval++;
206 goto fail;
207 }
208 if (siz1 > sizeof(cksum)) {
209 ipseclog((LOG_NOTICE, "sum length too large: %s\n",
210 ipsec4_logpacketstr(ip, spi)));
211 ipsecstat.in_inval++;
212 goto fail;
213 }
214
215 IP6_EXTHDR_GET(ah, struct ah *, m, off,
216 sizeof(struct ah) + sizoff + siz1);
217 if (ah == NULL) {
218 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n"));
219 ipsecstat.in_inval++;
220 goto fail;
221 }
222 }
223
224 /*
225 * check for sequence number.
226 */
227 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
228 if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav))
229 ; /* okey */
230 else {
231 ipsecstat.in_ahreplay++;
232 ipseclog((LOG_WARNING,
233 "replay packet in IPv4 AH input: %s %s\n",
234 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
235 goto fail;
236 }
237 }
238
239 /*
240 * alright, it seems sane. now we are going to check the
241 * cryptographic checksum.
242 */
243
244 {
245 #if 0
246 /*
247 * some of IP header fields are flipped to the host endian.
248 * convert them back to network endian. VERY stupid.
249 */
250 ip->ip_len = htons(ip->ip_len);
251 ip->ip_off = htons(ip->ip_off);
252 #endif
253 if (ah4_calccksum(m, cksum, siz1, algo, sav)) {
254 ipsecstat.in_inval++;
255 goto fail;
256 }
257 ipsecstat.in_ahhist[sav->alg_auth]++;
258 #if 0
259 /*
260 * flip them back.
261 */
262 ip->ip_len = ntohs(ip->ip_len);
263 ip->ip_off = ntohs(ip->ip_off);
264 #endif
265 }
266
267 {
268 caddr_t sumpos = NULL;
269
270 if (sav->flags & SADB_X_EXT_OLD) {
271 /* RFC 1826 */
272 sumpos = (caddr_t)(ah + 1);
273 } else {
274 /* RFC 2402 */
275 sumpos = (caddr_t)(((struct newah *)ah) + 1);
276 }
277
278 if (bcmp(sumpos, cksum, siz) != 0) {
279 ipseclog((LOG_WARNING,
280 "checksum mismatch in IPv4 AH input: %s %s\n",
281 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
282 ipsecstat.in_ahauthfail++;
283 goto fail;
284 }
285 }
286
287 m->m_flags |= M_AUTHIPHDR;
288 m->m_flags |= M_AUTHIPDGM;
289
290 #if 0
291 /*
292 * looks okey, but we need more sanity check.
293 * XXX should elaborate.
294 */
295 if (ah->ah_nxt == IPPROTO_IPIP || ah->ah_nxt == IPPROTO_IP) {
296 struct ip *nip;
297 size_t sizoff;
298
299 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
300
301 if (m->m_len < off + sizeof(struct ah) + sizoff + siz1 + hlen) {
302 m = m_pullup(m, off + sizeof(struct ah)
303 + sizoff + siz1 + hlen);
304 if (!m) {
305 ipseclog((LOG_DEBUG,
306 "IPv4 AH input: can't pullup\n"));
307 ipsecstat.in_inval++;
308 goto fail;
309 }
310 }
311
312 nip = (struct ip *)((u_char *)(ah + 1) + sizoff + siz1);
313 if (nip->ip_src.s_addr != ip->ip_src.s_addr
314 || nip->ip_dst.s_addr != ip->ip_dst.s_addr) {
315 m->m_flags &= ~M_AUTHIPHDR;
316 m->m_flags &= ~M_AUTHIPDGM;
317 }
318 }
319 #ifdef INET6
320 else if (ah->ah_nxt == IPPROTO_IPV6) {
321 m->m_flags &= ~M_AUTHIPHDR;
322 m->m_flags &= ~M_AUTHIPDGM;
323 }
324 #endif /* INET6 */
325 #endif /* 0 */
326
327 if (m->m_flags & M_AUTHIPHDR && m->m_flags & M_AUTHIPDGM) {
328 #if 0
329 ipseclog((LOG_DEBUG,
330 "IPv4 AH input: authentication succeess\n"));
331 #endif
332 ipsecstat.in_ahauthsucc++;
333 } else {
334 ipseclog((LOG_WARNING,
335 "authentication failed in IPv4 AH input: %s %s\n",
336 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
337 ipsecstat.in_ahauthfail++;
338 goto fail;
339 }
340
341 /*
342 * update sequence number.
343 */
344 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
345 if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) {
346 ipsecstat.in_ahreplay++;
347 goto fail;
348 }
349 }
350
351 /* was it transmitted over the IPsec tunnel SA? */
352 if (sav->flags & SADB_X_EXT_OLD) {
353 /* RFC 1826 */
354 stripsiz = sizeof(struct ah) + siz1;
355 } else {
356 /* RFC 2402 */
357 stripsiz = sizeof(struct newah) + siz1;
358 }
359 if (ipsec4_tunnel_validate(ip, nxt, sav)) {
360 /*
361 * strip off all the headers that precedes AH.
362 * IP xx AH IP' payload -> IP' payload
363 *
364 * XXX more sanity checks
365 * XXX relationship with gif?
366 */
367 u_int8_t tos;
368
369 tos = ip->ip_tos;
370 m_adj(m, off + stripsiz);
371 if (m->m_len < sizeof(*ip)) {
372 m = m_pullup(m, sizeof(*ip));
373 if (!m) {
374 ipsecstat.in_inval++;
375 goto fail;
376 }
377 }
378 ip = mtod(m, struct ip *);
379 /* ECN consideration. */
380 ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos);
381 if (!key_checktunnelsanity(sav, AF_INET,
382 (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) {
383 ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
384 "in IPv4 AH input: %s %s\n",
385 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
386 ipsecstat.in_inval++;
387 goto fail;
388 }
389
390 key_sa_recordxfer(sav, m);
391 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
392 ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) {
393 ipsecstat.in_nomem++;
394 goto fail;
395 }
396
397 s = splnet();
398 if (IF_QFULL(&ipintrq)) {
399 ipsecstat.in_inval++;
400 splx(s);
401 goto fail;
402 }
403 IF_ENQUEUE(&ipintrq, m);
404 m = NULL;
405 schednetisr(NETISR_IP); /* can be skipped but to make sure */
406 splx(s);
407 nxt = IPPROTO_DONE;
408 } else {
409 /*
410 * strip off AH.
411 */
412
413 ip = mtod(m, struct ip *);
414 /*
415 * even in m_pulldown case, we need to strip off AH so that
416 * we can compute checksum for multiple AH correctly.
417 */
418 if (m->m_len >= stripsiz + off) {
419 ovbcopy((caddr_t)ip, ((caddr_t)ip) + stripsiz, off);
420 m->m_data += stripsiz;
421 m->m_len -= stripsiz;
422 m->m_pkthdr.len -= stripsiz;
423 } else {
424 /*
425 * this comes with no copy if the boundary is on
426 * cluster
427 */
428 struct mbuf *n;
429
430 n = m_split(m, off, M_DONTWAIT);
431 if (n == NULL) {
432 /* m is retained by m_split */
433 goto fail;
434 }
435 m_adj(n, stripsiz);
436 /* m_cat does not update m_pkthdr.len */
437 m->m_pkthdr.len += n->m_pkthdr.len;
438 m_cat(m, n);
439 }
440
441 if (m->m_len < sizeof(*ip)) {
442 m = m_pullup(m, sizeof(*ip));
443 if (m == NULL) {
444 ipsecstat.in_inval++;
445 goto fail;
446 }
447 }
448 ip = mtod(m, struct ip *);
449 #ifdef IPLEN_FLIPPED
450 ip->ip_len = ip->ip_len - stripsiz;
451 #else
452 ip->ip_len = htons(ntohs(ip->ip_len) - stripsiz);
453 #endif
454 ip->ip_p = nxt;
455 /* forget about IP hdr checksum, the check has already been passed */
456
457 key_sa_recordxfer(sav, m);
458 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
459 ipsecstat.in_nomem++;
460 goto fail;
461 }
462
463 if (nxt != IPPROTO_DONE) {
464 if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
465 ipsec4_in_reject(m, NULL)) {
466 ipsecstat.in_polvio++;
467 goto fail;
468 }
469 (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt);
470 } else
471 m_freem(m);
472 m = NULL;
473 }
474
475 if (sav) {
476 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
477 printf("DP ah4_input call free SA:%p\n", sav));
478 key_freesav(sav);
479 }
480 ipsecstat.in_success++;
481 return;
482
483 fail:
484 if (sav) {
485 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
486 printf("DP ah4_input call free SA:%p\n", sav));
487 key_freesav(sav);
488 }
489 if (m)
490 m_freem(m);
491 return;
492 }
493
494 /* assumes that ip header and ah header are contiguous on mbuf */
495 void *
496 ah4_ctlinput(cmd, sa, v)
497 int cmd;
498 struct sockaddr *sa;
499 void *v;
500 {
501 struct ip *ip = v;
502 struct ah *ah;
503 struct icmp *icp;
504 struct secasvar *sav;
505
506 if (sa->sa_family != AF_INET ||
507 sa->sa_len != sizeof(struct sockaddr_in))
508 return NULL;
509 if ((unsigned)cmd >= PRC_NCMDS)
510 return NULL;
511 if (cmd == PRC_MSGSIZE && ip_mtudisc && ip && ip->ip_v == 4) {
512 /*
513 * Check to see if we have a valid SA corresponding to
514 * the address in the ICMP message payload.
515 */
516 ah = (struct ah *)((caddr_t)ip + (ip->ip_hl << 2));
517 if ((sav = key_allocsa(AF_INET,
518 (caddr_t) &ip->ip_src,
519 (caddr_t) &ip->ip_dst,
520 IPPROTO_AH, ah->ah_spi)) == NULL)
521 return NULL;
522 if (sav->state != SADB_SASTATE_MATURE &&
523 sav->state != SADB_SASTATE_DYING) {
524 key_freesav(sav);
525 return NULL;
526 }
527
528 /* XXX Further validation? */
529
530 key_freesav(sav);
531
532 /*
533 * Now that we've validated that we are actually communicating
534 * with the host indicated in the ICMP message, locate the
535 * ICMP header, recalculate the new MTU, and create the
536 * corresponding routing entry.
537 */
538 icp = (struct icmp *)((caddr_t)ip -
539 offsetof(struct icmp, icmp_ip));
540 icmp_mtudisc(icp, ip->ip_dst);
541
542 return NULL;
543 }
544
545 return NULL;
546 }
547 #endif /* INET */
548
549 #ifdef INET6
550 int
551 ah6_input(mp, offp, proto)
552 struct mbuf **mp;
553 int *offp, proto;
554 {
555 struct mbuf *m = *mp;
556 int off = *offp;
557 struct ip6_hdr *ip6;
558 struct ah *ah;
559 u_int32_t spi;
560 const struct ah_algorithm *algo;
561 size_t siz;
562 size_t siz1;
563 u_int8_t cksum[AH_MAXSUMSIZE];
564 struct secasvar *sav = NULL;
565 u_int16_t nxt;
566 int s;
567 size_t stripsiz = 0;
568
569 IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah));
570 if (ah == NULL) {
571 ipseclog((LOG_DEBUG, "IPv6 AH input: can't pullup\n"));
572 ipsec6stat.in_inval++;
573 return IPPROTO_DONE;
574 }
575 ip6 = mtod(m, struct ip6_hdr *);
576 nxt = ah->ah_nxt;
577
578 /* find the sassoc. */
579 spi = ah->ah_spi;
580
581 if (ntohs(ip6->ip6_plen) == 0) {
582 ipseclog((LOG_ERR, "IPv6 AH input: "
583 "AH with IPv6 jumbogram is not supported.\n"));
584 ipsec6stat.in_inval++;
585 goto fail;
586 }
587
588 if ((sav = key_allocsa(AF_INET6,
589 (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst,
590 IPPROTO_AH, spi)) == 0) {
591 ipseclog((LOG_WARNING,
592 "IPv6 AH input: no key association found for spi %u\n",
593 (u_int32_t)ntohl(spi)));
594 ipsec6stat.in_nosa++;
595 goto fail;
596 }
597 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
598 printf("DP ah6_input called to allocate SA:%p\n", sav));
599 if (sav->state != SADB_SASTATE_MATURE &&
600 sav->state != SADB_SASTATE_DYING) {
601 ipseclog((LOG_DEBUG,
602 "IPv6 AH input: non-mature/dying SA found for spi %u; ",
603 (u_int32_t)ntohl(spi)));
604 ipsec6stat.in_badspi++;
605 goto fail;
606 }
607
608 algo = ah_algorithm_lookup(sav->alg_auth);
609 if (!algo) {
610 ipseclog((LOG_DEBUG, "IPv6 AH input: "
611 "unsupported authentication algorithm for spi %u\n",
612 (u_int32_t)ntohl(spi)));
613 ipsec6stat.in_badspi++;
614 goto fail;
615 }
616
617 siz = (*algo->sumsiz)(sav);
618 siz1 = ((siz + 3) & ~(4 - 1));
619
620 /*
621 * sanity checks for header, 1.
622 */
623 {
624 int sizoff;
625
626 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
627
628 /*
629 * Here, we do not do "siz1 == siz". See ah4_input() for complete
630 * description.
631 */
632 if (siz1 < siz) {
633 ipseclog((LOG_NOTICE, "sum length too short in IPv6 AH input "
634 "(%lu, should be at least %lu): %s\n",
635 (u_long)siz1, (u_long)siz,
636 ipsec6_logpacketstr(ip6, spi)));
637 ipsec6stat.in_inval++;
638 goto fail;
639 }
640 if ((ah->ah_len << 2) - sizoff != siz1) {
641 ipseclog((LOG_NOTICE, "sum length mismatch in IPv6 AH input "
642 "(%d should be %lu): %s\n",
643 (ah->ah_len << 2) - sizoff, (u_long)siz1,
644 ipsec6_logpacketstr(ip6, spi)));
645 ipsec6stat.in_inval++;
646 goto fail;
647 }
648 if (siz1 > sizeof(cksum)) {
649 ipseclog((LOG_NOTICE, "sum length too large: %s\n",
650 ipsec6_logpacketstr(ip6, spi)));
651 ipsec6stat.in_inval++;
652 goto fail;
653 }
654
655 IP6_EXTHDR_GET(ah, struct ah *, m, off,
656 sizeof(struct ah) + sizoff + siz1);
657 if (ah == NULL) {
658 ipseclog((LOG_NOTICE, "couldn't pullup gather IPv6 AH checksum part"));
659 ipsec6stat.in_inval++;
660 m = NULL;
661 goto fail;
662 }
663 }
664
665 /*
666 * check for sequence number.
667 */
668 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
669 if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav))
670 ; /* okey */
671 else {
672 ipsec6stat.in_ahreplay++;
673 ipseclog((LOG_WARNING,
674 "replay packet in IPv6 AH input: %s %s\n",
675 ipsec6_logpacketstr(ip6, spi),
676 ipsec_logsastr(sav)));
677 goto fail;
678 }
679 }
680
681 /*
682 * alright, it seems sane. now we are going to check the
683 * cryptographic checksum.
684 */
685
686 if (ah6_calccksum(m, cksum, siz1, algo, sav)) {
687 ipsec6stat.in_inval++;
688 goto fail;
689 }
690 ipsec6stat.in_ahhist[sav->alg_auth]++;
691
692 {
693 caddr_t sumpos = NULL;
694
695 if (sav->flags & SADB_X_EXT_OLD) {
696 /* RFC 1826 */
697 sumpos = (caddr_t)(ah + 1);
698 } else {
699 /* RFC 2402 */
700 sumpos = (caddr_t)(((struct newah *)ah) + 1);
701 }
702
703 if (bcmp(sumpos, cksum, siz) != 0) {
704 ipseclog((LOG_WARNING,
705 "checksum mismatch in IPv6 AH input: %s %s\n",
706 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
707 ipsec6stat.in_ahauthfail++;
708 goto fail;
709 }
710 }
711
712 m->m_flags |= M_AUTHIPHDR;
713 m->m_flags |= M_AUTHIPDGM;
714
715 #if 0
716 /*
717 * looks okey, but we need more sanity check.
718 * XXX should elaborate.
719 */
720 if (ah->ah_nxt == IPPROTO_IPV6) {
721 struct ip6_hdr *nip6;
722 size_t sizoff;
723
724 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
725
726 IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1
727 + sizeof(struct ip6_hdr), IPPROTO_DONE);
728
729 nip6 = (struct ip6_hdr *)((u_char *)(ah + 1) + sizoff + siz1);
730 if (!IN6_ARE_ADDR_EQUAL(&nip6->ip6_src, &ip6->ip6_src)
731 || !IN6_ARE_ADDR_EQUAL(&nip6->ip6_dst, &ip6->ip6_dst)) {
732 m->m_flags &= ~M_AUTHIPHDR;
733 m->m_flags &= ~M_AUTHIPDGM;
734 }
735 } else if (ah->ah_nxt == IPPROTO_IPIP) {
736 m->m_flags &= ~M_AUTHIPHDR;
737 m->m_flags &= ~M_AUTHIPDGM;
738 } else if (ah->ah_nxt == IPPROTO_IP) {
739 m->m_flags &= ~M_AUTHIPHDR;
740 m->m_flags &= ~M_AUTHIPDGM;
741 }
742 #endif
743
744 if (m->m_flags & M_AUTHIPHDR && m->m_flags & M_AUTHIPDGM) {
745 #if 0
746 ipseclog((LOG_DEBUG,
747 "IPv6 AH input: authentication succeess\n"));
748 #endif
749 ipsec6stat.in_ahauthsucc++;
750 } else {
751 ipseclog((LOG_WARNING,
752 "authentication failed in IPv6 AH input: %s %s\n",
753 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
754 ipsec6stat.in_ahauthfail++;
755 goto fail;
756 }
757
758 /*
759 * update sequence number.
760 */
761 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
762 if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) {
763 ipsec6stat.in_ahreplay++;
764 goto fail;
765 }
766 }
767
768 /* was it transmitted over the IPsec tunnel SA? */
769 if (sav->flags & SADB_X_EXT_OLD) {
770 /* RFC 1826 */
771 stripsiz = sizeof(struct ah) + siz1;
772 } else {
773 /* RFC 2402 */
774 stripsiz = sizeof(struct newah) + siz1;
775 }
776 if (ipsec6_tunnel_validate(ip6, nxt, sav)) {
777 /*
778 * strip off all the headers that precedes AH.
779 * IP6 xx AH IP6' payload -> IP6' payload
780 *
781 * XXX more sanity checks
782 * XXX relationship with gif?
783 */
784 u_int32_t flowinfo; /* net endian */
785
786 flowinfo = ip6->ip6_flow;
787 m_adj(m, off + stripsiz);
788 if (m->m_len < sizeof(*ip6)) {
789 m = m_pullup(m, sizeof(*ip6));
790 if (!m) {
791 ipsec6stat.in_inval++;
792 goto fail;
793 }
794 }
795 ip6 = mtod(m, struct ip6_hdr *);
796 /* ECN consideration. */
797 ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow);
798 if (!key_checktunnelsanity(sav, AF_INET6,
799 (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) {
800 ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
801 "in IPv6 AH input: %s %s\n",
802 ipsec6_logpacketstr(ip6, spi),
803 ipsec_logsastr(sav)));
804 ipsec6stat.in_inval++;
805 goto fail;
806 }
807
808 key_sa_recordxfer(sav, m);
809 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
810 ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) {
811 ipsec6stat.in_nomem++;
812 goto fail;
813 }
814
815 s = splnet();
816 if (IF_QFULL(&ip6intrq)) {
817 ipsec6stat.in_inval++;
818 splx(s);
819 goto fail;
820 }
821 IF_ENQUEUE(&ip6intrq, m);
822 m = NULL;
823 schednetisr(NETISR_IPV6); /* can be skipped but to make sure */
824 splx(s);
825 nxt = IPPROTO_DONE;
826 } else {
827 /*
828 * strip off AH.
829 */
830 u_int8_t *prvnxtp;
831
832 /*
833 * Copy the value of the next header field of AH to the
834 * next header field of the previous header.
835 * This is necessary because AH will be stripped off below.
836 */
837 prvnxtp = ip6_get_prevhdr(m, off); /* XXX */
838 *prvnxtp = nxt;
839
840 ip6 = mtod(m, struct ip6_hdr *);
841 /*
842 * even in m_pulldown case, we need to strip off AH so that
843 * we can compute checksum for multiple AH correctly.
844 */
845 if (m->m_len >= stripsiz + off) {
846 ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
847 m->m_data += stripsiz;
848 m->m_len -= stripsiz;
849 m->m_pkthdr.len -= stripsiz;
850 } else {
851 /*
852 * this comes with no copy if the boundary is on
853 * cluster
854 */
855 struct mbuf *n;
856
857 n = m_split(m, off, M_DONTWAIT);
858 if (n == NULL) {
859 /* m is retained by m_split */
860 goto fail;
861 }
862 m_adj(n, stripsiz);
863 /* m_cat does not update m_pkthdr.len */
864 m->m_pkthdr.len += n->m_pkthdr.len;
865 m_cat(m, n);
866 }
867 ip6 = mtod(m, struct ip6_hdr *);
868 /* XXX jumbogram */
869 ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz);
870
871 key_sa_recordxfer(sav, m);
872 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
873 ipsec6stat.in_nomem++;
874 goto fail;
875 }
876 }
877
878 *offp = off;
879 *mp = m;
880
881 if (sav) {
882 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
883 printf("DP ah6_input call free SA:%p\n", sav));
884 key_freesav(sav);
885 }
886 ipsec6stat.in_success++;
887 return nxt;
888
889 fail:
890 if (sav) {
891 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
892 printf("DP ah6_input call free SA:%p\n", sav));
893 key_freesav(sav);
894 }
895 if (m)
896 m_freem(m);
897 return IPPROTO_DONE;
898 }
899
900 void
901 ah6_ctlinput(cmd, sa, d)
902 int cmd;
903 struct sockaddr *sa;
904 void *d;
905 {
906 const struct newah *ahp;
907 struct newah ah;
908 struct secasvar *sav;
909 struct ip6_hdr *ip6;
910 struct mbuf *m;
911 struct ip6ctlparam *ip6cp = NULL;
912 int off;
913 struct sockaddr_in6 *sa6_src, *sa6_dst;
914
915 if (sa->sa_family != AF_INET6 ||
916 sa->sa_len != sizeof(struct sockaddr_in6))
917 return;
918 if ((unsigned)cmd >= PRC_NCMDS)
919 return;
920
921 /* if the parameter is from icmp6, decode it. */
922 if (d != NULL) {
923 ip6cp = (struct ip6ctlparam *)d;
924 m = ip6cp->ip6c_m;
925 ip6 = ip6cp->ip6c_ip6;
926 off = ip6cp->ip6c_off;
927 } else {
928 m = NULL;
929 ip6 = NULL;
930 off = 0;
931 }
932
933 if (ip6) {
934 /*
935 * XXX: We assume that when ip6 is non NULL,
936 * M and OFF are valid.
937 */
938
939 /* check if we can safely examine src and dst ports */
940 if (m->m_pkthdr.len < off + sizeof(ah))
941 return;
942
943 if (m->m_len < off + sizeof(ah)) {
944 /*
945 * this should be rare case,
946 * so we compromise on this copy...
947 */
948 m_copydata(m, off, sizeof(ah), (caddr_t)&ah);
949 ahp = &ah;
950 } else
951 ahp = (struct newah *)(mtod(m, caddr_t) + off);
952
953 if (cmd == PRC_MSGSIZE) {
954 int valid = 0;
955
956 /*
957 * Check to see if we have a valid SA corresponding to
958 * the address in the ICMP message payload.
959 */
960 sa6_src = ip6cp->ip6c_src;
961 sa6_dst = (struct sockaddr_in6 *)sa;
962 sav = key_allocsa(AF_INET6,
963 (caddr_t)&sa6_src->sin6_addr,
964 (caddr_t)&sa6_dst->sin6_addr,
965 IPPROTO_AH, ahp->ah_spi);
966 if (sav) {
967 if (sav->state == SADB_SASTATE_MATURE ||
968 sav->state == SADB_SASTATE_DYING)
969 valid++;
970 key_freesav(sav);
971 }
972
973 /* XXX Further validation? */
974
975 /*
976 * Depending on the value of "valid" and routing table
977 * size (mtudisc_{hi,lo}wat), we will:
978 * - recalcurate the new MTU and create the
979 * corresponding routing entry, or
980 * - ignore the MTU change notification.
981 */
982 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
983 }
984
985 /* we normally notify single pcb here */
986 } else {
987 /* we normally notify any pcb here */
988 }
989 }
990 #endif /* INET6 */
Cache object: d35e164f045b6bee3266d67a32134d33
|