xref: /openbsd/sbin/isakmpd/nat_traversal.c (revision 875f57d0)
1 /*	$OpenBSD: nat_traversal.c,v 1.16 2005/07/25 15:03:47 hshoexer Exp $	*/
2 
3 /*
4  * Copyright (c) 2004 H�kan Olsson.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include <sys/types.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include "conf.h"
32 #include "exchange.h"
33 #include "hash.h"
34 #include "ipsec.h"
35 #include "isakmp_fld.h"
36 #include "isakmp_num.h"
37 #include "ipsec_num.h"
38 #include "hash.h"
39 #include "log.h"
40 #include "message.h"
41 #include "nat_traversal.h"
42 #include "prf.h"
43 #include "sa.h"
44 #include "timer.h"
45 #include "transport.h"
46 #include "util.h"
47 #include "virtual.h"
48 
49 int	disable_nat_t = 0;
50 
51 /*
52  * NAT-T capability of the other peer is determined by a particular vendor
53  * ID sent in the first message. This vendor ID string is supposed to be a
54  * MD5 hash of "RFC 3947".
55  *
56  * These seem to be the "well" known variants of this string in use by
57  * products today.
58  */
59 
60 static struct nat_t_cap isakmp_nat_t_cap[] = {
61 	{ VID_DRAFT_V2_N, EXCHANGE_FLAG_NAT_T_DRAFT,
62 	  "draft-ietf-ipsec-nat-t-ike-02\n", NULL, 0 },
63 	{ VID_DRAFT_V3, EXCHANGE_FLAG_NAT_T_DRAFT,
64 	  "draft-ietf-ipsec-nat-t-ike-03", NULL, 0 },
65 	{ VID_RFC3947, EXCHANGE_FLAG_NAT_T_RFC,
66 	  "RFC 3947", NULL, 0 },
67 };
68 
69 #define NUMNATTCAP	(sizeof isakmp_nat_t_cap / sizeof isakmp_nat_t_cap[0])
70 
71 /* In seconds. Recommended in draft-ietf-ipsec-udp-encaps-09.  */
72 #define NAT_T_KEEPALIVE_INTERVAL	20
73 
74 static int	nat_t_setup_hashes(void);
75 static int	nat_t_add_vendor_payload(struct message *, struct nat_t_cap *);
76 static int	nat_t_add_nat_d(struct message *, struct sockaddr *);
77 static int	nat_t_match_nat_d_payload(struct message *, struct sockaddr *);
78 
79 void
80 nat_t_init(void)
81 {
82 	nat_t_setup_hashes();
83 }
84 
85 /* Generate the NAT-T capability marker hashes. Executed only once.  */
86 static int
87 nat_t_setup_hashes(void)
88 {
89 	struct hash *hash;
90 	int n = NUMNATTCAP;
91 	int i;
92 
93 	/* The draft says to use MD5.  */
94 	hash = hash_get(HASH_MD5);
95 	if (!hash) {
96 		/* Should never happen.  */
97 		log_print("nat_t_setup_hashes: "
98 		    "could not find MD5 hash structure!");
99 		return -1;
100 	}
101 
102 	/* Populate isakmp_nat_t_cap with hashes.  */
103 	for (i = 0; i < n; i++) {
104 		isakmp_nat_t_cap[i].hashsize = hash->hashsize;
105 		isakmp_nat_t_cap[i].hash = (char *)malloc(hash->hashsize);
106 		if (!isakmp_nat_t_cap[i].hash) {
107 			log_error("nat_t_setup_hashes: malloc (%lu) failed",
108 			    (unsigned long)hash->hashsize);
109 			goto errout;
110 		}
111 
112 		hash->Init(hash->ctx);
113 		hash->Update(hash->ctx,
114 		    (unsigned char *)isakmp_nat_t_cap[i].text,
115 		    strlen(isakmp_nat_t_cap[i].text));
116 		hash->Final(isakmp_nat_t_cap[i].hash, hash->ctx);
117 
118 		LOG_DBG((LOG_EXCHANGE, 50, "nat_t_setup_hashes: "
119 		    "MD5(\"%s\") (%lu bytes)", isakmp_nat_t_cap[i].text,
120 		    (unsigned long)hash->hashsize));
121 		LOG_DBG_BUF((LOG_EXCHANGE, 50, "nat_t_setup_hashes",
122 		    isakmp_nat_t_cap[i].hash, hash->hashsize));
123 	}
124 
125 	return 0;
126 
127   errout:
128 	for (i = 0; i < n; i++)
129 		if (isakmp_nat_t_cap[i].hash)
130 			free(isakmp_nat_t_cap[i].hash);
131 	return -1;
132 }
133 
134 /* Add one NAT-T VENDOR payload.  */
135 static int
136 nat_t_add_vendor_payload(struct message *msg, struct nat_t_cap *cap)
137 {
138 	size_t	  buflen = cap->hashsize + ISAKMP_GEN_SZ;
139 	u_int8_t *buf;
140 
141 	if (disable_nat_t)
142 		return 0;
143 
144 	buf = malloc(buflen);
145 	if (!buf) {
146 		log_error("nat_t_add_vendor_payload: malloc (%lu) failed",
147 		    (unsigned long)buflen);
148 		return -1;
149 	}
150 
151 	SET_ISAKMP_GEN_LENGTH(buf, buflen);
152 	memcpy(buf + ISAKMP_VENDOR_ID_OFF, cap->hash, cap->hashsize);
153 	if (message_add_payload(msg, ISAKMP_PAYLOAD_VENDOR, buf, buflen, 1)) {
154 		free(buf);
155 		return -1;
156 	}
157 	return 0;
158 }
159 
160 /* Add the NAT-T capability markers (VENDOR payloads).  */
161 int
162 nat_t_add_vendor_payloads(struct message *msg)
163 {
164 	int i;
165 
166 	if (disable_nat_t)
167 		return 0;
168 
169 	for (i = 0; i < NUMNATTCAP; i++)
170 		if (nat_t_add_vendor_payload(msg, &isakmp_nat_t_cap[i]))
171 			return -1;
172 	return 0;
173 }
174 
175 /*
176  * Check an incoming message for NAT-T capability markers.
177  */
178 void
179 nat_t_check_vendor_payload(struct message *msg, struct payload *p)
180 {
181 	u_int8_t *pbuf = p->p;
182 	size_t	  vlen;
183 	int	  i;
184 
185 	if (disable_nat_t)
186 		return;
187 
188 	vlen = GET_ISAKMP_GEN_LENGTH(pbuf) - ISAKMP_GEN_SZ;
189 
190 	for (i = 0; i < NUMNATTCAP; i++) {
191 		if (vlen != isakmp_nat_t_cap[i].hashsize) {
192 			LOG_DBG((LOG_EXCHANGE, 50, "nat_t_check_vendor_payload: "
193 			    "bad size %lu != %lu", (unsigned long)vlen,
194 			    (unsigned long)isakmp_nat_t_cap[i].hashsize));
195 			continue;
196 		}
197 		if (memcmp(isakmp_nat_t_cap[i].hash, pbuf + ISAKMP_GEN_SZ,
198 		    vlen) == 0) {
199 			/* This peer is NAT-T capable.  */
200 			msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_CAP_PEER;
201 			msg->exchange->flags |= isakmp_nat_t_cap[i].flags;
202 			LOG_DBG((LOG_EXCHANGE, 10,
203 			    "nat_t_check_vendor_payload: "
204 			    "NAT-T capable peer detected"));
205 			p->flags |= PL_MARK;
206 		}
207 	}
208 
209 	return;
210 }
211 
212 /* Generate the NAT-D payload hash : HASH(CKY-I | CKY-R | IP | Port).  */
213 static u_int8_t *
214 nat_t_generate_nat_d_hash(struct message *msg, struct sockaddr *sa,
215     size_t *hashlen)
216 {
217 	struct ipsec_exch *ie = (struct ipsec_exch *)msg->exchange->data;
218 	struct hash	 *hash;
219 	u_int8_t	 *res;
220 	in_port_t	  port;
221 
222 	hash = hash_get(ie->hash->type);
223 	if (hash == NULL) {
224 		log_print ("nat_t_generate_nat_d_hash: no hash");
225 		return NULL;
226 	}
227 
228 	*hashlen = hash->hashsize;
229 
230 	res = (u_int8_t *)malloc((unsigned long)*hashlen);
231 	if (!res) {
232 		log_print("nat_t_generate_nat_d_hash: malloc (%lu) failed",
233 		    (unsigned long)*hashlen);
234 		*hashlen = 0;
235 		return NULL;
236 	}
237 
238 	port = sockaddr_port(sa);
239 	bzero(res, *hashlen);
240 
241 	hash->Init(hash->ctx);
242 	hash->Update(hash->ctx, msg->exchange->cookies,
243 	    sizeof msg->exchange->cookies);
244 	hash->Update(hash->ctx, sockaddr_addrdata(sa), sockaddr_addrlen(sa));
245 	hash->Update(hash->ctx, (unsigned char *)&port, sizeof port);
246 	hash->Final(res, hash->ctx);
247 	return res;
248 }
249 
250 /* Add a NAT-D payload to our message.  */
251 static int
252 nat_t_add_nat_d(struct message *msg, struct sockaddr *sa)
253 {
254 	int	  ret;
255 	u_int8_t *hbuf, *buf;
256 	size_t	  hbuflen, buflen;
257 
258 	hbuf = nat_t_generate_nat_d_hash(msg, sa, &hbuflen);
259 	if (!hbuf) {
260 		log_print("nat_t_add_nat_d: NAT-D hash gen failed");
261 		return -1;
262 	}
263 
264 	buflen = ISAKMP_NAT_D_DATA_OFF + hbuflen;
265 	buf = malloc(buflen);
266 	if (!buf) {
267 		log_error("nat_t_add_nat_d: malloc (%lu) failed",
268 		    (unsigned long)buflen);
269 		free(hbuf);
270 		return -1;
271 	}
272 
273 	SET_ISAKMP_GEN_LENGTH(buf, buflen);
274 	memcpy(buf + ISAKMP_NAT_D_DATA_OFF, hbuf, hbuflen);
275 	free(hbuf);
276 
277 	if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_RFC)
278 		ret = message_add_payload(msg, ISAKMP_PAYLOAD_NAT_D, buf,
279 		    buflen, 1);
280 	else if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_DRAFT)
281 		ret = message_add_payload(msg, ISAKMP_PAYLOAD_NAT_D_DRAFT,
282 		    buf, buflen, 1);
283 	else
284 		ret = -1;
285 
286 	if (ret) {
287 		free(buf);
288 		return -1;
289 	}
290 	return 0;
291 }
292 
293 /* We add two NAT-D payloads, one each for src and dst.  */
294 int
295 nat_t_exchange_add_nat_d(struct message *msg)
296 {
297 	struct sockaddr *sa;
298 
299 	/* Remote address first. */
300 	msg->transport->vtbl->get_dst(msg->transport, &sa);
301 	if (nat_t_add_nat_d(msg, sa))
302 		return -1;
303 
304 	msg->transport->vtbl->get_src(msg->transport, &sa);
305 	if (nat_t_add_nat_d(msg, sa))
306 		return -1;
307 	return 0;
308 }
309 
310 /* Generate and match a NAT-D hash against the NAT-D payload (pl.) data.  */
311 static int
312 nat_t_match_nat_d_payload(struct message *msg, struct sockaddr *sa)
313 {
314 	struct payload *p;
315 	u_int8_t *hbuf;
316 	size_t	 hbuflen;
317 	int	 found = 0;
318 
319 	/*
320 	 * If there are no NAT-D payloads in the message, return "found"
321 	 * as this will avoid NAT-T (see nat_t_exchange_check_nat_d()).
322 	 */
323 	if ((p = payload_first(msg, ISAKMP_PAYLOAD_NAT_D_DRAFT)) == NULL &&
324 	    (p = payload_first(msg, ISAKMP_PAYLOAD_NAT_D)) == NULL)
325 		return 1;
326 
327 	hbuf = nat_t_generate_nat_d_hash(msg, sa, &hbuflen);
328 	if (!hbuf)
329 		return 0;
330 
331 	while (p) {
332 		if (GET_ISAKMP_GEN_LENGTH (p->p) !=
333 		    hbuflen + ISAKMP_NAT_D_DATA_OFF)
334 			continue;
335 
336 		if (memcmp(p->p + ISAKMP_NAT_D_DATA_OFF, hbuf, hbuflen) == 0) {
337 			found++;
338 			break;
339 		}
340 		p = TAILQ_NEXT(p, link);
341 	}
342 	free(hbuf);
343 	return found;
344 }
345 
346 /*
347  * Check if we need to activate NAT-T, and if we need to send keepalive
348  * messages to the other side, i.e if we are a nat:ed peer.
349  */
350 int
351 nat_t_exchange_check_nat_d(struct message *msg)
352 {
353 	struct sockaddr *sa;
354 	int	 outgoing_path_is_clear, incoming_path_is_clear;
355 
356 	/* Assume trouble, i.e NAT-boxes in our path.  */
357 	outgoing_path_is_clear = incoming_path_is_clear = 0;
358 
359 	msg->transport->vtbl->get_src(msg->transport, &sa);
360 	if (nat_t_match_nat_d_payload(msg, sa))
361 		outgoing_path_is_clear = 1;
362 
363 	msg->transport->vtbl->get_dst(msg->transport, &sa);
364 	if (nat_t_match_nat_d_payload(msg, sa))
365 		incoming_path_is_clear = 1;
366 
367 	if (outgoing_path_is_clear && incoming_path_is_clear) {
368 		LOG_DBG((LOG_EXCHANGE, 40, "nat_t_exchange_check_nat_d: "
369 		    "no NAT"));
370 		return 0; /* No NAT-T required.  */
371 	}
372 
373 	/* NAT-T handling required.  */
374 	msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_ENABLE;
375 
376 	if (!outgoing_path_is_clear) {
377 		msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_KEEPALIVE;
378 		LOG_DBG((LOG_EXCHANGE, 10, "nat_t_exchange_check_nat_d: "
379 		    "NAT detected, we're behind it"));
380 	} else
381 		LOG_DBG ((LOG_EXCHANGE, 10,
382 		    "nat_t_exchange_check_nat_d: NAT detected"));
383 	return 1;
384 }
385 
386 static void
387 nat_t_send_keepalive(void *v_arg)
388 {
389 	struct sa *sa = (struct sa *)v_arg;
390 	struct transport *t;
391 	struct timeval now;
392 	int interval;
393 
394 	/* Send the keepalive message.  */
395 	t = ((struct virtual_transport *)sa->transport)->encap;
396 	t->vtbl->send_message(NULL, t);
397 
398 	/* Set new timer.  */
399 	interval = conf_get_num("General", "NAT-T-Keepalive", 0);
400 	if (interval < 1)
401 		interval = NAT_T_KEEPALIVE_INTERVAL;
402 	gettimeofday(&now, 0);
403 	now.tv_sec += interval;
404 
405 	sa->nat_t_keepalive = timer_add_event("nat_t_send_keepalive",
406 	    nat_t_send_keepalive, v_arg, &now);
407 	if (!sa->nat_t_keepalive)
408 		log_print("nat_t_send_keepalive: "
409 		    "timer_add_event() failed, will send no more keepalives");
410 }
411 
412 void
413 nat_t_setup_keepalive(struct sa *sa)
414 {
415 	struct sockaddr *src;
416 	struct timeval now;
417 
418 	if (sa->initiator)
419 		sa->transport->vtbl->get_src(sa->transport, &src);
420 	else
421 		sa->transport->vtbl->get_dst(sa->transport, &src);
422 
423 	if (!virtual_listen_lookup(src))
424 		return;
425 
426 	gettimeofday(&now, 0);
427 	now.tv_sec += NAT_T_KEEPALIVE_INTERVAL;
428 
429 	sa->nat_t_keepalive = timer_add_event("nat_t_send_keepalive",
430 	    nat_t_send_keepalive, sa, &now);
431 	if (!sa->nat_t_keepalive)
432 		log_print("nat_t_setup_keepalive: "
433 		    "timer_add_event() failed, will not send keepalives");
434 
435 	LOG_DBG((LOG_TRANSPORT, 50, "nat_t_setup_keepalive: "
436 	    "added event for phase 1 SA %p", sa));
437 }
438