GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/isakmpd/nat_traversal.c Lines: 0 161 0.0 %
Date: 2017-11-07 Branches: 0 74 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: nat_traversal.c,v 1.24 2015/08/20 22:05:51 deraadt 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 "log.h"
39
#include "message.h"
40
#include "nat_traversal.h"
41
#include "prf.h"
42
#include "sa.h"
43
#include "timer.h"
44
#include "transport.h"
45
#include "util.h"
46
#include "virtual.h"
47
48
int	disable_nat_t = 0;
49
50
/*
51
 * NAT-T capability of the other peer is determined by a particular vendor
52
 * ID sent in the first message. This vendor ID string is supposed to be a
53
 * MD5 hash of "RFC 3947".
54
 *
55
 * These seem to be the "well" known variants of this string in use by
56
 * products today.
57
 *
58
 * Note that the VID specified in draft 2 is ambiguous: It was
59
 * accidentally calculated from the string "draft-ietf-ipsec-nat-t-ike-02\n"
60
 * although the string was documented without the trailing '\n'. The authors
61
 * suggested afterwards to use the string with the trailing '\n'.
62
 */
63
64
static struct nat_t_cap isakmp_nat_t_cap[] = {
65
	{ VID_DRAFT_V2_N, EXCHANGE_FLAG_NAT_T_DRAFT,
66
	  "draft-ietf-ipsec-nat-t-ike-02\n", NULL, 0 },
67
	{ VID_DRAFT_V3, EXCHANGE_FLAG_NAT_T_DRAFT,
68
	  "draft-ietf-ipsec-nat-t-ike-03", NULL, 0 },
69
	{ VID_RFC3947, EXCHANGE_FLAG_NAT_T_RFC,
70
	  "RFC 3947", NULL, 0 },
71
};
72
73
#define NUMNATTCAP	(sizeof isakmp_nat_t_cap / sizeof isakmp_nat_t_cap[0])
74
75
/* In seconds. Recommended in draft-ietf-ipsec-udp-encaps-09.  */
76
#define NAT_T_KEEPALIVE_INTERVAL	20
77
78
static int	nat_t_setup_hashes(void);
79
static int	nat_t_add_vendor_payload(struct message *, struct nat_t_cap *);
80
static int	nat_t_add_nat_d(struct message *, struct sockaddr *);
81
static int	nat_t_match_nat_d_payload(struct message *, struct sockaddr *);
82
83
void
84
nat_t_init(void)
85
{
86
	nat_t_setup_hashes();
87
}
88
89
/* Generate the NAT-T capability marker hashes. Executed only once.  */
90
static int
91
nat_t_setup_hashes(void)
92
{
93
	struct hash *hash;
94
	int n = NUMNATTCAP;
95
	int i;
96
97
	/* The draft says to use MD5.  */
98
	hash = hash_get(HASH_MD5);
99
	if (!hash) {
100
		/* Should never happen.  */
101
		log_print("nat_t_setup_hashes: "
102
		    "could not find MD5 hash structure!");
103
		return -1;
104
	}
105
106
	/* Populate isakmp_nat_t_cap with hashes.  */
107
	for (i = 0; i < n; i++) {
108
		isakmp_nat_t_cap[i].hashsize = hash->hashsize;
109
		isakmp_nat_t_cap[i].hash = malloc(hash->hashsize);
110
		if (!isakmp_nat_t_cap[i].hash) {
111
			log_error("nat_t_setup_hashes: malloc (%lu) failed",
112
			    (unsigned long)hash->hashsize);
113
			goto errout;
114
		}
115
116
		hash->Init(hash->ctx);
117
		hash->Update(hash->ctx,
118
		    (unsigned char *)isakmp_nat_t_cap[i].text,
119
		    strlen(isakmp_nat_t_cap[i].text));
120
		hash->Final(isakmp_nat_t_cap[i].hash, hash->ctx);
121
122
		LOG_DBG((LOG_EXCHANGE, 50, "nat_t_setup_hashes: "
123
		    "MD5(\"%s\") (%lu bytes)", isakmp_nat_t_cap[i].text,
124
		    (unsigned long)hash->hashsize));
125
		LOG_DBG_BUF((LOG_EXCHANGE, 50, "nat_t_setup_hashes",
126
		    isakmp_nat_t_cap[i].hash, hash->hashsize));
127
	}
128
129
	return 0;
130
131
errout:
132
	for (i = 0; i < n; i++)
133
		free(isakmp_nat_t_cap[i].hash);
134
	return -1;
135
}
136
137
/* Add one NAT-T VENDOR payload.  */
138
static int
139
nat_t_add_vendor_payload(struct message *msg, struct nat_t_cap *cap)
140
{
141
	size_t	  buflen = cap->hashsize + ISAKMP_GEN_SZ;
142
	u_int8_t *buf;
143
144
	if (disable_nat_t)
145
		return 0;
146
147
	buf = malloc(buflen);
148
	if (!buf) {
149
		log_error("nat_t_add_vendor_payload: malloc (%lu) failed",
150
		    (unsigned long)buflen);
151
		return -1;
152
	}
153
154
	SET_ISAKMP_GEN_LENGTH(buf, buflen);
155
	memcpy(buf + ISAKMP_VENDOR_ID_OFF, cap->hash, cap->hashsize);
156
	if (message_add_payload(msg, ISAKMP_PAYLOAD_VENDOR, buf, buflen, 1)) {
157
		free(buf);
158
		return -1;
159
	}
160
	return 0;
161
}
162
163
/* Add the NAT-T capability markers (VENDOR payloads).  */
164
int
165
nat_t_add_vendor_payloads(struct message *msg)
166
{
167
	int i;
168
169
	if (disable_nat_t)
170
		return 0;
171
172
	for (i = 0; i < NUMNATTCAP; i++)
173
		if (nat_t_add_vendor_payload(msg, &isakmp_nat_t_cap[i]))
174
			return -1;
175
	return 0;
176
}
177
178
/*
179
 * Check an incoming message for NAT-T capability markers.
180
 */
