network - Major netmsg retooling, part 1
[dragonfly.git] / sys / netinet6 / ah_input.c
1 /*      $FreeBSD: src/sys/netinet6/ah_input.c,v 1.1.2.6 2002/04/28 05:40:26 suz Exp $   */
2 /*      $DragonFly: src/sys/netinet6/ah_input.c,v 1.14 2007/11/26 11:43:09 sephe Exp $  */
3 /*      $KAME: ah_input.c,v 1.67 2002/01/07 11:39:56 kjc Exp $  */
4
5 /*
6  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the project nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 /*
35  * RFC1826/2402 authentication header.
36  */
37
38 #include "opt_inet.h"
39 #include "opt_inet6.h"
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/malloc.h>
44 #include <sys/mbuf.h>
45 #include <sys/domain.h>
46 #include <sys/protosw.h>
47 #include <sys/socket.h>
48 #include <sys/errno.h>
49 #include <sys/time.h>
50 #include <sys/syslog.h>
51
52 #include <net/if.h>
53 #include <net/route.h>
54 #include <net/netisr.h>
55 #include <machine/cpu.h>
56 #include <machine/stdarg.h>
57
58 #include <netinet/in.h>
59 #include <netinet/in_systm.h>
60 #include <netinet/in_var.h>
61 #include <netinet/ip.h>
62 #include <netinet/ip_var.h>
63 #include <netinet/ip_ecn.h>
64 #ifdef INET6
65 #include <netinet6/ip6_ecn.h>
66 #endif
67
68 #ifdef INET6
69 #include <netinet/ip6.h>
70 #include <netinet6/ip6_var.h>
71 #include <netinet6/in6_pcb.h>
72 #include <netinet/icmp6.h>
73 #include <netinet6/ip6protosw.h>
74 #endif
75
76 #include <netinet6/ipsec.h>
77 #ifdef INET6
78 #include <netinet6/ipsec6.h>
79 #endif
80 #include <netinet6/ah.h>
81 #ifdef INET6
82 #include <netinet6/ah6.h>
83 #endif
84 #include <netproto/key/key.h>
85 #include <netproto/key/keydb.h>
86 #ifdef IPSEC_DEBUG
87 #include <netproto/key/key_debug.h>
88 #else
89 #define KEYDEBUG(lev,arg)
90 #endif
91
92 #include <machine/stdarg.h>
93
94 #include <net/net_osdep.h>
95
96 #define IPLEN_FLIPPED
97
98 #ifdef INET
99 extern struct protosw inetsw[];
100
101 int
102 ah4_input(struct mbuf **mp, int *offp, int proto)
103 {
104         int off;
105         struct mbuf *m;
106         struct ip *ip;
107         struct ah *ah;
108         u_int32_t spi;
109         const struct ah_algorithm *algo;
110         size_t siz;
111         size_t siz1;
112         u_char *cksum;
113         struct secasvar *sav = NULL;
114         u_int16_t nxt;
115         size_t hlen;
116         size_t stripsiz = 0;
117
118         off = *offp;
119         m = *mp;
120         *mp = NULL;
121
122 #ifndef PULLDOWN_TEST
123         if (m->m_len < off + sizeof(struct newah)) {
124                 m = m_pullup(m, off + sizeof(struct newah));
125                 if (!m) {
126                         ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;"
127                                 "dropping the packet for simplicity\n"));
128                         ipsecstat.in_inval++;
129                         goto fail;
130                 }
131         }
132
133         ip = mtod(m, struct ip *);
134         ah = (struct ah *)(((caddr_t)ip) + off);
135 #else
136         ip = mtod(m, struct ip *);
137         IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah));
138         if (ah == NULL) {
139                 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;"
140                         "dropping the packet for simplicity\n"));
141                 ipsecstat.in_inval++;
142                 goto fail;
143         }
144 #endif
145         nxt = ah->ah_nxt;
146 #ifdef _IP_VHL
147         hlen = IP_VHL_HL(ip->ip_vhl) << 2;
148 #else
149         hlen = ip->ip_hl << 2;
150 #endif
151
152         /* find the sassoc. */
153         spi = ah->ah_spi;
154
155         if ((sav = key_allocsa(AF_INET,
156                               (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst,
157                               IPPROTO_AH, spi)) == 0) {
158                 ipseclog((LOG_WARNING,
159                     "IPv4 AH input: no key association found for spi %u\n",
160                     (u_int32_t)ntohl(spi)));
161                 ipsecstat.in_nosa++;
162                 goto fail;
163         }
164         KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
165                 kprintf("DP ah4_input called to allocate SA:%p\n", sav));
166         if (sav->state != SADB_SASTATE_MATURE
167          && sav->state != SADB_SASTATE_DYING) {
168                 ipseclog((LOG_DEBUG,
169                     "IPv4 AH input: non-mature/dying SA found for spi %u\n",
170                     (u_int32_t)ntohl(spi)));
171                 ipsecstat.in_badspi++;
172                 goto fail;
173         }
174
175         algo = ah_algorithm_lookup(sav->alg_auth);
176         if (!algo) {
177                 ipseclog((LOG_DEBUG, "IPv4 AH input: "
178                     "unsupported authentication algorithm for spi %u\n",
179                     (u_int32_t)ntohl(spi)));
180                 ipsecstat.in_badspi++;
181                 goto fail;
182         }
183
184         siz = (*algo->sumsiz)(sav);
185         siz1 = ((siz + 3) & ~(4 - 1));
186
187         /*
188          * sanity checks for header, 1.
189          */
190     {
191         int sizoff;
192
193         sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
194
195         /*
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
198          * to 96 bits.
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.
202          *
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
212          *   work.
213          *
214          * We may need some clarification in the spec.
215          */
216         if (siz1 < siz) {
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                 ipsecstat.in_inval++;
222                 goto fail;
223         }
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                 ipsecstat.in_inval++;
230                 goto fail;
231         }
232
233 #ifndef PULLDOWN_TEST
234         if (m->m_len < off + sizeof(struct ah) + sizoff + siz1) {
235                 m = m_pullup(m, off + sizeof(struct ah) + sizoff + siz1);
236                 if (!m) {
237                         ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n"));
238                         ipsecstat.in_inval++;
239                         goto fail;
240                 }
241
242                 ip = mtod(m, struct ip *);
243                 ah = (struct ah *)(((caddr_t)ip) + off);
244         }
245 #else
246         IP6_EXTHDR_GET(ah, struct ah *, m, off,
247                 sizeof(struct ah) + sizoff + siz1);
248         if (ah == NULL) {
249                 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n"));
250                 ipsecstat.in_inval++;
251                 goto fail;
252         }
253 #endif
254     }
255
256         /*
257          * check for sequence number.
258          */
259         if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
260                 if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav))
261                         ; /* okey */
262                 else {
263                         ipsecstat.in_ahreplay++;
264                         ipseclog((LOG_WARNING,
265                             "replay packet in IPv4 AH input: %s %s\n",
266                             ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
267                         goto fail;
268                 }
269         }
270
271         /*
272          * alright, it seems sane.  now we are going to check the
273          * cryptographic checksum.
274          */
275         cksum = kmalloc(siz1, M_TEMP, M_NOWAIT);
276         if (!cksum) {
277                 ipseclog((LOG_DEBUG, "IPv4 AH input: "
278                     "couldn't alloc temporary region for cksum\n"));
279                 ipsecstat.in_inval++;
280                 goto fail;
281         }
282         
283         /*
284          * some of IP header fields are flipped to the host endian.
285          * convert them back to network endian.  VERY stupid.
286          */
287         ip->ip_len = htons(ip->ip_len + hlen);
288         ip->ip_off = htons(ip->ip_off);
289         if (ah4_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) {
290                 kfree(cksum, M_TEMP);
291                 ipsecstat.in_inval++;
292                 goto fail;
293         }
294         ipsecstat.in_ahhist[sav->alg_auth]++;
295         /*
296          * flip them back.
297          */
298         ip->ip_len = ntohs(ip->ip_len) - hlen;
299         ip->ip_off = ntohs(ip->ip_off);
300
301     {
302         caddr_t sumpos = NULL;
303
304         if (sav->flags & SADB_X_EXT_OLD) {
305                 /* RFC 1826 */
306                 sumpos = (caddr_t)(ah + 1);
307         } else {
308                 /* RFC 2402 */
309                 sumpos = (caddr_t)(((struct newah *)ah) + 1);
310         }
311
312         if (bcmp(sumpos, cksum, siz) != 0) {
313                 ipseclog((LOG_WARNING,
314                     "checksum mismatch in IPv4 AH input: %s %s\n",
315                     ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
316                 kfree(cksum, M_TEMP);
317                 ipsecstat.in_ahauthfail++;
318                 goto fail;
319         }
320     }
321
322         kfree(cksum, M_TEMP);
323
324         m->m_flags |= M_AUTHIPHDR;
325         m->m_flags |= M_AUTHIPDGM;
326
327 #if 0
328         /*
329          * looks okey, but we need more sanity check.
330          * XXX should elaborate.
331          */
332         if (ah->ah_nxt == IPPROTO_IPIP || ah->ah_nxt == IPPROTO_IP) {
333                 struct ip *nip;
334                 size_t sizoff;
335
336                 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
337
338                 if (m->m_len < off + sizeof(struct ah) + sizoff + siz1 + hlen) {
339                         m = m_pullup(m, off + sizeof(struct ah)
340                                         + sizoff + siz1 + hlen);
341                         if (!m) {
342                                 ipseclog((LOG_DEBUG,
343                                     "IPv4 AH input: can't pullup\n"));
344                                 ipsecstat.in_inval++;
345                                 goto fail;
346                         }
347                 }
348
349                 nip = (struct ip *)((u_char *)(ah + 1) + sizoff + siz1);
350                 if (nip->ip_src.s_addr != ip->ip_src.s_addr
351                  || nip->ip_dst.s_addr != ip->ip_dst.s_addr) {
352                         m->m_flags &= ~M_AUTHIPHDR;
353                         m->m_flags &= ~M_AUTHIPDGM;
354                 }
355         }
356 #ifdef INET6
357         else if (ah->ah_nxt == IPPROTO_IPV6) {
358                 m->m_flags &= ~M_AUTHIPHDR;
359                 m->m_flags &= ~M_AUTHIPDGM;
360         }
361 #endif /* INET6 */
362 #endif /* 0 */
363
364         if (m->m_flags & M_AUTHIPHDR
365          && m->m_flags & M_AUTHIPDGM) {
366 #if 0
367                 ipseclog((LOG_DEBUG,
368                     "IPv4 AH input: authentication succeess\n"));
369 #endif
370                 ipsecstat.in_ahauthsucc++;
371         } else {
372                 ipseclog((LOG_WARNING,
373                     "authentication failed in IPv4 AH input: %s %s\n",
374                     ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
375                 ipsecstat.in_ahauthfail++;
376                 goto fail;
377         }
378
379         /*
380          * update sequence number.
381          */
382         if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
383                 if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) {
384                         ipsecstat.in_ahreplay++;
385                         goto fail;
386                 }
387         }
388
389         /* was it transmitted over the IPsec tunnel SA? */
390         if (sav->flags & SADB_X_EXT_OLD) {
391                 /* RFC 1826 */
392                 stripsiz = sizeof(struct ah) + siz1;
393         } else {
394                 /* RFC 2402 */
395                 stripsiz = sizeof(struct newah) + siz1;
396         }
397         if (ipsec4_tunnel_validate(m, off + stripsiz, nxt, sav)) {
398                 /*
399                  * strip off all the headers that precedes AH.
400                  *      IP xx AH IP' payload -> IP' payload
401                  *
402                  * XXX more sanity checks
403                  * XXX relationship with gif?
404                  */
405                 u_int8_t tos;
406
407                 tos = ip->ip_tos;
408                 m_adj(m, off + stripsiz);
409                 if (m->m_len < sizeof(*ip)) {
410                         m = m_pullup(m, sizeof(*ip));
411                         if (!m) {
412                                 ipsecstat.in_inval++;
413                                 goto fail;
414                         }
415                 }
416                 ip = mtod(m, struct ip *);
417                 /* ECN consideration. */
418                 ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos);
419                 if (!key_checktunnelsanity(sav, AF_INET,
420                             (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) {
421                         ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
422                             "in IPv4 AH input: %s %s\n",
423                             ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
424                         ipsecstat.in_inval++;
425                         goto fail;
426                 }
427
428 #if 1
429                 /*
430                  * Should the inner packet be considered authentic?
431                  * My current answer is: NO.
432                  *
433                  * host1 -- gw1 === gw2 -- host2
434                  *      In this case, gw2 can trust the authenticity of the
435                  *      outer packet, but NOT inner.  Packet may be altered
436                  *      between host1 and gw1.
437                  *
438                  * host1 -- gw1 === host2
439                  *      This case falls into the same scenario as above.
440                  *
441                  * host1 === host2
442                  *      This case is the only case when we may be able to leave
443                  *      M_AUTHIPHDR and M_AUTHIPDGM set.
444                  *      However, if host1 is wrongly configured, and allows
445                  *      attacker to inject some packet with src=host1 and
446                  *      dst=host2, you are in risk.
447                  */
448                 m->m_flags &= ~M_AUTHIPHDR;
449                 m->m_flags &= ~M_AUTHIPDGM;
450 #endif
451
452                 key_sa_recordxfer(sav, m);
453                 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
454                     ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) {
455                         ipsecstat.in_nomem++;
456                         goto fail;
457                 }
458
459                 if (netisr_queue(NETISR_IP, m)) {
460                         ipsecstat.in_inval++;
461                         m = NULL;
462                         goto fail;
463                 }
464
465                 nxt = IPPROTO_DONE;
466         } else {
467                 /*
468                  * strip off AH.
469                  */
470
471                 ip = mtod(m, struct ip *);
472 #ifndef PULLDOWN_TEST
473                 /*
474                  * We do deep-copy since KAME requires that
475                  * the packet is placed in a single external mbuf.
476                  */
477                 ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), off);
478                 m->m_data += stripsiz;
479                 m->m_len -= stripsiz;
480                 m->m_pkthdr.len -= stripsiz;
481 #else
482                 /*
483                  * even in m_pulldown case, we need to strip off AH so that
484                  * we can compute checksum for multiple AH correctly.
485                  */
486                 if (m->m_len >= stripsiz + off) {
487                         ovbcopy((caddr_t)ip, ((caddr_t)ip) + stripsiz, off);
488                         m->m_data += stripsiz;
489                         m->m_len -= stripsiz;
490                         m->m_pkthdr.len -= stripsiz;
491                 } else {
492                         /*
493                          * this comes with no copy if the boundary is on
494                          * cluster
495                          */
496                         struct mbuf *n;
497
498                         n = m_split(m, off, MB_DONTWAIT);
499                         if (n == NULL) {
500                                 /* m is retained by m_split */
501                                 goto fail;
502                         }
503                         m_adj(n, stripsiz);
504                         /* m_cat does not update m_pkthdr.len */
505                         m->m_pkthdr.len += n->m_pkthdr.len;
506                         m_cat(m, n);
507                 }
508 #endif
509
510                 if (m->m_len < sizeof(*ip)) {
511                         m = m_pullup(m, sizeof(*ip));
512                         if (m == NULL) {
513                                 ipsecstat.in_inval++;
514                                 goto fail;
515                         }
516                 }
517                 ip = mtod(m, struct ip *);
518 #ifdef IPLEN_FLIPPED
519                 ip->ip_len = ip->ip_len - stripsiz;
520 #else
521                 ip->ip_len = htons(ntohs(ip->ip_len) - stripsiz);
522 #endif
523                 ip->ip_p = nxt;
524                 /* forget about IP hdr checksum, the check has already been passed */
525
526                 key_sa_recordxfer(sav, m);
527                 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
528                         ipsecstat.in_nomem++;
529                         goto fail;
530                 }
531
532                 if (nxt != IPPROTO_DONE) {
533                         if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) &&
534                             ipsec4_in_reject(m, NULL)) {
535                                 ipsecstat.in_polvio++;
536                                 goto fail;
537                         }
538                         if (!ip_lengthcheck(&m, 0)) {
539                                 /* freed in ip_lengthcheck() */
540                                 goto fail;
541                         }
542                         *mp = m;
543                         *offp = off;
544                         (*inetsw[ip_protox[nxt]].pr_input)(mp, offp, nxt);
545                 } else {
546                         m_freem(m);
547                 }
548                 m = NULL;
549         }
550
551         if (sav) {
552                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
553                         kprintf("DP ah4_input call free SA:%p\n", sav));
554                 key_freesav(sav);
555         }
556         ipsecstat.in_success++;
557         return(IPPROTO_DONE);
558
559 fail:
560         if (sav) {
561                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
562                         kprintf("DP ah4_input call free SA:%p\n", sav));
563                 key_freesav(sav);
564         }
565         if (m)
566                 m_freem(m);
567         return(IPPROTO_DONE);
568 }
569 #endif /* INET */
570
571 #ifdef INET6
572 int
573 ah6_input(struct mbuf **mp, int *offp, int proto)
574 {
575         struct mbuf *m = *mp;
576         int off = *offp;
577         struct ip6_hdr *ip6;
578         struct ah *ah;
579         u_int32_t spi;
580         const struct ah_algorithm *algo;
581         size_t siz;
582         size_t siz1;
583         u_char *cksum;
584         struct secasvar *sav = NULL;
585         u_int16_t nxt;
586         size_t stripsiz = 0;
587
588 #ifndef PULLDOWN_TEST
589         IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), IPPROTO_DONE);
590         ah = (struct ah *)(mtod(m, caddr_t) + off);
591 #else
592         IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah));
593         if (ah == NULL) {
594                 ipseclog((LOG_DEBUG, "IPv6 AH input: can't pullup\n"));
595                 ipsec6stat.in_inval++;
596                 return IPPROTO_DONE;
597         }
598 #endif
599         ip6 = mtod(m, struct ip6_hdr *);
600         nxt = ah->ah_nxt;
601
602         /* find the sassoc. */
603         spi = ah->ah_spi;
604
605         if (ntohs(ip6->ip6_plen) == 0) {
606                 ipseclog((LOG_ERR, "IPv6 AH input: "
607                     "AH with IPv6 jumbogram is not supported.\n"));
608                 ipsec6stat.in_inval++;
609                 goto fail;
610         }
611
612         if ((sav = key_allocsa(AF_INET6,
613                               (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst,
614                               IPPROTO_AH, spi)) == 0) {
615                 ipseclog((LOG_WARNING,
616                     "IPv6 AH input: no key association found for spi %u\n",
617                     (u_int32_t)ntohl(spi)));
618                 ipsec6stat.in_nosa++;
619                 goto fail;
620         }
621         KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
622                 kprintf("DP ah6_input called to allocate SA:%p\n", sav));
623         if (sav->state != SADB_SASTATE_MATURE
624          && sav->state != SADB_SASTATE_DYING) {
625                 ipseclog((LOG_DEBUG,
626                     "IPv6 AH input: non-mature/dying SA found for spi %u; ",
627                     (u_int32_t)ntohl(spi)));
628                 ipsec6stat.in_badspi++;
629                 goto fail;
630         }
631
632         algo = ah_algorithm_lookup(sav->alg_auth);
633         if (!algo) {
634                 ipseclog((LOG_DEBUG, "IPv6 AH input: "
635                     "unsupported authentication algorithm for spi %u\n",
636                     (u_int32_t)ntohl(spi)));
637                 ipsec6stat.in_badspi++;
638                 goto fail;
639         }
640
641         siz = (*algo->sumsiz)(sav);
642         siz1 = ((siz + 3) & ~(4 - 1));
643
644         /*
645          * sanity checks for header, 1.
646          */
647     {
648         int sizoff;
649
650         sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
651
652         /*
653          * Here, we do not do "siz1 == siz".  See ah4_input() for complete
654          * description.
655          */
656         if (siz1 < siz) {
657                 ipseclog((LOG_NOTICE, "sum length too short in IPv6 AH input "
658                     "(%lu, should be at least %lu): %s\n",
659                     (u_long)siz1, (u_long)siz,
660                     ipsec6_logpacketstr(ip6, spi)));
661                 ipsec6stat.in_inval++;
662                 goto fail;
663         }
664         if ((ah->ah_len << 2) - sizoff != siz1) {
665                 ipseclog((LOG_NOTICE, "sum length mismatch in IPv6 AH input "
666                     "(%d should be %lu): %s\n",
667                     (ah->ah_len << 2) - sizoff, (u_long)siz1,
668                     ipsec6_logpacketstr(ip6, spi)));
669                 ipsec6stat.in_inval++;
670                 goto fail;
671         }
672 #ifndef PULLDOWN_TEST
673         IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1, IPPROTO_DONE);
674 #else
675         IP6_EXTHDR_GET(ah, struct ah *, m, off,
676                 sizeof(struct ah) + sizoff + siz1);
677         if (ah == NULL) {
678                 ipseclog((LOG_NOTICE, "couldn't pullup gather IPv6 AH checksum part"));
679                 ipsec6stat.in_inval++;
680                 m = NULL;
681                 goto fail;
682         }
683 #endif
684     }
685
686         /*
687          * check for sequence number.
688          */
689         if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
690                 if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav))
691                         ; /* okey */
692                 else {
693                         ipsec6stat.in_ahreplay++;
694                         ipseclog((LOG_WARNING,
695                             "replay packet in IPv6 AH input: %s %s\n",
696                             ipsec6_logpacketstr(ip6, spi),
697                             ipsec_logsastr(sav)));
698                         goto fail;
699                 }
700         }
701
702         /*
703          * alright, it seems sane.  now we are going to check the
704          * cryptographic checksum.
705          */
706         cksum = kmalloc(siz1, M_TEMP, M_NOWAIT);
707         if (!cksum) {
708                 ipseclog((LOG_DEBUG, "IPv6 AH input: "
709                     "couldn't alloc temporary region for cksum\n"));
710                 ipsec6stat.in_inval++;
711                 goto fail;
712         }
713         
714         if (ah6_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) {
715                 kfree(cksum, M_TEMP);
716                 ipsec6stat.in_inval++;
717                 goto fail;
718         }
719         ipsec6stat.in_ahhist[sav->alg_auth]++;
720
721     {
722         caddr_t sumpos = NULL;
723
724         if (sav->flags & SADB_X_EXT_OLD) {
725                 /* RFC 1826 */
726                 sumpos = (caddr_t)(ah + 1);
727         } else {
728                 /* RFC 2402 */
729                 sumpos = (caddr_t)(((struct newah *)ah) + 1);
730         }
731
732         if (bcmp(sumpos, cksum, siz) != 0) {
733                 ipseclog((LOG_WARNING,
734                     "checksum mismatch in IPv6 AH input: %s %s\n",
735                     ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
736                 kfree(cksum, M_TEMP);
737                 ipsec6stat.in_ahauthfail++;
738                 goto fail;
739         }
740     }
741
742         kfree(cksum, M_TEMP);
743
744         m->m_flags |= M_AUTHIPHDR;
745         m->m_flags |= M_AUTHIPDGM;
746
747 #if 0
748         /*
749          * looks okey, but we need more sanity check.
750          * XXX should elaborate.
751          */
752         if (ah->ah_nxt == IPPROTO_IPV6) {
753                 struct ip6_hdr *nip6;
754                 size_t sizoff;
755
756                 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
757
758                 IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1
759                                 + sizeof(struct ip6_hdr), IPPROTO_DONE);
760
761                 nip6 = (struct ip6_hdr *)((u_char *)(ah + 1) + sizoff + siz1);
762                 if (!IN6_ARE_ADDR_EQUAL(&nip6->ip6_src, &ip6->ip6_src)
763                  || !IN6_ARE_ADDR_EQUAL(&nip6->ip6_dst, &ip6->ip6_dst)) {
764                         m->m_flags &= ~M_AUTHIPHDR;
765                         m->m_flags &= ~M_AUTHIPDGM;
766                 }
767         } else if (ah->ah_nxt == IPPROTO_IPIP) {
768                 m->m_flags &= ~M_AUTHIPHDR;
769                 m->m_flags &= ~M_AUTHIPDGM;
770         } else if (ah->ah_nxt == IPPROTO_IP) {
771                 m->m_flags &= ~M_AUTHIPHDR;
772                 m->m_flags &= ~M_AUTHIPDGM;
773         }
774 #endif
775
776         if (m->m_flags & M_AUTHIPHDR
777          && m->m_flags & M_AUTHIPDGM) {
778 #if 0
779                 ipseclog((LOG_DEBUG,
780                     "IPv6 AH input: authentication succeess\n"));
781 #endif
782                 ipsec6stat.in_ahauthsucc++;
783         } else {
784                 ipseclog((LOG_WARNING,
785                     "authentication failed in IPv6 AH input: %s %s\n",
786                     ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
787                 ipsec6stat.in_ahauthfail++;
788                 goto fail;
789         }
790
791         /*
792          * update sequence number.
793          */
794         if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
795                 if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) {
796                         ipsec6stat.in_ahreplay++;
797                         goto fail;
798                 }
799         }
800
801         /* was it transmitted over the IPsec tunnel SA? */
802         if (sav->flags & SADB_X_EXT_OLD) {
803                 /* RFC 1826 */
804                 stripsiz = sizeof(struct ah) + siz1;
805         } else {
806                 /* RFC 2402 */
807                 stripsiz = sizeof(struct newah) + siz1;
808         }
809         if (ipsec6_tunnel_validate(m, off + stripsiz, nxt, sav)) {
810                 /*
811                  * strip off all the headers that precedes AH.
812                  *      IP6 xx AH IP6' payload -> IP6' payload
813                  *
814                  * XXX more sanity checks
815                  * XXX relationship with gif?
816                  */
817                 u_int32_t flowinfo;     /* net endian */
818
819                 flowinfo = ip6->ip6_flow;
820                 m_adj(m, off + stripsiz);
821                 if (m->m_len < sizeof(*ip6)) {
822                         /*
823                          * m_pullup is prohibited in KAME IPv6 input processing
824                          * but there's no other way!
825                          */
826                         m = m_pullup(m, sizeof(*ip6));
827                         if (!m) {
828                                 ipsec6stat.in_inval++;
829                                 goto fail;
830                         }
831                 }
832                 ip6 = mtod(m, struct ip6_hdr *);
833                 /* ECN consideration. */
834                 ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow);
835                 if (!key_checktunnelsanity(sav, AF_INET6,
836                             (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) {
837                         ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
838                             "in IPv6 AH input: %s %s\n",
839                             ipsec6_logpacketstr(ip6, spi),
840                             ipsec_logsastr(sav)));
841                         ipsec6stat.in_inval++;
842                         goto fail;
843                 }
844
845 #if 1
846                 /*
847                  * should the inner packet be considered authentic?
848                  * see comment in ah4_input().
849                  */
850                 m->m_flags &= ~M_AUTHIPHDR;
851                 m->m_flags &= ~M_AUTHIPDGM;
852 #endif
853
854                 key_sa_recordxfer(sav, m);
855                 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
856                     ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) {
857                         ipsec6stat.in_nomem++;
858                         goto fail;
859                 }
860
861                 if (netisr_queue(NETISR_IPV6, m)) {
862                         ipsec6stat.in_inval++;
863                         m = NULL;
864                         goto fail;
865                 }
866
867                 nxt = IPPROTO_DONE;
868         } else {
869                 /*
870                  * strip off AH.
871                  */
872                 char *prvnxtp;
873
874                 /*
875                  * Copy the value of the next header field of AH to the
876                  * next header field of the previous header.
877                  * This is necessary because AH will be stripped off below.
878                  */
879                 prvnxtp = ip6_get_prevhdr(m, off); /* XXX */
880                 *prvnxtp = nxt;
881
882                 ip6 = mtod(m, struct ip6_hdr *);
883 #ifndef PULLDOWN_TEST
884                 /*
885                  * We do deep-copy since KAME requires that
886                  * the packet is placed in a single mbuf.
887                  */
888                 ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
889                 m->m_data += stripsiz;
890                 m->m_len -= stripsiz;
891                 m->m_pkthdr.len -= stripsiz;
892 #else
893                 /*
894                  * even in m_pulldown case, we need to strip off AH so that
895                  * we can compute checksum for multiple AH correctly.
896                  */
897                 if (m->m_len >= stripsiz + off) {
898                         ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
899                         m->m_data += stripsiz;
900                         m->m_len -= stripsiz;
901                         m->m_pkthdr.len -= stripsiz;
902                 } else {
903                         /*
904                          * this comes with no copy if the boundary is on
905                          * cluster
906                          */
907                         struct mbuf *n;
908
909                         n = m_split(m, off, MB_DONTWAIT);
910                         if (n == NULL) {
911                                 /* m is retained by m_split */
912                                 goto fail;
913                         }
914                         m_adj(n, stripsiz);
915                         /* m_cat does not update m_pkthdr.len */
916                         m->m_pkthdr.len += n->m_pkthdr.len;
917                         m_cat(m, n);
918                 }
919 #endif
920                 ip6 = mtod(m, struct ip6_hdr *);
921                 /* XXX jumbogram */
922                 ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz);
923
924                 key_sa_recordxfer(sav, m);
925                 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
926                         ipsec6stat.in_nomem++;
927                         goto fail;
928                 }
929         }
930
931         *offp = off;
932         *mp = m;
933
934         if (sav) {
935                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
936                         kprintf("DP ah6_input call free SA:%p\n", sav));
937                 key_freesav(sav);
938         }
939         ipsec6stat.in_success++;
940         return nxt;
941
942 fail:
943         if (sav) {
944                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
945                         kprintf("DP ah6_input call free SA:%p\n", sav));
946                 key_freesav(sav);
947         }
948         if (m)
949                 m_freem(m);
950         return IPPROTO_DONE;
951 }
952
953 void
954 ah6_ctlinput(int cmd, struct sockaddr *sa, void *d)
955 {
956         const struct newah *ahp;
957         struct newah ah;
958         struct secasvar *sav;
959         struct ip6_hdr *ip6;
960         struct mbuf *m;
961         struct ip6ctlparam *ip6cp = NULL;
962         int off;
963         struct sockaddr_in6 *sa6_src, *sa6_dst;
964
965         if (sa->sa_family != AF_INET6 ||
966             sa->sa_len != sizeof(struct sockaddr_in6))
967                 return;
968         if ((unsigned)cmd >= PRC_NCMDS)
969                 return;
970
971         /* if the parameter is from icmp6, decode it. */
972         if (d != NULL) {
973                 ip6cp = (struct ip6ctlparam *)d;
974                 m = ip6cp->ip6c_m;
975                 ip6 = ip6cp->ip6c_ip6;
976                 off = ip6cp->ip6c_off;
977         } else {
978                 m = NULL;
979                 ip6 = NULL;
980                 off = 0; /* fix warning */
981         }
982
983         if (ip6) {
984                 /*
985                  * XXX: We assume that when ip6 is non NULL,
986                  * M and OFF are valid.
987                  */
988
989                 /* check if we can safely examine src and dst ports */
990                 if (m->m_pkthdr.len < off + sizeof(ah))
991                         return;
992
993                 if (m->m_len < off + sizeof(ah)) {
994                         /*
995                          * this should be rare case,
996                          * so we compromise on this copy...
997                          */
998                         m_copydata(m, off, sizeof(ah), (caddr_t)&ah);
999                         ahp = &ah;
1000                 } else
1001                         ahp = (struct newah *)(mtod(m, caddr_t) + off);
1002
1003                 if (cmd == PRC_MSGSIZE) {
1004                         int valid = 0;
1005
1006                         /*
1007                          * Check to see if we have a valid SA corresponding to
1008                          * the address in the ICMP message payload.
1009                          */
1010                         sa6_src = ip6cp->ip6c_src;
1011                         sa6_dst = (struct sockaddr_in6 *)sa;
1012                         sav = key_allocsa(AF_INET6,
1013                                           (caddr_t)&sa6_src->sin6_addr,
1014                                           (caddr_t)&sa6_dst->sin6_addr,
1015                                           IPPROTO_AH, ahp->ah_spi);
1016                         if (sav) {
1017                                 if (sav->state == SADB_SASTATE_MATURE ||
1018                                     sav->state == SADB_SASTATE_DYING)
1019                                         valid++;
1020                                 key_freesav(sav);
1021                         }
1022
1023                         /* XXX Further validation? */
1024
1025                         /*
1026                          * Depending on the value of "valid" and routing table
1027                          * size (mtudisc_{hi,lo}wat), we will:
1028                          * - recalcurate the new MTU and create the
1029                          *   corresponding routing entry, or
1030                          * - ignore the MTU change notification.
1031                          */
1032                         icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
1033                 }
1034
1035                 /* we normally notify single pcb here */
1036         } else {
1037                 /* we normally notify any pcb here */
1038         }
1039 }
1040 #endif /* INET6 */