ipsec_output.c revision 1.40 1 /* $NetBSD: ipsec_output.c,v 1.40 2013/11/03 18:37:10 mrg Exp $ */
2
3 /*-
4 * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $FreeBSD: /repoman/r/ncvs/src/sys/netipsec/ipsec_output.c,v 1.3.2.2 2003/03/28 20:32:53 sam Exp $
29 */
30
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: ipsec_output.c,v 1.40 2013/11/03 18:37:10 mrg Exp $");
33
34 /*
35 * IPsec output processing.
36 */
37 #include "opt_inet.h"
38 #ifdef __FreeBSD__
39 #include "opt_inet6.h"
40 #endif
41 #include "opt_ipsec.h"
42
43 #include <sys/param.h>
44 #include <sys/systm.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/syslog.h>
51
52 #include <net/if.h>
53 #include <net/route.h>
54
55 #include <netinet/in.h>
56 #include <netinet/in_systm.h>
57 #include <netinet/ip.h>
58 #include <netinet/ip_var.h>
59 #include <netinet/in_var.h>
60 #include <netinet/ip_ecn.h>
61 #ifdef INET6
62 # ifdef __FreeBSD__
63 # include <netinet6/ip6_ecn.h>
64 # endif
65 #endif
66
67 #include <netinet/ip6.h>
68 #ifdef INET6
69 #include <netinet6/ip6_var.h>
70 #endif
71 #include <netinet/in_pcb.h>
72 #ifdef INET6
73 #include <netinet/icmp6.h>
74 #endif
75 #include <netinet/udp.h>
76
77 #include <netipsec/ipsec.h>
78 #include <netipsec/ipsec_var.h>
79 #include <netipsec/ipsec_private.h>
80 #ifdef INET6
81 #include <netipsec/ipsec6.h>
82 #endif
83 #include <netipsec/ah_var.h>
84 #include <netipsec/esp_var.h>
85 #include <netipsec/ipcomp_var.h>
86
87 #include <netipsec/xform.h>
88
89 #include <netipsec/key.h>
90 #include <netipsec/keydb.h>
91 #include <netipsec/key_debug.h>
92 #include <netipsec/ipsec_osdep.h>
93
94 #include <net/net_osdep.h> /* ovbcopy() in ipsec6_encapsulate() */
95
96
97 /*
98 * Add a IPSEC_OUT_DONE tag to mark that we have finished the ipsec processing
99 * It will be used by ip{,6}_output to check if we have already or not
100 * processed this packet.
101 */
102 static int
103 ipsec_register_done(struct mbuf *m, int * error)
104 {
105 struct m_tag *mtag;
106
107 mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE, 0, M_NOWAIT);
108 if (mtag == NULL) {
109 DPRINTF(("ipsec_register_done: could not get packet tag\n"));
110 *error = ENOMEM;
111 return -1;
112 }
113
114 m_tag_prepend(m, mtag);
115 return 0;
116 }
117
118 static int
119 ipsec_reinject_ipstack(struct mbuf *m, int af)
120 {
121 #ifdef INET
122 #ifdef __FreeBSD__
123 struct ip *ip;
124 #endif /* __FreeBSD_ */
125 #endif /* INET */
126 #if defined(INET) || defined(INET6)
127 int rv;
128 #endif
129
130 switch (af) {
131 #ifdef INET
132 case AF_INET:
133 #ifdef __FreeBSD__
134 ip = mtod(m, struct ip *);
135 /* FreeBSD ip_output() expects ip_len, ip_off in host endian */
136 ip->ip_len = ntohs(ip->ip_len);
137 ip->ip_off = ntohs(ip->ip_off);
138 #endif /* __FreeBSD_ */
139 KERNEL_LOCK(1, NULL);
140 rv = ip_output(m, NULL, NULL, IP_RAWOUTPUT|IP_NOIPNEWID,
141 NULL, NULL);
142 KERNEL_UNLOCK_ONE(NULL);
143 return rv;
144
145 #endif /* INET */
146 #ifdef INET6
147 case AF_INET6:
148 /*
149 * We don't need massage, IPv6 header fields are always in
150 * net endian.
151 */
152 KERNEL_LOCK(1, NULL);
153 rv = ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
154 KERNEL_UNLOCK_ONE(NULL);
155 return rv;
156 #endif /* INET6 */
157 }
158
159 panic("ipsec_reinject_ipstack : iunknown protocol family %u\n", af);
160 return -1; /* NOTREACHED */
161 }
162
163 int
164 ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr)
165 {
166 struct secasvar *sav;
167 struct secasindex *saidx;
168 int error;
169 #ifdef INET
170 struct ip * ip;
171 #endif /* INET */
172 #ifdef INET6
173 struct ip6_hdr * ip6;
174 #endif /* INET6 */
175 struct mbuf * mo;
176 struct udphdr *udp = NULL;
177 uint64_t * data = NULL;
178 int hlen, roff;
179
180 IPSEC_SPLASSERT_SOFTNET("ipsec_process_done");
181
182 IPSEC_ASSERT(m != NULL, ("ipsec_process_done: null mbuf"));
183 IPSEC_ASSERT(isr != NULL, ("ipsec_process_done: null ISR"));
184 sav = isr->sav;
185 IPSEC_ASSERT(sav != NULL, ("ipsec_process_done: null SA"));
186 IPSEC_ASSERT(sav->sah != NULL, ("ipsec_process_done: null SAH"));
187
188 saidx = &sav->sah->saidx;
189
190 if(sav->natt_type != 0) {
191 ip = mtod(m, struct ip *);
192
193 hlen = sizeof(struct udphdr);
194 if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
195 hlen += sizeof(uint64_t);
196
197 mo = m_makespace(m, sizeof(struct ip), hlen, &roff);
198 if (mo == NULL) {
199 DPRINTF(("ipsec_process_done : failed to inject"
200 "%u byte UDP for SA %s/%08lx\n",
201 hlen, ipsec_address(&saidx->dst),
202 (u_long) ntohl(sav->spi)));
203 error = ENOBUFS;
204 goto bad;
205 }
206
207 udp = (struct udphdr*) (mtod(mo, char*) + roff);
208 data = (uint64_t*) (udp + 1);
209
210 if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
211 *data = 0; /* NON-IKE Marker */
212
213 if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
214 udp->uh_sport = htons(UDP_ENCAP_ESPINUDP_PORT);
215 else
216 udp->uh_sport = key_portfromsaddr(&saidx->src);
217
218 udp->uh_dport = key_portfromsaddr(&saidx->dst);
219 udp->uh_sum = 0;
220 udp->uh_ulen = htons(m->m_pkthdr.len - (ip->ip_hl << 2));
221 }
222
223 switch (saidx->dst.sa.sa_family) {
224 #ifdef INET
225 case AF_INET:
226 /* Fix the header length, for AH processing. */
227 ip = mtod(m, struct ip *);
228 ip->ip_len = htons(m->m_pkthdr.len);
229 if (sav->natt_type != 0)
230 ip->ip_p = IPPROTO_UDP;
231 break;
232 #endif /* INET */
233 #ifdef INET6
234 case AF_INET6:
235 /* Fix the header length, for AH processing. */
236 if (m->m_pkthdr.len < sizeof (struct ip6_hdr)) {
237 error = ENXIO;
238 goto bad;
239 }
240 if (m->m_pkthdr.len - sizeof (struct ip6_hdr) > IPV6_MAXPACKET) {
241 /* No jumbogram support. */
242 error = ENXIO; /*?*/
243 goto bad;
244 }
245 ip6 = mtod(m, struct ip6_hdr *);
246 ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
247 if (sav->natt_type != 0)
248 ip6->ip6_nxt = IPPROTO_UDP;
249 break;
250 #endif /* INET6 */
251 default:
252 DPRINTF(("ipsec_process_done: unknown protocol family %u\n",
253 saidx->dst.sa.sa_family));
254 error = ENXIO;
255 goto bad;
256 }
257
258 key_sa_recordxfer(sav, m);
259
260 /*
261 * If there's another (bundled) SA to apply, do so.
262 * Note that this puts a burden on the kernel stack size.
263 * If this is a problem we'll need to introduce a queue
264 * to set the packet on so we can unwind the stack before
265 * doing further processing.
266 */
267 if (isr->next) {
268 IPSEC_STATINC(IPSEC_STAT_OUT_BUNDLESA);
269 switch ( saidx->dst.sa.sa_family ) {
270 #ifdef INET
271 case AF_INET:
272 return ipsec4_process_packet(m, isr->next, 0,0);
273 #endif /* INET */
274 #ifdef INET6
275 case AF_INET6:
276 return ipsec6_process_packet(m,isr->next);
277 #endif /* INET6 */
278 default :
279 DPRINTF(("ipsec_process_done: unknown protocol family %u\n",
280 saidx->dst.sa.sa_family));
281 error = ENXIO;
282 goto bad;
283 }
284 }
285
286 /*
287 * We're done with IPsec processing,
288 * mark that we have already processed the packet
289 * transmit it packet using the appropriate network protocol (IP or IPv6).
290 */
291
292 if (ipsec_register_done(m, &error) < 0)
293 goto bad;
294
295 return ipsec_reinject_ipstack(m, saidx->dst.sa.sa_family);
296 bad:
297 m_freem(m);
298 KEY_FREESAV(&sav);
299 return (error);
300 }
301
302 /*
303 * ipsec_nextisr can return :
304 * - isr == NULL and error != 0 => something is bad : the packet must be
305 * discarded
306 * - isr == NULL and error == 0 => no more rules to apply, ipsec processing
307 * is done, reinject it in ip stack
308 * - isr != NULL (error == 0) => we need to apply one rule to the packet
309 */
310 static struct ipsecrequest *
311 ipsec_nextisr(
312 struct mbuf *m,
313 struct ipsecrequest *isr,
314 int af,
315 struct secasindex *saidx,
316 int *error
317 )
318 {
319 #define IPSEC_OSTAT(x, y, z) \
320 do { \
321 switch (isr->saidx.proto) { \
322 case IPPROTO_ESP: \
323 ESP_STATINC(x); \
324 break; \
325 case IPPROTO_AH: \
326 AH_STATINC(y); \
327 break; \
328 default: \
329 IPCOMP_STATINC(z); \
330 break; \
331 } \
332 } while (/*CONSTCOND*/0)
333
334 struct secasvar *sav;
335
336 IPSEC_SPLASSERT_SOFTNET("ipsec_nextisr");
337 IPSEC_ASSERT(af == AF_INET || af == AF_INET6,
338 ("ipsec_nextisr: invalid address family %u", af));
339 again:
340 /*
341 * Craft SA index to search for proper SA. Note that
342 * we only fillin unspecified SA peers for transport
343 * mode; for tunnel mode they must already be filled in.
344 */
345 *saidx = isr->saidx;
346 if (isr->saidx.mode == IPSEC_MODE_TRANSPORT) {
347 /* Fillin unspecified SA peers only for transport mode */
348 if (af == AF_INET) {
349 struct sockaddr_in *sin;
350 struct ip *ip = mtod(m, struct ip *);
351
352 if (saidx->src.sa.sa_len == 0) {
353 sin = &saidx->src.sin;
354 sin->sin_len = sizeof(*sin);
355 sin->sin_family = AF_INET;
356 sin->sin_port = IPSEC_PORT_ANY;
357 sin->sin_addr = ip->ip_src;
358 }
359 if (saidx->dst.sa.sa_len == 0) {
360 sin = &saidx->dst.sin;
361 sin->sin_len = sizeof(*sin);
362 sin->sin_family = AF_INET;
363 sin->sin_port = IPSEC_PORT_ANY;
364 sin->sin_addr = ip->ip_dst;
365 }
366 } else {
367 struct sockaddr_in6 *sin6;
368 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
369
370 if (saidx->src.sin6.sin6_len == 0) {
371 sin6 = (struct sockaddr_in6 *)&saidx->src;
372 sin6->sin6_len = sizeof(*sin6);
373 sin6->sin6_family = AF_INET6;
374 sin6->sin6_port = IPSEC_PORT_ANY;
375 sin6->sin6_addr = ip6->ip6_src;
376 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
377 /* fix scope id for comparing SPD */
378 sin6->sin6_addr.s6_addr16[1] = 0;
379 sin6->sin6_scope_id =
380 ntohs(ip6->ip6_src.s6_addr16[1]);
381 }
382 }
383 if (saidx->dst.sin6.sin6_len == 0) {
384 sin6 = (struct sockaddr_in6 *)&saidx->dst;
385 sin6->sin6_len = sizeof(*sin6);
386 sin6->sin6_family = AF_INET6;
387 sin6->sin6_port = IPSEC_PORT_ANY;
388 sin6->sin6_addr = ip6->ip6_dst;
389 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
390 /* fix scope id for comparing SPD */
391 sin6->sin6_addr.s6_addr16[1] = 0;
392 sin6->sin6_scope_id =
393 ntohs(ip6->ip6_dst.s6_addr16[1]);
394 }
395 }
396 }
397 }
398
399 /*
400 * Lookup SA and validate it.
401 */
402 *error = key_checkrequest(isr, saidx);
403 if (*error != 0) {
404 /*
405 * IPsec processing is required, but no SA found.
406 * I assume that key_acquire() had been called
407 * to get/establish the SA. Here I discard
408 * this packet because it is responsibility for
409 * upper layer to retransmit the packet.
410 */
411 IPSEC_STATINC(IPSEC_STAT_OUT_NOSA);
412 goto bad;
413 }
414 sav = isr->sav;
415 /* sav may be NULL here if we have an USE rule */
416 if (sav == NULL) {
417 IPSEC_ASSERT(ipsec_get_reqlevel(isr) == IPSEC_LEVEL_USE,
418 ("ipsec_nextisr: no SA found, but required; level %u",
419 ipsec_get_reqlevel(isr)));
420 isr = isr->next;
421 /*
422 * No more rules to apply, return NULL isr and no error
423 * It can happen when the last rules are USE rules
424 * */
425 if (isr == NULL) {
426 *error = 0;
427 return isr;
428 }
429 goto again;
430 }
431
432 /*
433 * Check system global policy controls.
434 */
435 if ((isr->saidx.proto == IPPROTO_ESP && !esp_enable) ||
436 (isr->saidx.proto == IPPROTO_AH && !ah_enable) ||
437 (isr->saidx.proto == IPPROTO_IPCOMP && !ipcomp_enable)) {
438 DPRINTF(("ipsec_nextisr: IPsec outbound packet dropped due"
439 " to policy (check your sysctls)\n"));
440 IPSEC_OSTAT(ESP_STAT_PDROPS, AH_STAT_PDROPS,
441 IPCOMP_STAT_PDROPS);
442 *error = EHOSTUNREACH;
443 goto bad;
444 }
445
446 /*
447 * Sanity check the SA contents for the caller
448 * before they invoke the xform output method.
449 */
450 if (sav->tdb_xform == NULL) {
451 DPRINTF(("ipsec_nextisr: no transform for SA\n"));
452 IPSEC_OSTAT(ESP_STAT_NOXFORM, AH_STAT_NOXFORM,
453 IPCOMP_STAT_NOXFORM);
454 *error = EHOSTUNREACH;
455 goto bad;
456 }
457 return isr;
458 bad:
459 IPSEC_ASSERT(*error != 0, ("ipsec_nextisr: error return w/ no error code"));
460 return NULL;
461 #undef IPSEC_OSTAT
462 }
463
464 #ifdef INET
465 /*
466 * IPsec output logic for IPv4.
467 */
468 int
469 ipsec4_process_packet(
470 struct mbuf *m,
471 struct ipsecrequest *isr,
472 int flags,
473 int tunalready
474 )
475 {
476 struct secasindex saidx;
477 struct secasvar *sav;
478 struct ip *ip;
479 int s, error, i, off;
480
481 IPSEC_ASSERT(m != NULL, ("ipsec4_process_packet: null mbuf"));
482 IPSEC_ASSERT(isr != NULL, ("ipsec4_process_packet: null isr"));
483
484 s = splsoftnet(); /* insure SA contents don't change */
485
486 isr = ipsec_nextisr(m, isr, AF_INET, &saidx, &error);
487 if (isr == NULL) {
488 if (error != 0) {
489 goto bad;
490 } else {
491 if (ipsec_register_done(m, &error) < 0)
492 goto bad;
493
494 splx(s);
495 return ipsec_reinject_ipstack(m, AF_INET);
496 }
497 }
498
499 sav = isr->sav;
500 if (!tunalready) {
501 union sockaddr_union *dst = &sav->sah->saidx.dst;
502 int setdf;
503
504 /*
505 * Collect IP_DF state from the outer header.
506 */
507 if (dst->sa.sa_family == AF_INET) {
508 if (m->m_len < sizeof (struct ip) &&
509 (m = m_pullup(m, sizeof (struct ip))) == NULL) {
510 error = ENOBUFS;
511 goto bad;
512 }
513 ip = mtod(m, struct ip *);
514 /* Honor system-wide control of how to handle IP_DF */
515 switch (ip4_ipsec_dfbit) {
516 case 0: /* clear in outer header */
517 case 1: /* set in outer header */
518 setdf = ip4_ipsec_dfbit;
519 break;
520 default: /* propagate to outer header */
521 setdf = ip->ip_off;
522 #ifndef __FreeBSD__
523 /* On FreeBSD, ip_off and ip_len assumed in host endian. */
524 setdf = ntohs(setdf);
525 #endif
526 setdf = htons(setdf & IP_DF);
527 break;
528 }
529 } else {
530 ip = NULL; /* keep compiler happy */
531 setdf = 0;
532 }
533 /* Do the appropriate encapsulation, if necessary */
534 if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */
535 dst->sa.sa_family != AF_INET || /* PF mismatch */
536 #if 0
537 (sav->flags & SADB_X_SAFLAGS_TUNNEL) || /* Tunnel requ'd */
538 sav->tdb_xform->xf_type == XF_IP4 || /* ditto */
539 #endif
540 (dst->sa.sa_family == AF_INET && /* Proxy */
541 dst->sin.sin_addr.s_addr != INADDR_ANY &&
542 dst->sin.sin_addr.s_addr != ip->ip_dst.s_addr)) {
543 struct mbuf *mp;
544
545 /* Fix IPv4 header checksum and length */
546 if (m->m_len < sizeof (struct ip) &&
547 (m = m_pullup(m, sizeof (struct ip))) == NULL) {
548 error = ENOBUFS;
549 goto bad;
550 }
551 ip = mtod(m, struct ip *);
552 ip->ip_len = htons(m->m_pkthdr.len);
553 ip->ip_sum = 0;
554 ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
555
556 /* Encapsulate the packet */
557 error = ipip_output(m, isr, &mp, 0, 0);
558 if (mp == NULL && !error) {
559 /* Should never happen. */
560 DPRINTF(("ipsec4_process_packet: ipip_output "
561 "returns no mbuf and no error!"));
562 error = EFAULT;
563 }
564 if (error) {
565 if (mp) {
566 /* XXX: Should never happen! */
567 m_freem(mp);
568 }
569 m = NULL; /* ipip_output() already freed it */
570 goto bad;
571 }
572 m = mp, mp = NULL;
573 /*
574 * ipip_output clears IP_DF in the new header. If
575 * we need to propagate IP_DF from the outer header,
576 * then we have to do it here.
577 *
578 * XXX shouldn't assume what ipip_output does.
579 */
580 if (dst->sa.sa_family == AF_INET && setdf) {
581 if (m->m_len < sizeof (struct ip) &&
582 (m = m_pullup(m, sizeof (struct ip))) == NULL) {
583 error = ENOBUFS;
584 goto bad;
585 }
586 ip = mtod(m, struct ip *);
587 ip->ip_off |= IP_OFF_CONVERT(IP_DF);
588 }
589 }
590 }
591
592 /*
593 * Dispatch to the appropriate IPsec transform logic. The
594 * packet will be returned for transmission after crypto
595 * processing, etc. are completed. For encapsulation we
596 * bypass this call because of the explicit call done above
597 * (necessary to deal with IP_DF handling for IPv4).
598 *
599 * NB: m & sav are ``passed to caller'' who's reponsible for
600 * for reclaiming their resources.
601 */
602 if (sav->tdb_xform->xf_type != XF_IP4) {
603 union sockaddr_union *dst = &sav->sah->saidx.dst;
604 if (dst->sa.sa_family == AF_INET) {
605 ip = mtod(m, struct ip *);
606 i = ip->ip_hl << 2;
607 off = offsetof(struct ip, ip_p);
608 } else {
609 i = sizeof(struct ip6_hdr);
610 off = offsetof(struct ip6_hdr, ip6_nxt);
611 }
612 error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off);
613 } else {
614 error = ipsec_process_done(m, isr);
615 }
616 splx(s);
617 return error;
618 bad:
619 splx(s);
620 if (m)
621 m_freem(m);
622 return error;
623 }
624 #endif
625
626 #ifdef INET6
627 static void
628 compute_ipsec_pos(struct mbuf *m, int *i, int *off)
629 {
630 int nxt;
631 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr*);
632 struct ip6_ext ip6e;
633 int dstopt = 0;
634
635 *i = sizeof(struct ip6_hdr);
636 *off = offsetof(struct ip6_hdr, ip6_nxt);
637 nxt = ip6->ip6_nxt;
638
639 /*
640 * chase mbuf chain to find the appropriate place to
641 * put AH/ESP/IPcomp header.
642 * IPv6 hbh dest1 rthdr ah* [esp* dest2 payload]
643 */
644 do {
645 switch (nxt) {
646 case IPPROTO_AH:
647 case IPPROTO_ESP:
648 case IPPROTO_IPCOMP:
649 /*
650 * we should not skip security header added
651 * beforehand.
652 */
653 return;
654
655 case IPPROTO_HOPOPTS:
656 case IPPROTO_DSTOPTS:
657 case IPPROTO_ROUTING:
658 /*
659 * if we see 2nd destination option header,
660 * we should stop there.
661 */
662 if (nxt == IPPROTO_DSTOPTS && dstopt)
663 return;
664
665 if (nxt == IPPROTO_DSTOPTS) {
666 /*
667 * seen 1st or 2nd destination option.
668 * next time we see one, it must be 2nd.
669 */
670 dstopt = 1;
671 } else if (nxt == IPPROTO_ROUTING) {
672 /*
673 * if we see destionation option next
674 * time, it must be dest2.
675 */
676 dstopt = 2;
677 }
678
679 /* skip this header */
680 m_copydata(m, *i, sizeof(ip6e), &ip6e);
681 nxt = ip6e.ip6e_nxt;
682 *off = *i + offsetof(struct ip6_ext, ip6e_nxt);
683 /*
684 * we will never see nxt == IPPROTO_AH
685 * so it is safe to omit AH case.
686 */
687 *i += (ip6e.ip6e_len + 1) << 3;
688 break;
689 default:
690 return;
691 }
692 } while (*i < m->m_pkthdr.len);
693 }
694
695 static int
696 in6_sa_equal_addrwithscope(const struct sockaddr_in6 *sa, const struct in6_addr *ia)
697 {
698 struct in6_addr ia2;
699
700 memcpy(&ia2, &sa->sin6_addr, sizeof(ia2));
701 if (IN6_IS_SCOPE_LINKLOCAL(&sa->sin6_addr))
702 ia2.s6_addr16[1] = htons(sa->sin6_scope_id);
703
704 return IN6_ARE_ADDR_EQUAL(ia, &ia2);
705 }
706
707 int
708 ipsec6_process_packet(
709 struct mbuf *m,
710 struct ipsecrequest *isr
711 )
712 {
713 struct secasindex saidx;
714 struct secasvar *sav;
715 struct ip6_hdr *ip6;
716 int s, error, i, off;
717 union sockaddr_union *dst;
718
719 IPSEC_ASSERT(m != NULL, ("ipsec6_process_packet: null mbuf"));
720 IPSEC_ASSERT(isr != NULL, ("ipsec6_process_packet: null isr"));
721
722 s = splsoftnet(); /* insure SA contents don't change */
723
724 isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error);
725 if (isr == NULL) {
726 if (error != 0) {
727 /* XXX Should we send a notification ? */
728 goto bad;
729 } else {
730 if (ipsec_register_done(m, &error) < 0)
731 goto bad;
732
733 splx(s);
734 return ipsec_reinject_ipstack(m, AF_INET6);
735 }
736 }
737
738 sav = isr->sav;
739 dst = &sav->sah->saidx.dst;
740
741 ip6 = mtod(m, struct ip6_hdr *); /* XXX */
742
743 /* Do the appropriate encapsulation, if necessary */
744 if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */
745 dst->sa.sa_family != AF_INET6 || /* PF mismatch */
746 ((dst->sa.sa_family == AF_INET6) &&
747 (!IN6_IS_ADDR_UNSPECIFIED(&dst->sin6.sin6_addr)) &&
748 (!in6_sa_equal_addrwithscope(&dst->sin6,
749 &ip6->ip6_dst)))) {
750 struct mbuf *mp;
751
752 /* Fix IPv6 header payload length. */
753 if (m->m_len < sizeof(struct ip6_hdr))
754 if ((m = m_pullup(m,sizeof(struct ip6_hdr))) == NULL)
755 return ENOBUFS;
756
757 if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) {
758 /* No jumbogram support. */
759 m_freem(m);
760 return ENXIO; /*XXX*/
761 }
762
763 ip6 = mtod(m, struct ip6_hdr *);
764 ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
765
766 /* Encapsulate the packet */
767 error = ipip_output(m, isr, &mp, 0, 0);
768 if (mp == NULL && !error) {
769 /* Should never happen. */
770 DPRINTF(("ipsec6_process_packet: ipip_output "
771 "returns no mbuf and no error!"));
772 error = EFAULT;
773 }
774
775 if (error) {
776 if (mp) {
777 /* XXX: Should never happen! */
778 m_freem(mp);
779 }
780 m = NULL; /* ipip_output() already freed it */
781 goto bad;
782 }
783
784 m = mp;
785 mp = NULL;
786 }
787
788 if (dst->sa.sa_family == AF_INET) {
789 struct ip *ip;
790 ip = mtod(m, struct ip *);
791 i = ip->ip_hl << 2;
792 off = offsetof(struct ip, ip_p);
793 } else {
794 compute_ipsec_pos(m, &i, &off);
795 }
796 error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off);
797 splx(s);
798 return error;
799 bad:
800 splx(s);
801 if (m)
802 m_freem(m);
803 return error;
804 }
805 #endif /*INET6*/
806