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