1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
|
/* Libreswan NAT-Traversal
*
* Copyright (C) 2002-2003 Mathieu Lafon - Arkoon Network Security
* Copyright (C) 2005-2007 Michael Richardson <mcr@xelerance.com>
* Copyright (C) 2005 Ken Bantoft <ken@xelerance.com>
* Copyright (C) 2006 Bart Trojanowski <bart@jukie.net>
* Copyright (C) 2007-2010 Paul Wouters <paul@xelerance.com>
* Copyright (C) 2009 Tuomo Soini <tis@foobar.fi>
* Copyright (C) 2009 Gilles Espinasse <g.esp@free.fr>
* Copyright (C) 2009 David McCullough <david_mccullough@securecomputing.com>
* Copyright (C) 2011 Shinichi Furuso <Shinichi.Furuso@jp.sony.com>
* Copyright (C) 2012 Avesh Agarwal <avagarwa@redhat.com>
* Copyright (C) 2012 Paul Wouters <paul@libreswan.org>
* Copyright (C) 2012-2019 Paul Wouters <pwouters@redhat.com>
* Copyright (C) 2013-2019 D. Hugh Redelmeier <hugh@mimosa.com>
* Copyright (C) 2014 Antony Antony <antony@phenome.org>
* Copyright (C) 2019 Andrew Cagney <cagney@gnu.org>
* Copyright (C) 2017 Mayank Totale <mtotale@gmail.com>
*
* 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 <https://www.gnu.org/licenses/gpl2.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.
*/
#include "defs.h"
#include "log.h"
#include "state.h"
#include "nat_traversal.h"
#include "connections.h"
#include "ike_alg.h"
#include "ike_alg_hash.h"
#include "crypt_hash.h"
#include "ip_info.h"
#include "send.h"
#include "iface.h"
#include "state_db.h" /* for state_by_ike_spis() */
#include "show.h"
/* As per https://tools.ietf.org/html/rfc3948#section-4 */
#define DEFAULT_KEEP_ALIVE_SECS 20
deltatime_t nat_keepalive_period = DELTATIME_INIT(DEFAULT_KEEP_ALIVE_SECS);
void init_nat_traversal_timer(deltatime_t keep_alive, struct logger *logger)
{
if (keep_alive.is_set) {
/* truncate */
if (deltatime_cmp(keep_alive, <, one_second)) {
deltatime_buf db;
llog(RC_LOG, logger,
"NAT-Traversal: ignoring too small keep-alive period %s (less than 1 second)",
str_deltatime(keep_alive, &db));
} else if (deltatime_cmp(keep_alive, >, one_day)) {
deltatime_buf db;
llog(RC_LOG, logger,
"NAT-Traversal: ignoring too big keep-alive period %s (more than 1 day)",
str_deltatime(keep_alive, &db));
} else {
nat_keepalive_period = keep_alive;
}
}
deltatime_buf db;
llog(RC_LOG, logger, "NAT-Traversal: keep-alive period %ss",
str_deltatime(nat_keepalive_period, &db));
}
struct crypt_mac natd_hash(const struct hash_desc *hasher,
const ike_spis_t *spis,
const ip_endpoint endpoint,
struct logger *logger)
{
/* only responder's IKE SPI can be zero */
if (ike_spi_is_zero(&spis->initiator)) {
dbg("nat: IKE.SPIi is unexpectedly zero");
/* presumably because it was impaired?!? */
pexpect(impair.ike_initiator_spi.enabled &&
impair.ike_initiator_spi.value == 0);
}
if (ike_spi_is_zero(&spis->responder)) {
/* IKE_SA_INIT exchange */
dbg("nat: IKE.SPIr is zero");
}
/*
* RFC 3947
*
* HASH = HASH(IKE.SPIi | IKE.SPIr | IP | Port)
*
* All values in network order
*/
struct crypt_hash *ctx = crypt_hash_init("NATD", hasher, logger);
crypt_hash_digest_thing(ctx, "IKE SPIi", spis->initiator);
crypt_hash_digest_thing(ctx, "IKE SPIr", spis->responder);
ip_address ip = endpoint_address(endpoint);
shunk_t ap = address_as_shunk(&ip);
crypt_hash_digest_hunk(ctx, "IP addr", ap);
uint16_t np = nport(endpoint_port(endpoint));
crypt_hash_digest_thing(ctx, "PORT", np);
struct crypt_mac hash = crypt_hash_final_mac(&ctx);
if (DBGP(DBG_BASE)) {
DBG_log("natd_hash: hasher=%p(%d)", hasher,
(int)hasher->hash_digest_size);
DBG_dump_thing("natd_hash: icookie=", spis->initiator);
DBG_dump_thing("natd_hash: rcookie=", spis->responder);
DBG_dump_hunk("natd_hash: ip=", ap);
DBG_dump_thing("natd_hash: port=", np);
DBG_dump_hunk("natd_hash: hash=", hash);
}
return hash;
}
void natd_lookup_common(struct state *st,
const ip_endpoint sender,
bool found_me, bool found_peer)
{
st->hidden_variables.st_natd = ipv4_info.address.unspec;
/* update NAT-T settings for local policy */
switch (st->st_connection->config->encapsulation) {
case YNA_UNSET:
case YNA_AUTO:
dbg("NAT_TRAVERSAL encaps using auto-detect");
if (!found_me) {
dbg("NAT_TRAVERSAL this end is behind NAT");
st->hidden_variables.st_nated_host = true;
st->hidden_variables.st_natd = endpoint_address(sender);
} else {
dbg("NAT_TRAVERSAL this end is NOT behind NAT");
}
if (!found_peer) {
endpoint_buf b;
dbg("NAT_TRAVERSAL that end is behind NAT %s",
str_endpoint(&sender, &b));
st->hidden_variables.st_nated_peer = true;
st->hidden_variables.st_natd = endpoint_address(sender);
} else {
dbg("NAT_TRAVERSAL that end is NOT behind NAT");
}
break;
case YNA_NO:
st->hidden_variables.st_nat_traversal |= LEMPTY;
dbg("NAT_TRAVERSAL local policy prohibits encapsulation");
break;
case YNA_YES:
ldbg(st->logger, "NAT_TRAVERSAL local policy enforces encapsulation");
st->hidden_variables.st_nated_peer = true;
st->hidden_variables.st_nated_host = true;
st->hidden_variables.st_natd = endpoint_address(sender);
break;
}
if (st->st_connection->config->nat_keepalive) {
endpoint_buf b;
dbg("NAT_TRAVERSAL nat-keepalive enabled %s", str_endpoint(&sender, &b));
}
}
bool nat_traversal_detected(struct state *st)
{
return (st->hidden_variables.st_nated_host ||
st->hidden_variables.st_nated_peer);
}
static void nat_traversal_send_ka(struct state *st)
{
endpoint_buf b;
dbg("ka_event: send NAT-KA to %s (state=#%lu)",
str_endpoint(&st->st_remote_endpoint, &b),
st->st_serialno);
/* send keep alive */
dbg("sending NAT-T Keep Alive");
send_keepalive_using_state(st, "NAT-T Keep Alive");
}
/*
* Find ISAKMP States with NAT-T and send keep-alive
*/
static bool need_nat_keepalive(struct state *st)
{
const struct connection *c = st->st_connection;
if (!c->config->nat_keepalive) {
pdbg(st->logger, "NAT-keep-alive: not scheduled, nat-keepalive=no)");
return false;
}
if (!st->hidden_variables.st_nated_host) {
pdbg(st->logger, "NAT-keep-alive: not scheduled, not behind NAT");
return false;
}
/* XXX: .st_iface_endpoint, not c.interface - can be different */
if (!st->st_iface_endpoint->io->send_keepalive) {
pdbg(st->logger, "NAT-keep-alive: not scheduled, needed by %s protocol",
st->st_iface_endpoint->io->protocol->name);
return false;
}
return true;
}
void schedule_v1_nat_keepalive(struct state *st)
{
if (!need_nat_keepalive(st)) {
return;
}
pdbg(st->logger, "NAT-keep-alive: scheduled, period %jds",
deltasecs(nat_keepalive_period));
event_schedule(EVENT_v1_NAT_KEEPALIVE, nat_keepalive_period, st);
}
void schedule_v2_nat_keepalive(struct ike_sa *ike, where_t where)
{
if (!need_nat_keepalive(&ike->sa)) {
/* already logged */
return;
}
/*
* In IKEv2 all messages go through the established IKE SA.
* Hence, expect this to be established, at least when first
* scheduling the timer.
*
* However, the responder calls this code early (before
* processing child payloads), which means it is not
* established.
*/
if (!IS_IKE_SA_ESTABLISHED(&ike->sa)) {
pdbg(ike->sa.logger, "NAT-keep-alive: allowing non-established IKE SA when scheduling (responder yet to process Child payloads?) "PRI_WHERE,
pri_where(where));
}
/*
* crossing-streams can result in this established IKE SA is
* not being the most current. Thats OK. Need to still keep
* NAT open so it can later shutdown.
*/
if (ike->sa.st_connection->established_ike_sa != ike->sa.st_serialno) {
pdbg(ike->sa.logger, "NAT-keep-alive: allowing IKE SA crossing-stream with "PRI_SO" when scheduling "PRI_WHERE,
pri_so(ike->sa.st_connection->established_ike_sa),
pri_where(where));
}
pdbg(ike->sa.logger, "NAT-keep-alive: scheduled, period %jds",
deltasecs(nat_keepalive_period));
event_schedule(EVENT_v2_NAT_KEEPALIVE, nat_keepalive_period, &ike->sa);
}
#ifdef USE_IKEv1
void event_v1_nat_keepalive(struct state *st)
{
const struct connection *c = st->st_connection;
/*
* For IKEv1, there can be orphaned IPsec SA's. Since we are
* not checking the kernel we just have to always send the
* keepalive for all IPsec SAs.
*
* Older comment providing some backstory:
*
* ISAKMP SA and IPsec SA keepalives happen over the same
* port/NAT mapping. If the ISAKMP SA is idle and triggers
* keepalives, we don't need to check IPsec SA's being idle.
* If we were to check IPsec SA, we could then also update the
* ISAKMP SA, but we think this is too expensive (call
* get_sa_bundle_info() to kernel _and_ find ISAKMP SA.
*/
if (!IS_IPSEC_SA_ESTABLISHED(st)) {
pdbg(st->logger, "NAT-keep-alive: IPsec SA is not established");
return;
}
if (c->established_child_sa != st->st_serialno) {
pdbg(st->logger, "NAT-keep-alive: IPsec SA is not the current SA ("PRI_SO")",
pri_so(c->established_child_sa));
return;
}
pdbg(st->logger, "NAT-keep-alive: sending keep-alive");
nat_traversal_send_ka(st);
}
#endif
void event_v2_nat_keepalive(struct ike_sa *ike)
{
const struct connection *c = ike->sa.st_connection;
/*
* In IKEv2 all messages go through the IKE SA. Hence check
* its timers.
*/
if (!IS_IKE_SA_ESTABLISHED(&ike->sa)) {
pdbg(ike->sa.logger, "NAT-keep-alive: skipping send, as IKE SA is not established");
return;
}
if (c->established_ike_sa != ike->sa.st_serialno) {
pdbg(ike->sa.logger, "NAT-keep-alive: skipping send, IKE SA is not current ("PRI_SO")",
pri_so(c->established_ike_sa));
return;
}
/*
* If this IKE SA sent a packet recently, no need for anything
* eg, if short LIVENESS timers are used we can skip this.
*/
if (!is_monotime_epoch(ike->sa.st_v2_msgid_windows.last_sent) &&
deltasecs(monotime_diff(mononow(), ike->sa.st_v2_msgid_windows.last_sent)) < DEFAULT_KEEP_ALIVE_SECS) {
pdbg(ike->sa.logger, "NAT-keep-alive: skipping send, IKE SA recently sent a request");
return;
}
/*
* TODO or not?
*
* We could also check If there is IPsec SA encapsulation
* traffic, since then we also do not need to send keepalives,
* but that check is a little expensive as we have to find
* some/all IPsec states and ask the kernel, every 20s.
*
* XXX:
*
* But that call is being made every minute or so for
* LIVENESS, and it's NAT so probably not that many SAs, and
* finding the IKE SA is cheap.
*/
pdbg(ike->sa.logger, "NAT-keep-alive: sending keep-alive");
nat_traversal_send_ka(&ike->sa);
}
/*
* Re-map entire family.
*
* In IKEv1 this code needs to handle orphans - the children are
* around but the IKE (ISAKMP) SA is gone.
*/
struct new_mapp_nfo {
so_serial_t clonedfrom;
const ip_endpoint new_remote_endpoint;
};
static bool nat_traversal_update_family_mapp_state(struct state *st, void *data)
{
struct new_mapp_nfo *nfo = data;
if (pexpect(st->st_serialno == nfo->clonedfrom /*parent*/ ||
st->st_clonedfrom == nfo->clonedfrom /*sibling*/)) {
endpoint_buf b1;
endpoint_buf b2;
ip_endpoint st_remote_endpoint = st->st_remote_endpoint;
ldbg(st->logger, "new NAT mapping for #%lu, was %s, now %s",
st->st_serialno,
str_endpoint(&st_remote_endpoint, &b1),
str_endpoint(&nfo->new_remote_endpoint, &b2));
/* update it */
st->st_remote_endpoint = nfo->new_remote_endpoint;
st->hidden_variables.st_natd = endpoint_address(nfo->new_remote_endpoint);
struct connection *c = st->st_connection;
if (is_instance(c)) {
/* update remote */
c->remote->host.addr = endpoint_address(nfo->new_remote_endpoint);
/* then rebuild local<>remote host-pair */
}
}
return false; /* search for more */
}
/*
* this should only be called after packet has been
* verified/authenticated! (XXX: IKEv1?)
*
* XXX: Is this solving an IKEv1 only problem? IKEv2 only needs to
* update the IKE SA and seems to do it using update_ike_endpoints().
*/
void nat_traversal_change_port_lookup(struct msg_digest *md, struct state *st)
{
if (st == NULL)
return;
if (st->st_iface_endpoint->io->protocol == &ip_protocol_tcp ||
(md != NULL && md->iface->io->protocol == &ip_protocol_tcp)) {
/* XXX: when is MD NULL? */
return;
}
if (md != NULL) {
/*
* If source port/address has changed, update the family.
*
* Since IKEv1 allows orphans - parent deleted but
* children live on.
*/
if (!endpoint_eq_endpoint(md->sender, st->st_remote_endpoint)) {
struct new_mapp_nfo nfo = {
.clonedfrom = (st->st_clonedfrom != SOS_NOBODY ? st->st_clonedfrom : st->st_serialno),
.new_remote_endpoint = md->sender,
};
state_by_ike_spis(st->st_ike_version,
NULL /* clonedfrom */,
NULL /* v1_msgid */,
NULL /* role */,
&st->st_ike_spis,
nat_traversal_update_family_mapp_state,
&nfo,
__func__);
}
/*
* If interface type has changed, update local port (500/4500)
*/
if (md->iface != st->st_iface_endpoint) {
endpoint_buf b1, b2;
dbg("NAT-T: #%lu updating local interface from %s to %s (using md->iface in %s())",
st->st_serialno,
str_endpoint(&st->st_iface_endpoint->local_endpoint, &b1),
str_endpoint(&md->iface->local_endpoint, &b2), __func__);
iface_endpoint_delref(&st->st_iface_endpoint);
st->st_iface_endpoint = iface_endpoint_addref(md->iface);
}
}
}
void show_setup_natt(struct show *s)
{
show_separator(s);
show(s, "nat-traversal: keep-alive=%jd, nat-ikeport=%d",
deltasecs(nat_keepalive_period), NAT_IKE_UDP_PORT);
}
|