/* routines that interface with the kernel's IPsec mechanism * * Copyright (C) 2010 Tobias Brunner * Copyright (C) 2009 Andreas Steffen * Hochschule fuer Technik Rapperswil * * Copyright (C) 1998-2002 D. Hugh Redelmeier * Copyright (C) 1997 Angelos D. Keromytis * * 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 . * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for select(2) */ #include /* for select(2) */ #include #include #include "kameipsec.h" #include "constants.h" #include "defs.h" #include "connections.h" #include "state.h" #include "timer.h" #include "kernel.h" #include "kernel_pfkey.h" #include "log.h" #include "ca.h" #include "server.h" #include "whack.h" /* for RC_LOG_SERIOUS */ #include "keys.h" #include "crypto.h" #include "nat_traversal.h" #include "alg_info.h" #include "kernel_alg.h" #include "pluto.h" bool can_do_IPcomp = TRUE; /* can system actually perform IPCOMP? */ /* test if the routes required for two different connections agree * It is assumed that the destination subnets agree; we are only * testing that the interfaces and nexthops match. */ #define routes_agree(c, d) ((c)->interface == (d)->interface \ && sameaddr(&(c)->spd.this.host_nexthop, &(d)->spd.this.host_nexthop)) /* forward declaration */ static bool shunt_eroute(connection_t *c, struct spd_route *sr, enum routing_t rt_kind, unsigned int op, const char *opname); static void set_text_said(char *text_said, const ip_address *dst, ipsec_spi_t spi, int proto); /** * Default IPsec SA config (e.g. to install trap policies). */ static ipsec_sa_cfg_t null_ipsec_sa = { .mode = MODE_TRANSPORT, .esp = { .use = TRUE, }, }; /** * Helper function that converts an ip_subnet to a traffic_selector_t. */ static traffic_selector_t *traffic_selector_from_subnet(const ip_subnet *client, const u_int8_t proto) { traffic_selector_t *ts; host_t *net; net = host_create_from_sockaddr((sockaddr_t*)&client->addr); ts = traffic_selector_create_from_subnet(net, client->maskbits, proto, net->get_port(net)); return ts; } /** * Helper function that converts a traffic_selector_t to an ip_subnet. */ static ip_subnet subnet_from_traffic_selector(traffic_selector_t *ts) { ip_subnet subnet; host_t *net; u_int8_t mask; ts->to_subnet(ts, &net, &mask); subnet.addr = *(ip_address*)net->get_sockaddr(net); subnet.maskbits = mask; net->destroy(net); return subnet; } void record_and_initiate_opportunistic(const ip_subnet *ours, const ip_subnet *his, int transport_proto, const char *why) { ip_address src, dst; passert(samesubnettype(ours, his)); /* actually initiate opportunism */ networkof(ours, &src); networkof(his, &dst); initiate_opportunistic(&src, &dst, transport_proto, TRUE, NULL_FD); } /* Generate Unique SPI numbers. * * The returned SPI is in network byte order. */ ipsec_spi_t get_ipsec_spi(ipsec_spi_t avoid, int proto, struct spd_route *sr, bool tunnel) { host_t *host_src, *host_dst; u_int32_t spi; host_src = host_create_from_sockaddr((sockaddr_t*)&sr->that.host_addr); host_dst = host_create_from_sockaddr((sockaddr_t*)&sr->this.host_addr); if (hydra->kernel_interface->get_spi(hydra->kernel_interface, host_src, host_dst, proto, sr->reqid, &spi) != SUCCESS) { spi = 0; } host_src->destroy(host_src); host_dst->destroy(host_dst); return spi; } /* Generate Unique CPI numbers. * The result is returned as an SPI (4 bytes) in network order! * The real bits are in the nework-low-order 2 bytes. */ ipsec_spi_t get_my_cpi(struct spd_route *sr, bool tunnel) { host_t *host_src, *host_dst; u_int16_t cpi; host_src = host_create_from_sockaddr((sockaddr_t*)&sr->that.host_addr); host_dst = host_create_from_sockaddr((sockaddr_t*)&sr->this.host_addr); if (hydra->kernel_interface->get_cpi(hydra->kernel_interface, host_src, host_dst, sr->reqid, &cpi) != SUCCESS) { cpi = 0; } host_src->destroy(host_src); host_dst->destroy(host_dst); return htonl((u_int32_t)ntohs(cpi)); } /* Replace the shell metacharacters ', \, ", `, and $ in a character string * by escape sequences consisting of their octal values */ static void escape_metachar(const char *src, char *dst, size_t dstlen) { while (*src != '\0' && dstlen > 4) { switch (*src) { case '\'': case '\\': case '"': case '`': case '$': sprintf(dst,"\\%s%o", (*src < 64)?"0":"", *src); dst += 4; dstlen -= 4; break; default: *dst++ = *src; dstlen--; } src++; } *dst = '\0'; } /* invoke the updown script to do the routing and firewall commands required * * The user-specified updown script is run. Parameters are fed to it in * the form of environment variables. All such environment variables * have names starting with "PLUTO_". * * The operation to be performed is specified by PLUTO_VERB. This * verb has a suffix "-host" if the client on this end is just the * host; otherwise the suffix is "-client". If the address family * of the host is IPv6, an extra suffix of "-v6" is added. * * "prepare-host" and "prepare-client" are used to delete a route * that may exist (due to forces outside of Pluto). It is used to * prepare for pluto creating a route. * * "route-host" and "route-client" are used to install a route. * Since routing is based only on destination, the PLUTO_MY_CLIENT_* * values are probably of no use (using them may signify a bug). * * "unroute-host" and "unroute-client" are used to delete a route. * Since routing is based only on destination, the PLUTO_MY_CLIENT_* * values are probably of no use (using them may signify a bug). * * "up-host" and "up-client" are run when an eroute is added (not replaced). * They are useful for adjusting a firewall: usually for adding a rule * to let processed packets flow between clients. Note that only * one eroute may exist for a pair of client subnets but inbound * IPsec SAs may persist without an eroute. * * "down-host" and "down-client" are run when an eroute is deleted. * They are useful for adjusting a firewall. */ #ifndef DEFAULT_UPDOWN # define DEFAULT_UPDOWN "ipsec _updown" #endif static bool do_command(connection_t *c, struct spd_route *sr, struct state *st, const char *verb) { char cmd[1536]; /* arbitrary limit on shell command length */ const char *verb_suffix; /* figure out which verb suffix applies */ { const char *hs, *cs; switch (addrtypeof(&sr->this.host_addr)) { case AF_INET: hs = "-host"; cs = "-client"; break; case AF_INET6: hs = "-host-v6"; cs = "-client-v6"; break; default: loglog(RC_LOG_SERIOUS, "unknown address family"); return FALSE; } verb_suffix = subnetisaddr(&sr->this.client, &sr->this.host_addr) ? hs : cs; } /* form the command string */ { char nexthop_str[sizeof("PLUTO_NEXT_HOP='' ") +ADDRTOT_BUF] = "", srcip_str[sizeof("PLUTO_MY_SOURCEIP='' ")+ADDRTOT_BUF] = "", me_str[ADDRTOT_BUF], myid_str[BUF_LEN], myclient_str[SUBNETTOT_BUF], myclientnet_str[ADDRTOT_BUF], myclientmask_str[ADDRTOT_BUF], peer_str[ADDRTOT_BUF], peerid_str[BUF_LEN], peerclient_str[SUBNETTOT_BUF], peerclientnet_str[ADDRTOT_BUF], peerclientmask_str[ADDRTOT_BUF], peerca_str[BUF_LEN], mark_in[BUF_LEN] = "", mark_out[BUF_LEN] = "", udp_encap[BUF_LEN] = "", xauth_id_str[BUF_LEN] = "", secure_myid_str[BUF_LEN] = "", secure_peerid_str[BUF_LEN] = "", secure_peerca_str[BUF_LEN] = "", secure_xauth_id_str[BUF_LEN] = ""; ip_address ta; pubkey_list_t *p; if (addrbytesptr(&sr->this.host_nexthop, NULL) && !isanyaddr(&sr->this.host_nexthop)) { char *n; strcpy(nexthop_str, "PLUTO_NEXT_HOP='"); n = nexthop_str + strlen(nexthop_str); addrtot(&sr->this.host_nexthop, 0 ,n , sizeof(nexthop_str)-strlen(nexthop_str)); strncat(nexthop_str, "' ", sizeof(nexthop_str)); } if (!sr->this.host_srcip->is_anyaddr(sr->this.host_srcip)) { char *n; strcpy(srcip_str, "PLUTO_MY_SOURCEIP='"); n = srcip_str + strlen(srcip_str); snprintf(n, sizeof(srcip_str)-strlen(srcip_str), "%H", sr->this.host_srcip); strncat(srcip_str, "' ", sizeof(srcip_str)); } if (sr->mark_in.value) { snprintf(mark_in, sizeof(mark_in), "PLUTO_MARK_IN='%u/0x%08x' ", sr->mark_in.value, sr->mark_in.mask); } if (sr->mark_out.value) { snprintf(mark_out, sizeof(mark_out), "PLUTO_MARK_OUT='%u/0x%08x' ", sr->mark_out.value, sr->mark_out.mask); } if (st && (st->nat_traversal & NAT_T_DETECTED)) { snprintf(udp_encap, sizeof(udp_encap), "PLUTO_UDP_ENC='%u' ", sr->that.host_port); } addrtot(&sr->this.host_addr, 0, me_str, sizeof(me_str)); snprintf(myid_str, sizeof(myid_str), "%Y", sr->this.id); escape_metachar(myid_str, secure_myid_str, sizeof(secure_myid_str)); subnettot(&sr->this.client, 0, myclient_str, sizeof(myclientnet_str)); networkof(&sr->this.client, &ta); addrtot(&ta, 0, myclientnet_str, sizeof(myclientnet_str)); maskof(&sr->this.client, &ta); addrtot(&ta, 0, myclientmask_str, sizeof(myclientmask_str)); if (c->xauth_identity && c->xauth_identity->get_type(c->xauth_identity) != ID_ANY) { snprintf(xauth_id_str, sizeof(xauth_id_str), "%Y", c->xauth_identity); escape_metachar(xauth_id_str, secure_xauth_id_str, sizeof(secure_xauth_id_str)); snprintf(xauth_id_str, sizeof(xauth_id_str), "PLUTO_XAUTH_ID='%s' ", secure_xauth_id_str); } addrtot(&sr->that.host_addr, 0, peer_str, sizeof(peer_str)); snprintf(peerid_str, sizeof(peerid_str), "%Y", sr->that.id); escape_metachar(peerid_str, secure_peerid_str, sizeof(secure_peerid_str)); subnettot(&sr->that.client, 0, peerclient_str, sizeof(peerclientnet_str)); networkof(&sr->that.client, &ta); addrtot(&ta, 0, peerclientnet_str, sizeof(peerclientnet_str)); maskof(&sr->that.client, &ta); addrtot(&ta, 0, peerclientmask_str, sizeof(peerclientmask_str)); for (p = pubkeys; p != NULL; p = p->next) { pubkey_t *key = p->key; key_type_t type = key->public_key->get_type(key->public_key); int pathlen; if (type == KEY_RSA && sr->that.id->equals(sr->that.id, key->id) && trusted_ca(key->issuer, sr->that.ca, &pathlen)) { if (key->issuer) { snprintf(peerca_str, BUF_LEN, "%Y", key->issuer); escape_metachar(peerca_str, secure_peerca_str, BUF_LEN); } else { secure_peerca_str[0] = '\0'; } break; } } if (-1 == snprintf(cmd, sizeof(cmd) , "2>&1 " /* capture stderr along with stdout */ "PLUTO_VERSION='1.1' " /* change VERSION when interface spec changes */ "PLUTO_VERB='%s%s' " "PLUTO_CONNECTION='%s' " "%s" /* optional PLUTO_NEXT_HOP */ "PLUTO_INTERFACE='%s' " "%s" /* optional PLUTO_HOST_ACCESS */ "PLUTO_REQID='%u' " "PLUTO_ME='%s' " "PLUTO_MY_ID='%s' " "PLUTO_MY_CLIENT='%s' " "PLUTO_MY_CLIENT_NET='%s' " "PLUTO_MY_CLIENT_MASK='%s' " "PLUTO_MY_PORT='%u' " "PLUTO_MY_PROTOCOL='%u' " "PLUTO_PEER='%s' " "PLUTO_PEER_ID='%s' " "PLUTO_PEER_CLIENT='%s' " "PLUTO_PEER_CLIENT_NET='%s' " "PLUTO_PEER_CLIENT_MASK='%s' " "PLUTO_PEER_PORT='%u' " "PLUTO_PEER_PROTOCOL='%u' " "PLUTO_PEER_CA='%s' " "%s" /* optional PLUTO_MY_SRCIP */ "%s" /* optional PLUTO_XAUTH_ID */ "%s" /* optional PLUTO_MARK_IN */ "%s" /* optional PLUTO_MARK_OUT */ "%s" /* optional PLUTO_UDP_ENC */ "%s" /* actual script */ , verb, verb_suffix , c->name , nexthop_str , c->interface->vname , sr->this.hostaccess? "PLUTO_HOST_ACCESS='1' " : "" , sr->reqid , me_str , secure_myid_str , myclient_str , myclientnet_str , myclientmask_str , sr->this.port , sr->this.protocol , peer_str , secure_peerid_str , peerclient_str , peerclientnet_str , peerclientmask_str , sr->that.port , sr->that.protocol , secure_peerca_str , srcip_str , xauth_id_str , mark_in , mark_out , udp_encap , sr->this.updown == NULL? DEFAULT_UPDOWN : sr->this.updown)) { loglog(RC_LOG_SERIOUS, "%s%s command too long!", verb, verb_suffix); return FALSE; } } DBG(DBG_CONTROL, DBG_log("executing %s%s: %s" , verb, verb_suffix, cmd)); /* invoke the script, catching stderr and stdout * It may be of concern that some file descriptors will * be inherited. For the ones under our control, we * have done fcntl(fd, F_SETFD, FD_CLOEXEC) to prevent this. * Any used by library routines (perhaps the resolver or syslog) * will remain. */ FILE *f = popen(cmd, "r"); if (f == NULL) { loglog(RC_LOG_SERIOUS, "unable to popen %s%s command", verb, verb_suffix); return FALSE; } /* log any output */ for (;;) { /* if response doesn't fit in this buffer, it will be folded */ char resp[256]; if (fgets(resp, sizeof(resp), f) == NULL) { if (ferror(f)) { log_errno((e, "fgets failed on output of %s%s command" , verb, verb_suffix)); return FALSE; } else { passert(feof(f)); break; } } else { char *e = resp + strlen(resp); if (e > resp && e[-1] == '\n') e[-1] = '\0'; /* trim trailing '\n' */ plog("%s%s output: %s", verb, verb_suffix, resp); } } /* report on and react to return code */ { int r = pclose(f); if (r == -1) { log_errno((e, "pclose failed for %s%s command" , verb, verb_suffix)); return FALSE; } else if (WIFEXITED(r)) { if (WEXITSTATUS(r) != 0) { loglog(RC_LOG_SERIOUS, "%s%s command exited with status %d" , verb, verb_suffix, WEXITSTATUS(r)); return FALSE; } } else if (WIFSIGNALED(r)) { loglog(RC_LOG_SERIOUS, "%s%s command exited with signal %d" , verb, verb_suffix, WTERMSIG(r)); return FALSE; } else { loglog(RC_LOG_SERIOUS, "%s%s command exited with unknown status %d" , verb, verb_suffix, r); return FALSE; } } return TRUE; } /* Check that we can route (and eroute). Diagnose if we cannot. */ enum routability { route_impossible = 0, route_easy = 1, route_nearconflict = 2, route_farconflict = 3 }; static enum routability could_route(connection_t *c) { struct spd_route *esr, *rosr; connection_t *ero /* who, if anyone, owns our eroute? */ , *ro = route_owner(c, &rosr, &ero, &esr); /* who owns our route? */ /* it makes no sense to route a connection that is ISAKMP-only */ if (!NEVER_NEGOTIATE(c->policy) && !HAS_IPSEC_POLICY(c->policy)) { loglog(RC_ROUTE, "cannot route an ISAKMP-only connection"); return route_impossible; } /* if this is a Road Warrior template, we cannot route. * Opportunistic template is OK. */ if (c->kind == CK_TEMPLATE && !(c->policy & POLICY_OPPO)) { loglog(RC_ROUTE, "cannot route Road Warrior template"); return route_impossible; } /* if we don't know nexthop, we cannot route */ if (isanyaddr(&c->spd.this.host_nexthop)) { loglog(RC_ROUTE, "cannot route connection without knowing our nexthop"); return route_impossible; } /* if routing would affect IKE messages, reject */ if (c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT && c->spd.this.host_port != IKE_UDP_PORT && addrinsubnet(&c->spd.that.host_addr, &c->spd.that.client)) { loglog(RC_LOG_SERIOUS, "cannot install route: peer is within its client"); return route_impossible; } /* If there is already a route for peer's client subnet * and it disagrees about interface or nexthop, we cannot steal it. * Note: if this connection is already routed (perhaps for another * state object), the route will agree. * This is as it should be -- it will arise during rekeying. */ if (ro != NULL && !routes_agree(ro, c)) { loglog(RC_LOG_SERIOUS, "cannot route -- route already in use for \"%s\"" , ro->name); return route_impossible; /* another connection already using the eroute */ } /* if there is an eroute for another connection, there is a problem */ if (ero != NULL && ero != c) { connection_t *ero2, *ero_top; connection_t *inside, *outside; /* * note, wavesec (PERMANENT) goes *outside* and * OE goes *inside* (TEMPLATE) */ inside = NULL; outside= NULL; if (ero->kind == CK_PERMANENT && c->kind == CK_TEMPLATE) { outside = ero; inside = c; } else if (c->kind == CK_PERMANENT && ero->kind == CK_TEMPLATE) { outside = c; inside = ero; } /* okay, check again, with correct order */ if (outside && outside->kind == CK_PERMANENT && inside && inside->kind == CK_TEMPLATE) { char inst[CONN_INST_BUF]; /* this is a co-terminal attempt of the "near" kind. */ /* when chaining, we chain from inside to outside */ /* XXX permit multiple deep connections? */ passert(inside->policy_next == NULL); inside->policy_next = outside; /* since we are going to steal the eroute from the secondary * policy, we need to make sure that it no longer thinks that * it owns the eroute. */ outside->spd.eroute_owner = SOS_NOBODY; outside->spd.routing = RT_UNROUTED_KEYED; /* set the priority of the new eroute owner to be higher * than that of the current eroute owner */ inside->prio = outside->prio + 1; fmt_conn_instance(inside, inst); loglog(RC_LOG_SERIOUS , "conflict on eroute (%s), switching eroute to %s and linking %s" , inst, inside->name, outside->name); return route_nearconflict; } /* look along the chain of policies for one with the same name */ ero_top = ero; for (ero2 = ero; ero2 != NULL; ero2 = ero->policy_next) { if (ero2->kind == CK_TEMPLATE && streq(ero2->name, c->name)) break; } /* If we fell of the end of the list, then we found no TEMPLATE * so there must be a conflict that we can't resolve. * As the names are not equal, then we aren't replacing/rekeying. */ if (ero2 == NULL) { char inst[CONN_INST_BUF]; fmt_conn_instance(ero, inst); loglog(RC_LOG_SERIOUS , "cannot install eroute -- it is in use for \"%s\"%s #%lu" , ero->name, inst, esr->eroute_owner); return route_impossible; } } return route_easy; } bool trap_connection(connection_t *c) { switch (could_route(c)) { case route_impossible: return FALSE; case route_nearconflict: case route_easy: /* RT_ROUTED_TUNNEL is treated specially: we don't override * because we don't want to lose track of the IPSEC_SAs etc. */ if (c->spd.routing < RT_ROUTED_TUNNEL) { return route_and_eroute(c, &c->spd, NULL); } return TRUE; case route_farconflict: return FALSE; } return FALSE; } /** * Delete any eroute for a connection and unroute it if route isn't shared */ void unroute_connection(connection_t *c) { struct spd_route *sr; enum routing_t cr; for (sr = &c->spd; sr; sr = sr->next) { cr = sr->routing; if (erouted(cr)) { /* cannot handle a live one */ passert(sr->routing != RT_ROUTED_TUNNEL); shunt_eroute(c, sr, RT_UNROUTED, ERO_DELETE, "delete"); } sr->routing = RT_UNROUTED; /* do now so route_owner won't find us */ /* only unroute if no other connection shares it */ if (routed(cr) && route_owner(c, NULL, NULL, NULL) == NULL) { (void) do_command(c, sr, NULL, "unroute"); } } } static void set_text_said(char *text_said, const ip_address *dst, ipsec_spi_t spi, int proto) { ip_said said; initsaid(dst, spi, proto, &said); satot(&said, 0, text_said, SATOT_BUF); } /** * Setup an IPsec route entry. * op is one of the ERO_* operators. */ static bool raw_eroute(const ip_address *this_host, const ip_subnet *this_client, const ip_address *that_host, const ip_subnet *that_client, mark_t mark, ipsec_spi_t spi, unsigned int proto, unsigned int satype, unsigned int transport_proto, ipsec_sa_cfg_t *sa, unsigned int op, const char *opname USED_BY_DEBUG) { traffic_selector_t *ts_src, *ts_dst; host_t *host_src, *host_dst; policy_type_t type = POLICY_IPSEC; policy_dir_t dir = POLICY_OUT; char text_said[SATOT_BUF]; bool ok = TRUE, routed = FALSE, deleting = (op & ERO_MASK) == ERO_DELETE, replacing = op & (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT); set_text_said(text_said, that_host, spi, proto); DBG(DBG_CONTROL | DBG_KERNEL, { int sport = ntohs(portof(&this_client->addr)); int dport = ntohs(portof(&that_client->addr)); char mybuf[SUBNETTOT_BUF]; char peerbuf[SUBNETTOT_BUF]; subnettot(this_client, 0, mybuf, sizeof(mybuf)); subnettot(that_client, 0, peerbuf, sizeof(peerbuf)); DBG_log("%s eroute %s:%d -> %s:%d => %s:%d" , opname, mybuf, sport, peerbuf, dport , text_said, transport_proto); }); if (satype == SADB_X_SATYPE_INT) { switch (ntohl(spi)) { case SPI_PASS: type = POLICY_PASS; break; case SPI_DROP: case SPI_REJECT: type = POLICY_DROP; break; case SPI_TRAP: case SPI_TRAPSUBNET: case SPI_HOLD: if (op & (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT)) { return TRUE; } routed = TRUE; break; } } if (op & (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT)) { dir = POLICY_IN; } host_src = host_create_from_sockaddr((sockaddr_t*)this_host); host_dst = host_create_from_sockaddr((sockaddr_t*)that_host); ts_src = traffic_selector_from_subnet(this_client, transport_proto); ts_dst = traffic_selector_from_subnet(that_client, transport_proto); if (deleting || replacing) { hydra->kernel_interface->del_policy(hydra->kernel_interface, ts_src, ts_dst, dir, mark, routed); } if (!deleting) { ok = hydra->kernel_interface->add_policy(hydra->kernel_interface, host_src, host_dst, ts_src, ts_dst, dir, type, sa, mark, routed) == SUCCESS; } if (dir == POLICY_IN) { /* handle forward policy */ dir = POLICY_FWD; if (deleting || replacing) { hydra->kernel_interface->del_policy(hydra->kernel_interface, ts_src, ts_dst, dir, mark, routed); } if (!deleting && ok && (sa->mode == MODE_TUNNEL || satype == SADB_X_SATYPE_INT)) { ok = hydra->kernel_interface->add_policy(hydra->kernel_interface, host_src, host_dst, ts_src, ts_dst, dir, type, sa, mark, routed) == SUCCESS; } } host_src->destroy(host_src); host_dst->destroy(host_dst); ts_src->destroy(ts_src); ts_dst->destroy(ts_dst); return ok; } static bool eroute_connection(struct spd_route *sr, ipsec_spi_t spi, unsigned int proto, unsigned int satype, ipsec_sa_cfg_t *sa, unsigned int op, const char *opname) { const ip_address *peer = &sr->that.host_addr; char buf2[256]; bool ok; snprintf(buf2, sizeof(buf2) , "eroute_connection %s", opname); if (proto == SA_INT) { peer = aftoinfo(addrtypeof(peer))->any; } ok = raw_eroute(peer, &sr->that.client, &sr->this.host_addr, &sr->this.client, sr->mark_in, spi, proto, satype, sr->this.protocol, sa, op | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT), buf2); return raw_eroute(&sr->this.host_addr, &sr->this.client, peer, &sr->that.client, sr->mark_out, spi, proto, satype, sr->this.protocol, sa, op, buf2) && ok; } /* assign a bare hold to a connection */ bool assign_hold(connection_t *c USED_BY_DEBUG, struct spd_route *sr, int transport_proto, const ip_address *src, const ip_address *dst) { /* either the automatically installed %hold eroute is broad enough * or we try to add a broader one and delete the automatic one. * Beware: this %hold might be already handled, but still squeak * through because of a race. */ enum routing_t ro = sr->routing /* routing, old */ , rn = ro; /* routing, new */ passert(LHAS(LELEM(CK_PERMANENT) | LELEM(CK_INSTANCE), c->kind)); /* figure out what routing should become */ switch (ro) { case RT_UNROUTED: rn = RT_UNROUTED_HOLD; break; case RT_ROUTED_PROSPECTIVE: rn = RT_ROUTED_HOLD; break; default: /* no change: this %hold is old news and should just be deleted */ break; } /* We need a broad %hold * First we ensure that there is a broad %hold. * There may already be one (race condition): no need to create one. * There may already be a %trap: replace it. * There may not be any broad eroute: add %hold. */ if (rn != ro) { if (erouted(ro) ? !eroute_connection(sr, htonl(SPI_HOLD), SA_INT, SADB_X_SATYPE_INT, &null_ipsec_sa, ERO_REPLACE, "replace %trap with broad %hold") : !eroute_connection(sr, htonl(SPI_HOLD), SA_INT, SADB_X_SATYPE_INT, &null_ipsec_sa, ERO_ADD, "add broad %hold")) { return FALSE; } } sr->routing = rn; return TRUE; } /* install or remove eroute for SA Group */ static bool sag_eroute(struct state *st, struct spd_route *sr, unsigned op, const char *opname) { u_int inner_proto, inner_satype; ipsec_spi_t inner_spi = 0; ipsec_sa_cfg_t sa = { .mode = MODE_TRANSPORT, }; bool tunnel = FALSE; if (st->st_ah.present) { inner_spi = st->st_ah.attrs.spi; inner_proto = SA_AH; inner_satype = SADB_SATYPE_AH; sa.ah.use = TRUE; sa.ah.spi = inner_spi; tunnel |= st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL; } if (st->st_esp.present) { inner_spi = st->st_esp.attrs.spi; inner_proto = SA_ESP; inner_satype = SADB_SATYPE_ESP; sa.esp.use = TRUE; sa.esp.spi = inner_spi; tunnel |= st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL; } if (st->st_ipcomp.present) { inner_spi = st->st_ipcomp.attrs.spi; inner_proto = SA_COMP; inner_satype = SADB_X_SATYPE_COMP; sa.ipcomp.transform = st->st_ipcomp.attrs.transid; sa.ipcomp.cpi = htons(ntohl(inner_spi)); tunnel |= st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL; } if (!sa.ah.use && !sa.esp.use && !sa.ipcomp.transform) { impossible(); /* no transform at all! */ } if (tunnel) { inner_spi = st->st_tunnel_out_spi; inner_proto = SA_IPIP; inner_satype = SADB_X_SATYPE_IPIP; sa.mode = MODE_TUNNEL; } sa.reqid = sr->reqid; return eroute_connection(sr, inner_spi, inner_proto, inner_satype, &sa, op, opname); } /* compute a (host-order!) SPI to implement the policy in connection c */ ipsec_spi_t shunt_policy_spi(connection_t *c, bool prospective) { /* note: these are in host order :-( */ static const ipsec_spi_t shunt_spi[] = { SPI_TRAP, /* --initiateontraffic */ SPI_PASS, /* --pass */ SPI_DROP, /* --drop */ SPI_REJECT, /* --reject */ }; static const ipsec_spi_t fail_spi[] = { 0, /* --none*/ SPI_PASS, /* --failpass */ SPI_DROP, /* --faildrop */ SPI_REJECT, /* --failreject */ }; return prospective ? shunt_spi[(c->policy & POLICY_SHUNT_MASK) >> POLICY_SHUNT_SHIFT] : fail_spi[(c->policy & POLICY_FAIL_MASK) >> POLICY_FAIL_SHIFT]; } /* Add/replace/delete a shunt eroute. * Such an eroute determines the fate of packets without the use * of any SAs. These are defaults, in effect. * If a negotiation has not been attempted, use %trap. * If negotiation has failed, the choice between %trap/%pass/%drop/%reject * is specified in the policy of connection c. */ static bool shunt_eroute(connection_t *c, struct spd_route *sr, enum routing_t rt_kind, unsigned int op, const char *opname) { /* We are constructing a special SAID for the eroute. * The destination doesn't seem to matter, but the family does. * The protocol is SA_INT -- mark this as shunt. * The satype has no meaning, but is required for PF_KEY header! * The SPI signifies the kind of shunt. */ ipsec_spi_t spi = shunt_policy_spi(c, rt_kind == RT_ROUTED_PROSPECTIVE); if (spi == 0) { /* we're supposed to end up with no eroute: rejig op and opname */ switch (op) { case ERO_REPLACE: /* replace with nothing == delete */ op = ERO_DELETE; opname = "delete"; break; case ERO_ADD: /* add nothing == do nothing */ return TRUE; case ERO_DELETE: /* delete remains delete */ break; default: bad_case(op); } } if (sr->routing == RT_ROUTED_ECLIPSED && c->kind == CK_TEMPLATE) { /* We think that we have an eroute, but we don't. * Adjust the request and account for eclipses. */ passert(eclipsable(sr)); switch (op) { case ERO_REPLACE: /* really an add */ op = ERO_ADD; opname = "replace eclipsed"; eclipse_count--; break; case ERO_DELETE: /* delete unnecessary: we don't actually have an eroute */ eclipse_count--; return TRUE; case ERO_ADD: default: bad_case(op); } } else if (eclipse_count > 0 && op == ERO_DELETE && eclipsable(sr)) { /* maybe we are uneclipsing something */ struct spd_route *esr; connection_t *ue = eclipsed(c, &esr); if (ue != NULL) { esr->routing = RT_ROUTED_PROSPECTIVE; return shunt_eroute(ue, esr , RT_ROUTED_PROSPECTIVE, ERO_REPLACE, "restoring eclipsed"); } } return eroute_connection(sr, htonl(spi), SA_INT, SADB_X_SATYPE_INT, &null_ipsec_sa, op, opname); } static bool setup_half_ipsec_sa(struct state *st, bool inbound) { host_t *host_src, *host_dst; connection_t *c = st->st_connection; struct end *src, *dst; ipsec_mode_t mode = MODE_TRANSPORT; ipsec_sa_cfg_t sa = { .mode = 0 }; lifetime_cfg_t lt_none = { .time = { .rekey = 0 } }; mark_t mark; bool ok = TRUE; /* SPIs, saved for undoing, if necessary */ struct kernel_sa said[EM_MAXRELSPIS], *said_next = said; if (inbound) { src = &c->spd.that; dst = &c->spd.this; mark = c->spd.mark_in; } else { src = &c->spd.this; dst = &c->spd.that; mark = c->spd.mark_out; } host_src = host_create_from_sockaddr((sockaddr_t*)&src->host_addr); host_dst = host_create_from_sockaddr((sockaddr_t*)&dst->host_addr); if (st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL || st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL || st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) { mode = MODE_TUNNEL; } sa.mode = mode; sa.reqid = c->spd.reqid; memset(said, 0, sizeof(said)); /* set up IPCOMP SA, if any */ if (st->st_ipcomp.present) { ipsec_spi_t ipcomp_spi = inbound ? st->st_ipcomp.our_spi : st->st_ipcomp.attrs.spi; switch (st->st_ipcomp.attrs.transid) { case IPCOMP_DEFLATE: break; default: loglog(RC_LOG_SERIOUS, "IPCOMP transform %s not implemented", enum_name(&ipcomp_transformid_names, st->st_ipcomp.attrs.transid)); goto fail; } sa.ipcomp.cpi = htons(ntohl(ipcomp_spi)); sa.ipcomp.transform = st->st_ipcomp.attrs.transid; said_next->spi = ipcomp_spi; said_next->proto = IPPROTO_COMP; if (hydra->kernel_interface->add_sa(hydra->kernel_interface, host_src, host_dst, ipcomp_spi, said_next->proto, c->spd.reqid, mark, 0, <_none, ENCR_UNDEFINED, chunk_empty, AUTH_UNDEFINED, chunk_empty, mode, st->st_ipcomp.attrs.transid, 0 /* cpi */, FALSE, FALSE, inbound, NULL, NULL) != SUCCESS) { goto fail; } said_next++; mode = MODE_TRANSPORT; } /* set up ESP SA, if any */ if (st->st_esp.present) { ipsec_spi_t esp_spi = inbound ? st->st_esp.our_spi : st->st_esp.attrs.spi; u_char *esp_dst_keymat = inbound ? st->st_esp.our_keymat : st->st_esp.peer_keymat; bool encap = st->nat_traversal & NAT_T_DETECTED; encryption_algorithm_t enc_alg; integrity_algorithm_t auth_alg; const struct esp_info *ei; chunk_t enc_key, auth_key; u_int16_t key_len; if ((ei = kernel_alg_esp_info(st->st_esp.attrs.transid, st->st_esp.attrs.auth)) == NULL) { loglog(RC_LOG_SERIOUS, "ESP transform %s / auth %s" " not implemented yet", enum_name(&esp_transform_names, st->st_esp.attrs.transid), enum_name(&auth_alg_names, st->st_esp.attrs.auth)); goto fail; } key_len = st->st_esp.attrs.key_len / 8; if (key_len) { /* XXX: must change to check valid _range_ key_len */ if (key_len > ei->enckeylen) { loglog(RC_LOG_SERIOUS, "ESP transform %s: key_len=%d > %d", enum_name(&esp_transform_names, st->st_esp.attrs.transid), (int)key_len, (int)ei->enckeylen); goto fail; } } else { key_len = ei->enckeylen; } switch (ei->transid) { case ESP_3DES: /* 168 bits in kernel, need 192 bits for keymat_len */ if (key_len == 21) { key_len = 24; } break; case ESP_DES: /* 56 bits in kernel, need 64 bits for keymat_len */ if (key_len == 7) { key_len = 8; } break; case ESP_AES_CCM_8: case ESP_AES_CCM_12: case ESP_AES_CCM_16: key_len += 3; break; case ESP_AES_GCM_8: case ESP_AES_GCM_12: case ESP_AES_GCM_16: case ESP_AES_CTR: case ESP_AES_GMAC: key_len += 4; break; default: break; } if (encap) { host_src->set_port(host_src, src->host_port); host_dst->set_port(host_dst, dst->host_port); // st->nat_oa is currently unused } /* divide up keying material */ enc_alg = encryption_algorithm_from_esp(st->st_esp.attrs.transid); enc_key.ptr = esp_dst_keymat; enc_key.len = key_len; auth_alg = integrity_algorithm_from_esp(st->st_esp.attrs.auth); auth_alg = auth_alg ? : AUTH_UNDEFINED; auth_key.ptr = esp_dst_keymat + key_len; auth_key.len = ei->authkeylen; sa.esp.use = TRUE; sa.esp.spi = esp_spi; said_next->spi = esp_spi; said_next->proto = IPPROTO_ESP; if (hydra->kernel_interface->add_sa(hydra->kernel_interface, host_src, host_dst, esp_spi, said_next->proto, c->spd.reqid, mark, 0, <_none, enc_alg, enc_key, auth_alg, auth_key, mode, IPCOMP_NONE, 0 /* cpi */, encap, FALSE, inbound, NULL, NULL) != SUCCESS) { goto fail; } said_next++; mode = MODE_TRANSPORT; } /* set up AH SA, if any */ if (st->st_ah.present) { ipsec_spi_t ah_spi = inbound ? st->st_ah.our_spi : st->st_ah.attrs.spi; u_char *ah_dst_keymat = inbound ? st->st_ah.our_keymat : st->st_ah.peer_keymat; integrity_algorithm_t auth_alg; chunk_t auth_key; auth_alg = integrity_algorithm_from_esp(st->st_ah.attrs.auth); auth_key.ptr = ah_dst_keymat; auth_key.len = st->st_ah.keymat_len; sa.ah.use = TRUE; sa.ah.spi = ah_spi; said_next->spi = ah_spi; said_next->proto = IPPROTO_AH; if (hydra->kernel_interface->add_sa(hydra->kernel_interface, host_src, host_dst, ah_spi, said_next->proto, c->spd.reqid, mark, 0, <_none, ENCR_UNDEFINED, chunk_empty, auth_alg, auth_key, mode, IPCOMP_NONE, 0 /* cpi */, FALSE, FALSE, inbound, NULL, NULL) != SUCCESS) { goto fail; } said_next++; mode = MODE_TRANSPORT; } goto cleanup; fail: /* undo the done SPIs */ while (said_next-- != said) { hydra->kernel_interface->del_sa(hydra->kernel_interface, host_src, host_dst, said_next->spi, said_next->proto, 0 /* cpi */, mark); } ok = FALSE; cleanup: host_src->destroy(host_src); host_dst->destroy(host_dst); return ok; } static bool teardown_half_ipsec_sa(struct state *st, bool inbound) { connection_t *c = st->st_connection; const struct end *src, *dst; host_t *host_src, *host_dst; ipsec_spi_t spi; mark_t mark; bool result = TRUE; if (inbound) { src = &c->spd.that; dst = &c->spd.this; mark = c->spd.mark_in; } else { src = &c->spd.this; dst = &c->spd.that; mark = c->spd.mark_out; } host_src = host_create_from_sockaddr((sockaddr_t*)&src->host_addr); host_dst = host_create_from_sockaddr((sockaddr_t*)&dst->host_addr); if (st->st_ah.present) { spi = inbound ? st->st_ah.our_spi : st->st_ah.attrs.spi; result &= hydra->kernel_interface->del_sa(hydra->kernel_interface, host_src, host_dst, spi, IPPROTO_AH, 0 /* cpi */, mark) == SUCCESS; } if (st->st_esp.present) { spi = inbound ? st->st_esp.our_spi : st->st_esp.attrs.spi; result &= hydra->kernel_interface->del_sa(hydra->kernel_interface, host_src, host_dst, spi, IPPROTO_ESP, 0 /* cpi */, mark) == SUCCESS; } if (st->st_ipcomp.present) { spi = inbound ? st->st_ipcomp.our_spi : st->st_ipcomp.attrs.spi; result &= hydra->kernel_interface->del_sa(hydra->kernel_interface, host_src, host_dst, spi, IPPROTO_COMP, 0 /* cpi */, mark) == SUCCESS; } host_src->destroy(host_src); host_dst->destroy(host_dst); return result; } /* * get information about a given sa */ bool get_sa_info(struct state *st, bool inbound, u_int *bytes, time_t *use_time) { connection_t *c = st->st_connection; traffic_selector_t *ts_src = NULL, *ts_dst = NULL; host_t *host_src = NULL, *host_dst = NULL; const struct end *src, *dst; ipsec_spi_t spi; mark_t mark; u_int64_t bytes_kernel = 0; bool result = FALSE; *use_time = UNDEFINED_TIME; if (!st->st_esp.present) { goto failed; } if (inbound) { src = &c->spd.that; dst = &c->spd.this; mark = c->spd.mark_in; spi = st->st_esp.our_spi; } else { src = &c->spd.this; dst = &c->spd.that; mark = c->spd.mark_out; spi = st->st_esp.attrs.spi; } host_src = host_create_from_sockaddr((sockaddr_t*)&src->host_addr); host_dst = host_create_from_sockaddr((sockaddr_t*)&dst->host_addr); switch(hydra->kernel_interface->query_sa(hydra->kernel_interface, host_src, host_dst, spi, IPPROTO_ESP, mark, &bytes_kernel)) { case FAILED: goto failed; case SUCCESS: *bytes = bytes_kernel; break; case NOT_SUPPORTED: default: break; } if (st->st_serialno == c->spd.eroute_owner) { u_int32_t time_kernel; ts_src = traffic_selector_from_subnet(&src->client, src->protocol); ts_dst = traffic_selector_from_subnet(&dst->client, dst->protocol); if (hydra->kernel_interface->query_policy(hydra->kernel_interface, ts_src, ts_dst, inbound ? POLICY_IN : POLICY_OUT, mark, &time_kernel) != SUCCESS) { goto failed; } *use_time = time_kernel; if (inbound && st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) { if (hydra->kernel_interface->query_policy(hydra->kernel_interface, ts_src, ts_dst, POLICY_FWD, mark, &time_kernel) != SUCCESS) { goto failed; } *use_time = max(*use_time, time_kernel); } } result = TRUE; failed: DESTROY_IF(host_src); DESTROY_IF(host_dst); DESTROY_IF(ts_src); DESTROY_IF(ts_dst); return result; } /** * Handler for kernel events (called by thread-pool thread) */ kernel_listener_t *kernel_handler; /** * Data for acquire events */ typedef struct { /** Subnets */ ip_subnet src, dst; /** Transport protocol */ int proto; } acquire_data_t; /** * Callback for acquire events (called by main thread) */ void handle_acquire(acquire_data_t *this) { record_and_initiate_opportunistic(&this->src, &this->dst, this->proto, "%acquire"); } METHOD(kernel_listener_t, acquire, bool, kernel_listener_t *this, u_int32_t reqid, traffic_selector_t *src_ts, traffic_selector_t *dst_ts) { if (src_ts && dst_ts) { acquire_data_t *data; DBG(DBG_CONTROL, DBG_log("creating acquire event for policy %R === %R " "with reqid {%u}", src_ts, dst_ts, reqid)); INIT(data, .src = subnet_from_traffic_selector(src_ts), .dst = subnet_from_traffic_selector(dst_ts), .proto = src_ts->get_protocol(src_ts), ); pluto->events->queue(pluto->events, (void*)handle_acquire, data, free); } else { DBG(DBG_CONTROL, DBG_log("ignoring acquire without traffic selectors for policy " "with reqid {%u}", reqid)); } DESTROY_IF(src_ts); DESTROY_IF(dst_ts); return TRUE; } /** * Data for mapping events */ typedef struct { /** reqid, spi of affected SA */ u_int32_t reqid, spi; /** new endpont */ ip_address new_end; } mapping_data_t; /** * Callback for mapping events (called by main thread) */ void handle_mapping(mapping_data_t *this) { process_nat_t_new_mapping(this->reqid, this->spi, &this->new_end); } METHOD(kernel_listener_t, mapping, bool, kernel_listener_t *this, u_int32_t reqid, u_int32_t spi, host_t *remote) { mapping_data_t *data; DBG(DBG_CONTROL, DBG_log("creating mapping event for SA with SPI %.8x and reqid {%u}", spi, reqid)); INIT(data, .reqid = reqid, .spi = spi, .new_end = *(ip_address*)remote->get_sockaddr(remote), ); pluto->events->queue(pluto->events, (void*)handle_mapping, data, free); return TRUE; } void init_kernel(void) { /* register SA types that we can negotiate */ can_do_IPcomp = FALSE; /* until we get a response from the kernel */ pfkey_register(); INIT(kernel_handler, .acquire = _acquire, .mapping = _mapping, ); hydra->kernel_interface->add_listener(hydra->kernel_interface, kernel_handler); } void kernel_finalize() { hydra->kernel_interface->remove_listener(hydra->kernel_interface, kernel_handler); free(kernel_handler); } /* Note: install_inbound_ipsec_sa is only used by the Responder. * The Responder will subsequently use install_ipsec_sa for the outbound. * The Initiator uses install_ipsec_sa to install both at once. */ bool install_inbound_ipsec_sa(struct state *st) { connection_t *const c = st->st_connection; /* If our peer has a fixed-address client, check if we already * have a route for that client that conflicts. We will take this * as proof that that route and the connections using it are * obsolete and should be eliminated. Interestingly, this is * the only case in which we can tell that a connection is obsolete. */ passert(c->kind == CK_PERMANENT || c->kind == CK_INSTANCE); if (c->spd.that.has_client) { for (;;) { struct spd_route *esr; connection_t *o = route_owner(c, &esr, NULL, NULL); if (o == NULL) { break; /* nobody has a route */ } /* note: we ignore the client addresses at this end */ if (sameaddr(&o->spd.that.host_addr, &c->spd.that.host_addr) && o->interface == c->interface) { break; /* existing route is compatible */ } if (o->kind == CK_TEMPLATE && streq(o->name, c->name)) { break; /* ??? is this good enough?? */ } loglog(RC_LOG_SERIOUS, "route to peer's client conflicts with \"%s\" %s; releasing old connection to free the route" , o->name, ip_str(&o->spd.that.host_addr)); release_connection(o, FALSE); } } DBG(DBG_CONTROL, DBG_log("install_inbound_ipsec_sa() checking if we can route")); /* check that we will be able to route and eroute */ switch (could_route(c)) { case route_easy: case route_nearconflict: break; default: return FALSE; } /* (attempt to) actually set up the SAs */ return setup_half_ipsec_sa(st, TRUE); } /* Install a route and then a prospective shunt eroute or an SA group eroute. * Assumption: could_route gave a go-ahead. * Any SA Group must have already been created. * On failure, steps will be unwound. */ bool route_and_eroute(connection_t *c, struct spd_route *sr, struct state *st) { struct spd_route *esr; struct spd_route *rosr; connection_t *ero /* who, if anyone, owns our eroute? */ , *ro = route_owner(c, &rosr, &ero, &esr); bool eroute_installed = FALSE , firewall_notified = FALSE , route_installed = FALSE; connection_t *ero_top; DBG(DBG_CONTROLMORE, DBG_log("route_and_eroute with c: %s (next: %s) ero:%s esr:{%p} ro:%s rosr:{%p} and state: %lu" , c->name , (c->policy_next ? c->policy_next->name : "none") , ero ? ero->name : "null" , esr , ro ? ro->name : "null" , rosr , st ? st->st_serialno : 0)); /* look along the chain of policies for one with the same name */ ero_top = ero; #if 0 /* XXX - mcr this made sense before, and likely will make sense * again, so I'l leaving this to remind me what is up */ if (ero!= NULL && ero->routing == RT_UNROUTED_KEYED) ero = NULL; for (ero2 = ero; ero2 != NULL; ero2 = ero->policy_next) if ((ero2->kind == CK_TEMPLATE || ero2->kind==CK_SECONDARY) && streq(ero2->name, c->name)) break; #endif /* install the eroute */ if (ero != NULL) { /* We're replacing an eroute */ /* if no state provided, then install a shunt for later */ if (st == NULL) { eroute_installed = shunt_eroute(c, sr, RT_ROUTED_PROSPECTIVE , ERO_REPLACE, "replace"); } else { eroute_installed = sag_eroute(st, sr, ERO_REPLACE, "replace"); } #if 0 /* XXX - MCR. I previously felt that this was a bogus check */ if (ero != NULL && ero != c && esr != sr) { /* By elimination, we must be eclipsing ero. Check. */ passert(ero->kind == CK_TEMPLATE && streq(ero->name, c->name)); passert(LHAS(LELEM(RT_ROUTED_PROSPECTIVE) | LELEM(RT_ROUTED_ECLIPSED) , esr->routing)); passert(samesubnet(&esr->this.client, &sr->this.client) && samesubnet(&esr->that.client, &sr->that.client)); } #endif } else { /* we're adding an eroute */ /* if no state provided, then install a shunt for later */ if (st == NULL) { eroute_installed = shunt_eroute(c, sr, RT_ROUTED_PROSPECTIVE , ERO_ADD, "add"); } else { eroute_installed = sag_eroute(st, sr, ERO_ADD, "add"); } } /* notify the firewall of a new tunnel */ if (eroute_installed) { /* do we have to notify the firewall? Yes, if we are installing * a tunnel eroute and the firewall wasn't notified * for a previous tunnel with the same clients. Any Previous * tunnel would have to be for our connection, so the actual * test is simple. */ firewall_notified = st == NULL /* not a tunnel eroute */ || sr->eroute_owner != SOS_NOBODY /* already notified */ || do_command(c, sr, st, "up"); /* go ahead and notify */ } /* install the route */ DBG(DBG_CONTROL, DBG_log("route_and_eroute: firewall_notified: %s" , firewall_notified ? "true" : "false")); if (!firewall_notified) { /* we're in trouble -- don't do routing */ } else if (ro == NULL) { /* a new route: no deletion required, but preparation is */ (void) do_command(c, sr, st, "prepare"); /* just in case; ignore failure */ route_installed = do_command(c, sr, st, "route"); } else if (routed(sr->routing) || routes_agree(ro, c)) { route_installed = TRUE; /* nothing to be done */ } else { /* Some other connection must own the route * and the route must disagree. But since could_route * must have allowed our stealing it, we'll do so. * * A feature of LINUX allows us to install the new route * before deleting the old if the nexthops differ. * This reduces the "window of vulnerability" when packets * might flow in the clear. */ if (sameaddr(&sr->this.host_nexthop, &esr->this.host_nexthop)) { (void) do_command(ro, sr, st, "unroute"); route_installed = do_command(c, sr, st, "route"); } else { route_installed = do_command(c, sr, st, "route"); (void) do_command(ro, sr, st, "unroute"); } /* record unrouting */ if (route_installed) { do { passert(!erouted(rosr->routing)); rosr->routing = RT_UNROUTED; /* no need to keep old value */ ro = route_owner(c, &rosr, NULL, NULL); } while (ro != NULL); } } /* all done -- clean up */ if (route_installed) { /* Success! */ if (ero != NULL && ero != c) { /* check if ero is an ancestor of c. */ connection_t *ero2; for (ero2 = c; ero2 != NULL && ero2 != c; ero2 = ero2->policy_next) ; if (ero2 == NULL) { /* By elimination, we must be eclipsing ero. Checked above. */ if (ero->spd.routing != RT_ROUTED_ECLIPSED) { ero->spd.routing = RT_ROUTED_ECLIPSED; eclipse_count++; } } } if (st == NULL) { passert(sr->eroute_owner == SOS_NOBODY); sr->routing = RT_ROUTED_PROSPECTIVE; } else { char cib[CONN_INST_BUF]; sr->routing = RT_ROUTED_TUNNEL; DBG(DBG_CONTROL, DBG_log("route_and_eroute: instance \"%s\"%s, setting eroute_owner {spd=%p,sr=%p} to #%ld (was #%ld) (newest_ipsec_sa=#%ld)" , st->st_connection->name , (fmt_conn_instance(st->st_connection, cib), cib) , &st->st_connection->spd, sr , st->st_serialno , sr->eroute_owner , st->st_connection->newest_ipsec_sa)); sr->eroute_owner = st->st_serialno; } return TRUE; } else { /* Failure! Unwind our work. */ if (firewall_notified && sr->eroute_owner == SOS_NOBODY) (void) do_command(c, sr, st, "down"); if (eroute_installed) { /* Restore original eroute, if we can. * Since there is nothing much to be done if the restoration * fails, ignore success or failure. */ if (ero != NULL) { /* restore ero's former glory */ if (esr->eroute_owner == SOS_NOBODY) { /* note: normal or eclipse case */ (void) shunt_eroute(ero, esr , esr->routing, ERO_REPLACE, "restore"); } else { /* Try to find state that owned eroute. * Don't do anything if it cannot be found. * This case isn't likely since we don't run * the updown script when replacing a SA group * with its successor (for the same conn). */ struct state *ost = state_with_serialno(esr->eroute_owner); if (ost != NULL) (void) sag_eroute(ost, esr, ERO_REPLACE, "restore"); } } else { /* there was no previous eroute: delete whatever we installed */ if (st == NULL) { (void) shunt_eroute(c, sr, sr->routing, ERO_DELETE, "delete"); } else { (void) sag_eroute(st, sr, ERO_DELETE, "delete"); } } } return FALSE; } } bool install_ipsec_sa(struct state *st, bool inbound_also) { struct spd_route *sr; DBG(DBG_CONTROL, DBG_log("install_ipsec_sa() for #%ld: %s" , st->st_serialno , inbound_also? "inbound and outbound" : "outbound only")); switch (could_route(st->st_connection)) { case route_easy: case route_nearconflict: break; default: return FALSE; } /* (attempt to) actually set up the SA group */ if ((inbound_also && !setup_half_ipsec_sa(st, TRUE)) || !setup_half_ipsec_sa(st, FALSE)) { return FALSE; } for (sr = &st->st_connection->spd; sr != NULL; sr = sr->next) { DBG(DBG_CONTROL, DBG_log("sr for #%ld: %s" , st->st_serialno , enum_name(&routing_story, sr->routing))); /* * if the eroute owner is not us, then make it us. * See test co-terminal-02, pluto-rekey-01, pluto-unit-02/oppo-twice */ pexpect(sr->eroute_owner == SOS_NOBODY || sr->routing >= RT_ROUTED_TUNNEL); if (sr->eroute_owner != st->st_serialno && sr->routing != RT_UNROUTED_KEYED) { if (!route_and_eroute(st->st_connection, sr, st)) { delete_ipsec_sa(st, FALSE); /* XXX go and unroute any SRs that were successfully * routed already. */ return FALSE; } } } return TRUE; } /* delete an IPSEC SA. * we may not succeed, but we bull ahead anyway because * we cannot do anything better by recognizing failure */ void delete_ipsec_sa(struct state *st, bool inbound_only) { if (!inbound_only) { /* If the state is the eroute owner, we must adjust * the routing for the connection. */ connection_t *c = st->st_connection; struct spd_route *sr; passert(st->st_connection); for (sr = &c->spd; sr; sr = sr->next) { if (sr->eroute_owner == st->st_serialno && sr->routing == RT_ROUTED_TUNNEL) { sr->eroute_owner = SOS_NOBODY; /* Routing should become RT_ROUTED_FAILURE, * but if POLICY_FAIL_NONE, then we just go * right back to RT_ROUTED_PROSPECTIVE as if no * failure happened. */ sr->routing = (c->policy & POLICY_FAIL_MASK) == POLICY_FAIL_NONE ? RT_ROUTED_PROSPECTIVE : RT_ROUTED_FAILURE; (void) do_command(c, sr, st, "down"); if ((c->policy & POLICY_DONT_REKEY) && c->kind == CK_INSTANCE) { /* in this special case, even if the connection * is still alive (due to an ISAKMP SA), * we get rid of routing. * Even though there is still an eroute, the c->routing * setting will convince unroute_connection to delete it. * unroute_connection would be upset if c->routing == RT_ROUTED_TUNNEL */ unroute_connection(c); } else { (void) shunt_eroute(c, sr, sr->routing, ERO_REPLACE, "replace with shunt"); } } } (void) teardown_half_ipsec_sa(st, FALSE); } (void) teardown_half_ipsec_sa(st, TRUE); } static bool update_nat_t_ipsec_esp_sa (struct state *st, bool inbound) { connection_t *c = st->st_connection; host_t *host_src, *host_dst, *new_src, *new_dst; ipsec_spi_t spi = inbound ? st->st_esp.our_spi : st->st_esp.attrs.spi; struct end *src = inbound ? &c->spd.that : &c->spd.this, *dst = inbound ? &c->spd.this : &c->spd.that; mark_t mark = inbound ? c->spd.mark_in : c->spd.mark_out; bool result; host_src = host_create_from_sockaddr((sockaddr_t*)&src->host_addr); host_dst = host_create_from_sockaddr((sockaddr_t*)&dst->host_addr); new_src = host_src->clone(host_src); new_dst = host_dst->clone(host_dst); new_src->set_port(new_src, src->host_port); new_dst->set_port(new_dst, dst->host_port); result = hydra->kernel_interface->update_sa(hydra->kernel_interface, spi, IPPROTO_ESP, 0 /* cpi */, host_src, host_dst, new_src, new_dst, TRUE /* encap */, TRUE /* new_encap */, mark) == SUCCESS; host_src->destroy(host_src); host_dst->destroy(host_dst); new_src->destroy(new_src); new_dst->destroy(new_dst); return result; } bool update_ipsec_sa (struct state *st) { if (IS_IPSEC_SA_ESTABLISHED(st->st_state)) { if (st->st_esp.present && ( (!update_nat_t_ipsec_esp_sa (st, TRUE)) || (!update_nat_t_ipsec_esp_sa (st, FALSE)))) { return FALSE; } } else if (IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(st->st_state)) { if (st->st_esp.present && !update_nat_t_ipsec_esp_sa (st, FALSE)) { return FALSE; } } else { DBG_log("assert failed at %s:%d st_state=%d", __FILE__, __LINE__, st->st_state); return FALSE; } return TRUE; } /* Check if there was traffic on given SA during the last idle_max * seconds. If TRUE, the SA was idle and DPD exchange should be performed. * If FALSE, DPD is not necessary. We also return TRUE for errors, as they * could mean that the SA is broken and needs to be replace anyway. */ bool was_eroute_idle(struct state *st, time_t idle_max, time_t *idle_time) { time_t use_time; u_int bytes; int ret = TRUE; passert(st != NULL); if (get_sa_info(st, TRUE, &bytes, &use_time) && use_time != UNDEFINED_TIME) { *idle_time = time_monotonic(NULL) - use_time; ret = *idle_time >= idle_max; } return ret; }