xref: /openbsd-src/sys/netinet/ipsec_output.c (revision 8500990981f885cbe5e6a4958549cacc238b5ae6)
1 /*	$OpenBSD: ipsec_output.c,v 1.28 2003/12/02 23:16:29 markus 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 <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/mbuf.h>
26 #include <sys/socket.h>
27 #include <sys/kernel.h>
28 
29 #include <net/if.h>
30 #include <net/route.h>
31 
32 #ifdef INET
33 #include <netinet/in.h>
34 #include <netinet/in_systm.h>
35 #include <netinet/ip.h>
36 #include <netinet/in_pcb.h>
37 #include <netinet/ip_var.h>
38 #endif /* INET */
39 
40 #ifdef INET6
41 #ifndef INET
42 #include <netinet/in.h>
43 #endif
44 #include <netinet6/in6_var.h>
45 #endif /* INET6 */
46 
47 #include <netinet/udp.h>
48 #include <netinet/ip_ipsp.h>
49 #include <netinet/ip_ah.h>
50 #include <netinet/ip_esp.h>
51 #include <netinet/ip_ipcomp.h>
52 #include <crypto/xform.h>
53 
54 #ifdef ENCDEBUG
55 #define DPRINTF(x)	if (encdebug) printf x
56 #else
57 #define DPRINTF(x)
58 #endif
59 
60 int	udpencap_enable = 0;	/* disabled by default */
61 int	udpencap_port = 4500;	/* triggers decapsulation */
62 
63 /*
64  * Loop over a tdb chain, taking into consideration protocol tunneling. The
65  * fourth argument is set if the first encapsulation header is already in
66  * place.
67  */
68 int
69 ipsp_process_packet(struct mbuf *m, struct tdb *tdb, int af, int tunalready)
70 {
71 	struct timeval tv;
72 	int i, off, error;
73 	struct mbuf *mp;
74 
75 #ifdef INET
76 	int setdf = 0;
77 	struct ip *ip;
78 #endif /* INET */
79 #ifdef INET6
80 	struct ip6_hdr *ip6;
81 #endif /* INET6 */
82 
83 	/* Check that the transform is allowed by the administrator. */
84 	if ((tdb->tdb_sproto == IPPROTO_ESP && !esp_enable) ||
85 	    (tdb->tdb_sproto == IPPROTO_AH && !ah_enable) ||
86 	    (tdb->tdb_sproto == IPPROTO_IPCOMP && !ipcomp_enable)) {
87 		DPRINTF(("ipsp_process_packet(): IPsec outbound packet "
88 		    "dropped due to policy (check your sysctls)\n"));
89 		m_freem(m);
90 		return EHOSTUNREACH;
91 	}
92 
93 	/* Sanity check. */
94 	if (!tdb->tdb_xform) {
95 		DPRINTF(("ipsp_process_packet(): uninitialized TDB\n"));
96 		m_freem(m);
97 		return EHOSTUNREACH;
98 	}
99 
100 	/* Check if the SPI is invalid. */
101 	if (tdb->tdb_flags & TDBF_INVALID) {
102 		DPRINTF(("ipsp_process_packet(): attempt to use invalid "
103 		    "SA %s/%08x/%u\n", ipsp_address(tdb->tdb_dst),
104 		    ntohl(tdb->tdb_spi), tdb->tdb_sproto));
105 		m_freem(m);
106 		return ENXIO;
107 	}
108 
109 	/* Check that the network protocol is supported */
110 	switch (tdb->tdb_dst.sa.sa_family) {
111 #ifdef INET
112 	case AF_INET:
113 		break;
114 #endif /* INET */
115 
116 #ifdef INET6
117 	case AF_INET6:
118 		break;
119 #endif /* INET6 */
120 
121 	default:
122 		DPRINTF(("ipsp_process_packet(): attempt to use "
123 		    "SA %s/%08x/%u for protocol family %d\n",
124 		    ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi),
125 		    tdb->tdb_sproto, tdb->tdb_dst.sa.sa_family));
126 		m_freem(m);
127 		return ENXIO;
128 	}
129 
130 	/*
131 	 * Register first use if applicable, setup relevant expiration timer.
132 	 */
133 	if (tdb->tdb_first_use == 0) {
134 		int pri;
135 
136 		pri = splhigh();
137 		tdb->tdb_first_use = time.tv_sec;
138 		splx(pri);
139 
140 		tv.tv_usec = 0;
141 
142 		tv.tv_sec = tdb->tdb_first_use + tdb->tdb_exp_first_use;
143 		if (tdb->tdb_flags & TDBF_FIRSTUSE)
144 			timeout_add(&tdb->tdb_first_tmo,
145 			    hzto(&tv));
146 
147 		tv.tv_sec = tdb->tdb_first_use + tdb->tdb_soft_first_use;
148 		if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE)
149 			timeout_add(&tdb->tdb_sfirst_tmo,
150 			    hzto(&tv));
151 	}
152 
153 	/*
154 	 * Check for tunneling if we don't have the first header in place.
155 	 * When doing Ethernet-over-IP, we are handed an already-encapsulated
156 	 * frame, so we don't need to re-encapsulate.
157 	 */
158 	if (tunalready == 0) {
159 		/*
160 		 * If the target protocol family is different, we know we'll be
161 		 * doing tunneling.
162 		 */
163 		if (af == tdb->tdb_dst.sa.sa_family) {
164 #ifdef INET
165 			if (af == AF_INET)
166 				i = sizeof(struct ip);
167 #endif /* INET */
168 
169 #ifdef INET6
170 			if (af == AF_INET6)
171 				i = sizeof(struct ip6_hdr);
172 #endif /* INET6 */
173 
174 			/* Bring the network header in the first mbuf. */
175 			if (m->m_len < i) {
176 				if ((m = m_pullup(m, i)) == NULL)
177 					return ENOBUFS;
178 			}
179 
180 #ifdef INET
181 			ip = mtod(m, struct ip *);
182 
183 			/*
184 			 * This is not a bridge packet, remember if we
185 			 * had IP_DF.
186 			 */
187 			setdf = ip->ip_off & htons(IP_DF);
188 #endif /* INET */
189 
190 #ifdef INET6
191 			ip6 = mtod(m, struct ip6_hdr *);
192 #endif /* INET6 */
193 		}
194 
195 		/* Do the appropriate encapsulation, if necessary. */
196 		if ((tdb->tdb_dst.sa.sa_family != af) || /* PF mismatch */
197 		    (tdb->tdb_flags & TDBF_TUNNELING) || /* Tunneling needed */
198 		    (tdb->tdb_xform->xf_type == XF_IP4) || /* ditto */
199 #ifdef INET
200 		    ((tdb->tdb_dst.sa.sa_family == AF_INET) &&
201 			(tdb->tdb_dst.sin.sin_addr.s_addr != INADDR_ANY) &&
202 			(tdb->tdb_dst.sin.sin_addr.s_addr != ip->ip_dst.s_addr)) ||
203 #endif /* INET */
204 #ifdef INET6
205 		    ((tdb->tdb_dst.sa.sa_family == AF_INET6) &&
206 			(!IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_dst.sin6.sin6_addr)) &&
207 			(!IN6_ARE_ADDR_EQUAL(&tdb->tdb_dst.sin6.sin6_addr,
208 			    &ip6->ip6_dst))) ||
209 #endif /* INET6 */
210 		    0) {
211 #ifdef INET
212 			/* Fix IPv4 header checksum and length. */
213 			if (af == AF_INET) {
214 				if (m->m_len < sizeof(struct ip))
215 					if ((m = m_pullup(m,
216 					    sizeof(struct ip))) == NULL)
217 						return ENOBUFS;
218 
219 				ip = mtod(m, struct ip *);
220 				ip->ip_len = htons(m->m_pkthdr.len);
221 				ip->ip_sum = 0;
222 				ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
223 			}
224 #endif /* INET */
225 
226 #ifdef INET6
227 			/* Fix IPv6 header payload length. */
228 			if (af == AF_INET6) {
229 				if (m->m_len < sizeof(struct ip6_hdr))
230 					if ((m = m_pullup(m,
231 					    sizeof(struct ip6_hdr))) == NULL)
232 						return ENOBUFS;
233 
234 				if (m->m_pkthdr.len - sizeof(*ip6) >
235 				    IPV6_MAXPACKET) {
236 					/* No jumbogram support. */
237 					m_freem(m);
238 					return ENXIO;	/*?*/
239 				}
240 				ip6 = mtod(m, struct ip6_hdr *);
241 				ip6->ip6_plen = htons(m->m_pkthdr.len
242 				    - sizeof(*ip6));
243 			}
244 #endif /* INET6 */
245 
246 			/* Encapsulate -- the last two arguments are unused. */
247 			error = ipip_output(m, tdb, &mp, 0, 0);
248 			if ((mp == NULL) && (!error))
249 				error = EFAULT;
250 			if (error) {
251 				if (mp)	{
252 					m_freem(mp);
253 					mp = NULL;
254 				}
255 				return error;
256 			}
257 
258 			m = mp;
259 			mp = NULL;
260 
261 #ifdef INET
262 			if (tdb->tdb_dst.sa.sa_family == AF_INET && setdf) {
263 				if (m->m_len < sizeof(struct ip))
264 					if ((m = m_pullup(m,
265 					    sizeof(struct ip))) == NULL)
266 						return ENOBUFS;
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 			tdb->tdb_flags |= TDBF_USEDTUNNEL;
274 #endif
275 		}
276 
277 		/* We may be done with this TDB */
278 		if (tdb->tdb_xform->xf_type == XF_IP4)
279 			return ipsp_process_done(m, tdb);
280 	} else {
281 		/*
282 		 * If this is just an IP-IP TDB and we're told there's
283 		 * already an encapsulation header, move on.
284 		 */
285 		if (tdb->tdb_xform->xf_type == XF_IP4)
286 			return ipsp_process_done(m, tdb);
287 	}
288 
289 	/* Extract some information off the headers. */
290 	switch (tdb->tdb_dst.sa.sa_family) {
291 #ifdef INET
292 	case AF_INET:
293 		ip = mtod(m, struct ip *);
294 		i = ip->ip_hl << 2;
295 		off = offsetof(struct ip, ip_p);
296 		break;
297 #endif /* INET */
298 
299 #ifdef INET6
300 	case AF_INET6:
301 		ip6 = mtod(m, struct ip6_hdr *);
302 		i = sizeof(struct ip6_hdr);
303 		off = offsetof(struct ip6_hdr, ip6_nxt);
304 		break;
305 #endif /* INET6 */
306 	}
307 
308 	/* Non expansion policy for IPCOMP */
309 	if (tdb->tdb_sproto == IPPROTO_IPCOMP) {
310 		if ((m->m_pkthdr.len - i) < tdb->tdb_compalgxform->minlen) {
311 			extern struct ipcompstat ipcompstat;
312 
313 			/* No need to compress, leave the packet untouched */
314 			ipcompstat.ipcomps_minlen++;
315 			return ipsp_process_done(m, tdb);
316 		}
317 	}
318 
319 	/* Invoke the IPsec transform. */
320 	return (*(tdb->tdb_xform->xf_output))(m, tdb, NULL, i, off);
321 }
322 
323 /*
324  * Called by the IPsec output transform callbacks, to transmit the packet
325  * or do further processing, as necessary.
326  */
327 int
328 ipsp_process_done(struct mbuf *m, struct tdb *tdb)
329 {
330 #ifdef INET
331 	struct ip *ip;
332 #endif /* INET */
333 
334 #ifdef INET6
335 	struct ip6_hdr *ip6;
336 #endif /* INET6 */
337 
338 	struct tdb_ident *tdbi;
339 	struct m_tag *mtag;
340 
341 	tdb->tdb_last_used = time.tv_sec;
342 
343 	if (udpencap_enable && udpencap_port &&
344 	    (tdb->tdb_flags & TDBF_UDPENCAP) != 0) {
345 		struct mbuf *mi;
346 		struct udphdr *uh;
347 
348 		mi = m_inject(m, sizeof(struct ip), sizeof(struct udphdr),
349 		    M_DONTWAIT);
350 		if (mi == NULL) {
351 			m_freem(m);
352 			return ENOMEM;
353 		}
354 		uh = mtod(mi, struct udphdr *);
355 		uh->uh_sport = uh->uh_dport = htons(udpencap_port);
356 		if (tdb->tdb_udpencap_port)
357 			uh->uh_dport = tdb->tdb_udpencap_port;
358 
359 		uh->uh_ulen = htons(m->m_pkthdr.len - sizeof(struct ip));
360 		uh->uh_sum = 0;
361 		espstat.esps_udpencout++;
362 	}
363 
364 	switch (tdb->tdb_dst.sa.sa_family) {
365 #ifdef INET
366 	case AF_INET:
367 		/* Fix the header length, for AH processing. */
368 		ip = mtod(m, struct ip *);
369 		ip->ip_len = htons(m->m_pkthdr.len);
370 		if ((tdb->tdb_flags & TDBF_UDPENCAP) != 0)
371 			ip->ip_p = IPPROTO_UDP;
372 		break;
373 #endif /* INET */
374 
375 #ifdef INET6
376 	case AF_INET6:
377 		/* Fix the header length, for AH processing. */
378 		if (m->m_pkthdr.len < sizeof(*ip6)) {
379 			m_freem(m);
380 			return ENXIO;
381 		}
382 		if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) {
383 			/* No jumbogram support. */
384 			m_freem(m);
385 			return ENXIO;
386 		}
387 		ip6 = mtod(m, struct ip6_hdr *);
388 		ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
389 		if ((tdb->tdb_flags & TDBF_UDPENCAP) != 0)
390 			ip6->ip6_nxt = IPPROTO_UDP;
391 		break;
392 #endif /* INET6 */
393 
394 	default:
395 		m_freem(m);
396 		DPRINTF(("ipsp_process_done(): unknown protocol family (%d)\n",
397 		    tdb->tdb_dst.sa.sa_family));
398 		return ENXIO;
399 	}
400 
401 	/*
402 	 * Add a record of what we've done or what needs to be done to the
403 	 * packet.
404 	 */
405 	if ((tdb->tdb_flags & TDBF_SKIPCRYPTO) == 0)
406 		mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE,
407 		    sizeof(struct tdb_ident),
408 		    M_NOWAIT);
409 	else
410 		mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED,
411 		    sizeof(struct tdb_ident), M_NOWAIT);
412 
413 	if (mtag == NULL) {
414 		m_freem(m);
415 		DPRINTF(("ipsp_process_done(): could not allocate packet "
416 		    "tag\n"));
417 		return ENOMEM;
418 	}
419 
420 	tdbi = (struct tdb_ident *)(mtag + 1);
421 	bcopy(&tdb->tdb_dst, &tdbi->dst, sizeof(union sockaddr_union));
422 	tdbi->proto = tdb->tdb_sproto;
423 	tdbi->spi = tdb->tdb_spi;
424 
425 	m_tag_prepend(m, mtag);
426 
427 	/* If there's another (bundled) TDB to apply, do so. */
428 	if (tdb->tdb_onext)
429 		return ipsp_process_packet(m, tdb->tdb_onext,
430 		    tdb->tdb_dst.sa.sa_family, 0);
431 
432 	/*
433 	 * We're done with IPsec processing, transmit the packet using the
434 	 * appropriate network protocol (IP or IPv6). SPD lookup will be
435 	 * performed again there.
436 	 */
437 	switch (tdb->tdb_dst.sa.sa_family) {
438 #ifdef INET
439 	case AF_INET:
440 		return ip_output(m, (void *)NULL, (void *)NULL, IP_RAWOUTPUT, (void *)NULL, (void *)NULL);
441 #endif /* INET */
442 
443 #ifdef INET6
444 	case AF_INET6:
445 		/*
446 		 * We don't need massage, IPv6 header fields are always in
447 		 * net endian.
448 		 */
449 		return ip6_output(m, NULL, NULL, 0, NULL, NULL);
450 #endif /* INET6 */
451 	}
452 	return EINVAL; /* Not reached. */
453 }
454 
455 ssize_t
456 ipsec_hdrsz(struct tdb *tdbp)
457 {
458 	ssize_t adjust;
459 
460 	switch (tdbp->tdb_sproto) {
461 	case IPPROTO_ESP:
462 		if (tdbp->tdb_encalgxform == NULL)
463 			return (-1);
464 
465 		/* Header length */
466 		if (tdbp->tdb_flags & TDBF_NOREPLAY)
467 			adjust = sizeof(u_int32_t) + tdbp->tdb_ivlen;
468 		else
469 			adjust = 2 * sizeof(u_int32_t) + tdbp->tdb_ivlen;
470 		/* Authenticator */
471 		if (tdbp->tdb_authalgxform != NULL)
472 			adjust += AH_HMAC_HASHLEN;
473 		/* Padding */
474 		adjust += tdbp->tdb_encalgxform->blocksize;
475 		break;
476 
477 	case IPPROTO_AH:
478 		if (tdbp->tdb_authalgxform == NULL)
479 			return (-1);
480 
481 		if (!(tdbp->tdb_flags & TDBF_NOREPLAY))
482 			adjust = AH_FLENGTH + sizeof(u_int32_t);
483 		else
484 			adjust = AH_FLENGTH;
485 		adjust += tdbp->tdb_authalgxform->authsize;
486 		break;
487 
488 	default:
489 		return (-1);
490 	}
491 
492 	if (!(tdbp->tdb_flags & TDBF_TUNNELING) &&
493 	    !(tdbp->tdb_flags & TDBF_USEDTUNNEL))
494 		return (adjust);
495 
496 	switch (tdbp->tdb_dst.sa.sa_family) {
497 #ifdef INET
498 	case AF_INET:
499 		adjust += sizeof(struct ip);
500 		break;
501 #endif /* INET */
502 #ifdef INET6
503 	case AF_INET6:
504 		adjust += sizeof(struct ip6_hdr);
505 		break;
506 #endif /* INET6 */
507 	}
508 
509 	return (adjust);
510 }
511 
512 void
513 ipsec_adjust_mtu(struct mbuf *m, u_int32_t mtu)
514 {
515 	struct tdb_ident *tdbi;
516 	struct tdb *tdbp;
517 	struct m_tag *mtag;
518 	ssize_t adjust;
519 	int s;
520 
521 	s = spltdb();
522 
523 	for (mtag = m_tag_find(m, PACKET_TAG_IPSEC_OUT_DONE, NULL); mtag;
524 	     mtag = m_tag_find(m, PACKET_TAG_IPSEC_OUT_DONE, mtag)) {
525 		tdbi = (struct tdb_ident *)(mtag + 1);
526 		tdbp = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
527 		if (tdbp == NULL)
528 			break;
529 
530 		if ((adjust = ipsec_hdrsz(tdbp)) == -1)
531 			break;
532 
533 		mtu -= adjust;
534 		tdbp->tdb_mtu = mtu;
535 		tdbp->tdb_mtutimeout = time.tv_sec + ip_mtudisc_timeout;
536 	}
537 
538 	splx(s);
539 }
540