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