181
void
182
nat_t_check_vendor_payload(struct message *msg, struct payload *p)
183
{
184
	u_int8_t *pbuf = p->p;
185
	size_t	  vlen;
186
	int	  i;
187
188
	if (disable_nat_t)
189
		return;
190
191
	vlen = GET_ISAKMP_GEN_LENGTH(pbuf) - ISAKMP_GEN_SZ;
192
193
	for (i = 0; i < NUMNATTCAP; i++) {
194
		if (vlen != 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 = malloc(*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
	for (; p; p = TAILQ_NEXT(p, link)) {
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
	}
341
	free(hbuf);
342
	return found;
343
}
344
345
/*
346
 * Check if we need to activate NAT-T, and if we need to send keepalive
347
 * messages to the other side, i.e if we are a nat:ed peer.
348
 */
349
int
350
nat_t_exchange_check_nat_d(struct message *msg)
351
{
352
	struct sockaddr *sa;
353
	int	 outgoing_path_is_clear, incoming_path_is_clear;
354
355
	/* Assume trouble, i.e NAT-boxes in our path.  */
356
	outgoing_path_is_clear = incoming_path_is_clear = 0;
357
358
	msg->transport->vtbl->get_src(msg->transport, &sa);
359
	if (nat_t_match_nat_d_payload(msg, sa))
360
		outgoing_path_is_clear = 1;
361
362
	msg->transport->vtbl->get_dst(msg->transport, &sa);
363
	if (nat_t_match_nat_d_payload(msg, sa))
364
		incoming_path_is_clear = 1;
365
366
	if (outgoing_path_is_clear && incoming_path_is_clear) {
367
		LOG_DBG((LOG_EXCHANGE, 40, "nat_t_exchange_check_nat_d: "
368
		    "no NAT"));
369
		return 0; /* No NAT-T required.  */
370
	}
371
372
	/* NAT-T handling required.  */
373
	msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_ENABLE;
374
375
	if (!outgoing_path_is_clear) {
376
		msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_KEEPALIVE;
377
		LOG_DBG((LOG_EXCHANGE, 10, "nat_t_exchange_check_nat_d: "
378
		    "NAT detected, we're behind it"));
379
	} else
380
		LOG_DBG ((LOG_EXCHANGE, 10,
381
		    "nat_t_exchange_check_nat_d: NAT detected"));
382
	return 1;
383
}
384
385
static void
386
nat_t_send_keepalive(void *v_arg)
387
{
388
	struct sa *sa = (struct sa *)v_arg;
389
	struct transport *t;
390
	struct timeval now;
391
	int interval;
392
393
	/* Send the keepalive message.  */
394
	t = ((struct virtual_transport *)sa->transport)->encap;
395
	t->vtbl->send_message(NULL, t);
396
397
	/* Set new timer.  */
398
	interval = conf_get_num("General", "NAT-T-Keepalive", 0);
399
	if (interval < 1)
400
		interval = NAT_T_KEEPALIVE_INTERVAL;
401
	gettimeofday(&now, 0);
402
	now.tv_sec += interval;
403
404
	sa->nat_t_keepalive = timer_add_event("nat_t_send_keepalive",
405
	    nat_t_send_keepalive, v_arg, &now);
406
	if (!sa->nat_t_keepalive)
407
		log_print("nat_t_send_keepalive: "
408
		    "timer_add_event() failed, will send no more keepalives");
409
}
410
411
void
412
nat_t_setup_keepalive(struct sa *sa)
413
{
414
	struct sockaddr *src;
415
	struct timeval now;
416
417
	if (sa->initiator)
418
		sa->transport->vtbl->get_src(sa->transport, &src);
419
	else
420
		sa->transport->vtbl->get_dst(sa->transport, &src);
421
422
	if (!virtual_listen_lookup(src))
423
		return;
424
425
	gettimeofday(&now, 0);
426
	now.tv_sec += NAT_T_KEEPALIVE_INTERVAL;
427
428
	sa->nat_t_keepalive = timer_add_event("nat_t_send_keepalive",
429
	    nat_t_send_keepalive, sa, &now);
430
	if (!sa->nat_t_keepalive)
431
		log_print("nat_t_setup_keepalive: "
432
		    "timer_add_event() failed, will not send keepalives");
433
434
	LOG_DBG((LOG_TRANSPORT, 50, "nat_t_setup_keepalive: "
435
	    "added event for phase 1 SA %p", sa));
436
}