diff options
Diffstat (limited to 'keyexchange/isakmpd-20041012/nat_traversal.c')
-rw-r--r-- | keyexchange/isakmpd-20041012/nat_traversal.c | 439 |
1 files changed, 0 insertions, 439 deletions
diff --git a/keyexchange/isakmpd-20041012/nat_traversal.c b/keyexchange/isakmpd-20041012/nat_traversal.c deleted file mode 100644 index 86d2d57..0000000 --- a/keyexchange/isakmpd-20041012/nat_traversal.c +++ /dev/null @@ -1,439 +0,0 @@ -/* $OpenBSD: nat_traversal.c,v 1.17 2006/06/14 14:03:33 hshoexer Exp $ */ - -/* - * Copyright (c) 2004 Håkan Olsson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/types.h> -#include <stdlib.h> -#include <string.h> - -#include "sysdep.h" - -#include "conf.h" -#include "exchange.h" -#include "hash.h" -#include "ipsec.h" -#include "isakmp_fld.h" -#include "isakmp_num.h" -#include "ipsec_num.h" -#include "hash.h" -#include "log.h" -#include "message.h" -#include "nat_traversal.h" -#include "prf.h" -#include "sa.h" -#include "timer.h" -#include "transport.h" -#include "util.h" -#include "virtual.h" - -int disable_nat_t = 0; - -/* - * NAT-T capability of the other peer is determined by a particular vendor - * ID sent in the first message. This vendor ID string is supposed to be a - * MD5 hash of "RFC 3947". - * - * These seem to be the "well" known variants of this string in use by - * products today. - */ - -static struct nat_t_cap isakmp_nat_t_cap[] = { - { VID_DRAFT_V2_N, EXCHANGE_FLAG_NAT_T_DRAFT, - "draft-ietf-ipsec-nat-t-ike-02\n", NULL, 0 }, - { VID_DRAFT_V3, EXCHANGE_FLAG_NAT_T_DRAFT, - "draft-ietf-ipsec-nat-t-ike-03", NULL, 0 }, - { VID_RFC3947, EXCHANGE_FLAG_NAT_T_RFC, - "RFC 3947", NULL, 0 }, -}; - -#define NUMNATTCAP (sizeof isakmp_nat_t_cap / sizeof isakmp_nat_t_cap[0]) - -/* In seconds. Recommended in draft-ietf-ipsec-udp-encaps-09. */ -#define NAT_T_KEEPALIVE_INTERVAL 20 - -static int nat_t_setup_hashes(void); -static int nat_t_add_vendor_payload(struct message *, struct nat_t_cap *); -static int nat_t_add_nat_d(struct message *, struct sockaddr *); -static int nat_t_match_nat_d_payload(struct message *, struct sockaddr *); - -void -nat_t_init(void) -{ - nat_t_setup_hashes(); -} - -/* Generate the NAT-T capability marker hashes. Executed only once. */ -static int -nat_t_setup_hashes(void) -{ - struct hash *hash; - int n = NUMNATTCAP; - int i; - - /* The draft says to use MD5. */ - hash = hash_get(HASH_MD5); - if (!hash) { - /* Should never happen. */ - log_print("nat_t_setup_hashes: " - "could not find MD5 hash structure!"); - return -1; - } - - /* Populate isakmp_nat_t_cap with hashes. */ - for (i = 0; i < n; i++) { - isakmp_nat_t_cap[i].hashsize = hash->hashsize; - isakmp_nat_t_cap[i].hash = (char *)malloc(hash->hashsize); - if (!isakmp_nat_t_cap[i].hash) { - log_error("nat_t_setup_hashes: malloc (%lu) failed", - (unsigned long)hash->hashsize); - goto errout; - } - - hash->Init(hash->ctx); - hash->Update(hash->ctx, - (unsigned char *)isakmp_nat_t_cap[i].text, - strlen(isakmp_nat_t_cap[i].text)); - hash->Final(isakmp_nat_t_cap[i].hash, hash->ctx); - - LOG_DBG((LOG_EXCHANGE, 50, "nat_t_setup_hashes: " - "MD5(\"%s\") (%lu bytes)", isakmp_nat_t_cap[i].text, - (unsigned long)hash->hashsize)); - LOG_DBG_BUF((LOG_EXCHANGE, 50, "nat_t_setup_hashes", - isakmp_nat_t_cap[i].hash, hash->hashsize)); - } - - return 0; - -errout: - for (i = 0; i < n; i++) - if (isakmp_nat_t_cap[i].hash) - free(isakmp_nat_t_cap[i].hash); - return -1; -} - -/* Add one NAT-T VENDOR payload. */ -static int -nat_t_add_vendor_payload(struct message *msg, struct nat_t_cap *cap) -{ - size_t buflen = cap->hashsize + ISAKMP_GEN_SZ; - u_int8_t *buf; - - if (disable_nat_t) - return 0; - - buf = malloc(buflen); - if (!buf) { - log_error("nat_t_add_vendor_payload: malloc (%lu) failed", - (unsigned long)buflen); - return -1; - } - - SET_ISAKMP_GEN_LENGTH(buf, buflen); - memcpy(buf + ISAKMP_VENDOR_ID_OFF, cap->hash, cap->hashsize); - if (message_add_payload(msg, ISAKMP_PAYLOAD_VENDOR, buf, buflen, 1)) { - free(buf); - return -1; - } - return 0; -} - -/* Add the NAT-T capability markers (VENDOR payloads). */ -int -nat_t_add_vendor_payloads(struct message *msg) -{ - int i; - - if (disable_nat_t) - return 0; - - for (i = 0; i < NUMNATTCAP; i++) - if (nat_t_add_vendor_payload(msg, &isakmp_nat_t_cap[i])) - return -1; - return 0; -} - -/* - * Check an incoming message for NAT-T capability markers. - */ -void -nat_t_check_vendor_payload(struct message *msg, struct payload *p) -{ - u_int8_t *pbuf = p->p; - size_t vlen; - int i; - - if (disable_nat_t) - return; - - vlen = GET_ISAKMP_GEN_LENGTH(pbuf) - ISAKMP_GEN_SZ; - - for (i = 0; i < NUMNATTCAP; i++) { - if (vlen != isakmp_nat_t_cap[i].hashsize) { - LOG_DBG((LOG_EXCHANGE, 50, "nat_t_check_vendor_payload: " - "bad size %lu != %lu", (unsigned long)vlen, - (unsigned long)isakmp_nat_t_cap[i].hashsize)); - continue; - } - if (memcmp(isakmp_nat_t_cap[i].hash, pbuf + ISAKMP_GEN_SZ, - vlen) == 0) { - /* This peer is NAT-T capable. */ - msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_CAP_PEER; - msg->exchange->flags |= isakmp_nat_t_cap[i].flags; - LOG_DBG((LOG_EXCHANGE, 10, - "nat_t_check_vendor_payload: " - "NAT-T capable peer detected")); - p->flags |= PL_MARK; - } - } - - return; -} - -/* Generate the NAT-D payload hash : HASH(CKY-I | CKY-R | IP | Port). */ -static u_int8_t * -nat_t_generate_nat_d_hash(struct message *msg, struct sockaddr *sa, - size_t *hashlen) -{ - struct ipsec_exch *ie = (struct ipsec_exch *)msg->exchange->data; - struct hash *hash; - u_int8_t *res; - in_port_t port; - - hash = hash_get(ie->hash->type); - if (hash == NULL) { - log_print ("nat_t_generate_nat_d_hash: no hash"); - return NULL; - } - - *hashlen = hash->hashsize; - - res = (u_int8_t *)malloc((unsigned long)*hashlen); - if (!res) { - log_print("nat_t_generate_nat_d_hash: malloc (%lu) failed", - (unsigned long)*hashlen); - *hashlen = 0; - return NULL; - } - - port = sockaddr_port(sa); - bzero(res, *hashlen); - - hash->Init(hash->ctx); - hash->Update(hash->ctx, msg->exchange->cookies, - sizeof msg->exchange->cookies); - hash->Update(hash->ctx, sockaddr_addrdata(sa), sockaddr_addrlen(sa)); - hash->Update(hash->ctx, (unsigned char *)&port, sizeof port); - hash->Final(res, hash->ctx); - return res; -} - -/* Add a NAT-D payload to our message. */ -static int -nat_t_add_nat_d(struct message *msg, struct sockaddr *sa) -{ - int ret; - u_int8_t *hbuf, *buf; - size_t hbuflen, buflen; - - hbuf = nat_t_generate_nat_d_hash(msg, sa, &hbuflen); - if (!hbuf) { - log_print("nat_t_add_nat_d: NAT-D hash gen failed"); - return -1; - } - - buflen = ISAKMP_NAT_D_DATA_OFF + hbuflen; - buf = malloc(buflen); - if (!buf) { - log_error("nat_t_add_nat_d: malloc (%lu) failed", - (unsigned long)buflen); - free(hbuf); - return -1; - } - - SET_ISAKMP_GEN_LENGTH(buf, buflen); - memcpy(buf + ISAKMP_NAT_D_DATA_OFF, hbuf, hbuflen); - free(hbuf); - - if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_RFC) - ret = message_add_payload(msg, ISAKMP_PAYLOAD_NAT_D, buf, - buflen, 1); - else if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_DRAFT) - ret = message_add_payload(msg, ISAKMP_PAYLOAD_NAT_D_DRAFT, - buf, buflen, 1); - else - ret = -1; - - if (ret) { - free(buf); - return -1; - } - return 0; -} - -/* We add two NAT-D payloads, one each for src and dst. */ -int -nat_t_exchange_add_nat_d(struct message *msg) -{ - struct sockaddr *sa; - - /* Remote address first. */ - msg->transport->vtbl->get_dst(msg->transport, &sa); - if (nat_t_add_nat_d(msg, sa)) - return -1; - - msg->transport->vtbl->get_src(msg->transport, &sa); - if (nat_t_add_nat_d(msg, sa)) - return -1; - return 0; -} - -/* Generate and match a NAT-D hash against the NAT-D payload (pl.) data. */ -static int -nat_t_match_nat_d_payload(struct message *msg, struct sockaddr *sa) -{ - struct payload *p; - u_int8_t *hbuf; - size_t hbuflen; - int found = 0; - - /* - * If there are no NAT-D payloads in the message, return "found" - * as this will avoid NAT-T (see nat_t_exchange_check_nat_d()). - */ - if ((p = payload_first(msg, ISAKMP_PAYLOAD_NAT_D_DRAFT)) == NULL && - (p = payload_first(msg, ISAKMP_PAYLOAD_NAT_D)) == NULL) - return 1; - - hbuf = nat_t_generate_nat_d_hash(msg, sa, &hbuflen); - if (!hbuf) - return 0; - - while (p) { - if (GET_ISAKMP_GEN_LENGTH (p->p) != - hbuflen + ISAKMP_NAT_D_DATA_OFF) - continue; - - if (memcmp(p->p + ISAKMP_NAT_D_DATA_OFF, hbuf, hbuflen) == 0) { - found++; - break; - } - p = TAILQ_NEXT(p, link); - } - free(hbuf); - return found; -} - -/* - * Check if we need to activate NAT-T, and if we need to send keepalive - * messages to the other side, i.e if we are a nat:ed peer. - */ -int -nat_t_exchange_check_nat_d(struct message *msg) -{ - struct sockaddr *sa; - int outgoing_path_is_clear, incoming_path_is_clear; - - /* Assume trouble, i.e NAT-boxes in our path. */ - outgoing_path_is_clear = incoming_path_is_clear = 0; - - msg->transport->vtbl->get_src(msg->transport, &sa); - if (nat_t_match_nat_d_payload(msg, sa)) - outgoing_path_is_clear = 1; - - msg->transport->vtbl->get_dst(msg->transport, &sa); - if (nat_t_match_nat_d_payload(msg, sa)) - incoming_path_is_clear = 1; - - if (outgoing_path_is_clear && incoming_path_is_clear) { - LOG_DBG((LOG_EXCHANGE, 40, "nat_t_exchange_check_nat_d: " - "no NAT")); - return 0; /* No NAT-T required. */ - } - - /* NAT-T handling required. */ - msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_ENABLE; - - if (!outgoing_path_is_clear) { - msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_KEEPALIVE; - LOG_DBG((LOG_EXCHANGE, 10, "nat_t_exchange_check_nat_d: " - "NAT detected, we're behind it")); - } else - LOG_DBG ((LOG_EXCHANGE, 10, - "nat_t_exchange_check_nat_d: NAT detected")); - return 1; -} - -static void -nat_t_send_keepalive(void *v_arg) -{ - struct sa *sa = (struct sa *)v_arg; - struct transport *t; - struct timeval now; - int interval; - - /* Send the keepalive message. */ - t = ((struct virtual_transport *)sa->transport)->encap; - t->vtbl->send_message(NULL, t); - - /* Set new timer. */ - interval = conf_get_num("General", "NAT-T-Keepalive", 0); - if (interval < 1) - interval = NAT_T_KEEPALIVE_INTERVAL; - gettimeofday(&now, 0); - now.tv_sec += interval; - - sa->nat_t_keepalive = timer_add_event("nat_t_send_keepalive", - nat_t_send_keepalive, v_arg, &now); - if (!sa->nat_t_keepalive) - log_print("nat_t_send_keepalive: " - "timer_add_event() failed, will send no more keepalives"); -} - -void -nat_t_setup_keepalive(struct sa *sa) -{ - struct sockaddr *src; - struct timeval now; - - if (sa->initiator) - sa->transport->vtbl->get_src(sa->transport, &src); - else - sa->transport->vtbl->get_dst(sa->transport, &src); - - if (!virtual_listen_lookup(src)) - return; - - gettimeofday(&now, 0); - now.tv_sec += NAT_T_KEEPALIVE_INTERVAL; - - sa->nat_t_keepalive = timer_add_event("nat_t_send_keepalive", - nat_t_send_keepalive, sa, &now); - if (!sa->nat_t_keepalive) - log_print("nat_t_setup_keepalive: " - "timer_add_event() failed, will not send keepalives"); - - LOG_DBG((LOG_TRANSPORT, 50, "nat_t_setup_keepalive: " - "added event for phase 1 SA %p", sa)); -} |