📄 nat_traversal.c
字号:
/* Openswan NAT-Traversal * Copyright (C) 2002-2003 Mathieu Lafon - Arkoon Network Security * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * RCSID $Id: nat_traversal.c,v 1.26.2.6 2006/01/04 18:57:52 ken Exp $ */#ifdef NAT_TRAVERSAL#include <stdio.h>#include <stdlib.h>#include <ctype.h>#include <stdarg.h>#include <syslog.h>#include <errno.h>#include <string.h>#include <unistd.h>#include <signal.h> /* used only if MSG_NOSIGNAL not defined */#include <sys/queue.h>#include <openswan.h>#include <openswan/ipsec_policy.h>#include <pfkeyv2.h>#include <pfkey.h>#include "constants.h"#include "oswlog.h"#include "defs.h"#include "log.h"#include "server.h"#include "state.h"#include "id.h"#include "x509.h"#include "pgp.h"#include "certs.h"#include "smartcard.h"#ifdef XAUTH_USEPAM#include <security/pam_appl.h>#endif#include "connections.h"#include "packet.h"#include "demux.h"#include "kernel.h"#include "whack.h"#include "timer.h"#include "ike_alg.h"#include "cookie.h"#include "sha1.h"#include "md5.h"#include "crypto.h"#include "vendor.h"#include "natt_defines.h"#include "nat_traversal.h"#define NAT_D_DEBUG#define NAT_T_SUPPORT_LAST_DRAFTS#define DEFAULT_KEEP_ALIVE_PERIOD 20bool nat_traversal_enabled = FALSE;bool nat_traversal_support_non_ike = FALSE;bool nat_traversal_support_port_floating = FALSE;static unsigned int _kap = 0;static unsigned int _ka_evt = 0;static bool _force_ka = 0;static const char *natt_version = "0.6c";void init_nat_traversal (bool activate, unsigned int keep_alive_period, bool fka, bool spf){ nat_traversal_enabled = activate; nat_traversal_support_non_ike = activate;#ifdef NAT_T_SUPPORT_LAST_DRAFTS nat_traversal_support_port_floating = activate ? spf : FALSE; openswan_log("Setting NAT-Traversal port-4500 floating to %s" , nat_traversal_support_port_floating ? "on" : "off"); openswan_log(" port floating activation criteria nat_t=%d/port_fload=%d" , activate, spf);#endif { FILE *f = fopen("/proc/net/ipsec/natt", "r"); char n; if(f != NULL) { n=getc(f); if(n=='0') { nat_traversal_enabled = FALSE; nat_traversal_support_non_ike=FALSE; nat_traversal_support_port_floating=FALSE; openswan_log(" KLIPS does not have NAT-Traversal built in (see /proc/net/ipsec/natt)\n"); } fclose(f); } } _force_ka = fka; _kap = keep_alive_period ? keep_alive_period : DEFAULT_KEEP_ALIVE_PERIOD; plog(" including NAT-Traversal patch (Version %s)%s%s%s", natt_version, activate ? "" : " [disabled]", activate & fka ? " [Force KeepAlive]" : "", activate & !spf ? " [Port Floating disabled]" : "");}static void disable_nat_traversal(int type){ if (type == ESPINUDP_WITH_NON_IKE) nat_traversal_support_non_ike = FALSE; else { openswan_log("NAT-Traversal port floating turned off"); nat_traversal_support_port_floating = FALSE; } if (!nat_traversal_support_non_ike && !nat_traversal_support_port_floating) { openswan_log("NAT-Traversal is turned OFF due to lack of KERNEL support: %d/%d" , nat_traversal_support_non_ike , nat_traversal_support_port_floating); nat_traversal_enabled = FALSE; }}static void _natd_hash(const struct hash_desc *hasher, char *hash, u_int8_t *icookie, u_int8_t *rcookie, const ip_address *ip, u_int16_t port /* network order */){ union hash_ctx ctx; if (is_zero_cookie(icookie)) DBG_log("_natd_hash: Warning, icookie is zero !!"); if (is_zero_cookie(rcookie)) DBG_log("_natd_hash: Warning, rcookie is zero !!"); /** * draft-ietf-ipsec-nat-t-ike-01.txt * * HASH = HASH(CKY-I | CKY-R | IP | Port) * * All values in network order */ hasher->hash_init(&ctx); hasher->hash_update(&ctx, icookie, COOKIE_SIZE); hasher->hash_update(&ctx, rcookie, COOKIE_SIZE); switch (addrtypeof(ip)) { case AF_INET: hasher->hash_update(&ctx, (const u_char *)&ip->u.v4.sin_addr.s_addr, sizeof(ip->u.v4.sin_addr.s_addr)); break; case AF_INET6: hasher->hash_update(&ctx, (const u_char *)&ip->u.v6.sin6_addr.s6_addr, sizeof(ip->u.v6.sin6_addr.s6_addr)); break; } hasher->hash_update(&ctx, (const u_char *)&port, sizeof(u_int16_t)); hasher->hash_final(hash, &ctx);#ifdef NAT_D_DEBUG DBG(DBG_NATT, DBG_log("_natd_hash: hasher=%p(%d)", hasher, (int)hasher->hash_digest_len); DBG_dump("_natd_hash: icookie=", icookie, COOKIE_SIZE); DBG_dump("_natd_hash: rcookie=", rcookie, COOKIE_SIZE); switch (addrtypeof(ip)) { case AF_INET: DBG_dump("_natd_hash: ip=", &ip->u.v4.sin_addr.s_addr, sizeof(ip->u.v4.sin_addr.s_addr)); break; } DBG_log("_natd_hash: port=%d", ntohs(port)); DBG_dump("_natd_hash: hash=", hash, hasher->hash_digest_len); );#endif}/** * Add NAT-Traversal VIDs (supported ones) * * Used when we're Initiator */bool nat_traversal_add_vid(u_int8_t np, pb_stream *outs){ bool r = TRUE; DBG(DBG_NATT , DBG_log("nat add vid. port: %d nonike: %d" , nat_traversal_support_port_floating , nat_traversal_support_non_ike)); if (nat_traversal_support_port_floating) { if (r) r = out_vendorid(np, outs, VID_NATT_RFC); if (r) r = out_vendorid(np, outs, VID_NATT_IETF_03); if (r) r = out_vendorid(np, outs, VID_NATT_IETF_02); if (r) r = out_vendorid(np, outs, VID_NATT_IETF_02_N); } if (nat_traversal_support_non_ike) { if (r) r = out_vendorid(np, outs, VID_NATT_IETF_00); } return r;}u_int32_t nat_traversal_vid_to_method(unsigned short nat_t_vid){ switch (nat_t_vid) { case VID_NATT_IETF_00: return LELEM(NAT_TRAVERSAL_IETF_00_01); break; case VID_NATT_IETF_02: case VID_NATT_IETF_02_N: case VID_NATT_IETF_03: return LELEM(NAT_TRAVERSAL_IETF_02_03); break; case VID_NATT_DRAFT_IETF_IPSEC_NAT_T_IKE: return LELEM(NAT_TRAVERSAL_OSX); break; case VID_NATT_RFC: return LELEM(NAT_TRAVERSAL_RFC); break; } return 0;}void nat_traversal_natd_lookup(struct msg_digest *md){ unsigned char hash_me[MAX_DIGEST_LEN]; unsigned char hash_him[MAX_DIGEST_LEN]; struct payload_digest *p; struct state *st = md->st; bool found_me = FALSE; bool found_him= FALSE; int i; if (!st || !md->iface || !st->st_oakley.hasher) { loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d", __FILE__, __LINE__); return; } /** Count NAT-D **/ for (p = md->chain[ISAKMP_NEXT_NATD_RFC], i=0; p != NULL; p = p->next, i++); /** * We need at least 2 NAT-D (1 for us, many for peer) */ if (i < 2) { loglog(RC_LOG_SERIOUS, "NAT-Traversal: Only %d NAT-D - Aborting NAT-Traversal negotiation", i); st->hidden_variables.st_nat_traversal = 0; return; } /** * First one with my IP & port */ _natd_hash(st->st_oakley.hasher, hash_me , st->st_icookie, st->st_rcookie , &(md->iface->ip_addr) , ntohs(md->iface->port)); /** * The others with sender IP & port */ _natd_hash(st->st_oakley.hasher, hash_him , st->st_icookie, st->st_rcookie , &(md->sender), ntohs(md->sender_port)); for (p = md->chain[ISAKMP_NEXT_NATD_RFC], i=0; p != NULL && (!found_me || !found_him); p = p->next) {#ifdef NAT_D_DEBUG DBG(DBG_NATT, DBG_log("NAT_TRAVERSAL hash=%d (me:%d) (him:%d)" , i, found_me, found_him); DBG_dump("expected NAT-D(me):", hash_me, st->st_oakley.hasher->hash_digest_len); DBG_dump("expected NAT-D(him):", hash_him, st->st_oakley.hasher->hash_digest_len); DBG_dump("received NAT-D:", p->pbs.cur, pbs_left(&p->pbs)); );#endif if ( (pbs_left(&p->pbs) == st->st_oakley.hasher->hash_digest_len) && (memcmp(p->pbs.cur, hash_me , st->st_oakley.hasher->hash_digest_len)==0)) { found_me = TRUE; } if ( (pbs_left(&p->pbs) == st->st_oakley.hasher->hash_digest_len) && (memcmp(p->pbs.cur, hash_him , st->st_oakley.hasher->hash_digest_len)==0)) { found_him = TRUE; } i++; } DBG(DBG_NATT, DBG_log("NAT_TRAVERSAL hash=%d (me:%d) (him:%d)" , i, found_me, found_him)); if(!found_me) { st->hidden_variables.st_nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_ME); } if(!found_him) { st->hidden_variables.st_nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_PEER); st->hidden_variables.st_natd = md->sender; } if(st->st_connection->forceencaps) { st->hidden_variables.st_nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_PEER); st->hidden_variables.st_nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_ME); }}bool nat_traversal_add_natd(u_int8_t np, pb_stream *outs, struct msg_digest *md){ char hash[MAX_DIGEST_LEN]; struct state *st = md->st; unsigned int nat_np; if (!st || !st->st_oakley.hasher) { loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d", __FILE__, __LINE__); return FALSE; } DBG(DBG_EMITTING, DBG_log("sending NATD payloads")); nat_np = (st->hidden_variables.st_nat_traversal & NAT_T_WITH_RFC_VALUES ? ISAKMP_NEXT_NATD_RFC : (st->hidden_variables.st_nat_traversal & NAT_T_WITH_NATD_BADDRAFT_VALUES ? ISAKMP_NEXT_NATD_BADDRAFTS : ISAKMP_NEXT_NATD_DRAFTS)); if (!out_modify_previous_np(nat_np, outs)) { return FALSE; } /** * First one with sender IP & port */ if(st->st_connection->forceencaps) { _natd_hash(st->st_oakley.hasher , hash, st->st_icookie , is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie , &(md->sender) , 0); } else { _natd_hash(st->st_oakley.hasher, hash, st->st_icookie , is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie , &(md->sender) , htons(md->sender_port)); } if (!out_generic_raw(nat_np, &isakmp_nat_d, outs , hash , st->st_oakley.hasher->hash_digest_len , "NAT-D")) { return FALSE; } /** * Second one with my IP & port */ if(st->st_connection->forceencaps) { _natd_hash(st->st_oakley.hasher, hash , st->st_icookie , is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie , &(md->iface->ip_addr),0); } else { _natd_hash(st->st_oakley.hasher, hash , st->st_icookie , is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie , &(md->iface->ip_addr) , htons(md->iface->port)); } return (out_generic_raw(np, &isakmp_nat_d, outs, hash, st->st_oakley.hasher->hash_digest_len, "NAT-D"));}/** * nat_traversal_natoa_lookup() * * Look for NAT-OA in message */void nat_traversal_natoa_lookup(struct msg_digest *md){ struct payload_digest *p; struct state *st = md->st; int i; ip_address ip; if (!st || !md->iface) { loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d", __FILE__, __LINE__); return; } /** Initialize NAT-OA */ anyaddr(AF_INET, &st->hidden_variables.st_nat_oa); /** Count NAT-OA **/ for (p = md->chain[ISAKMP_NEXT_NATOA_RFC], i=0; p != NULL; p = p->next, i++); DBG(DBG_NATT, DBG_log("NAT-Traversal: received %d NAT-OA.", i); ); if (i==0) { return; } else if (!(st->hidden_variables.st_nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_PEER))) { loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %d NAT-OA. " "ignored because peer is not NATed", i); return; } else if (i>1) { loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %d NAT-OA. " "using first, ignoring others", i); } /** Take first **/ p = md->chain[ISAKMP_NEXT_NATOA_RFC]; DBG(DBG_PARSING, DBG_dump("NAT-OA:", p->pbs.start, pbs_room(&p->pbs)); ); switch (p->payload.nat_oa.isanoa_idtype) { case ID_IPV4_ADDR: if (pbs_left(&p->pbs) == sizeof(struct in_addr)) { initaddr(p->pbs.cur, pbs_left(&p->pbs) , AF_INET, &ip); } else { loglog(RC_LOG_SERIOUS , "NAT-Traversal: received IPv4 NAT-OA " "with invalid IP size (%d)" , (int)pbs_left(&p->pbs)); return; } break; case ID_IPV6_ADDR: if (pbs_left(&p->pbs) == sizeof(struct in6_addr)) { initaddr(p->pbs.cur, pbs_left(&p->pbs) , AF_INET6, &ip); } else { loglog(RC_LOG_SERIOUS , "NAT-Traversal: received IPv6 NAT-OA " "with invalid IP size (%d)" , (int)pbs_left(&p->pbs)); return; } break; default: loglog(RC_LOG_SERIOUS, "NAT-Traversal: " "invalid ID Type (%d) in NAT-OA - ignored", p->payload.nat_oa.isanoa_idtype); return; break; } DBG(DBG_NATT, { char ip_t[ADDRTOT_BUF]; addrtot(&ip, 0, ip_t, sizeof(ip_t)); DBG_log("received NAT-OA: %s", ip_t); } ); if (isanyaddr(&ip)) { loglog(RC_LOG_SERIOUS , "NAT-Traversal: received %%any NAT-OA..."); } else { st->hidden_variables.st_nat_oa = ip; }}bool nat_traversal_add_natoa(u_int8_t np, pb_stream *outs, struct state *st){ struct isakmp_nat_oa natoa; pb_stream pbs; unsigned char ip_val[sizeof(struct in6_addr)]; size_t ip_len = 0; ip_address *ip; unsigned int nat_np; if ((!st) || (!st->st_connection)) { loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -