1 /* $OpenBSD: ipsec_output.c,v 1.98 2024/02/11 01:27:45 bluhm Exp $ */
2 /*
3 * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
4 *
5 * Copyright (c) 2000-2001 Angelos D. Keromytis.
6 *
7 * Permission to use, copy, and modify this software with or without fee
8 * is hereby granted, provided that this entire notice is included in
9 * all copies of any software which is or includes a copy or
10 * modification of this software.
11 * You may use this code under the GNU public license if you so wish. Please
12 * contribute changes back to the authors under this freer than GPL license
13 * so that we may further the use of strong encryption without limitations to
14 * all.
15 *
16 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
18 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
19 * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
20 * PURPOSE.
21 */
22
23 #include "pf.h"
24
25 #include <sys/param.h>
26 #include <sys/systm.h>
27 #include <sys/mbuf.h>
28 #include <sys/socket.h>
29 #include <sys/kernel.h>
30 #include <sys/timeout.h>
31
32 #include <net/if.h>
33 #include <net/route.h>
34
35 #include <netinet/in.h>
36 #include <netinet/ip.h>
37 #include <netinet/in_pcb.h>
38 #include <netinet/ip_var.h>
39 #include <netinet6/ip6_var.h>
40
41 #if NPF > 0
42 #include <net/pfvar.h>
43 #endif
44
45 #include <netinet/udp.h>
46 #include <netinet/ip_ipip.h>
47 #include <netinet/ip_ah.h>
48 #include <netinet/ip_esp.h>
49 #include <netinet/ip_ipcomp.h>
50
51 #include <crypto/cryptodev.h>
52 #include <crypto/xform.h>
53
54 #ifdef ENCDEBUG
55 #define DPRINTF(fmt, args...) \
56 do { \
57 if (encdebug) \
58 printf("%s: " fmt "\n", __func__, ## args); \
59 } while (0)
60 #else
61 #define DPRINTF(fmt, args...) \
62 do { } while (0)
63 #endif
64
65 int udpencap_enable = 1; /* enabled by default */
66 int udpencap_port = 4500; /* triggers decapsulation */
67
68 /*
69 * Loop over a tdb chain, taking into consideration protocol tunneling. The
70 * fourth argument is set if the first encapsulation header is already in
71 * place.
72 */
73 int
ipsp_process_packet(struct mbuf * m,struct tdb * tdb,int af,int tunalready)74 ipsp_process_packet(struct mbuf *m, struct tdb *tdb, int af, int tunalready)
75 {
76 int hlen, off, error;
77 #ifdef INET6
78 struct ip6_ext ip6e;
79 int nxt;
80 int dstopt = 0;
81 #endif
82
83 int setdf = 0;
84 struct ip *ip;
85 #ifdef INET6
86 struct ip6_hdr *ip6;
87 #endif /* INET6 */
88
89 #ifdef ENCDEBUG
90 char buf[INET6_ADDRSTRLEN];
91 #endif
92
93 /* Check that the transform is allowed by the administrator. */
94 if ((tdb->tdb_sproto == IPPROTO_ESP && !esp_enable) ||
95 (tdb->tdb_sproto == IPPROTO_AH && !ah_enable) ||
96 (tdb->tdb_sproto == IPPROTO_IPCOMP && !ipcomp_enable)) {
97 DPRINTF("IPsec outbound packet dropped due to policy "
98 "(check your sysctls)");
99 error = EHOSTUNREACH;
100 goto drop;
101 }
102
103 /* Sanity check. */
104 if (!tdb->tdb_xform) {
105 DPRINTF("uninitialized TDB");
106 error = EHOSTUNREACH;
107 goto drop;
108 }
109
110 /* Check if the SPI is invalid. */
111 if (tdb->tdb_flags & TDBF_INVALID) {
112 DPRINTF("attempt to use invalid SA %s/%08x/%u",
113 ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
114 ntohl(tdb->tdb_spi), tdb->tdb_sproto);
115 error = ENXIO;
116 goto drop;
117 }
118
119 /* Check that the network protocol is supported */
120 switch (tdb->tdb_dst.sa.sa_family) {
121 case AF_INET:
122 break;
123
124 #ifdef INET6
125 case AF_INET6:
126 break;
127 #endif /* INET6 */
128
129 default:
130 DPRINTF("attempt to use SA %s/%08x/%u for protocol family %d",
131 ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
132 ntohl(tdb->tdb_spi), tdb->tdb_sproto,
133 tdb->tdb_dst.sa.sa_family);
134 error = EPFNOSUPPORT;
135 goto drop;
136 }
137
138 /*
139 * Register first use if applicable, setup relevant expiration timer.
140 */
141 if (tdb->tdb_first_use == 0) {
142 tdb->tdb_first_use = gettime();
143 if (tdb->tdb_flags & TDBF_FIRSTUSE) {
144 if (timeout_add_sec(&tdb->tdb_first_tmo,
145 tdb->tdb_exp_first_use))
146 tdb_ref(tdb);
147 }
148 if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE) {
149 if (timeout_add_sec(&tdb->tdb_sfirst_tmo,
150 tdb->tdb_soft_first_use))
151 tdb_ref(tdb);
152 }
153 }
154
155 /*
156 * Check for tunneling if we don't have the first header in place.
157 * When doing Ethernet-over-IP, we are handed an already-encapsulated
158 * frame, so we don't need to re-encapsulate.
159 */
160 if (tunalready == 0) {
161 /*
162 * If the target protocol family is different, we know we'll be
163 * doing tunneling.
164 */
165 if (af == tdb->tdb_dst.sa.sa_family) {
166 switch (af) {
167 case AF_INET:
168 hlen = sizeof(struct ip);
169 break;
170 #ifdef INET6
171 case AF_INET6:
172 hlen = sizeof(struct ip6_hdr);
173 break;
174 #endif /* INET6 */
175 }
176
177 /* Bring the network header in the first mbuf. */
178 if (m->m_len < hlen) {
179 if ((m = m_pullup(m, hlen)) == NULL) {
180 error = ENOBUFS;
181 goto drop;
182 }
183 }
184
185 if (af == AF_INET) {
186 ip = mtod(m, struct ip *);
187
188 /*
189 * This is not a bridge packet, remember if we
190 * had IP_DF.
191 */
192 setdf = ip->ip_off & htons(IP_DF);
193 }
194
195 #ifdef INET6
196 if (af == AF_INET6)
197 ip6 = mtod(m, struct ip6_hdr *);
198 #endif /* INET6 */
199 }
200
201 /* Do the appropriate encapsulation, if necessary. */
202 if ((tdb->tdb_dst.sa.sa_family != af) || /* PF mismatch */
203 (tdb->tdb_flags & TDBF_TUNNELING) || /* Tunneling needed */
204 (tdb->tdb_xform->xf_type == XF_IP4) || /* ditto */
205 ((tdb->tdb_dst.sa.sa_family == AF_INET) &&
206 (tdb->tdb_dst.sin.sin_addr.s_addr != INADDR_ANY) &&
207 (tdb->tdb_dst.sin.sin_addr.s_addr != ip->ip_dst.s_addr)) ||
208 #ifdef INET6
209 ((tdb->tdb_dst.sa.sa_family == AF_INET6) &&
210 (!IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_dst.sin6.sin6_addr)) &&
211 (!IN6_ARE_ADDR_EQUAL(&tdb->tdb_dst.sin6.sin6_addr,
212 &ip6->ip6_dst))) ||
213 #endif /* INET6 */
214 0) {
215 /* Fix IPv4 header checksum and length. */
216 if (af == AF_INET) {
217 if (m->m_len < sizeof(struct ip))
218 if ((m = m_pullup(m,
219 sizeof(struct ip))) == NULL) {
220 error = ENOBUFS;
221 goto drop;
222 }
223
224 ip = mtod(m, struct ip *);
225 ip->ip_len = htons(m->m_pkthdr.len);
226 ip->ip_sum = 0;
227 ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
228 }
229
230 #ifdef INET6
231 /* Fix IPv6 header payload length. */
232 if (af == AF_INET6) {
233 if (m->m_len < sizeof(struct ip6_hdr))
234 if ((m = m_pullup(m,
235 sizeof(struct ip6_hdr))) == NULL) {
236 error = ENOBUFS;
237 goto drop;
238 }
239
240 if (m->m_pkthdr.len - sizeof(*ip6) >
241 IPV6_MAXPACKET) {
242 /* No jumbogram support. */
243 error = ENXIO; /*?*/
244 goto drop;
245 }
246 ip6 = mtod(m, struct ip6_hdr *);
247 ip6->ip6_plen = htons(m->m_pkthdr.len
248 - sizeof(*ip6));
249 }
250 #endif /* INET6 */
251
252 /* Encapsulate -- m may be changed or set to NULL. */
253 error = ipip_output(&m, tdb);
254 if ((m == NULL) && (!error))
255 error = EFAULT;
256 if (error)
257 goto drop;
258
259 if (tdb->tdb_dst.sa.sa_family == AF_INET && setdf) {
260 if (m->m_len < sizeof(struct ip))
261 if ((m = m_pullup(m,
262 sizeof(struct ip))) == NULL) {
263 error = ENOBUFS;
264 goto drop;
265 }
266
267 ip = mtod(m, struct ip *);
268 ip->ip_off |= htons(IP_DF);
269 }
270
271 /* Remember that we appended a tunnel header. */
272 mtx_enter(&tdb->tdb_mtx);
273 tdb->tdb_flags |= TDBF_USEDTUNNEL;
274 mtx_leave(&tdb->tdb_mtx);
275 }
276 }
277
278 /*
279 * If this is just an IP-IP TDB and we're told there's already an
280 * encapsulation header or ipip_output() has encapsulated it, move on.
281 */
282 if (tdb->tdb_xform->xf_type == XF_IP4)
283 return ipsp_process_done(m, tdb);
284
285 /* Extract some information off the headers. */
286 switch (tdb->tdb_dst.sa.sa_family) {
287 case AF_INET:
288 ip = mtod(m, struct ip *);
289 hlen = ip->ip_hl << 2;
290 off = offsetof(struct ip, ip_p);
291 break;
292
293 #ifdef INET6
294 case AF_INET6:
295 ip6 = mtod(m, struct ip6_hdr *);
296 hlen = sizeof(struct ip6_hdr);
297 off = offsetof(struct ip6_hdr, ip6_nxt);
298 nxt = ip6->ip6_nxt;
299 /*
300 * chase mbuf chain to find the appropriate place to
301 * put AH/ESP/IPcomp header.
302 * IPv6 hbh dest1 rthdr ah* [esp* dest2 payload]
303 */
304 do {
305 switch (nxt) {
306 case IPPROTO_AH:
307 case IPPROTO_ESP:
308 case IPPROTO_IPCOMP:
309 /*
310 * we should not skip security header added
311 * beforehand.
312 */
313 goto exitip6loop;
314
315 case IPPROTO_HOPOPTS:
316 case IPPROTO_DSTOPTS:
317 case IPPROTO_ROUTING:
318 /*
319 * if we see 2nd destination option header,
320 * we should stop there.
321 */
322 if (nxt == IPPROTO_DSTOPTS && dstopt)
323 goto exitip6loop;
324
325 if (nxt == IPPROTO_DSTOPTS) {
326 /*
327 * seen 1st or 2nd destination option.
328 * next time we see one, it must be 2nd.
329 */
330 dstopt = 1;
331 } else if (nxt == IPPROTO_ROUTING) {
332 /*
333 * if we see destination option next
334 * time, it must be dest2.
335 */
336 dstopt = 2;
337 }
338 if (m->m_pkthdr.len < hlen + sizeof(ip6e)) {
339 error = EINVAL;
340 goto drop;
341 }
342 /* skip this header */
343 m_copydata(m, hlen, sizeof(ip6e),
344 (caddr_t)&ip6e);
345 nxt = ip6e.ip6e_nxt;
346 off = hlen + offsetof(struct ip6_ext, ip6e_nxt);
347 /*
348 * we will never see nxt == IPPROTO_AH
349 * so it is safe to omit AH case.
350 */
351 hlen += (ip6e.ip6e_len + 1) << 3;
352 break;
353 default:
354 goto exitip6loop;
355 }
356 } while (hlen < m->m_pkthdr.len);
357 exitip6loop:
358 break;
359 #endif /* INET6 */
360 default:
361 error = EPFNOSUPPORT;
362 goto drop;
363 }
364
365 if (m->m_pkthdr.len < hlen) {
366 error = EINVAL;
367 goto drop;
368 }
369
370 ipsecstat_add(ipsec_ouncompbytes, m->m_pkthdr.len);
371 tdbstat_add(tdb, tdb_ouncompbytes, m->m_pkthdr.len);
372
373 /* Non expansion policy for IPCOMP */
374 if (tdb->tdb_sproto == IPPROTO_IPCOMP) {
375 if ((m->m_pkthdr.len - hlen) < tdb->tdb_compalgxform->minlen) {
376 /* No need to compress, leave the packet untouched */
377 ipcompstat_inc(ipcomps_minlen);
378 return ipsp_process_done(m, tdb);
379 }
380 }
381
382 /* Invoke the IPsec transform. */
383 return (*(tdb->tdb_xform->xf_output))(m, tdb, hlen, off);
384
385 drop:
386 m_freem(m);
387 return error;
388 }
389
390 /*
391 * Called by the IPsec output transform callbacks, to transmit the packet
392 * or do further processing, as necessary.
393 */
394 int
ipsp_process_done(struct mbuf * m,struct tdb * tdb)395 ipsp_process_done(struct mbuf *m, struct tdb *tdb)
396 {
397 struct ip *ip;
398 #ifdef INET6
399 struct ip6_hdr *ip6;
400 #endif /* INET6 */
401 struct tdb *tdbo;
402 struct tdb_ident *tdbi;
403 struct m_tag *mtag;
404 int roff, error;
405
406 NET_ASSERT_LOCKED();
407
408 tdb->tdb_last_used = gettime();
409
410 if ((tdb->tdb_flags & TDBF_UDPENCAP) != 0) {
411 struct mbuf *mi;
412 struct udphdr *uh;
413 int iphlen;
414
415 if (!udpencap_enable || !udpencap_port) {
416 error = ENXIO;
417 goto drop;
418 }
419
420 switch (tdb->tdb_dst.sa.sa_family) {
421 case AF_INET:
422 iphlen = sizeof(struct ip);
423 break;
424 #ifdef INET6
425 case AF_INET6:
426 iphlen = sizeof(struct ip6_hdr);
427 break;
428 #endif /* INET6 */
429 default:
430 DPRINTF("unknown protocol family (%d)",
431 tdb->tdb_dst.sa.sa_family);
432 error = EPFNOSUPPORT;
433 goto drop;
434 }
435
436 mi = m_makespace(m, iphlen, sizeof(struct udphdr), &roff);
437 if (mi == NULL) {
438 error = ENOMEM;
439 goto drop;
440 }
441 uh = (struct udphdr *)(mtod(mi, caddr_t) + roff);
442 uh->uh_sport = uh->uh_dport = htons(udpencap_port);
443 if (tdb->tdb_udpencap_port)
444 uh->uh_dport = tdb->tdb_udpencap_port;
445
446 uh->uh_ulen = htons(m->m_pkthdr.len - iphlen);
447 uh->uh_sum = 0;
448 #ifdef INET6
449 if (tdb->tdb_dst.sa.sa_family == AF_INET6)
450 m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT;
451 #endif /* INET6 */
452 espstat_inc(esps_udpencout);
453 }
454
455 switch (tdb->tdb_dst.sa.sa_family) {
456 case AF_INET:
457 /* Fix the header length, for AH processing. */
458 ip = mtod(m, struct ip *);
459 ip->ip_len = htons(m->m_pkthdr.len);
460 if ((tdb->tdb_flags & TDBF_UDPENCAP) != 0)
461 ip->ip_p = IPPROTO_UDP;
462 break;
463
464 #ifdef INET6
465 case AF_INET6:
466 /* Fix the header length, for AH processing. */
467 if (m->m_pkthdr.len < sizeof(*ip6)) {
468 error = ENXIO;
469 goto drop;
470 }
471 if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) {
472 /* No jumbogram support. */
473 error = ENXIO;
474 goto drop;
475 }
476 ip6 = mtod(m, struct ip6_hdr *);
477 ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
478 if ((tdb->tdb_flags & TDBF_UDPENCAP) != 0)
479 ip6->ip6_nxt = IPPROTO_UDP;
480 break;
481 #endif /* INET6 */
482
483 default:
484 DPRINTF("unknown protocol family (%d)",
485 tdb->tdb_dst.sa.sa_family);
486 error = EPFNOSUPPORT;
487 goto drop;
488 }
489
490 /*
491 * Add a record of what we've done or what needs to be done to the
492 * packet.
493 */
494 mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE, sizeof(struct tdb_ident),
495 M_NOWAIT);
496 if (mtag == NULL) {
497 DPRINTF("could not allocate packet tag");
498 error = ENOMEM;
499 goto drop;
500 }
501
502 tdbi = (struct tdb_ident *)(mtag + 1);
503 tdbi->dst = tdb->tdb_dst;
504 tdbi->proto = tdb->tdb_sproto;
505 tdbi->spi = tdb->tdb_spi;
506 tdbi->rdomain = tdb->tdb_rdomain;
507
508 m_tag_prepend(m, mtag);
509
510 ipsecstat_pkt(ipsec_opackets, ipsec_obytes, m->m_pkthdr.len);
511 tdbstat_pkt(tdb, tdb_opackets, tdb_obytes, m->m_pkthdr.len);
512
513 /* If there's another (bundled) TDB to apply, do so. */
514 tdbo = tdb_ref(tdb->tdb_onext);
515 if (tdbo != NULL) {
516 KERNEL_ASSERT_LOCKED();
517 error = ipsp_process_packet(m, tdbo,
518 tdb->tdb_dst.sa.sa_family, 0);
519 tdb_unref(tdbo);
520 return error;
521 }
522
523 #if NPF > 0
524 /* Add pf tag if requested. */
525 pf_tag_packet(m, tdb->tdb_tag, -1);
526 pf_pkt_addr_changed(m);
527 #endif
528 if (tdb->tdb_rdomain != tdb->tdb_rdomain_post)
529 m->m_pkthdr.ph_rtableid = tdb->tdb_rdomain_post;
530
531 /*
532 * We're done with IPsec processing, transmit the packet using the
533 * appropriate network protocol (IP or IPv6). SPD lookup will be
534 * performed again there.
535 */
536 switch (tdb->tdb_dst.sa.sa_family) {
537 case AF_INET:
538 error = ip_output(m, NULL, NULL, IP_RAWOUTPUT, NULL, NULL, 0);
539 break;
540 #ifdef INET6
541 case AF_INET6:
542 /*
543 * We don't need massage, IPv6 header fields are always in
544 * net endian.
545 */
546 error = ip6_output(m, NULL, NULL, 0, NULL, NULL);
547 break;
548 #endif /* INET6 */
549 default:
550 error = EPFNOSUPPORT;
551 break;
552 }
553 return error;
554
555 drop:
556 m_freem(m);
557 return error;
558 }
559
560 ssize_t
ipsec_hdrsz(struct tdb * tdbp)561 ipsec_hdrsz(struct tdb *tdbp)
562 {
563 ssize_t adjust;
564
565 switch (tdbp->tdb_sproto) {
566 case IPPROTO_IPIP:
567 adjust = 0;
568 break;
569
570 case IPPROTO_ESP:
571 if (tdbp->tdb_encalgxform == NULL)
572 return (-1);
573
574 /* Header length */
575 adjust = 2 * sizeof(u_int32_t) + tdbp->tdb_ivlen;
576 if (tdbp->tdb_flags & TDBF_UDPENCAP)
577 adjust += sizeof(struct udphdr);
578 /* Authenticator */
579 if (tdbp->tdb_authalgxform != NULL)
580 adjust += tdbp->tdb_authalgxform->authsize;
581 /* Padding */
582 adjust += MAX(4, tdbp->tdb_encalgxform->blocksize);
583 break;
584
585 case IPPROTO_AH:
586 if (tdbp->tdb_authalgxform == NULL)
587 return (-1);
588
589 adjust = AH_FLENGTH + sizeof(u_int32_t);
590 adjust += tdbp->tdb_authalgxform->authsize;
591 break;
592
593 default:
594 return (-1);
595 }
596
597 if (!(tdbp->tdb_flags & TDBF_TUNNELING) &&
598 !(tdbp->tdb_flags & TDBF_USEDTUNNEL))
599 return (adjust);
600
601 switch (tdbp->tdb_dst.sa.sa_family) {
602 case AF_INET:
603 adjust += sizeof(struct ip);
604 break;
605 #ifdef INET6
606 case AF_INET6:
607 adjust += sizeof(struct ip6_hdr);
608 break;
609 #endif /* INET6 */
610 }
611
612 return (adjust);
613 }
614
615 void
ipsec_adjust_mtu(struct mbuf * m,u_int32_t mtu)616 ipsec_adjust_mtu(struct mbuf *m, u_int32_t mtu)
617 {
618 struct tdb_ident *tdbi;
619 struct tdb *tdbp;
620 struct m_tag *mtag;
621 ssize_t adjust;
622
623 NET_ASSERT_LOCKED();
624
625 for (mtag = m_tag_find(m, PACKET_TAG_IPSEC_OUT_DONE, NULL); mtag;
626 mtag = m_tag_find(m, PACKET_TAG_IPSEC_OUT_DONE, mtag)) {
627 tdbi = (struct tdb_ident *)(mtag + 1);
628 tdbp = gettdb(tdbi->rdomain, tdbi->spi, &tdbi->dst,
629 tdbi->proto);
630 if (tdbp == NULL)
631 break;
632
633 if ((adjust = ipsec_hdrsz(tdbp)) == -1) {
634 tdb_unref(tdbp);
635 break;
636 }
637
638 mtu -= adjust;
639 tdbp->tdb_mtu = mtu;
640 tdbp->tdb_mtutimeout = gettime() + ip_mtudisc_timeout;
641 DPRINTF("spi %08x mtu %d adjust %ld mbuf %p",
642 ntohl(tdbp->tdb_spi), tdbp->tdb_mtu, adjust, m);
643 tdb_unref(tdbp);
644 }
645 }
646