1 /* $OpenBSD: nat_traversal.c,v 1.8 2004/11/18 18:15:46 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 "sysdep.h" 32 33 #include "conf.h" 34 #include "exchange.h" 35 #include "hash.h" 36 #include "ipsec.h" 37 #include "isakmp_fld.h" 38 #include "isakmp_num.h" 39 #include "ipsec_num.h" 40 #include "hash.h" 41 #include "log.h" 42 #include "message.h" 43 #include "nat_traversal.h" 44 #include "prf.h" 45 #include "sa.h" 46 #include "timer.h" 47 #include "transport.h" 48 #include "util.h" 49 #include "virtual.h" 50 51 /* 52 * XXX According to draft-ietf-ipsec-nat-t-ike-07.txt, the NAT-T 53 * capability of the other peer is determined by a particular vendor ID 54 * sent as the first message. This vendor ID string is supposed to be a 55 * MD5 hash of "RFC XXXX", where XXXX is the future RFC number. 56 * 57 * These seem to be the "well" known variants of this string in use by 58 * products today. 59 */ 60 static const char *isakmp_nat_t_cap_text[] = { 61 "draft-ietf-ipsec-nat-t-ike-02\n", /* V2 */ 62 "draft-ietf-ipsec-nat-t-ike-03", /* V3 */ 63 #ifdef notyet 64 "RFC XXXX", 65 #endif 66 }; 67 68 /* In seconds. Recommended in draft-ietf-ipsec-udp-encaps-09. */ 69 #define NAT_T_KEEPALIVE_INTERVAL 20 70 71 /* The MD5 hashes of the above strings is put in this array. */ 72 static char **nat_t_hashes; 73 static size_t nat_t_hashsize; 74 75 static int nat_t_setup_hashes(void); 76 static int nat_t_add_vendor_payload(struct message *, char *); 77 static int nat_t_add_nat_d(struct message *, struct sockaddr *); 78 static int nat_t_match_nat_d_payload(struct message *, struct sockaddr *); 79 80 void 81 nat_t_init(void) 82 { 83 nat_t_hashes = (char **)NULL; 84 } 85 86 /* Generate the NAT-T capability marker hashes. Executed only once. */ 87 static int 88 nat_t_setup_hashes(void) 89 { 90 struct hash *hash; 91 int n = sizeof isakmp_nat_t_cap_text / sizeof isakmp_nat_t_cap_text[0]; 92 int i; 93 94 /* The draft says to use MD5. */ 95 hash = hash_get(HASH_MD5); 96 if (!hash) { 97 /* Should never happen. */ 98 log_print("nat_t_setup_hashes: " 99 "could not find MD5 hash structure!"); 100 return -1; 101 } 102 nat_t_hashsize = hash->hashsize; 103 104 /* Allocate one more than is necessary, i.e NULL terminated. */ 105 nat_t_hashes = (char **)calloc((size_t)(n + 1), sizeof(char *)); 106 if (!nat_t_hashes) { 107 log_error("nat_t_setup_hashes: calloc (%lu,%lu) failed", 108 (unsigned long)n, (unsigned long)sizeof(char *)); 109 return -1; 110 } 111 112 /* Populate with hashes. */ 113 for (i = 0; i < n; i++) { 114 nat_t_hashes[i] = (char *)malloc(nat_t_hashsize); 115 if (!nat_t_hashes[i]) { 116 log_error("nat_t_setup_hashes: malloc (%lu) failed", 117 (unsigned long)nat_t_hashsize); 118 goto errout; 119 } 120 121 hash->Init(hash->ctx); 122 hash->Update(hash->ctx, 123 (unsigned char *)isakmp_nat_t_cap_text[i], 124 strlen(isakmp_nat_t_cap_text[i])); 125 hash->Final(nat_t_hashes[i], hash->ctx); 126 127 LOG_DBG((LOG_EXCHANGE, 50, "nat_t_setup_hashes: " 128 "MD5(\"%s\") (%lu bytes)", isakmp_nat_t_cap_text[i], 129 (unsigned long)nat_t_hashsize)); 130 LOG_DBG_BUF((LOG_EXCHANGE, 50, "nat_t_setup_hashes", 131 nat_t_hashes[i], nat_t_hashsize)); 132 } 133 134 return 0; 135 136 errout: 137 for (i = 0; i < n; i++) 138 if (nat_t_hashes[i]) 139 free(nat_t_hashes[i]); 140 free(nat_t_hashes); 141 nat_t_hashes = NULL; 142 return -1; 143 } 144 145 /* Add one NAT-T VENDOR payload. */ 146 static int 147 nat_t_add_vendor_payload(struct message *msg, char *hash) 148 { 149 size_t buflen = nat_t_hashsize + ISAKMP_GEN_SZ; 150 u_int8_t *buf; 151 152 buf = malloc(buflen); 153 if (!buf) { 154 log_error("nat_t_add_vendor_payload: malloc (%lu) failed", 155 (unsigned long)buflen); 156 return -1; 157 } 158 159 SET_ISAKMP_GEN_LENGTH(buf, buflen); 160 memcpy(buf + ISAKMP_VENDOR_ID_OFF, hash, nat_t_hashsize); 161 if (message_add_payload(msg, ISAKMP_PAYLOAD_VENDOR, buf, buflen, 1)) { 162 free(buf); 163 return -1; 164 } 165 166 return 0; 167 } 168 169 /* Add the NAT-T capability markers (VENDOR payloads). */ 170 int 171 nat_t_add_vendor_payloads(struct message *msg) 172 { 173 int i = 0; 174 175 if (!nat_t_hashes) 176 if (nat_t_setup_hashes()) 177 return 0; /* XXX should this be an error? */ 178 179 while (nat_t_hashes[i]) 180 if (nat_t_add_vendor_payload(msg, nat_t_hashes[i++])) 181 return -1; 182 183 return 0; 184 } 185 186 /* 187 * Check an incoming message for NAT-T capability markers. 188 */ 189 void 190 nat_t_check_vendor_payload(struct message *msg, struct payload *p) 191 { 192 u_int8_t *pbuf = p->p; 193 size_t vlen; 194 int i = 0; 195 196 /* Already checked? */ 197 if (p->flags & PL_MARK || 198 msg->exchange->flags & EXCHANGE_FLAG_NAT_T_CAP_PEER) 199 return; 200 201 if (!nat_t_hashes) 202 if (nat_t_setup_hashes()) 203 return; 204 205 vlen = GET_ISAKMP_GEN_LENGTH(pbuf) - ISAKMP_GEN_SZ; 206 if (vlen != nat_t_hashsize) { 207 LOG_DBG((LOG_EXCHANGE, 50, "nat_t_check_vendor_payload: " 208 "bad size %lu != %lu", (unsigned long)vlen, 209 (unsigned long)nat_t_hashsize)); 210 return; 211 } 212 213 while (nat_t_hashes[i]) 214 if (memcmp(nat_t_hashes[i++], pbuf + ISAKMP_GEN_SZ, 215 vlen) == 0) { 216 /* This peer is NAT-T capable. */ 217 msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_CAP_PEER; 218 LOG_DBG((LOG_EXCHANGE, 10, 219 "nat_t_check_vendor_payload: " 220 "NAT-T capable peer detected")); 221 p->flags |= PL_MARK; 222 return; 223 } 224 225 return; 226 } 227 228 /* Generate the NAT-D payload hash : HASH(CKY-I | CKY-R | IP | Port). */ 229 static u_int8_t * 230 nat_t_generate_nat_d_hash(struct message *msg, struct sockaddr *sa, 231 size_t *hashlen) 232 { 233 struct ipsec_exch *ie = (struct ipsec_exch *)msg->exchange->data; 234 struct hash *hash; 235 u_int8_t *res; 236 in_port_t port; 237 238 hash = hash_get(ie->hash->type); 239 if (hash == NULL) { 240 log_print ("nat_t_generate_nat_d_hash: no hash"); 241 return NULL; 242 } 243 244 *hashlen = hash->hashsize; 245 246 res = (u_int8_t *)malloc((unsigned long)*hashlen); 247 if (!res) { 248 log_print("nat_t_generate_nat_d_hash: malloc (%lu) failed", 249 (unsigned long)*hashlen); 250 *hashlen = 0; 251 return NULL; 252 } 253 254 port = sockaddr_port(sa); 255 memset(res, 0, *hashlen); 256 257 hash->Init(hash->ctx); 258 hash->Update(hash->ctx, msg->exchange->cookies, 259 sizeof msg->exchange->cookies); 260 hash->Update(hash->ctx, sockaddr_addrdata(sa), sockaddr_addrlen(sa)); 261 hash->Update(hash->ctx, (unsigned char *)&port, sizeof port); 262 hash->Final(res, hash->ctx); 263 264 return res; 265 } 266 267 /* Add a NAT-D payload to our message. */ 268 static int 269 nat_t_add_nat_d(struct message *msg, struct sockaddr *sa) 270 { 271 u_int8_t *hbuf, *buf; 272 size_t hbuflen, buflen; 273 274 hbuf = nat_t_generate_nat_d_hash(msg, sa, &hbuflen); 275 if (!hbuf) { 276 log_print("nat_t_add_nat_d: NAT-D hash gen failed"); 277 return -1; 278 } 279 280 buflen = ISAKMP_NAT_D_DATA_OFF + hbuflen; 281 buf = malloc(buflen); 282 if (!buf) { 283 log_error("nat_t_add_nat_d: malloc (%lu) failed", 284 (unsigned long)buflen); 285 free(hbuf); 286 return -1; 287 } 288 289 SET_ISAKMP_GEN_LENGTH(buf, buflen); 290 memcpy(buf + ISAKMP_NAT_D_DATA_OFF, hbuf, hbuflen); 291 free(hbuf); 292 293 if (message_add_payload(msg, ISAKMP_PAYLOAD_NAT_D, buf, buflen, 1)) { 294 free(buf); 295 return -1; 296 } 297 298 return 0; 299 } 300 301 /* We add two NAT-D payloads, one each for src and dst. */ 302 int 303 nat_t_exchange_add_nat_d(struct message *msg) 304 { 305 struct sockaddr *sa; 306 307 /* Remote address first. */ 308 msg->transport->vtbl->get_dst(msg->transport, &sa); 309 if (nat_t_add_nat_d(msg, sa)) 310 return -1; 311 312 msg->transport->vtbl->get_src(msg->transport, &sa); 313 if (nat_t_add_nat_d(msg, sa)) 314 return -1; 315 316 return 0; 317 } 318 319 /* Generate and match a NAT-D hash against the NAT-D payload (pl.) data. */ 320 static int 321 nat_t_match_nat_d_payload(struct message *msg, struct sockaddr *sa) 322 { 323 struct payload *p; 324 u_int8_t *hbuf; 325 size_t hbuflen; 326 int found = 0; 327 328 /* 329 * If there are no NAT-D payloads in the message, return "found" 330 * as this will avoid NAT-T (see nat_t_exchange_check_nat_d()). 331 */ 332 p = payload_first(msg, ISAKMP_PAYLOAD_NAT_D); 333 if (!p) 334 return 1; 335 336 hbuf = nat_t_generate_nat_d_hash(msg, sa, &hbuflen); 337 if (!hbuf) 338 return 0; 339 340 while (p) { 341 if (GET_ISAKMP_GEN_LENGTH (p->p) != 342 hbuflen + ISAKMP_NAT_D_DATA_OFF) 343 continue; 344 345 if (memcmp(p->p + ISAKMP_NAT_D_DATA_OFF, hbuf, hbuflen) == 0) { 346 found++; 347 break; 348 } 349 p = TAILQ_NEXT(p, link); 350 } 351 free(hbuf); 352 return found; 353 } 354 355 /* 356 * Check if we need to activate NAT-T, and if we need to send keepalive 357 * messages to the other side, i.e if we are a nat:ed peer. 358 */ 359 int 360 nat_t_exchange_check_nat_d(struct message *msg) 361 { 362 struct sockaddr *sa; 363 int outgoing_path_is_clear, incoming_path_is_clear; 364 365 /* Assume trouble, i.e NAT-boxes in our path. */ 366 outgoing_path_is_clear = incoming_path_is_clear = 0; 367 368 msg->transport->vtbl->get_src(msg->transport, &sa); 369 if (nat_t_match_nat_d_payload(msg, sa)) 370 outgoing_path_is_clear = 1; 371 372 msg->transport->vtbl->get_dst(msg->transport, &sa); 373 if (nat_t_match_nat_d_payload(msg, sa)) 374 incoming_path_is_clear = 1; 375 376 if (outgoing_path_is_clear && incoming_path_is_clear) { 377 LOG_DBG((LOG_EXCHANGE, 40, "nat_t_exchange_check_nat_d: " 378 "no NAT")); 379 return 0; /* No NAT-T required. */ 380 } 381 382 /* NAT-T handling required. */ 383 msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_ENABLE; 384 385 if (!outgoing_path_is_clear) { 386 msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_KEEPALIVE; 387 LOG_DBG((LOG_EXCHANGE, 10, "nat_t_exchange_check_nat_d: " 388 "NAT detected, we're behind it")); 389 } else 390 LOG_DBG ((LOG_EXCHANGE, 10, 391 "nat_t_exchange_check_nat_d: NAT detected")); 392 return 1; 393 } 394 395 static void 396 nat_t_send_keepalive(void *v_arg) 397 { 398 struct sa *sa = (struct sa *)v_arg; 399 struct transport *t; 400 struct timeval now; 401 int interval; 402 403 /* Send the keepalive message. */ 404 t = ((struct virtual_transport *)sa->transport)->encap; 405 t->vtbl->send_message(NULL, t); 406 407 /* Set new timer. */ 408 interval = conf_get_num("General", "NAT-T-Keepalive", 0); 409 if (interval < 1) 410 interval = NAT_T_KEEPALIVE_INTERVAL; 411 gettimeofday(&now, 0); 412 now.tv_sec += interval; 413 414 sa->nat_t_keepalive = timer_add_event("nat_t_send_keepalive", 415 nat_t_send_keepalive, v_arg, &now); 416 if (!sa->nat_t_keepalive) 417 log_print("nat_t_send_keepalive: " 418 "timer_add_event() failed, will send no more keepalives"); 419 } 420 421 void 422 nat_t_setup_keepalive(struct sa *sa) 423 { 424 struct sockaddr *src; 425 struct timeval now; 426 427 if (sa->initiator) 428 sa->transport->vtbl->get_src(sa->transport, &src); 429 else 430 sa->transport->vtbl->get_dst(sa->transport, &src); 431 432 if (!virtual_listen_lookup(src)) 433 return; 434 435 gettimeofday(&now, 0); 436 now.tv_sec += NAT_T_KEEPALIVE_INTERVAL; 437 438 sa->nat_t_keepalive = timer_add_event("nat_t_send_keepalive", 439 nat_t_send_keepalive, sa, &now); 440 if (!sa->nat_t_keepalive) 441 log_print("nat_t_setup_keepalive: " 442 "timer_add_event() failed, will not send keepalives"); 443 444 LOG_DBG((LOG_TRANSPORT, 50, "nat_t_setup_keepalive: " 445 "added event for phase 1 SA %p", sa)); 446 } 447