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