xref: /openbsd-src/sbin/isakmpd/nat_traversal.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: nat_traversal.c,v 1.20 2007/05/05 17:43:34 cloder 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 			continue;
197 		}
198 		if (memcmp(isakmp_nat_t_cap[i].hash, pbuf + ISAKMP_GEN_SZ,
199 		    vlen) == 0) {
200 			/* This peer is NAT-T capable.  */
201 			msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_CAP_PEER;
202 			msg->exchange->flags |= isakmp_nat_t_cap[i].flags;
203 			LOG_DBG((LOG_EXCHANGE, 10,
204 			    "nat_t_check_vendor_payload: "
205 			    "NAT-T capable peer detected"));
206 			p->flags |= PL_MARK;
207 		}
208 	}
209 
210 	return;
211 }
212 
213 /* Generate the NAT-D payload hash : HASH(CKY-I | CKY-R | IP | Port).  */
214 static u_int8_t *
215 nat_t_generate_nat_d_hash(struct message *msg, struct sockaddr *sa,
216     size_t *hashlen)
217 {
218 	struct ipsec_exch *ie = (struct ipsec_exch *)msg->exchange->data;
219 	struct hash	 *hash;
220 	u_int8_t	 *res;
221 	in_port_t	  port;
222 
223 	hash = hash_get(ie->hash->type);
224 	if (hash == NULL) {
225 		log_print ("nat_t_generate_nat_d_hash: no hash");
226 		return NULL;
227 	}
228 
229 	*hashlen = hash->hashsize;
230 
231 	res = (u_int8_t *)malloc((unsigned long)*hashlen);
232 	if (!res) {
233 		log_print("nat_t_generate_nat_d_hash: malloc (%lu) failed",
234 		    (unsigned long)*hashlen);
235 		*hashlen = 0;
236 		return NULL;
237 	}
238 
239 	port = sockaddr_port(sa);
240 	bzero(res, *hashlen);
241 
242 	hash->Init(hash->ctx);
243 	hash->Update(hash->ctx, msg->exchange->cookies,
244 	    sizeof msg->exchange->cookies);
245 	hash->Update(hash->ctx, sockaddr_addrdata(sa), sockaddr_addrlen(sa));
246 	hash->Update(hash->ctx, (unsigned char *)&port, sizeof port);
247 	hash->Final(res, hash->ctx);
248 	return res;
249 }
250 
251 /* Add a NAT-D payload to our message.  */
252 static int
253 nat_t_add_nat_d(struct message *msg, struct sockaddr *sa)
254 {
255 	int	  ret;
256 	u_int8_t *hbuf, *buf;
257 	size_t	  hbuflen, buflen;
258 
259 	hbuf = nat_t_generate_nat_d_hash(msg, sa, &hbuflen);
260 	if (!hbuf) {
261 		log_print("nat_t_add_nat_d: NAT-D hash gen failed");
262 		return -1;
263 	}
264 
265 	buflen = ISAKMP_NAT_D_DATA_OFF + hbuflen;
266 	buf = malloc(buflen);
267 	if (!buf) {
268 		log_error("nat_t_add_nat_d: malloc (%lu) failed",
269 		    (unsigned long)buflen);
270 		free(hbuf);
271 		return -1;
272 	}
273 
274 	SET_ISAKMP_GEN_LENGTH(buf, buflen);
275 	memcpy(buf + ISAKMP_NAT_D_DATA_OFF, hbuf, hbuflen);
276 	free(hbuf);
277 
278 	if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_RFC)
279 		ret = message_add_payload(msg, ISAKMP_PAYLOAD_NAT_D, buf,
280 		    buflen, 1);
281 	else if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_DRAFT)
282 		ret = message_add_payload(msg, ISAKMP_PAYLOAD_NAT_D_DRAFT,
283 		    buf, buflen, 1);
284 	else
285 		ret = -1;
286 
287 	if (ret) {
288 		free(buf);
289 		return -1;
290 	}
291 	return 0;
292 }
293 
294 /* We add two NAT-D payloads, one each for src and dst.  */
295 int
296 nat_t_exchange_add_nat_d(struct message *msg)
297 {
298 	struct sockaddr *sa;
299 
300 	/* Remote address first. */
301 	msg->transport->vtbl->get_dst(msg->transport, &sa);
302 	if (nat_t_add_nat_d(msg, sa))
303 		return -1;
304 
305 	msg->transport->vtbl->get_src(msg->transport, &sa);
306 	if (nat_t_add_nat_d(msg, sa))
307 		return -1;
308 	return 0;
309 }
310 
311 /* Generate and match a NAT-D hash against the NAT-D payload (pl.) data.  */
312 static int
313 nat_t_match_nat_d_payload(struct message *msg, struct sockaddr *sa)
314 {
315 	struct payload *p;
316 	u_int8_t *hbuf;
317 	size_t	 hbuflen;
318 	int	 found = 0;
319 
320 	/*
321 	 * If there are no NAT-D payloads in the message, return "found"
322 	 * as this will avoid NAT-T (see nat_t_exchange_check_nat_d()).
323 	 */
324 	if ((p = payload_first(msg, ISAKMP_PAYLOAD_NAT_D_DRAFT)) == NULL &&
325 	    (p = payload_first(msg, ISAKMP_PAYLOAD_NAT_D)) == NULL)
326 		return 1;
327 
328 	hbuf = nat_t_generate_nat_d_hash(msg, sa, &hbuflen);
329 	if (!hbuf)
330 		return 0;
331 
332 	while (p) {
333 		if (GET_ISAKMP_GEN_LENGTH (p->p) !=
334 		    hbuflen + ISAKMP_NAT_D_DATA_OFF)
335 			continue;
336 
337 		if (memcmp(p->p + ISAKMP_NAT_D_DATA_OFF, hbuf, hbuflen) == 0) {
338 			found++;
339 			break;
340 		}
341 		p = TAILQ_NEXT(p, link);
342 	}
343 	free(hbuf);
344 	return found;
345 }
346 
347 /*
348  * Check if we need to activate NAT-T, and if we need to send keepalive
349  * messages to the other side, i.e if we are a nat:ed peer.
350  */
351 int
352 nat_t_exchange_check_nat_d(struct message *msg)
353 {
354 	struct sockaddr *sa;
355 	int	 outgoing_path_is_clear, incoming_path_is_clear;
356 
357 	/* Assume trouble, i.e NAT-boxes in our path.  */
358 	outgoing_path_is_clear = incoming_path_is_clear = 0;
359 
360 	msg->transport->vtbl->get_src(msg->transport, &sa);
361 	if (nat_t_match_nat_d_payload(msg, sa))
362 		outgoing_path_is_clear = 1;
363 
364 	msg->transport->vtbl->get_dst(msg->transport, &sa);
365 	if (nat_t_match_nat_d_payload(msg, sa))
366 		incoming_path_is_clear = 1;
367 
368 	if (outgoing_path_is_clear && incoming_path_is_clear) {
369 		LOG_DBG((LOG_EXCHANGE, 40, "nat_t_exchange_check_nat_d: "
370 		    "no NAT"));
371 		return 0; /* No NAT-T required.  */
372 	}
373 
374 	/* NAT-T handling required.  */
375 	msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_ENABLE;
376 
377 	if (!outgoing_path_is_clear) {
378 		msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_KEEPALIVE;
379 		LOG_DBG((LOG_EXCHANGE, 10, "nat_t_exchange_check_nat_d: "
380 		    "NAT detected, we're behind it"));
381 	} else
382 		LOG_DBG ((LOG_EXCHANGE, 10,
383 		    "nat_t_exchange_check_nat_d: NAT detected"));
384 	return 1;
385 }
386 
387 static void
388 nat_t_send_keepalive(void *v_arg)
389 {
390 	struct sa *sa = (struct sa *)v_arg;
391 	struct transport *t;
392 	struct timeval now;
393 	int interval;
394 
395 	/* Send the keepalive message.  */
396 	t = ((struct virtual_transport *)sa->transport)->encap;
397 	t->vtbl->send_message(NULL, t);
398 
399 	/* Set new timer.  */
400 	interval = conf_get_num("General", "NAT-T-Keepalive", 0);
401 	if (interval < 1)
402 		interval = NAT_T_KEEPALIVE_INTERVAL;
403 	gettimeofday(&now, 0);
404 	now.tv_sec += interval;
405 
406 	sa->nat_t_keepalive = timer_add_event("nat_t_send_keepalive",
407 	    nat_t_send_keepalive, v_arg, &now);
408 	if (!sa->nat_t_keepalive)
409 		log_print("nat_t_send_keepalive: "
410 		    "timer_add_event() failed, will send no more keepalives");
411 }
412 
413 void
414 nat_t_setup_keepalive(struct sa *sa)
415 {
416 	struct sockaddr *src;
417 	struct timeval now;
418 
419 	if (sa->initiator)
420 		sa->transport->vtbl->get_src(sa->transport, &src);
421 	else
422 		sa->transport->vtbl->get_dst(sa->transport, &src);
423 
424 	if (!virtual_listen_lookup(src))
425 		return;
426 
427 	gettimeofday(&now, 0);
428 	now.tv_sec += NAT_T_KEEPALIVE_INTERVAL;
429 
430 	sa->nat_t_keepalive = timer_add_event("nat_t_send_keepalive",
431 	    nat_t_send_keepalive, sa, &now);
432 	if (!sa->nat_t_keepalive)
433 		log_print("nat_t_setup_keepalive: "
434 		    "timer_add_event() failed, will not send keepalives");
435 
436 	LOG_DBG((LOG_TRANSPORT, 50, "nat_t_setup_keepalive: "
437 	    "added event for phase 1 SA %p", sa));
438 }
439