1 /* $OpenBSD: nat_traversal.c,v 1.25 2017/12/05 20:31:45 jca 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
nat_t_init(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
nat_t_setup_hashes(void)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
nat_t_add_vendor_payload(struct message * msg,struct nat_t_cap * cap)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
nat_t_add_vendor_payloads(struct message * msg)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
nat_t_check_vendor_payload(struct message * msg,struct payload * p)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 *
nat_t_generate_nat_d_hash(struct message * msg,struct sockaddr * sa,size_t * hashlen)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
nat_t_add_nat_d(struct message * msg,struct sockaddr * sa)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
nat_t_exchange_add_nat_d(struct message * msg)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
nat_t_match_nat_d_payload(struct message * msg,struct sockaddr * sa)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
nat_t_exchange_check_nat_d(struct message * msg)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
nat_t_send_keepalive(void * v_arg)386 nat_t_send_keepalive(void *v_arg)
387 {
388 struct sa *sa = (struct sa *)v_arg;
389 struct transport *t;
390 struct timespec 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 clock_gettime(CLOCK_MONOTONIC, &now);
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
nat_t_setup_keepalive(struct sa * sa)412 nat_t_setup_keepalive(struct sa *sa)
413 {
414 struct sockaddr *src;
415 struct timespec 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 clock_gettime(CLOCK_MONOTONIC, &now);
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 }
437