2002-02-11 10:05:58 +00:00
|
|
|
/*
|
|
|
|
protocol_key.c -- handle the meta-protocol, key exchange
|
2006-04-26 13:52:58 +00:00
|
|
|
Copyright (C) 1999-2005 Ivo Timmermans,
|
2014-12-24 21:15:40 +00:00
|
|
|
2000-2014 Guus Sliepen <guus@tinc-vpn.org>
|
2002-02-11 10:05:58 +00:00
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
2009-09-24 22:01:00 +00:00
|
|
|
You should have received a copy of the GNU General Public License along
|
|
|
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2002-02-11 10:05:58 +00:00
|
|
|
*/
|
|
|
|
|
2003-07-17 15:06:27 +00:00
|
|
|
#include "system.h"
|
2002-02-11 10:05:58 +00:00
|
|
|
|
2008-12-11 14:44:44 +00:00
|
|
|
#include "cipher.h"
|
2003-07-17 15:06:27 +00:00
|
|
|
#include "connection.h"
|
2009-06-05 21:03:28 +00:00
|
|
|
#include "crypto.h"
|
2003-07-17 15:06:27 +00:00
|
|
|
#include "logger.h"
|
2002-02-11 10:05:58 +00:00
|
|
|
#include "net.h"
|
|
|
|
#include "netutl.h"
|
|
|
|
#include "node.h"
|
2011-07-03 13:59:49 +00:00
|
|
|
#include "prf.h"
|
2003-07-17 15:06:27 +00:00
|
|
|
#include "protocol.h"
|
2012-07-30 16:36:59 +00:00
|
|
|
#include "sptps.h"
|
2003-07-17 15:06:27 +00:00
|
|
|
#include "utils.h"
|
|
|
|
#include "xalloc.h"
|
2002-02-11 10:05:58 +00:00
|
|
|
|
2008-12-11 14:44:44 +00:00
|
|
|
static bool mykeyused = false;
|
2002-02-11 10:05:58 +00:00
|
|
|
|
2011-05-28 01:57:20 +00:00
|
|
|
void send_key_changed(void) {
|
2012-02-20 16:12:48 +00:00
|
|
|
send_request(everyone, "%d %x %s", KEY_CHANGED, rand(), myself->name);
|
2002-09-09 21:25:28 +00:00
|
|
|
|
2010-02-03 10:18:46 +00:00
|
|
|
/* Immediately send new keys to directly connected nodes to keep UDP mappings alive */
|
2002-09-09 21:25:28 +00:00
|
|
|
|
2012-10-07 22:35:38 +00:00
|
|
|
for list_each(connection_t, c, connection_list)
|
2014-07-12 10:57:03 +00:00
|
|
|
if(c->edge && c->node && c->node->status.reachable && !c->node->status.sptps)
|
2012-10-07 22:35:38 +00:00
|
|
|
send_ans_key(c->node);
|
2012-07-30 16:36:59 +00:00
|
|
|
|
|
|
|
/* Force key exchange for connections using SPTPS */
|
|
|
|
|
|
|
|
if(experimental) {
|
2012-10-07 22:35:38 +00:00
|
|
|
for splay_each(node_t, n, node_tree)
|
2012-07-31 19:43:49 +00:00
|
|
|
if(n->status.reachable && n->status.validkey && n->status.sptps)
|
2012-07-30 16:36:59 +00:00
|
|
|
sptps_force_kex(&n->sptps);
|
2010-02-03 10:18:46 +00:00
|
|
|
}
|
2002-02-11 10:05:58 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:44:15 +00:00
|
|
|
bool key_changed_h(connection_t *c, const char *request) {
|
2002-09-09 21:25:28 +00:00
|
|
|
char name[MAX_STRING_SIZE];
|
|
|
|
node_t *n;
|
|
|
|
|
2007-05-19 22:23:02 +00:00
|
|
|
if(sscanf(request, "%*d %*x " MAX_STRING, name) != 1) {
|
2012-02-26 17:37:36 +00:00
|
|
|
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "KEY_CHANGED",
|
2002-09-09 21:25:28 +00:00
|
|
|
c->name, c->hostname);
|
2003-07-22 20:55:21 +00:00
|
|
|
return false;
|
2002-09-09 21:25:28 +00:00
|
|
|
}
|
|
|
|
|
2007-05-19 22:23:02 +00:00
|
|
|
if(seen_request(request))
|
2003-07-22 20:55:21 +00:00
|
|
|
return true;
|
2002-09-09 21:25:28 +00:00
|
|
|
|
|
|
|
n = lookup_node(name);
|
|
|
|
|
|
|
|
if(!n) {
|
2012-02-26 17:37:36 +00:00
|
|
|
logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) origin %s which does not exist",
|
2002-09-09 21:25:28 +00:00
|
|
|
"KEY_CHANGED", c->name, c->hostname, name);
|
2010-01-23 17:48:01 +00:00
|
|
|
return true;
|
2002-09-09 21:25:28 +00:00
|
|
|
}
|
|
|
|
|
2012-07-31 19:43:49 +00:00
|
|
|
if(!n->status.sptps) {
|
2012-07-30 16:36:59 +00:00
|
|
|
n->status.validkey = false;
|
|
|
|
n->last_req_key = 0;
|
|
|
|
}
|
2002-09-09 21:25:28 +00:00
|
|
|
|
|
|
|
/* Tell the others */
|
|
|
|
|
2003-11-17 15:30:18 +00:00
|
|
|
if(!tunnelserver)
|
2007-05-19 22:23:02 +00:00
|
|
|
forward_request(c, request);
|
2002-09-09 21:25:28 +00:00
|
|
|
|
2003-07-22 20:55:21 +00:00
|
|
|
return true;
|
2002-02-11 10:05:58 +00:00
|
|
|
}
|
|
|
|
|
2014-12-24 21:15:40 +00:00
|
|
|
static bool send_initial_sptps_data(void *handle, uint8_t type, const void *data, size_t len) {
|
2012-07-30 16:36:59 +00:00
|
|
|
node_t *to = handle;
|
|
|
|
to->sptps.send_data = send_sptps_data;
|
|
|
|
char buf[len * 4 / 3 + 5];
|
|
|
|
b64encode(data, buf, len);
|
|
|
|
return send_request(to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, myself->name, to->name, REQ_KEY, buf);
|
|
|
|
}
|
|
|
|
|
2009-06-05 21:03:28 +00:00
|
|
|
bool send_req_key(node_t *to) {
|
2012-07-31 19:43:49 +00:00
|
|
|
if(to->status.sptps) {
|
2012-07-30 16:36:59 +00:00
|
|
|
if(!node_read_ecdsa_public_key(to)) {
|
2014-05-18 18:47:04 +00:00
|
|
|
logger(DEBUG_PROTOCOL, LOG_DEBUG, "No Ed25519 key known for %s (%s)", to->name, to->hostname);
|
2012-07-19 23:02:51 +00:00
|
|
|
send_request(to->nexthop->connection, "%d %s %s %d", REQ_KEY, myself->name, to->name, REQ_PUBKEY);
|
2012-07-30 16:36:59 +00:00
|
|
|
return true;
|
|
|
|
}
|
2012-10-14 12:33:54 +00:00
|
|
|
|
|
|
|
if(to->sptps.label)
|
|
|
|
logger(DEBUG_ALWAYS, LOG_DEBUG, "send_req_key(%s) called while sptps->label != NULL!", to->name);
|
|
|
|
|
2012-10-10 15:17:49 +00:00
|
|
|
char label[25 + strlen(myself->name) + strlen(to->name)];
|
2012-07-30 16:36:59 +00:00
|
|
|
snprintf(label, sizeof label, "tinc UDP key expansion %s %s", myself->name, to->name);
|
2012-08-02 15:23:51 +00:00
|
|
|
sptps_stop(&to->sptps);
|
|
|
|
to->status.validkey = false;
|
2012-10-07 11:31:19 +00:00
|
|
|
to->status.waitingforkey = true;
|
2013-03-08 13:11:15 +00:00
|
|
|
to->last_req_key = now.tv_sec;
|
2012-08-02 15:44:59 +00:00
|
|
|
to->incompression = myself->incompression;
|
2012-10-10 15:17:49 +00:00
|
|
|
return sptps_start(&to->sptps, to, true, true, myself->connection->ecdsa, to->ecdsa, label, sizeof label, send_initial_sptps_data, receive_sptps_record);
|
2012-07-19 23:02:51 +00:00
|
|
|
}
|
2012-07-30 16:36:59 +00:00
|
|
|
|
2012-07-19 23:02:51 +00:00
|
|
|
return send_request(to->nexthop->connection, "%d %s %s", REQ_KEY, myself->name, to->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* REQ_KEY is overloaded to allow arbitrary requests to be routed between two nodes. */
|
|
|
|
|
|
|
|
static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, int reqno) {
|
|
|
|
switch(reqno) {
|
|
|
|
case REQ_PUBKEY: {
|
2014-09-21 09:38:41 +00:00
|
|
|
if(!node_read_ecdsa_public_key(from)) {
|
|
|
|
/* Request their key *before* we send our key back. Otherwise the first SPTPS packet from them will get dropped. */
|
|
|
|
logger(DEBUG_PROTOCOL, LOG_DEBUG, "Preemptively requesting Ed25519 key for %s (%s)", from->name, from->hostname);
|
|
|
|
send_request(from->nexthop->connection, "%d %s %s %d", REQ_KEY, myself->name, from->name, REQ_PUBKEY);
|
|
|
|
}
|
2013-05-01 15:17:22 +00:00
|
|
|
char *pubkey = ecdsa_get_base64_public_key(myself->connection->ecdsa);
|
2012-07-19 23:02:51 +00:00
|
|
|
send_request(from->nexthop->connection, "%d %s %s %d %s", REQ_KEY, myself->name, from->name, ANS_PUBKEY, pubkey);
|
|
|
|
free(pubkey);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ANS_PUBKEY: {
|
|
|
|
if(node_read_ecdsa_public_key(from)) {
|
2012-09-28 15:51:48 +00:00
|
|
|
logger(DEBUG_PROTOCOL, LOG_WARNING, "Got ANS_PUBKEY from %s (%s) even though we already have his pubkey", from->name, from->hostname);
|
2012-07-19 23:02:51 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-07-30 16:36:59 +00:00
|
|
|
char pubkey[MAX_STRING_SIZE];
|
2013-05-01 15:17:22 +00:00
|
|
|
if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING, pubkey) != 1 || !(from->ecdsa = ecdsa_set_base64_public_key(pubkey))) {
|
2012-07-19 23:02:51 +00:00
|
|
|
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "ANS_PUBKEY", from->name, from->hostname, "invalid pubkey");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-05-18 18:47:04 +00:00
|
|
|
logger(DEBUG_PROTOCOL, LOG_INFO, "Learned Ed25519 public key from %s (%s)", from->name, from->hostname);
|
|
|
|
append_config_file(from->name, "Ed25519PublicKey", pubkey);
|
2012-07-19 23:02:51 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-07-30 16:36:59 +00:00
|
|
|
case REQ_KEY: {
|
|
|
|
if(!node_read_ecdsa_public_key(from)) {
|
2014-05-18 18:47:04 +00:00
|
|
|
logger(DEBUG_PROTOCOL, LOG_DEBUG, "No Ed25519 key known for %s (%s)", from->name, from->hostname);
|
2012-07-30 16:36:59 +00:00
|
|
|
send_request(from->nexthop->connection, "%d %s %s %d", REQ_KEY, myself->name, from->name, REQ_PUBKEY);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-10-14 12:33:54 +00:00
|
|
|
if(from->sptps.label)
|
|
|
|
logger(DEBUG_ALWAYS, LOG_DEBUG, "Got REQ_KEY from %s while we already started a SPTPS session!", from->name);
|
|
|
|
|
2012-07-30 16:36:59 +00:00
|
|
|
char buf[MAX_STRING_SIZE];
|
2013-05-28 11:39:15 +00:00
|
|
|
int len;
|
|
|
|
|
|
|
|
if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING, buf) != 1 || !(len = b64decode(buf, buf, strlen(buf)))) {
|
2012-10-14 12:33:54 +00:00
|
|
|
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "REQ_SPTPS_START", from->name, from->hostname, "invalid SPTPS data");
|
2012-07-30 16:36:59 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
char label[25 + strlen(from->name) + strlen(myself->name)];
|
|
|
|
snprintf(label, sizeof label, "tinc UDP key expansion %s %s", from->name, myself->name);
|
2012-08-02 15:23:51 +00:00
|
|
|
sptps_stop(&from->sptps);
|
|
|
|
from->status.validkey = false;
|
2012-10-07 11:31:19 +00:00
|
|
|
from->status.waitingforkey = true;
|
2013-03-08 13:11:15 +00:00
|
|
|
from->last_req_key = now.tv_sec;
|
2012-10-10 15:17:49 +00:00
|
|
|
sptps_start(&from->sptps, from, false, true, myself->connection->ecdsa, from->ecdsa, label, sizeof label, send_sptps_data, receive_sptps_record);
|
2012-07-30 16:36:59 +00:00
|
|
|
sptps_receive_data(&from->sptps, buf, len);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-10-14 12:33:54 +00:00
|
|
|
case REQ_SPTPS: {
|
2012-10-07 12:03:50 +00:00
|
|
|
if(!from->status.validkey) {
|
2012-10-14 12:33:54 +00:00
|
|
|
logger(DEBUG_PROTOCOL, LOG_ERR, "Got REQ_SPTPS from %s (%s) but we don't have a valid key yet", from->name, from->hostname);
|
2012-10-07 12:03:50 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
char buf[MAX_STRING_SIZE];
|
2013-05-28 11:39:15 +00:00
|
|
|
int len;
|
|
|
|
if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING, buf) != 1 || !(len = b64decode(buf, buf, strlen(buf)))) {
|
2012-10-14 12:33:54 +00:00
|
|
|
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "REQ_SPTPS", from->name, from->hostname, "invalid SPTPS data");
|
2012-10-07 12:03:50 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
sptps_receive_data(&from->sptps, buf, len);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-07-19 23:02:51 +00:00
|
|
|
default:
|
|
|
|
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown extended REQ_KEY request from %s (%s): %s", from->name, from->hostname, request);
|
|
|
|
return true;
|
|
|
|
}
|
2002-02-11 10:05:58 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:44:15 +00:00
|
|
|
bool req_key_h(connection_t *c, const char *request) {
|
2002-09-09 21:25:28 +00:00
|
|
|
char from_name[MAX_STRING_SIZE];
|
|
|
|
char to_name[MAX_STRING_SIZE];
|
|
|
|
node_t *from, *to;
|
2012-07-19 23:02:51 +00:00
|
|
|
int reqno = 0;
|
2002-09-09 21:25:28 +00:00
|
|
|
|
2012-07-19 23:02:51 +00:00
|
|
|
if(sscanf(request, "%*d " MAX_STRING " " MAX_STRING " %d", from_name, to_name, &reqno) < 2) {
|
2012-02-26 17:37:36 +00:00
|
|
|
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "REQ_KEY", c->name,
|
2002-09-09 21:25:28 +00:00
|
|
|
c->hostname);
|
2003-07-22 20:55:21 +00:00
|
|
|
return false;
|
2002-09-09 21:25:28 +00:00
|
|
|
}
|
|
|
|
|
2010-01-23 17:48:01 +00:00
|
|
|
if(!check_id(from_name) || !check_id(to_name)) {
|
2012-02-26 17:37:36 +00:00
|
|
|
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "REQ_KEY", c->name, c->hostname, "invalid name");
|
2010-01-23 17:48:01 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2002-09-09 21:25:28 +00:00
|
|
|
from = lookup_node(from_name);
|
|
|
|
|
|
|
|
if(!from) {
|
2012-02-26 17:37:36 +00:00
|
|
|
logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list",
|
2002-09-09 21:25:28 +00:00
|
|
|
"REQ_KEY", c->name, c->hostname, from_name);
|
2010-01-23 17:48:01 +00:00
|
|
|
return true;
|
2002-09-09 21:25:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
to = lookup_node(to_name);
|
|
|
|
|
|
|
|
if(!to) {
|
2012-02-26 17:37:36 +00:00
|
|
|
logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list",
|
2002-09-09 21:25:28 +00:00
|
|
|
"REQ_KEY", c->name, c->hostname, to_name);
|
2010-01-23 17:48:01 +00:00
|
|
|
return true;
|
2002-09-09 21:25:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if this key request is for us */
|
|
|
|
|
2012-10-10 15:17:49 +00:00
|
|
|
if(to == myself) { /* Yes */
|
2012-07-31 19:43:49 +00:00
|
|
|
/* Is this an extended REQ_KEY message? */
|
2012-07-19 23:02:51 +00:00
|
|
|
if(experimental && reqno)
|
|
|
|
return req_key_ext_h(c, request, from, reqno);
|
|
|
|
|
2012-07-31 19:43:49 +00:00
|
|
|
/* No, just send our key back */
|
2009-04-02 23:05:23 +00:00
|
|
|
send_ans_key(from);
|
2002-09-09 21:25:28 +00:00
|
|
|
} else {
|
2003-11-17 15:30:18 +00:00
|
|
|
if(tunnelserver)
|
2010-01-23 17:48:01 +00:00
|
|
|
return true;
|
2003-11-17 15:30:18 +00:00
|
|
|
|
2008-12-11 15:21:40 +00:00
|
|
|
if(!to->status.reachable) {
|
2012-09-28 15:51:48 +00:00
|
|
|
logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) destination %s which is not reachable",
|
2008-12-11 15:21:40 +00:00
|
|
|
"REQ_KEY", c->name, c->hostname, to_name);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Add UDP datagram relay support to SPTPS.
This commit changes the layout of UDP datagrams to include a 6-byte
destination node ID at the very beginning of the datagram (i.e. before
the source node ID and the seqno). Note that this only applies to SPTPS.
Thanks to this new field, it is now possible to send SPTPS datagrams to
nodes that are not the final recipient of the packets, thereby using
these nodes as relay nodes. Previously SPTPS was unable to relay packets
using UDP, and required a fallback to TCP if the final recipient could
not be contacted directly using UDP. In that sense it fixes a regression
that SPTPS introduced with regard to the legacy protocol.
This change also updates tinc's low-level routing logic (i.e.
send_sptps_data()) to automatically use this relaying facility if at all
possible. Specifically, it will relay packets if we don't have a
confirmed UDP link to the final recipient (but we have one with the next
hop node), or if IndirectData is specified. This is similar to how the
legacy protocol forwards packets.
When sending packets directly without any relaying, the sender node uses
a special value for the destination node ID: instead of setting the
field to the ID of the recipient node, it writes a zero ID instead. This
allows the recipient node to distinguish between a relayed packet and a
direct packet, which is important when determining the UDP address of
the sending node.
On the relay side, relay nodes will happily relay packets that have a
destination ID which is non-zero *and* is different from their own,
provided that the source IP address of the packet is known. This is to
prevent abuse by random strangers, since a node can't authenticate the
packets that are being relayed through it.
This change keeps the protocol number from the previous datagram format
change (source IDs), 17.4. Compatibility is still preserved with 1.0 and
with pre-1.1 releases. Note, however, that nodes running this code won't
understand datagrams sent from nodes that only use source IDs and
vice-versa (not that we really care).
There is one caveat: in the current state, there is no way for the
original sender to know what the PMTU is beyond the first hop, and
contrary to the legacy protocol, relay nodes can't apply MSS clamping
because they can't decrypt the relayed packets. This leads to
inefficient scenarios where a reduced PMTU over some link that's part of
the relay path will result in relays falling back to TCP to send packets
to their final destinations.
Another caveat is that once a packet gets sent over TCP, it will use
TCP over the entire path, even if it is technically possible to use UDP
beyond the TCP-only link(s).
Arguably, these two caveats can be fixed by improving the
metaconnection protocol, but that's out of scope for this change. TODOs
are added instead. In any case, this is no worse than before.
In addition, this change increases SPTPS datagram overhead by another
6 bytes for the destination ID, on top of the existing 6-byte overhead
from the source ID.
2014-09-28 11:38:06 +00:00
|
|
|
/* TODO: forwarding SPTPS packets in this way is inefficient because we send them over TCP without checking for UDP connectivity */
|
2009-06-05 21:03:28 +00:00
|
|
|
send_request(to->nexthop->connection, "%s", request);
|
2002-09-09 21:25:28 +00:00
|
|
|
}
|
2002-02-11 10:05:58 +00:00
|
|
|
|
2003-07-22 20:55:21 +00:00
|
|
|
return true;
|
2002-02-11 10:05:58 +00:00
|
|
|
}
|
|
|
|
|
2009-06-05 21:03:28 +00:00
|
|
|
bool send_ans_key(node_t *to) {
|
2012-07-31 19:43:49 +00:00
|
|
|
if(to->status.sptps)
|
2012-07-30 16:36:59 +00:00
|
|
|
abort();
|
2011-07-03 11:17:28 +00:00
|
|
|
|
2014-05-18 19:51:42 +00:00
|
|
|
size_t keylen = myself->incipher ? cipher_keylength(myself->incipher) : 1;
|
2008-12-11 14:44:44 +00:00
|
|
|
char key[keylen * 2 + 1];
|
2002-09-09 21:25:28 +00:00
|
|
|
|
2014-05-18 19:51:42 +00:00
|
|
|
randomize(key, keylen);
|
|
|
|
|
2013-05-01 15:17:22 +00:00
|
|
|
cipher_close(to->incipher);
|
|
|
|
digest_close(to->indigest);
|
2012-10-09 14:27:28 +00:00
|
|
|
|
2014-05-18 19:51:42 +00:00
|
|
|
if(myself->incipher) {
|
|
|
|
to->incipher = cipher_open_by_nid(cipher_get_nid(myself->incipher));
|
|
|
|
if(!to->incipher)
|
|
|
|
abort();
|
|
|
|
if(!cipher_set_key(to->incipher, key, false))
|
|
|
|
abort();
|
|
|
|
}
|
2002-09-09 21:25:28 +00:00
|
|
|
|
2014-05-18 19:51:42 +00:00
|
|
|
if(myself->indigest) {
|
|
|
|
to->indigest = digest_open_by_nid(digest_get_nid(myself->indigest), digest_length(myself->indigest));
|
|
|
|
if(!to->indigest)
|
|
|
|
abort();
|
|
|
|
if(!digest_set_key(to->indigest, key, keylen))
|
|
|
|
abort();
|
|
|
|
}
|
2013-05-01 15:17:22 +00:00
|
|
|
|
2014-05-18 19:51:42 +00:00
|
|
|
to->incompression = myself->incompression;
|
2009-05-24 17:31:31 +00:00
|
|
|
|
2008-12-11 14:44:44 +00:00
|
|
|
bin2hex(key, key, keylen);
|
2002-09-09 21:25:28 +00:00
|
|
|
|
2009-05-24 17:31:31 +00:00
|
|
|
// Reset sequence number and late packet window
|
|
|
|
mykeyused = true;
|
|
|
|
to->received_seqno = 0;
|
2013-01-15 12:33:16 +00:00
|
|
|
to->received = 0;
|
2010-11-13 18:05:50 +00:00
|
|
|
if(replaywin) memset(to->late, 0, replaywin);
|
2009-04-02 23:05:23 +00:00
|
|
|
|
2012-07-21 10:51:53 +00:00
|
|
|
return send_request(to->nexthop->connection, "%d %s %s %s %d %d %d %d", ANS_KEY,
|
2009-06-05 21:03:28 +00:00
|
|
|
myself->name, to->name, key,
|
2013-05-01 15:17:22 +00:00
|
|
|
cipher_get_nid(to->incipher),
|
|
|
|
digest_get_nid(to->indigest),
|
|
|
|
(int)digest_length(to->indigest),
|
2009-06-05 21:03:28 +00:00
|
|
|
to->incompression);
|
2002-02-11 10:05:58 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 14:44:15 +00:00
|
|
|
bool ans_key_h(connection_t *c, const char *request) {
|
2002-09-09 21:25:28 +00:00
|
|
|
char from_name[MAX_STRING_SIZE];
|
|
|
|
char to_name[MAX_STRING_SIZE];
|
|
|
|
char key[MAX_STRING_SIZE];
|
2012-10-10 15:17:49 +00:00
|
|
|
char address[MAX_STRING_SIZE] = "";
|
|
|
|
char port[MAX_STRING_SIZE] = "";
|
2009-12-18 00:15:25 +00:00
|
|
|
int cipher, digest, maclength, compression, keylen;
|
2002-09-09 21:25:28 +00:00
|
|
|
node_t *from, *to;
|
|
|
|
|
2011-07-13 20:52:52 +00:00
|
|
|
if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d "MAX_STRING" "MAX_STRING,
|
2002-09-09 21:25:28 +00:00
|
|
|
from_name, to_name, key, &cipher, &digest, &maclength,
|
2010-02-01 23:51:44 +00:00
|
|
|
&compression, address, port) < 7) {
|
2012-02-26 17:37:36 +00:00
|
|
|
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "ANS_KEY", c->name,
|
2002-09-09 21:25:28 +00:00
|
|
|
c->hostname);
|
2003-07-22 20:55:21 +00:00
|
|
|
return false;
|
2002-02-11 10:05:58 +00:00
|
|
|
}
|
2002-09-09 21:25:28 +00:00
|
|
|
|
2010-01-23 17:48:01 +00:00
|
|
|
if(!check_id(from_name) || !check_id(to_name)) {
|
2012-02-26 17:37:36 +00:00
|
|
|
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "ANS_KEY", c->name, c->hostname, "invalid name");
|
2010-01-23 17:48:01 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2002-09-09 21:25:28 +00:00
|
|
|
from = lookup_node(from_name);
|
|
|
|
|
|
|
|
if(!from) {
|
2012-02-26 17:37:36 +00:00
|
|
|
logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list",
|
2002-09-09 21:25:28 +00:00
|
|
|
"ANS_KEY", c->name, c->hostname, from_name);
|
2010-01-23 17:48:01 +00:00
|
|
|
return true;
|
2002-09-09 21:25:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
to = lookup_node(to_name);
|
|
|
|
|
|
|
|
if(!to) {
|
2012-02-26 17:37:36 +00:00
|
|
|
logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list",
|
2002-09-09 21:25:28 +00:00
|
|
|
"ANS_KEY", c->name, c->hostname, to_name);
|
2010-01-23 17:48:01 +00:00
|
|
|
return true;
|
2002-02-11 10:05:58 +00:00
|
|
|
}
|
2002-09-09 21:25:28 +00:00
|
|
|
|
|
|
|
/* Forward it if necessary */
|
|
|
|
|
|
|
|
if(to != myself) {
|
2003-11-17 15:30:18 +00:00
|
|
|
if(tunnelserver)
|
2010-01-23 17:48:01 +00:00
|
|
|
return true;
|
2003-11-17 15:30:18 +00:00
|
|
|
|
2008-12-11 15:21:40 +00:00
|
|
|
if(!to->status.reachable) {
|
2012-02-26 17:37:36 +00:00
|
|
|
logger(DEBUG_ALWAYS, LOG_WARNING, "Got %s from %s (%s) destination %s which is not reachable",
|
2008-12-11 15:21:40 +00:00
|
|
|
"ANS_KEY", c->name, c->hostname, to_name);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-06-04 14:03:19 +00:00
|
|
|
if(!*address && from->address.sa.sa_family != AF_UNSPEC) {
|
2010-04-17 10:33:15 +00:00
|
|
|
char *address, *port;
|
2012-02-26 17:37:36 +00:00
|
|
|
logger(DEBUG_PROTOCOL, LOG_DEBUG, "Appending reflexive UDP address to ANS_KEY from %s to %s", from->name, to->name);
|
2010-04-17 10:33:15 +00:00
|
|
|
sockaddr2str(&from->address, &address, &port);
|
|
|
|
send_request(to->nexthop->connection, "%s %s %s", request, address, port);
|
|
|
|
free(address);
|
|
|
|
free(port);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-05-19 22:23:02 +00:00
|
|
|
return send_request(to->nexthop->connection, "%s", request);
|
2002-02-11 10:05:58 +00:00
|
|
|
}
|
2002-09-09 21:25:28 +00:00
|
|
|
|
2012-09-30 11:45:47 +00:00
|
|
|
/* Don't use key material until every check has passed. */
|
2013-05-01 15:17:22 +00:00
|
|
|
cipher_close(from->outcipher);
|
|
|
|
digest_close(from->outdigest);
|
2012-09-30 11:45:47 +00:00
|
|
|
from->status.validkey = false;
|
|
|
|
|
2012-08-02 15:44:59 +00:00
|
|
|
if(compression < 0 || compression > 11) {
|
|
|
|
logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses bogus compression level!", from->name, from->hostname);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
from->outcompression = compression;
|
|
|
|
|
2012-07-30 16:36:59 +00:00
|
|
|
/* SPTPS or old-style key exchange? */
|
|
|
|
|
2012-07-31 19:43:49 +00:00
|
|
|
if(from->status.sptps) {
|
2012-07-30 16:36:59 +00:00
|
|
|
char buf[strlen(key)];
|
|
|
|
int len = b64decode(key, buf, strlen(key));
|
|
|
|
|
2013-05-28 11:39:15 +00:00
|
|
|
if(!len || !sptps_receive_data(&from->sptps, buf, len))
|
2012-07-30 16:36:59 +00:00
|
|
|
logger(DEBUG_ALWAYS, LOG_ERR, "Error processing SPTPS data from %s (%s)", from->name, from->hostname);
|
|
|
|
|
|
|
|
if(from->status.validkey) {
|
|
|
|
if(*address && *port) {
|
|
|
|
logger(DEBUG_PROTOCOL, LOG_DEBUG, "Using reflexive UDP address from %s: %s port %s", from->name, address, port);
|
|
|
|
sockaddr_t sa = str2sockaddr(address, port);
|
|
|
|
update_node_udp(from, &sa);
|
|
|
|
}
|
|
|
|
|
2014-10-04 13:25:16 +00:00
|
|
|
/* Don't send probes if we can't send UDP packets directly to that node.
|
|
|
|
TODO: the indirect (via) condition can change at any time as edges are added and removed, so this should probably be moved to graph.c. */
|
|
|
|
if((from->via == myself || from->via == from) && from->options & OPTION_PMTU_DISCOVERY && !(from->options & OPTION_TCPONLY))
|
2012-07-30 16:36:59 +00:00
|
|
|
send_mtu_probe(from);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-09-09 21:25:28 +00:00
|
|
|
/* Check and lookup cipher and digest algorithms */
|
|
|
|
|
2013-11-28 13:19:55 +00:00
|
|
|
if(cipher) {
|
|
|
|
if(!(from->outcipher = cipher_open_by_nid(cipher))) {
|
|
|
|
logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses unknown cipher!", from->name, from->hostname);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
from->outcipher = NULL;
|
2008-12-11 14:44:44 +00:00
|
|
|
}
|
2007-11-07 02:47:05 +00:00
|
|
|
|
2013-11-28 13:19:55 +00:00
|
|
|
if(digest) {
|
|
|
|
if(!(from->outdigest = digest_open_by_nid(digest, maclength))) {
|
|
|
|
logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses unknown digest!", from->name, from->hostname);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
from->outdigest = NULL;
|
2008-12-11 14:44:44 +00:00
|
|
|
}
|
2007-11-07 02:47:05 +00:00
|
|
|
|
2013-05-01 15:17:22 +00:00
|
|
|
if(maclength != digest_length(from->outdigest)) {
|
2012-02-26 17:37:36 +00:00
|
|
|
logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses bogus MAC length!", from->name, from->hostname);
|
2008-12-11 14:44:44 +00:00
|
|
|
return false;
|
2002-09-09 21:25:28 +00:00
|
|
|
}
|
|
|
|
|
2012-07-30 16:36:59 +00:00
|
|
|
/* Process key */
|
2011-07-16 18:21:44 +00:00
|
|
|
|
2012-07-30 16:36:59 +00:00
|
|
|
keylen = hex2bin(key, key, sizeof key);
|
2011-07-03 11:17:28 +00:00
|
|
|
|
2014-05-18 19:51:42 +00:00
|
|
|
if(keylen != (from->outcipher ? cipher_keylength(from->outcipher) : 1)) {
|
2012-07-30 16:36:59 +00:00
|
|
|
logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses wrong keylength!", from->name, from->hostname);
|
|
|
|
return true;
|
|
|
|
}
|
2008-12-11 14:44:44 +00:00
|
|
|
|
2012-07-30 16:36:59 +00:00
|
|
|
/* Update our copy of the origin's packet key */
|
2011-07-03 11:17:28 +00:00
|
|
|
|
2014-05-18 19:51:42 +00:00
|
|
|
if(from->outcipher && !cipher_set_key(from->outcipher, key, true))
|
2013-05-10 18:30:47 +00:00
|
|
|
return false;
|
2014-05-18 19:51:42 +00:00
|
|
|
if(from->outdigest && !digest_set_key(from->outdigest, key, keylen))
|
2013-05-10 18:30:47 +00:00
|
|
|
return false;
|
2008-12-11 14:44:44 +00:00
|
|
|
|
|
|
|
from->status.validkey = true;
|
|
|
|
from->sent_seqno = 0;
|
2003-10-11 12:16:13 +00:00
|
|
|
|
2010-02-01 23:51:44 +00:00
|
|
|
if(*address && *port) {
|
2012-02-26 17:37:36 +00:00
|
|
|
logger(DEBUG_PROTOCOL, LOG_DEBUG, "Using reflexive UDP address from %s: %s port %s", from->name, address, port);
|
2010-02-01 23:51:44 +00:00
|
|
|
sockaddr_t sa = str2sockaddr(address, port);
|
|
|
|
update_node_udp(from, &sa);
|
|
|
|
}
|
|
|
|
|
2013-07-20 21:59:57 +00:00
|
|
|
if(from->options & OPTION_PMTU_DISCOVERY && !(from->options & OPTION_TCPONLY))
|
2003-12-20 19:47:53 +00:00
|
|
|
send_mtu_probe(from);
|
2003-05-06 21:13:18 +00:00
|
|
|
|
2003-07-22 20:55:21 +00:00
|
|
|
return true;
|
2002-02-11 10:05:58 +00:00
|
|
|
}
|