1 /* $FreeBSD$ */
2 /* $OpenBSD: ip_ipcomp.c,v 1.1 2001/07/05 12:08:52 jjbg Exp $ */
3
4 /*-
5 * Copyright (c) 2001 Jean-Jacques Bernard-Gundol (jj@wabbitt.org)
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 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 /* IP payload compression protocol (IPComp), see RFC 2393 */
32 #include "opt_inet.h"
33 #include "opt_inet6.h"
34 #include "opt_ipsec.h"
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/mbuf.h>
39 #include <sys/lock.h>
40 #include <sys/mutex.h>
41 #include <sys/socket.h>
42 #include <sys/kernel.h>
43 #include <sys/protosw.h>
44 #include <sys/sysctl.h>
45
46 #include <netinet/in.h>
47 #include <netinet/in_systm.h>
48 #include <netinet/ip.h>
49 #include <netinet/ip_var.h>
50 #include <netinet/ip_encap.h>
51
52 #include <net/netisr.h>
53 #include <net/vnet.h>
54
55 #include <netipsec/ipsec.h>
56 #include <netipsec/xform.h>
57
58 #ifdef INET6
59 #include <netinet/ip6.h>
60 #include <netinet6/ip6_var.h>
61 #include <netipsec/ipsec6.h>
62 #endif
63
64 #include <netipsec/ipcomp.h>
65 #include <netipsec/ipcomp_var.h>
66
67 #include <netipsec/key.h>
68 #include <netipsec/key_debug.h>
69
70 #include <opencrypto/cryptodev.h>
71 #include <opencrypto/deflate.h>
72 #include <opencrypto/xform.h>
73
74 VNET_DEFINE(int, ipcomp_enable) = 1;
75 VNET_PCPUSTAT_DEFINE(struct ipcompstat, ipcompstat);
76 VNET_PCPUSTAT_SYSINIT(ipcompstat);
77
78 #ifdef VIMAGE
79 VNET_PCPUSTAT_SYSUNINIT(ipcompstat);
80 #endif /* VIMAGE */
81
82 SYSCTL_DECL(_net_inet_ipcomp);
83 SYSCTL_INT(_net_inet_ipcomp, OID_AUTO, ipcomp_enable,
84 CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ipcomp_enable), 0, "");
85 SYSCTL_VNET_PCPUSTAT(_net_inet_ipcomp, IPSECCTL_STATS, stats,
86 struct ipcompstat, ipcompstat,
87 "IPCOMP statistics (struct ipcompstat, netipsec/ipcomp_var.h");
88
89 static int ipcomp_input_cb(struct cryptop *crp);
90 static int ipcomp_output_cb(struct cryptop *crp);
91
92 /*
93 * RFC 3173 p 2.2. Non-Expansion Policy:
94 * If the total size of a compressed payload and the IPComp header, as
95 * defined in section 3, is not smaller than the size of the original
96 * payload, the IP datagram MUST be sent in the original non-compressed
97 * form.
98 *
99 * When we use IPComp in tunnel mode, for small packets we will receive
100 * encapsulated IP-IP datagrams without any compression and without IPComp
101 * header.
102 */
103 static int
104 ipcomp_encapcheck(union sockaddr_union *src, union sockaddr_union *dst)
105 {
106 struct secasvar *sav;
107
108 sav = key_allocsa_tunnel(src, dst, IPPROTO_IPCOMP);
109 if (sav == NULL)
110 return (0);
111 key_freesav(&sav);
112
113 if (src->sa.sa_family == AF_INET)
114 return (sizeof(struct in_addr) << 4);
115 else
116 return (sizeof(struct in6_addr) << 4);
117 }
118
119 static int
120 ipcomp_nonexp_input(struct mbuf **mp, int *offp, int proto)
121 {
122 int isr;
123
124 switch (proto) {
125 #ifdef INET
126 case IPPROTO_IPV4:
127 isr = NETISR_IP;
128 break;
129 #endif
130 #ifdef INET6
131 case IPPROTO_IPV6:
132 isr = NETISR_IPV6;
133 break;
134 #endif
135 default:
136 IPCOMPSTAT_INC(ipcomps_nopf);
137 m_freem(*mp);
138 return (IPPROTO_DONE);
139 }
140 m_adj(*mp, *offp);
141 IPCOMPSTAT_ADD(ipcomps_ibytes, (*mp)->m_pkthdr.len);
142 IPCOMPSTAT_INC(ipcomps_input);
143 netisr_dispatch(isr, *mp);
144 return (IPPROTO_DONE);
145 }
146
147 /*
148 * ipcomp_init() is called when an CPI is being set up.
149 */
150 static int
151 ipcomp_init(struct secasvar *sav, struct xformsw *xsp)
152 {
153 const struct comp_algo *tcomp;
154 struct cryptoini cric;
155
156 /* NB: algorithm really comes in alg_enc and not alg_comp! */
157 tcomp = comp_algorithm_lookup(sav->alg_enc);
158 if (tcomp == NULL) {
159 DPRINTF(("%s: unsupported compression algorithm %d\n", __func__,
160 sav->alg_comp));
161 return EINVAL;
162 }
163 sav->alg_comp = sav->alg_enc; /* set for doing histogram */
164 sav->tdb_xform = xsp;
165 sav->tdb_compalgxform = tcomp;
166
167 /* Initialize crypto session */
168 bzero(&cric, sizeof (cric));
169 cric.cri_alg = sav->tdb_compalgxform->type;
170
171 return crypto_newsession(&sav->tdb_cryptoid, &cric, V_crypto_support);
172 }
173
174 /*
175 * ipcomp_zeroize() used when IPCA is deleted
176 */
177 static int
178 ipcomp_zeroize(struct secasvar *sav)
179 {
180 int err;
181
182 err = crypto_freesession(sav->tdb_cryptoid);
183 sav->tdb_cryptoid = 0;
184 return err;
185 }
186
187 /*
188 * ipcomp_input() gets called to uncompress an input packet
189 */
190 static int
191 ipcomp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
192 {
193 struct xform_data *xd;
194 struct cryptodesc *crdc;
195 struct cryptop *crp;
196 struct ipcomp *ipcomp;
197 caddr_t addr;
198 int error, hlen = IPCOMP_HLENGTH;
199
200 /*
201 * Check that the next header of the IPComp is not IPComp again, before
202 * doing any real work. Given it is not possible to do double
203 * compression it means someone is playing tricks on us.
204 */
205 error = ENOBUFS;
206 if (m->m_len < skip + hlen && (m = m_pullup(m, skip + hlen)) == NULL) {
207 IPCOMPSTAT_INC(ipcomps_hdrops); /*XXX*/
208 DPRINTF(("%s: m_pullup failed\n", __func__));
209 key_freesav(&sav);
210 return (error);
211 }
212 addr = (caddr_t) mtod(m, struct ip *) + skip;
213 ipcomp = (struct ipcomp *)addr;
214 if (ipcomp->comp_nxt == IPPROTO_IPCOMP) {
215 IPCOMPSTAT_INC(ipcomps_pdrops); /* XXX have our own stats? */
216 DPRINTF(("%s: recursive compression detected\n", __func__));
217 error = EINVAL;
218 goto bad;
219 }
220
221 /* Get crypto descriptors */
222 crp = crypto_getreq(1);
223 if (crp == NULL) {
224 DPRINTF(("%s: no crypto descriptors\n", __func__));
225 IPCOMPSTAT_INC(ipcomps_crypto);
226 goto bad;
227 }
228 /* Get IPsec-specific opaque pointer */
229 xd = malloc(sizeof(*xd), M_XDATA, M_NOWAIT | M_ZERO);
230 if (xd == NULL) {
231 DPRINTF(("%s: cannot allocate xform_data\n", __func__));
232 IPCOMPSTAT_INC(ipcomps_crypto);
233 crypto_freereq(crp);
234 goto bad;
235 }
236 crdc = crp->crp_desc;
237
238 crdc->crd_skip = skip + hlen;
239 crdc->crd_len = m->m_pkthdr.len - (skip + hlen);
240 crdc->crd_inject = skip;
241
242 /* Decompression operation */
243 crdc->crd_alg = sav->tdb_compalgxform->type;
244
245
246 /* Crypto operation descriptor */
247 crp->crp_ilen = m->m_pkthdr.len - (skip + hlen);
248 crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_CBIFSYNC;
249 crp->crp_buf = (caddr_t) m;
250 crp->crp_callback = ipcomp_input_cb;
251 crp->crp_opaque = (caddr_t) xd;
252
253 /* These are passed as-is to the callback */
254 xd->sav = sav;
255 xd->protoff = protoff;
256 xd->skip = skip;
257 xd->vnet = curvnet;
258
259 SECASVAR_LOCK(sav);
260 crp->crp_sid = xd->cryptoid = sav->tdb_cryptoid;
261 SECASVAR_UNLOCK(sav);
262
263 return crypto_dispatch(crp);
264 bad:
265 m_freem(m);
266 key_freesav(&sav);
267 return (error);
268 }
269
270 /*
271 * IPComp input callback from the crypto driver.
272 */
273 static int
274 ipcomp_input_cb(struct cryptop *crp)
275 {
276 IPSEC_DEBUG_DECLARE(char buf[IPSEC_ADDRSTRLEN]);
277 struct cryptodesc *crd;
278 struct xform_data *xd;
279 struct mbuf *m;
280 struct secasvar *sav;
281 struct secasindex *saidx;
282 caddr_t addr;
283 uint64_t cryptoid;
284 int hlen = IPCOMP_HLENGTH, error, clen;
285 int skip, protoff;
286 uint8_t nproto;
287
288 crd = crp->crp_desc;
289
290 m = (struct mbuf *) crp->crp_buf;
291 xd = (struct xform_data *) crp->crp_opaque;
292 CURVNET_SET(xd->vnet);
293 sav = xd->sav;
294 skip = xd->skip;
295 protoff = xd->protoff;
296 cryptoid = xd->cryptoid;
297 saidx = &sav->sah->saidx;
298 IPSEC_ASSERT(saidx->dst.sa.sa_family == AF_INET ||
299 saidx->dst.sa.sa_family == AF_INET6,
300 ("unexpected protocol family %u", saidx->dst.sa.sa_family));
301
302 /* Check for crypto errors */
303 if (crp->crp_etype) {
304 if (crp->crp_etype == EAGAIN) {
305 /* Reset the session ID */
306 if (ipsec_updateid(sav, &crp->crp_sid, &cryptoid) != 0)
307 crypto_freesession(cryptoid);
308 xd->cryptoid = crp->crp_sid;
309 CURVNET_RESTORE();
310 return (crypto_dispatch(crp));
311 }
312 IPCOMPSTAT_INC(ipcomps_noxform);
313 DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype));
314 error = crp->crp_etype;
315 goto bad;
316 }
317 /* Shouldn't happen... */
318 if (m == NULL) {
319 IPCOMPSTAT_INC(ipcomps_crypto);
320 DPRINTF(("%s: null mbuf returned from crypto\n", __func__));
321 error = EINVAL;
322 goto bad;
323 }
324 IPCOMPSTAT_INC(ipcomps_hist[sav->alg_comp]);
325
326 clen = crp->crp_olen; /* Length of data after processing */
327
328 /* Release the crypto descriptors */
329 free(xd, M_XDATA), xd = NULL;
330 crypto_freereq(crp), crp = NULL;
331
332 /* In case it's not done already, adjust the size of the mbuf chain */
333 m->m_pkthdr.len = clen + hlen + skip;
334
335 if (m->m_len < skip + hlen && (m = m_pullup(m, skip + hlen)) == NULL) {
336 IPCOMPSTAT_INC(ipcomps_hdrops); /*XXX*/
337 DPRINTF(("%s: m_pullup failed\n", __func__));
338 error = EINVAL; /*XXX*/
339 goto bad;
340 }
341
342 /* Keep the next protocol field */
343 addr = (caddr_t) mtod(m, struct ip *) + skip;
344 nproto = ((struct ipcomp *) addr)->comp_nxt;
345
346 /* Remove the IPCOMP header */
347 error = m_striphdr(m, skip, hlen);
348 if (error) {
349 IPCOMPSTAT_INC(ipcomps_hdrops);
350 DPRINTF(("%s: bad mbuf chain, IPCA %s/%08lx\n", __func__,
351 ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
352 (u_long) ntohl(sav->spi)));
353 goto bad;
354 }
355
356 /* Restore the Next Protocol field */
357 m_copyback(m, protoff, sizeof (u_int8_t), (u_int8_t *) &nproto);
358
359 switch (saidx->dst.sa.sa_family) {
360 #ifdef INET6
361 case AF_INET6:
362 error = ipsec6_common_input_cb(m, sav, skip, protoff);
363 break;
364 #endif
365 #ifdef INET
366 case AF_INET:
367 error = ipsec4_common_input_cb(m, sav, skip, protoff);
368 break;
369 #endif
370 default:
371 panic("%s: Unexpected address family: %d saidx=%p", __func__,
372 saidx->dst.sa.sa_family, saidx);
373 }
374 CURVNET_RESTORE();
375 return error;
376 bad:
377 CURVNET_RESTORE();
378 if (sav != NULL)
379 key_freesav(&sav);
380 if (m != NULL)
381 m_freem(m);
382 if (xd != NULL)
383 free(xd, M_XDATA);
384 if (crp != NULL)
385 crypto_freereq(crp);
386 return error;
387 }
388
389 /*
390 * IPComp output routine, called by ipsec[46]_perform_request()
391 */
392 static int
393 ipcomp_output(struct mbuf *m, struct secpolicy *sp, struct secasvar *sav,
394 u_int idx, int skip, int protoff)
395 {
396 IPSEC_DEBUG_DECLARE(char buf[IPSEC_ADDRSTRLEN]);
397 const struct comp_algo *ipcompx;
398 struct cryptodesc *crdc;
399 struct cryptop *crp;
400 struct xform_data *xd;
401 int error, ralen, maxpacketsize;
402
403 IPSEC_ASSERT(sav != NULL, ("null SA"));
404 ipcompx = sav->tdb_compalgxform;
405 IPSEC_ASSERT(ipcompx != NULL, ("null compression xform"));
406
407 /*
408 * Do not touch the packet in case our payload to compress
409 * is lower than the minimal threshold of the compression
410 * alogrithm. We will just send out the data uncompressed.
411 * See RFC 3173, 2.2. Non-Expansion Policy.
412 */
413 if (m->m_pkthdr.len <= ipcompx->minlen) {
414 IPCOMPSTAT_INC(ipcomps_threshold);
415 return ipsec_process_done(m, sp, sav, idx);
416 }
417
418 ralen = m->m_pkthdr.len - skip; /* Raw payload length before comp. */
419 IPCOMPSTAT_INC(ipcomps_output);
420
421 /* Check for maximum packet size violations. */
422 switch (sav->sah->saidx.dst.sa.sa_family) {
423 #ifdef INET
424 case AF_INET:
425 maxpacketsize = IP_MAXPACKET;
426 break;
427 #endif /* INET */
428 #ifdef INET6
429 case AF_INET6:
430 maxpacketsize = IPV6_MAXPACKET;
431 break;
432 #endif /* INET6 */
433 default:
434 IPCOMPSTAT_INC(ipcomps_nopf);
435 DPRINTF(("%s: unknown/unsupported protocol family %d, "
436 "IPCA %s/%08lx\n", __func__,
437 sav->sah->saidx.dst.sa.sa_family,
438 ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
439 (u_long) ntohl(sav->spi)));
440 error = EPFNOSUPPORT;
441 goto bad;
442 }
443 if (ralen + skip + IPCOMP_HLENGTH > maxpacketsize) {
444 IPCOMPSTAT_INC(ipcomps_toobig);
445 DPRINTF(("%s: packet in IPCA %s/%08lx got too big "
446 "(len %u, max len %u)\n", __func__,
447 ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
448 (u_long) ntohl(sav->spi),
449 ralen + skip + IPCOMP_HLENGTH, maxpacketsize));
450 error = EMSGSIZE;
451 goto bad;
452 }
453
454 /* Update the counters */
455 IPCOMPSTAT_ADD(ipcomps_obytes, m->m_pkthdr.len - skip);
456
457 m = m_unshare(m, M_NOWAIT);
458 if (m == NULL) {
459 IPCOMPSTAT_INC(ipcomps_hdrops);
460 DPRINTF(("%s: cannot clone mbuf chain, IPCA %s/%08lx\n",
461 __func__, ipsec_address(&sav->sah->saidx.dst, buf,
462 sizeof(buf)), (u_long) ntohl(sav->spi)));
463 error = ENOBUFS;
464 goto bad;
465 }
466
467 /* Ok now, we can pass to the crypto processing. */
468
469 /* Get crypto descriptors */
470 crp = crypto_getreq(1);
471 if (crp == NULL) {
472 IPCOMPSTAT_INC(ipcomps_crypto);
473 DPRINTF(("%s: failed to acquire crypto descriptor\n",__func__));
474 error = ENOBUFS;
475 goto bad;
476 }
477 crdc = crp->crp_desc;
478
479 /* Compression descriptor */
480 crdc->crd_skip = skip;
481 crdc->crd_len = ralen;
482 crdc->crd_flags = CRD_F_COMP;
483 crdc->crd_inject = skip;
484
485 /* Compression operation */
486 crdc->crd_alg = ipcompx->type;
487
488 /* IPsec-specific opaque crypto info */
489 xd = malloc(sizeof(struct xform_data), M_XDATA, M_NOWAIT | M_ZERO);
490 if (xd == NULL) {
491 IPCOMPSTAT_INC(ipcomps_crypto);
492 DPRINTF(("%s: failed to allocate xform_data\n", __func__));
493 crypto_freereq(crp);
494 error = ENOBUFS;
495 goto bad;
496 }
497
498 xd->sp = sp;
499 xd->sav = sav;
500 xd->idx = idx;
501 xd->skip = skip;
502 xd->protoff = protoff;
503 xd->vnet = curvnet;
504
505 /* Crypto operation descriptor */
506 crp->crp_ilen = m->m_pkthdr.len; /* Total input length */
507 crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_CBIFSYNC;
508 crp->crp_buf = (caddr_t) m;
509 crp->crp_callback = ipcomp_output_cb;
510 crp->crp_opaque = (caddr_t) xd;
511
512 SECASVAR_LOCK(sav);
513 crp->crp_sid = xd->cryptoid = sav->tdb_cryptoid;
514 SECASVAR_UNLOCK(sav);
515
516 return crypto_dispatch(crp);
517 bad:
518 if (m)
519 m_freem(m);
520 key_freesav(&sav);
521 key_freesp(&sp);
522 return (error);
523 }
524
525 /*
526 * IPComp output callback from the crypto driver.
527 */
528 static int
529 ipcomp_output_cb(struct cryptop *crp)
530 {
531 IPSEC_DEBUG_DECLARE(char buf[IPSEC_ADDRSTRLEN]);
532 struct xform_data *xd;
533 struct secpolicy *sp;
534 struct secasvar *sav;
535 struct mbuf *m;
536 uint64_t cryptoid;
537 u_int idx;
538 int error, skip, protoff;
539
540 m = (struct mbuf *) crp->crp_buf;
541 xd = (struct xform_data *) crp->crp_opaque;
542 CURVNET_SET(xd->vnet);
543 idx = xd->idx;
544 sp = xd->sp;
545 sav = xd->sav;
546 skip = xd->skip;
547 protoff = xd->protoff;
548 cryptoid = xd->cryptoid;
549
550 /* Check for crypto errors */
551 if (crp->crp_etype) {
552 if (crp->crp_etype == EAGAIN) {
553 /* Reset the session ID */
554 if (ipsec_updateid(sav, &crp->crp_sid, &cryptoid) != 0)
555 crypto_freesession(cryptoid);
556 xd->cryptoid = crp->crp_sid;
557 CURVNET_RESTORE();
558 return (crypto_dispatch(crp));
559 }
560 IPCOMPSTAT_INC(ipcomps_noxform);
561 DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype));
562 error = crp->crp_etype;
563 goto bad;
564 }
565 /* Shouldn't happen... */
566 if (m == NULL) {
567 IPCOMPSTAT_INC(ipcomps_crypto);
568 DPRINTF(("%s: bogus return buffer from crypto\n", __func__));
569 error = EINVAL;
570 goto bad;
571 }
572 IPCOMPSTAT_INC(ipcomps_hist[sav->alg_comp]);
573
574 if (crp->crp_ilen - skip > crp->crp_olen) {
575 struct mbuf *mo;
576 struct ipcomp *ipcomp;
577 int roff;
578 uint8_t prot;
579
580 /* Compression helped, inject IPCOMP header. */
581 mo = m_makespace(m, skip, IPCOMP_HLENGTH, &roff);
582 if (mo == NULL) {
583 IPCOMPSTAT_INC(ipcomps_wrap);
584 DPRINTF(("%s: IPCOMP header inject failed "
585 "for IPCA %s/%08lx\n",
586 __func__, ipsec_address(&sav->sah->saidx.dst, buf,
587 sizeof(buf)), (u_long) ntohl(sav->spi)));
588 error = ENOBUFS;
589 goto bad;
590 }
591 ipcomp = (struct ipcomp *)(mtod(mo, caddr_t) + roff);
592
593 /* Initialize the IPCOMP header */
594 /* XXX alignment always correct? */
595 switch (sav->sah->saidx.dst.sa.sa_family) {
596 #ifdef INET
597 case AF_INET:
598 ipcomp->comp_nxt = mtod(m, struct ip *)->ip_p;
599 break;
600 #endif /* INET */
601 #ifdef INET6
602 case AF_INET6:
603 ipcomp->comp_nxt = mtod(m, struct ip6_hdr *)->ip6_nxt;
604 break;
605 #endif
606 }
607 ipcomp->comp_flags = 0;
608 ipcomp->comp_cpi = htons((u_int16_t) ntohl(sav->spi));
609
610 /* Fix Next Protocol in IPv4/IPv6 header */
611 prot = IPPROTO_IPCOMP;
612 m_copyback(m, protoff, sizeof(u_int8_t),
613 (u_char *)&prot);
614
615 /* Adjust the length in the IP header */
616 switch (sav->sah->saidx.dst.sa.sa_family) {
617 #ifdef INET
618 case AF_INET:
619 mtod(m, struct ip *)->ip_len = htons(m->m_pkthdr.len);
620 break;
621 #endif /* INET */
622 #ifdef INET6
623 case AF_INET6:
624 mtod(m, struct ip6_hdr *)->ip6_plen =
625 htons(m->m_pkthdr.len) - sizeof(struct ip6_hdr);
626 break;
627 #endif /* INET6 */
628 default:
629 IPCOMPSTAT_INC(ipcomps_nopf);
630 DPRINTF(("%s: unknown/unsupported protocol "
631 "family %d, IPCA %s/%08lx\n", __func__,
632 sav->sah->saidx.dst.sa.sa_family,
633 ipsec_address(&sav->sah->saidx.dst, buf,
634 sizeof(buf)), (u_long) ntohl(sav->spi)));
635 error = EPFNOSUPPORT;
636 goto bad;
637 }
638 } else {
639 /* Compression was useless, we have lost time. */
640 IPCOMPSTAT_INC(ipcomps_uncompr);
641 DPRINTF(("%s: compressions was useless %d - %d <= %d\n",
642 __func__, crp->crp_ilen, skip, crp->crp_olen));
643 /* XXX remember state to not compress the next couple
644 * of packets, RFC 3173, 2.2. Non-Expansion Policy */
645 }
646
647 /* Release the crypto descriptor */
648 free(xd, M_XDATA);
649 crypto_freereq(crp);
650
651 /* NB: m is reclaimed by ipsec_process_done. */
652 error = ipsec_process_done(m, sp, sav, idx);
653 CURVNET_RESTORE();
654 return (error);
655 bad:
656 if (m)
657 m_freem(m);
658 CURVNET_RESTORE();
659 free(xd, M_XDATA);
660 crypto_freereq(crp);
661 key_freesav(&sav);
662 key_freesp(&sp);
663 return (error);
664 }
665
666 #ifdef INET
667 static const struct encaptab *ipe4_cookie = NULL;
668 extern struct domain inetdomain;
669 static struct protosw ipcomp4_protosw = {
670 .pr_type = SOCK_RAW,
671 .pr_domain = &inetdomain,
672 .pr_protocol = 0 /* IPPROTO_IPV[46] */,
673 .pr_flags = PR_ATOMIC | PR_ADDR | PR_LASTHDR,
674 .pr_input = ipcomp_nonexp_input,
675 .pr_output = rip_output,
676 .pr_ctloutput = rip_ctloutput,
677 .pr_usrreqs = &rip_usrreqs
678 };
679
680 static int
681 ipcomp4_nonexp_encapcheck(const struct mbuf *m, int off, int proto,
682 void *arg __unused)
683 {
684 union sockaddr_union src, dst;
685 const struct ip *ip;
686
687 if (V_ipcomp_enable == 0)
688 return (0);
689 if (proto != IPPROTO_IPV4 && proto != IPPROTO_IPV6)
690 return (0);
691 bzero(&src, sizeof(src));
692 bzero(&dst, sizeof(dst));
693 src.sa.sa_family = dst.sa.sa_family = AF_INET;
694 src.sin.sin_len = dst.sin.sin_len = sizeof(struct sockaddr_in);
695 ip = mtod(m, const struct ip *);
696 src.sin.sin_addr = ip->ip_src;
697 dst.sin.sin_addr = ip->ip_dst;
698 return (ipcomp_encapcheck(&src, &dst));
699 }
700 #endif
701 #ifdef INET6
702 static const struct encaptab *ipe6_cookie = NULL;
703 extern struct domain inet6domain;
704 static struct protosw ipcomp6_protosw = {
705 .pr_type = SOCK_RAW,
706 .pr_domain = &inet6domain,
707 .pr_protocol = 0 /* IPPROTO_IPV[46] */,
708 .pr_flags = PR_ATOMIC | PR_ADDR | PR_LASTHDR,
709 .pr_input = ipcomp_nonexp_input,
710 .pr_output = rip6_output,
711 .pr_ctloutput = rip6_ctloutput,
712 .pr_usrreqs = &rip6_usrreqs
713 };
714
715 static int
716 ipcomp6_nonexp_encapcheck(const struct mbuf *m, int off, int proto,
717 void *arg __unused)
718 {
719 union sockaddr_union src, dst;
720 const struct ip6_hdr *ip6;
721
722 if (V_ipcomp_enable == 0)
723 return (0);
724 if (proto != IPPROTO_IPV4 && proto != IPPROTO_IPV6)
725 return (0);
726 bzero(&src, sizeof(src));
727 bzero(&dst, sizeof(dst));
728 src.sa.sa_family = dst.sa.sa_family = AF_INET;
729 src.sin6.sin6_len = dst.sin6.sin6_len = sizeof(struct sockaddr_in6);
730 ip6 = mtod(m, const struct ip6_hdr *);
731 src.sin6.sin6_addr = ip6->ip6_src;
732 dst.sin6.sin6_addr = ip6->ip6_dst;
733 if (IN6_IS_SCOPE_LINKLOCAL(&src.sin6.sin6_addr)) {
734 /* XXX: sa6_recoverscope() */
735 src.sin6.sin6_scope_id =
736 ntohs(src.sin6.sin6_addr.s6_addr16[1]);
737 src.sin6.sin6_addr.s6_addr16[1] = 0;
738 }
739 if (IN6_IS_SCOPE_LINKLOCAL(&dst.sin6.sin6_addr)) {
740 /* XXX: sa6_recoverscope() */
741 dst.sin6.sin6_scope_id =
742 ntohs(dst.sin6.sin6_addr.s6_addr16[1]);
743 dst.sin6.sin6_addr.s6_addr16[1] = 0;
744 }
745 return (ipcomp_encapcheck(&src, &dst));
746 }
747 #endif
748
749 static struct xformsw ipcomp_xformsw = {
750 .xf_type = XF_IPCOMP,
751 .xf_name = "IPcomp",
752 .xf_init = ipcomp_init,
753 .xf_zeroize = ipcomp_zeroize,
754 .xf_input = ipcomp_input,
755 .xf_output = ipcomp_output,
756 };
757
758 static void
759 ipcomp_attach(void)
760 {
761
762 #ifdef INET
763 ipe4_cookie = encap_attach_func(AF_INET, -1,
764 ipcomp4_nonexp_encapcheck, &ipcomp4_protosw, NULL);
765 #endif
766 #ifdef INET6
767 ipe6_cookie = encap_attach_func(AF_INET6, -1,
768 ipcomp6_nonexp_encapcheck, &ipcomp6_protosw, NULL);
769 #endif
770 xform_attach(&ipcomp_xformsw);
771 }
772
773 static void
774 ipcomp_detach(void)
775 {
776
777 #ifdef INET
778 encap_detach(ipe4_cookie);
779 #endif
780 #ifdef INET6
781 encap_detach(ipe6_cookie);
782 #endif
783 xform_detach(&ipcomp_xformsw);
784 }
785
786 SYSINIT(ipcomp_xform_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE,
787 ipcomp_attach, NULL);
788 SYSUNINIT(ipcomp_xform_uninit, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE,
789 ipcomp_detach, NULL);
Cache object: 87f9c29311bc76e81e7158d5393bb410
|