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