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