xref: /openbsd/sbin/isakmpd/nat_traversal.c (revision b7984483)
1 /*	$OpenBSD: nat_traversal.c,v 1.19 2007/04/16 13:01:39 moritz 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  * Note that the VID specified in draft 2 is ambiguous: It was
60  * accidentally calculated from the string "draft-ietf-ipsec-nat-t-ike-02\n"
61  * although the string was documented without the trailing '\n'. The authors
62  * suggested afterwards to use the string with the trailing '\n'.
63  */
64 
65 static struct nat_t_cap isakmp_nat_t_cap[] = {
66 	{ VID_DRAFT_V2_N, EXCHANGE_FLAG_NAT_T_DRAFT,
67 	  "draft-ietf-ipsec-nat-t-ike-02\n", NULL, 0 },
68 	{ VID_DRAFT_V3, EXCHANGE_FLAG_NAT_T_DRAFT,
69 	  "draft-ietf-ipsec-nat-t-ike-03", NULL, 0 },
70 	{ VID_RFC3947, EXCHANGE_FLAG_NAT_T_RFC,
71 	  "RFC 3947", NULL, 0 },
72 };
73 
74 #define NUMNATTCAP	(sizeof isakmp_nat_t_cap / sizeof isakmp_nat_t_cap[0])
75 
76 /* In seconds. Recommended in draft-ietf-ipsec-udp-encaps-09.  */
77 #define NAT_T_KEEPALIVE_INTERVAL	20
78 
79 static int	nat_t_setup_hashes(void);
80 static int	nat_t_add_vendor_payload(struct message *, struct nat_t_cap *);
81 static int	nat_t_add_nat_d(struct message *, struct sockaddr *);
82 static int	nat_t_match_nat_d_payload(struct message *, struct sockaddr *);
83 
84 void
85 nat_t_init(void)
86 {
87 	nat_t_setup_hashes();
88 }
89 
90 /* Generate the NAT-T capability marker hashes. Executed only once.  */
91 static int
92 nat_t_setup_hashes(void)
93 {
94 	struct hash *hash;
95 	int n = NUMNATTCAP;
96 	int i;
97 
98 	/* The draft says to use MD5.  */
99 	hash = hash_get(HASH_MD5);
100 	if (!hash) {
101 		/* Should never happen.  */
102 		log_print("nat_t_setup_hashes: "
103 		    "could not find MD5 hash structure!");
104 		return -1;
105 	}
106 
107 	/* Populate isakmp_nat_t_cap with hashes.  */
108 	for (i = 0; i < n; i++) {
109 		isakmp_nat_t_cap[i].hashsize = hash->hashsize;
110 		isakmp_nat_t_cap[i].hash = (char *)malloc(hash->hashsize);
111 		if (!isakmp_nat_t_cap[i].hash) {
112 			log_error("nat_t_setup_hashes: malloc (%lu) failed",
113 			    (unsigned long)hash->hashsize);
114 			goto errout;
115 		}
116 
117 		hash->Init(hash->ctx);
118 		hash->Update(hash->ctx,
119 		    (unsigned char *)isakmp_nat_t_cap[i].text,
120 		    strlen(isakmp_nat_t_cap[i].text));
121 		hash->Final(isakmp_nat_t_cap[i].hash, hash->ctx);
122 
123 		LOG_DBG((LOG_EXCHANGE, 50, "nat_t_setup_hashes: "
124 		    "MD5(\"%s\") (%lu bytes)", isakmp_nat_t_cap[i].text,
125 		    (unsigned long)hash->hashsize));
126 		LOG_DBG_BUF((LOG_EXCHANGE, 50, "nat_t_setup_hashes",
127 		    isakmp_nat_t_cap[i].hash, hash->hashsize));
128 	}
129 
130 	return 0;
131 
132 errout:
133 	for (i = 0; i < n; i++)
134 		free(isakmp_nat_t_cap[i].hash);
135 	return -1;
136 }
137 
138 /* Add one NAT-T VENDOR payload.  */
139 static int
140 nat_t_add_vendor_payload(struct message *msg, struct nat_t_cap *cap)
141 {
142 	size_t	  buflen = cap->hashsize + ISAKMP_GEN_SZ;
143 	u_int8_t *buf;
144 
145 	if (disable_nat_t)
146 		return 0;
147 
148 	buf = malloc(buflen);
149 	if (!buf) {
150 		log_error("nat_t_add_vendor_payload: malloc (%lu) failed",
151 		    (unsigned long)buflen);
152 		return -1;
153 	}
154 
155 	SET_ISAKMP_GEN_LENGTH(buf, buflen);
156 	memcpy(buf + ISAKMP_VENDOR_ID_OFF, cap->hash, cap->hashsize);
157 	if (message_add_payload(msg, ISAKMP_PAYLOAD_VENDOR, buf, buflen, 1)) {
158 		free(buf);
159 		return -1;
160 	}
161 	return 0;
162 }
163 
164 /* Add the NAT-T capability markers (VENDOR payloads).  */
165 int
166 nat_t_add_vendor_payloads(struct message *msg)
167 {
168 	int i;
169 
170 	if (disable_nat_t)
171 		return 0;
172 
173 	for (i = 0; i < NUMNATTCAP; i++)
174 		if (nat_t_add_vendor_payload(msg, &isakmp_nat_t_cap[i]))
175 			return -1;
176 	return 0;
177 }
178 
179 /*
180  * Check an incoming message for NAT-T capability markers.
181  */
182 void
183 nat_t_check_vendor_payload(struct message *msg, struct payload *p)
184 {
185 	u_int8_t *pbuf = p->p;
186 	size_t	  vlen;
187 	int	  i;
188 
189 	if (disable_nat_t)
190 		return;
191 
192 	vlen = GET_ISAKMP_GEN_LENGTH(pbuf) - ISAKMP_GEN_SZ;
193 
194 	for (i = 0; i < NUMNATTCAP; i++) {
195 		if (vlen != isakmp_nat_t_cap[i].hashsize) {
196 			LOG_DBG((LOG_EXCHANGE, 50, "nat_t_check_vendor_payload: "
197 			    "bad size %lu != %lu", (unsigned long)vlen,
198 			    (unsigned long)isakmp_nat_t_cap[i].hashsize));
199 			continue;
200 		}
201 		if (memcmp(isakmp_nat_t_cap[i].hash, pbuf + ISAKMP_GEN_SZ,
202 		    vlen) == 0) {
203 			/* This peer is NAT-T capable.  */
204 			msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_CAP_PEER;
205 			msg->exchange->flags |= isakmp_nat_t_cap[i].flags;
206 			LOG_DBG((LOG_EXCHANGE, 10,
207 			    "nat_t_check_vendor_payload: "
208 			    "NAT-T capable peer detected"));
209 			p->flags |= PL_MARK;
210 		}
211 	}
212 
213 	return;
214 }
215 
216 /* Generate the NAT-D payload hash : HASH(CKY-I | CKY-R | IP | Port).  */
217 static u_int8_t *
218 nat_t_generate_nat_d_hash(struct message *msg, struct sockaddr *sa,
219     size_t *hashlen)
220 {
221 	struct ipsec_exch *ie = (struct ipsec_exch *)msg->exchange->data;
222 	struct hash	 *hash;
223 	u_int8_t	 *res;
224 	in_port_t	  port;
225 
226 	hash = hash_get(ie->hash->type);
227 	if (hash == NULL) {
228 		log_print ("nat_t_generate_nat_d_hash: no hash");
229 		return NULL;
230 	}
231 
232 	*hashlen = hash->hashsize;
233 
234 	res = (u_int8_t *)malloc((unsigned long)*hashlen);
235 	if (!res) {
236 		log_print("nat_t_generate_nat_d_hash: malloc (%lu) failed",
237 		    (unsigned long)*hashlen);
238 		*hashlen = 0;
239 		return NULL;
240 	}
241 
242 	port = sockaddr_port(sa);
243 	bzero(res, *hashlen);
244 
245 	hash->Init(hash->ctx);
246 	hash->Update(hash->ctx, msg->exchange->cookies,
247 	    sizeof msg->exchange->cookies);
248 	hash->Update(hash->ctx, sockaddr_addrdata(sa), sockaddr_addrlen(sa));
249 	hash->Update(hash->ctx, (unsigned char *)&port, sizeof port);
250 	hash->Final(res, hash->ctx);
251 	return res;
252 }
253 
254 /* Add a NAT-D payload to our message.  */
255 static int
256 nat_t_add_nat_d(struct message *msg, struct sockaddr *sa)
257 {
258 	int	  ret;
259 	u_int8_t *hbuf, *buf;
260 	size_t	  hbuflen, buflen;
261 
262 	hbuf = nat_t_generate_nat_d_hash(msg, sa, &hbuflen);
263 	if (!hbuf) {
264 		log_print("nat_t_add_nat_d: NAT-D hash gen failed");
265 		return -1;
266 	}
267 
268 	buflen = ISAKMP_NAT_D_DATA_OFF + hbuflen;
269 	buf = malloc(buflen);
270 	if (!buf) {
271 		log_error("nat_t_add_nat_d: malloc (%lu) failed",
272 		    (unsigned long)buflen);
273 		free(hbuf);
274 		return -1;
275 	}
276 
277 	SET_ISAKMP_GEN_LENGTH(buf, buflen);
278 	memcpy(buf + ISAKMP_NAT_D_DATA_OFF, hbuf, hbuflen);
279 	free(hbuf);
280 
281 	if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_RFC)
282 		ret = message_add_payload(msg, ISAKMP_PAYLOAD_NAT_D, buf,
283 		    buflen, 1);
284 	else if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_DRAFT)
285 		ret = message_add_payload(msg, ISAKMP_PAYLOAD_NAT_D_DRAFT,
286 		    buf, buflen, 1);
287 	else
288 		ret = -1;
289 
290 	if (ret) {
291 		free(buf);
292 		return -1;
293 	}
294 	return 0;
295 }
296 
297 /* We add two NAT-D payloads, one each for src and dst.  */
298 int
299 nat_t_exchange_add_nat_d(struct message *msg)
300 {
301 	struct sockaddr *sa;
302 
303 	/* Remote address first. */
304 	msg->transport->vtbl->get_dst(msg->transport, &sa);
305 	if (nat_t_add_nat_d(msg, sa))
306 		return -1;
307 
308 	msg->transport->vtbl->get_src(msg->transport, &sa);
309 	if (nat_t_add_nat_d(msg, sa))
310 		return -1;
311 	return 0;
312 }
313 
314 /* Generate and match a NAT-D hash against the NAT-D payload (pl.) data.  */
315 static int
316 nat_t_match_nat_d_payload(struct message *msg, struct sockaddr *sa)
317 {
318 	struct payload *p;
319 	u_int8_t *hbuf;
320 	size_t	 hbuflen;
321 	int	 found = 0;
322 
323 	/*
324 	 * If there are no NAT-D payloads in the message, return "found"
325 	 * as this will avoid NAT-T (see nat_t_exchange_check_nat_d()).
326 	 */
327 	if ((p = payload_first(msg, ISAKMP_PAYLOAD_NAT_D_DRAFT)) == NULL &&
328 	    (p = payload_first(msg, ISAKMP_PAYLOAD_NAT_D)) == NULL)
329 		return 1;
330 
331 	hbuf = nat_t_generate_nat_d_hash(msg, sa, &hbuflen);
332 	if (!hbuf)
333 		return 0;
334 
335 	while (p) {
336 		if (GET_ISAKMP_GEN_LENGTH (p->p) !=
337 		    hbuflen + ISAKMP_NAT_D_DATA_OFF)
338 			continue;
339 
340 		if (memcmp(p->p + ISAKMP_NAT_D_DATA_OFF, hbuf, hbuflen) == 0) {
341 			found++;
342 			break;
343 		}
344 		p = TAILQ_NEXT(p, link);
345 	}
346 	free(hbuf);
347 	return found;
348 }
349 
350 /*
351  * Check if we need to activate NAT-T, and if we need to send keepalive
352  * messages to the other side, i.e if we are a nat:ed peer.
353  */
354 int
355 nat_t_exchange_check_nat_d(struct message *msg)
356 {
357 	struct sockaddr *sa;
358 	int	 outgoing_path_is_clear, incoming_path_is_clear;
359 
360 	/* Assume trouble, i.e NAT-boxes in our path.  */
361 	outgoing_path_is_clear = incoming_path_is_clear = 0;
362 
363 	msg->transport->vtbl->get_src(msg->transport, &sa);
364 	if (nat_t_match_nat_d_payload(msg, sa))
365 		outgoing_path_is_clear = 1;
366 
367 	msg->transport->vtbl->get_dst(msg->transport, &sa);
368 	if (nat_t_match_nat_d_payload(msg, sa))
369 		incoming_path_is_clear = 1;
370 
371 	if (outgoing_path_is_clear && incoming_path_is_clear) {
372 		LOG_DBG((LOG_EXCHANGE, 40, "nat_t_exchange_check_nat_d: "
373 		    "no NAT"));
374 		return 0; /* No NAT-T required.  */
375 	}
376 
377 	/* NAT-T handling required.  */
378 	msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_ENABLE;
379 
380 	if (!outgoing_path_is_clear) {
381 		msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_KEEPALIVE;
382 		LOG_DBG((LOG_EXCHANGE, 10, "nat_t_exchange_check_nat_d: "
383 		    "NAT detected, we're behind it"));
384 	} else
385 		LOG_DBG ((LOG_EXCHANGE, 10,
386 		    "nat_t_exchange_check_nat_d: NAT detected"));
387 	return 1;
388 }
389 
390 static void
391 nat_t_send_keepalive(void *v_arg)
392 {
393 	struct sa *sa = (struct sa *)v_arg;
394 	struct transport *t;
395 	struct timeval now;
396 	int interval;
397 
398 	/* Send the keepalive message.  */
399 	t = ((struct virtual_transport *)sa->transport)->encap;
400 	t->vtbl->send_message(NULL, t);
401 
402 	/* Set new timer.  */
403 	interval = conf_get_num("General", "NAT-T-Keepalive", 0);
404 	if (interval < 1)
405 		interval = NAT_T_KEEPALIVE_INTERVAL;
406 	gettimeofday(&now, 0);
407 	now.tv_sec += interval;
408 
409 	sa->nat_t_keepalive = timer_add_event("nat_t_send_keepalive",
410 	    nat_t_send_keepalive, v_arg, &now);
411 	if (!sa->nat_t_keepalive)
412 		log_print("nat_t_send_keepalive: "
413 		    "timer_add_event() failed, will send no more keepalives");
414 }
415 
416 void
417 nat_t_setup_keepalive(struct sa *sa)
418 {
419 	struct sockaddr *src;
420 	struct timeval now;
421 
422 	if (sa->initiator)
423 		sa->transport->vtbl->get_src(sa->transport, &src);
424 	else
425 		sa->transport->vtbl->get_dst(sa->transport, &src);
426 
427 	if (!virtual_listen_lookup(src))
428 		return;
429 
430 	gettimeofday(&now, 0);
431 	now.tv_sec += NAT_T_KEEPALIVE_INTERVAL;
432 
433 	sa->nat_t_keepalive = timer_add_event("nat_t_send_keepalive",
434 	    nat_t_send_keepalive, sa, &now);
435 	if (!sa->nat_t_keepalive)
436 		log_print("nat_t_setup_keepalive: "
437 		    "timer_add_event() failed, will not send keepalives");
438 
439 	LOG_DBG((LOG_TRANSPORT, 50, "nat_t_setup_keepalive: "
440 	    "added event for phase 1 SA %p", sa));
441 }
442