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