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