1 /* $NetBSD: ipsec_output.c,v 1.17.2.2 2007/10/31 12:39:30 liamjfoy 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.17.2.2 2007/10/31 12:39:30 liamjfoy 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
76 #include <netipsec/ipsec.h>
77 #include <netipsec/ipsec_var.h>
78 #ifdef INET6
79 #include <netipsec/ipsec6.h>
80 #endif
81 #include <netipsec/ah_var.h>
82 #include <netipsec/esp_var.h>
83 #include <netipsec/ipcomp_var.h>
84
85 #include <netipsec/xform.h>
86
87 #include <netipsec/key.h>
88 #include <netipsec/keydb.h>
89 #include <netipsec/key_debug.h>
90 #include <netipsec/ipsec_osdep.h>
91
92 #include <net/net_osdep.h> /* ovbcopy() in ipsec6_encapsulate() */
93
94 int
95 ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr)
96 {
97 struct tdb_ident *tdbi;
98 struct m_tag *mtag;
99 struct secasvar *sav;
100 struct secasindex *saidx;
101 int error;
102
103 IPSEC_SPLASSERT_SOFTNET("ipsec_process_done");
104
105 IPSEC_ASSERT(m != NULL, ("ipsec_process_done: null mbuf"));
106 IPSEC_ASSERT(isr != NULL, ("ipsec_process_done: null ISR"));
107 sav = isr->sav;
108 IPSEC_ASSERT(sav != NULL, ("ipsec_process_done: null SA"));
109 IPSEC_ASSERT(sav->sah != NULL, ("ipsec_process_done: null SAH"));
110
111 saidx = &sav->sah->saidx;
112 switch (saidx->dst.sa.sa_family) {
113 #ifdef INET
114 case AF_INET:
115 /* Fix the header length, for AH processing. */
116 mtod(m, struct ip *)->ip_len = htons(m->m_pkthdr.len);
117 break;
118 #endif /* INET */
119 #ifdef INET6
120 case AF_INET6:
121 /* Fix the header length, for AH processing. */
122 if (m->m_pkthdr.len < sizeof (struct ip6_hdr)) {
123 error = ENXIO;
124 goto bad;
125 }
126 if (m->m_pkthdr.len - sizeof (struct ip6_hdr) > IPV6_MAXPACKET) {
127 /* No jumbogram support. */
128 error = ENXIO; /*?*/
129 goto bad;
130 }
131 mtod(m, struct ip6_hdr *)->ip6_plen =
132 htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
133 break;
134 #endif /* INET6 */
135 default:
136 DPRINTF(("ipsec_process_done: unknown protocol family %u\n",
137 saidx->dst.sa.sa_family));
138 error = ENXIO;
139 goto bad;
140 }
141
142 /*
143 * Add a record of what we've done or what needs to be done to the
144 * packet.
145 */
146 mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE,
147 sizeof(struct tdb_ident), M_NOWAIT);
148 if (mtag == NULL) {
149 DPRINTF(("ipsec_process_done: could not get packet tag\n"));
150 error = ENOMEM;
151 goto bad;
152 }
153
154 tdbi = (struct tdb_ident *)(mtag + 1);
155 tdbi->dst = saidx->dst;
156 tdbi->proto = saidx->proto;
157 tdbi->spi = sav->spi;
158 m_tag_prepend(m, mtag);
159
160 /*
161 * If there's another (bundled) SA to apply, do so.
162 * Note that this puts a burden on the kernel stack size.
163 * If this is a problem we'll need to introduce a queue
164 * to set the packet on so we can unwind the stack before
165 * doing further processing.
166 */
167 if (isr->next) {
168 newipsecstat.ips_out_bundlesa++;
169 switch ( saidx->dst.sa.sa_family ) {
170 #ifdef INET
171 case AF_INET:
172 return ipsec4_process_packet(m, isr->next, 0,0);
173 #endif /* INET */
174 #ifdef INET6
175 case AF_INET6:
176 return ipsec6_process_packet(m,isr->next);
177 #endif /* INET6 */
178 default :
179 DPRINTF(("ipsec_process_done: unknown protocol family %u\n",
180 saidx->dst.sa.sa_family));
181 error = ENXIO;
182 goto bad;
183 }
184 }
185
186 /*
187 * We're done with IPsec processing, transmit the packet using the
188 * appropriate network protocol (IP or IPv6). SPD lookup will be
189 * performed again there.
190 */
191 switch (saidx->dst.sa.sa_family) {
192 #ifdef INET
193 struct ip *ip;
194 case AF_INET:
195 ip = mtod(m, struct ip *);
196 #ifdef __FreeBSD__
197 /* FreeBSD ip_output() expects ip_len, ip_off in host endian */
198 ip->ip_len = ntohs(ip->ip_len);
199 ip->ip_off = ntohs(ip->ip_off);
200 #endif /* __FreeBSD_ */
201 return ip_output(m, NULL, NULL, IP_RAWOUTPUT,
202 (struct ip_moptions *)NULL, (struct socket *)NULL);
203
204 #endif /* INET */
205 #ifdef INET6
206 case AF_INET6:
207 /*
208 * We don't need massage, IPv6 header fields are always in
209 * net endian.
210 */
211 return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
212 #endif /* INET6 */
213 }
214 panic("ipsec_process_done");
215 bad:
216 m_freem(m);
217 KEY_FREESAV(&sav);
218 return (error);
219 }
220
221 static struct ipsecrequest *
222 ipsec_nextisr(
223 struct mbuf *m,
224 struct ipsecrequest *isr,
225 int af,
226 struct secasindex *saidx,
227 int *error
228 )
229 {
230 #define IPSEC_OSTAT(x,y,z) (isr->saidx.proto == IPPROTO_ESP ? (x)++ : \
231 isr->saidx.proto == IPPROTO_AH ? (y)++ : (z)++)
232 struct secasvar *sav;
233
234 IPSEC_SPLASSERT_SOFTNET("ipsec_nextisr");
235 IPSEC_ASSERT(af == AF_INET || af == AF_INET6,
236 ("ipsec_nextisr: invalid address family %u", af));
237 again:
238 /*
239 * Craft SA index to search for proper SA. Note that
240 * we only fillin unspecified SA peers for transport
241 * mode; for tunnel mode they must already be filled in.
242 */
243 *saidx = isr->saidx;
244 if (isr->saidx.mode == IPSEC_MODE_TRANSPORT) {
245 /* Fillin unspecified SA peers only for transport mode */
246 if (af == AF_INET) {
247 struct sockaddr_in *sin;
248 struct ip *ip = mtod(m, struct ip *);
249
250 if (saidx->src.sa.sa_len == 0) {
251 sin = &saidx->src.sin;
252 sin->sin_len = sizeof(*sin);
253 sin->sin_family = AF_INET;
254 sin->sin_port = IPSEC_PORT_ANY;
255 sin->sin_addr = ip->ip_src;
256 }
257 if (saidx->dst.sa.sa_len == 0) {
258 sin = &saidx->dst.sin;
259 sin->sin_len = sizeof(*sin);
260 sin->sin_family = AF_INET;
261 sin->sin_port = IPSEC_PORT_ANY;
262 sin->sin_addr = ip->ip_dst;
263 }
264 } else {
265 struct sockaddr_in6 *sin6;
266 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
267
268 if (saidx->src.sin6.sin6_len == 0) {
269 sin6 = (struct sockaddr_in6 *)&saidx->src;
270 sin6->sin6_len = sizeof(*sin6);
271 sin6->sin6_family = AF_INET6;
272 sin6->sin6_port = IPSEC_PORT_ANY;
273 sin6->sin6_addr = ip6->ip6_src;
274 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
275 /* fix scope id for comparing SPD */
276 sin6->sin6_addr.s6_addr16[1] = 0;
277 sin6->sin6_scope_id =
278 ntohs(ip6->ip6_src.s6_addr16[1]);
279 }
280 }
281 if (saidx->dst.sin6.sin6_len == 0) {
282 sin6 = (struct sockaddr_in6 *)&saidx->dst;
283 sin6->sin6_len = sizeof(*sin6);
284 sin6->sin6_family = AF_INET6;
285 sin6->sin6_port = IPSEC_PORT_ANY;
286 sin6->sin6_addr = ip6->ip6_dst;
287 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
288 /* fix scope id for comparing SPD */
289 sin6->sin6_addr.s6_addr16[1] = 0;
290 sin6->sin6_scope_id =
291 ntohs(ip6->ip6_dst.s6_addr16[1]);
292 }
293 }
294 }
295 }
296
297 /*
298 * Lookup SA and validate it.
299 */
300 *error = key_checkrequest(isr, saidx);
301 if (*error != 0) {
302 /*
303 * IPsec processing is required, but no SA found.
304 * I assume that key_acquire() had been called
305 * to get/establish the SA. Here I discard
306 * this packet because it is responsibility for
307 * upper layer to retransmit the packet.
308 */
309 newipsecstat.ips_out_nosa++;
310 goto bad;
311 }
312 sav = isr->sav;
313 if (sav == NULL) { /* XXX valid return */
314 IPSEC_ASSERT(ipsec_get_reqlevel(isr) == IPSEC_LEVEL_USE,
315 ("ipsec_nextisr: no SA found, but required; level %u",
316 ipsec_get_reqlevel(isr)));
317 isr = isr->next;
318 if (isr == NULL) {
319 /*XXXstatistic??*/
320 *error = EINVAL; /*XXX*/
321 return isr;
322 }
323 goto again;
324 }
325
326 /*
327 * Check system global policy controls.
328 */
329 if ((isr->saidx.proto == IPPROTO_ESP && !esp_enable) ||
330 (isr->saidx.proto == IPPROTO_AH && !ah_enable) ||
331 (isr->saidx.proto == IPPROTO_IPCOMP && !ipcomp_enable)) {
332 DPRINTF(("ipsec_nextisr: IPsec outbound packet dropped due"
333 " to policy (check your sysctls)\n"));
334 IPSEC_OSTAT(espstat.esps_pdrops, ahstat.ahs_pdrops,
335 ipcompstat.ipcomps_pdrops);
336 *error = EHOSTUNREACH;
337 goto bad;
338 }
339
340 /*
341 * Sanity check the SA contents for the caller
342 * before they invoke the xform output method.
343 */
344 if (sav->tdb_xform == NULL) {
345 DPRINTF(("ipsec_nextisr: no transform for SA\n"));
346 IPSEC_OSTAT(espstat.esps_noxform, ahstat.ahs_noxform,
347 ipcompstat.ipcomps_noxform);
348 *error = EHOSTUNREACH;
349 goto bad;
350 }
351 return isr;
352 bad:
353 IPSEC_ASSERT(*error != 0, ("ipsec_nextisr: error return w/ no error code"));
354 return NULL;
355 #undef IPSEC_OSTAT
356 }
357
358 #ifdef INET
359 /*
360 * IPsec output logic for IPv4.
361 */
362 int
363 ipsec4_process_packet(
364 struct mbuf *m,
365 struct ipsecrequest *isr,
366 int flags,
367 int tunalready
368 )
369 {
370 struct secasindex saidx;
371 struct secasvar *sav;
372 struct ip *ip;
373 int s, error, i, off;
374
375 IPSEC_ASSERT(m != NULL, ("ipsec4_process_packet: null mbuf"));
376 IPSEC_ASSERT(isr != NULL, ("ipsec4_process_packet: null isr"));
377
378 s = splsoftnet(); /* insure SA contents don't change */
379
380 isr = ipsec_nextisr(m, isr, AF_INET, &saidx, &error);
381 if (isr == NULL)
382 goto bad;
383
384 sav = isr->sav;
385 if (!tunalready) {
386 union sockaddr_union *dst = &sav->sah->saidx.dst;
387 int setdf;
388
389 /*
390 * Collect IP_DF state from the outer header.
391 */
392 if (dst->sa.sa_family == AF_INET) {
393 if (m->m_len < sizeof (struct ip) &&
394 (m = m_pullup(m, sizeof (struct ip))) == NULL) {
395 error = ENOBUFS;
396 goto bad;
397 }
398 ip = mtod(m, struct ip *);
399 /* Honor system-wide control of how to handle IP_DF */
400 switch (ip4_ipsec_dfbit) {
401 case 0: /* clear in outer header */
402 case 1: /* set in outer header */
403 setdf = ip4_ipsec_dfbit;
404 break;
405 default: /* propagate to outer header */
406 setdf = ip->ip_off;
407 #ifndef __FreeBSD__
408 /* On FreeBSD, ip_off and ip_len assumed in host endian. */
409 setdf = ntohs(setdf);
410 #endif
411 setdf = htons(setdf & IP_DF);
412 break;
413 }
414 } else {
415 ip = NULL; /* keep compiler happy */
416 setdf = 0;
417 }
418 /* Do the appropriate encapsulation, if necessary */
419 if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */
420 dst->sa.sa_family != AF_INET || /* PF mismatch */
421 #if 0
422 (sav->flags & SADB_X_SAFLAGS_TUNNEL) || /* Tunnel requ'd */
423 sav->tdb_xform->xf_type == XF_IP4 || /* ditto */
424 #endif
425 (dst->sa.sa_family == AF_INET && /* Proxy */
426 dst->sin.sin_addr.s_addr != INADDR_ANY &&
427 dst->sin.sin_addr.s_addr != ip->ip_dst.s_addr)) {
428 struct mbuf *mp;
429
430 /* Fix IPv4 header checksum and length */
431 if (m->m_len < sizeof (struct ip) &&
432 (m = m_pullup(m, sizeof (struct ip))) == NULL) {
433 error = ENOBUFS;
434 goto bad;
435 }
436 ip = mtod(m, struct ip *);
437 ip->ip_len = htons(m->m_pkthdr.len);
438 ip->ip_sum = 0;
439 #ifdef _IP_VHL
440 if (ip->ip_vhl == IP_VHL_BORING)
441 ip->ip_sum = in_cksum_hdr(ip);
442 else
443 ip->ip_sum = in_cksum(m,
444 _IP_VHL_HL(ip->ip_vhl) << 2);
445 #else
446 ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
447 #endif
448
449 /* Encapsulate the packet */
450 error = ipip_output(m, isr, &mp, 0, 0);
451 if (mp == NULL && !error) {
452 /* Should never happen. */
453 DPRINTF(("ipsec4_process_packet: ipip_output "
454 "returns no mbuf and no error!"));
455 error = EFAULT;
456 }
457 if (error) {
458 if (mp) {
459 /* XXX: Should never happen! */
460 m_freem(mp);
461 }
462 m = NULL; /* ipip_output() already freed it */
463 goto bad;
464 }
465 m = mp, mp = NULL;
466 /*
467 * ipip_output clears IP_DF in the new header. If
468 * we need to propagate IP_DF from the outer header,
469 * then we have to do it here.
470 *
471 * XXX shouldn't assume what ipip_output does.
472 */
473 if (dst->sa.sa_family == AF_INET && setdf) {
474 if (m->m_len < sizeof (struct ip) &&
475 (m = m_pullup(m, sizeof (struct ip))) == NULL) {
476 error = ENOBUFS;
477 goto bad;
478 }
479 ip = mtod(m, struct ip *);
480 ip->ip_off |= IP_OFF_CONVERT(IP_DF);
481 }
482 }
483 }
484
485 /*
486 * Dispatch to the appropriate IPsec transform logic. The
487 * packet will be returned for transmission after crypto
488 * processing, etc. are completed. For encapsulation we
489 * bypass this call because of the explicit call done above
490 * (necessary to deal with IP_DF handling for IPv4).
491 *
492 * NB: m & sav are ``passed to caller'' who's reponsible for
493 * for reclaiming their resources.
494 */
495 if (sav->tdb_xform->xf_type != XF_IP4) {
496 ip = mtod(m, struct ip *);
497 i = ip->ip_hl << 2;
498 off = offsetof(struct ip, ip_p);
499 error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off);
500 } else {
501 error = ipsec_process_done(m, isr);
502 }
503 splx(s);
504 return error;
505 bad:
506 splx(s);
507 if (m)
508 m_freem(m);
509 return error;
510 }
511 #endif
512
513 #ifdef INET6
514 int
515 ipsec6_process_packet(
516 struct mbuf *m,
517 struct ipsecrequest *isr
518 )
519 {
520 struct secasindex saidx;
521 struct secasvar *sav;
522 struct ip6_hdr *ip6;
523 int s, error, i, off;
524
525 IPSEC_ASSERT(m != NULL, ("ipsec6_process_packet: null mbuf"));
526 IPSEC_ASSERT(isr != NULL, ("ipsec6_process_packet: null isr"));
527
528 s = splsoftnet(); /* insure SA contents don't change */
529 isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error);
530 if (isr == NULL) {
531 // XXX Should we send a notification ?
532 goto bad;
533 }
534
535 sav = isr->sav;
536 if (sav->tdb_xform->xf_type != XF_IP4) {
537 i = sizeof(struct ip6_hdr);
538 off = offsetof(struct ip6_hdr, ip6_nxt);
539 error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off);
540 } else {
541 union sockaddr_union *dst = &sav->sah->saidx.dst;
542
543 ip6 = mtod(m, struct ip6_hdr *);
544
545 /* Do the appropriate encapsulation, if necessary */
546 if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */
547 dst->sa.sa_family != AF_INET6 || /* PF mismatch */
548 ((dst->sa.sa_family == AF_INET6) &&
549 (!IN6_IS_ADDR_UNSPECIFIED(&dst->sin6.sin6_addr)) &&
550 (!IN6_ARE_ADDR_EQUAL(&dst->sin6.sin6_addr,
551 &ip6->ip6_dst)))
552 )
553 {
554 struct mbuf *mp;
555 /* Fix IPv6 header payload length. */
556 if (m->m_len < sizeof(struct ip6_hdr))
557 if ((m = m_pullup(m,sizeof(struct ip6_hdr))) == NULL)
558 return ENOBUFS;
559
560 if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) {
561 /* No jumbogram support. */
562 m_freem(m);
563 return ENXIO; /*XXX*/
564 }
565 ip6 = mtod(m, struct ip6_hdr *);
566 ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
567
568 /* Encapsulate the packet */
569 error = ipip_output(m, isr, &mp, 0, 0);
570 if (mp == NULL && !error) {
571 /* Should never happen. */
572 DPRINTF(("ipsec6_process_packet: ipip_output "
573 "returns no mbuf and no error!"));
574 error = EFAULT;
575 }
576
577 if (error) {
578 if (mp) {
579 /* XXX: Should never happen! */
580 m_freem(mp);
581 }
582 m = NULL; /* ipip_output() already freed it */
583 goto bad;
584 }
585
586 m = mp;
587 mp = NULL;
588 }
589
590 error = ipsec_process_done(m,isr);
591 }
592 splx(s);
593 return error;
594 bad:
595 splx(s);
596 if (m)
597 m_freem(m);
598 return error;
599 }
600 #endif /*INET6*/
Cache object: 1071946cdd15a1017aef7d49974a5307
|