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