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
65int	udpencap_enable = 1;	/* enabled by default */
66int	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 */
73int
74ipsp_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 */
394int
395ipsp_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
560ssize_t
561ipsec_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
615void
616ipsec_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