/*
protocol.c -- handle the meta-protocol
- Copyright (C) 1999,2000 Ivo Timmermans <itimmermans@bigfoot.com>,
- 2000 Guus Sliepen <guus@sliepen.warande.net>
+ Copyright (C) 1999-2001 Ivo Timmermans <itimmermans@bigfoot.com>,
+ 2000,2001 Guus Sliepen <guus@sliepen.warande.net>
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
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id: protocol.c,v 1.28.4.63 2000/11/22 18:54:08 guus Exp $
+ $Id: protocol.c,v 1.28.4.76 2001/01/08 20:35:30 guus Exp $
*/
#include "config.h"
#include <utils.h>
#include <xalloc.h>
+#include <avl_tree.h>
+#include <list.h>
#include <netinet/in.h>
for (i = 0; i < strlen(id); i++)
if(!isalnum(id[i]) && id[i] != '_')
return -1;
-
+
return 0;
}
-/* Generic request routines - takes care of logging and error detection as well */
+/* Generic request routines - takes care of logging and error
+ detection as well */
int send_request(connection_t *cl, const char *format, ...)
{
int len, request;
cp
- /* Use vsnprintf instead of vasprintf: faster, no memory fragmentation, cleanup is automatic,
- and there is a limit on the input buffer anyway */
+ /* Use vsnprintf instead of vasprintf: faster, no memory
+ fragmentation, cleanup is automatic, and there is a limit on the
+ input buffer anyway */
va_start(args, format);
len = vsnprintf(buffer, MAXBUFSIZE, format, args);
(H) SHA1,
(E) Encrypted with symmetric cipher.
- Part of the challenge is directly used to set the symmetric cipher key and the initial vector.
- Since a man-in-the-middle cannot decrypt the RSA challenges, this means that he cannot get or
- forge the key for the symmetric cipher.
+ Part of the challenge is directly used to set the symmetric cipher
+ key and the initial vector. Since a man-in-the-middle cannot
+ decrypt the RSA challenges, this means that he cannot get or forge
+ the key for the symmetric cipher.
*/
int send_id(connection_t *cl)
int id_h(connection_t *cl)
{
connection_t *old;
- config_t const *cfg;
+ unsigned short int port;
+ char name[MAX_STRING_SIZE];
+ avl_node_t *node;
cp
- if(sscanf(cl->buffer, "%*d %as %d %lx %hd", &cl->name, &cl->protocol_version, &cl->options, &cl->port) != 4)
+ if(sscanf(cl->buffer, "%*d "MAX_STRING" %d %lx %hd", name, &cl->protocol_version, &cl->options, &port) != 4)
{
syslog(LOG_ERR, _("Got bad ID from %s"), cl->hostname);
return -1;
/* Check if identity is a valid name */
- if(check_id(cl->name))
+ if(check_id(name))
{
syslog(LOG_ERR, _("Peer %s uses invalid identity name"), cl->hostname);
return -1;
}
+
+ /* Copy string to cl */
+
+ cl->name = xstrdup(name);
/* Load information about peer */
id_add(cl);
+ /* And uhr... cl->port just changed so we have to unlink it from the connection tree and re-insert... */
+
+ node = avl_unlink(connection_tree, cl);
+ cl->port = port;
+ avl_insert_node(connection_tree, node);
+
/* Read in the public key, so that we can send a challenge */
- if((cfg = get_config_val(cl->config, config_publickey)))
- {
- cl->rsa_key = RSA_new();
- BN_hex2bn(&cl->rsa_key->n, cfg->data.ptr);
- BN_hex2bn(&cl->rsa_key->e, "FFFF");
- }
- else
- {
- syslog(LOG_ERR, _("No public key known for %s (%s)"), cl->name, cl->hostname);
- return -1;
- }
+ if(read_rsa_public_key(cl))
+ return -1;
+
cp
return send_challenge(cl);
}
RAND_bytes(cl->hischallenge, len);
cl->hischallenge[0] &= 0x7F; /* Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
-
+cp
if(debug_lvl >= DEBUG_SCARY_THINGS)
{
bin2hex(cl->hischallenge, buffer, len);
}
/* Encrypt the random data */
-
+
if(RSA_public_encrypt(len, cl->hischallenge, buffer, cl->rsa_key, RSA_NO_PADDING) != len) /* NO_PADDING because the message size equals the RSA key size and it is totally random */
{
syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
bin2hex(buffer, buffer, len);
buffer[len*2] = '\0';
-
+cp
/* Send the challenge */
cl->allow_request = CHAL_REPLY;
int challenge_h(connection_t *cl)
{
- char *buffer;
+ char buffer[MAX_STRING_SIZE];
int len;
cp
- if(sscanf(cl->buffer, "%*d %as", &buffer) != 1)
+ if(sscanf(cl->buffer, "%*d "MAX_STRING, buffer) != 1)
{
syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
return -1;
if(strlen(buffer) != len*2)
{
syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
- free(buffer);
return -1;
}
if(RSA_private_decrypt(len, buffer, cl->mychallenge, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
{
syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
- free(buffer);
return -1;
}
syslog(LOG_DEBUG, _("Received random challenge (unencrypted): %s"), buffer);
}
- free(buffer);
-
/* Rest is done by send_chal_reply() */
cp
return send_chal_reply(cl);
int chal_reply_h(connection_t *cl)
{
- char *hishash;
+ char hishash[MAX_STRING_SIZE];
char myhash[SHA_DIGEST_LENGTH];
cp
- if(sscanf(cl->buffer, "%*d %as", &hishash) != 1)
+ if(sscanf(cl->buffer, "%*d "MAX_STRING, hishash) != 1)
{
syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
- free(hishash);
return -1;
}
if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
{
syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
- free(hishash);
return -1;
}
hishash[SHA_DIGEST_LENGTH*2] = '\0';
syslog(LOG_DEBUG, _("Expected challenge reply: %s"), hishash);
}
- free(hishash);
return -1;
}
- free(hishash);
-
/* Identity has now been positively verified.
If we are accepting this new connection, then send our identity,
if we are making this connecting, acknowledge.
int metakey_h(connection_t *cl)
{
- char *buffer;
+ char buffer[MAX_STRING_SIZE];
int len;
cp
- if(sscanf(cl->buffer, "%*d %as", &buffer) != 1)
+ if(sscanf(cl->buffer, "%*d "MAX_STRING, buffer) != 1)
{
syslog(LOG_ERR, _("Got bad METAKEY from %s (%s)"), cl->name, cl->hostname);
return -1;
if(strlen(buffer) != len*2)
{
syslog(LOG_ERR, _("Intruder: wrong meta key length from %s (%s)"), cl->name, cl->hostname);
- free(buffer);
return -1;
}
if(RSA_private_decrypt(len, buffer, cl->cipher_inkey, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
{
syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
- free(buffer);
return -1;
}
syslog(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), buffer);
}
- free(buffer);
-
EVP_DecryptInit(cl->cipher_inctx, EVP_bf_cfb(), cl->cipher_inkey, cl->cipher_inkey + EVP_bf_cfb()->key_len);
cp
if(cl->status.outgoing)
cl->allow_request = ACK;
- setup_vpn_connection(cl);
-
x = send_request(cl, "%d", ACK);
cl->status.encryptout = 1;
cp
int ack_h(connection_t *cl)
{
+ config_t const *cfg;
connection_t *old, *p;
subnet_t *subnet;
- rbl_t *rbl, *rbl2;
+ avl_node_t *node, *node2;
cp
/* Okay, before we active the connection, we check if there is another entry
in the connection list with the same name. If so, it presumably is an
if(!cl->status.outgoing)
send_ack(cl);
+ /* Check some options */
+
+ if((cfg = get_config_val(cl->config, config_indirectdata)))
+ {
+ if(cfg->data.val == stupid_true)
+ cl->options |= OPTION_INDIRECT;
+ }
+
+ if((cfg = get_config_val(cl->config, config_tcponly)))
+ {
+ if(cfg->data.val == stupid_true)
+ cl->options |= OPTION_TCPONLY;
+ }
+
/* Send him our subnets */
- RBL_FOREACH(myself->subnet_tree, rbl)
+ for(node = myself->subnet_tree->head; node; node = node->next)
{
- subnet = (subnet_t *)rbl->data;
+ subnet = (subnet_t *)node->data;
send_add_subnet(cl, subnet);
}
/* And send him all the hosts and their subnets we know... */
- RBL_FOREACH(connection_tree, rbl)
+ for(node = connection_tree->head; node; node = node->next)
{
- p = (connection_t *)rbl->data;
+ p = (connection_t *)node->data;
if(p != cl && p->status.active)
{
send_add_host(cl, p);
- RBL_FOREACH(p->subnet_tree, rbl2)
+ for(node2 = p->subnet_tree->head; node2; node2 = node2->next)
{
- subnet = (subnet_t *)rbl2->data;
+ subnet = (subnet_t *)node2->data;
send_add_subnet(cl, subnet);
}
}
{
int x;
char *netstr;
+ char *owner;
cp
+ if(cl->options & OPTION_INDIRECT)
+ owner = myself->name;
+ else
+ owner = subnet->owner->name;
+
x = send_request(cl, "%d %s %s", ADD_SUBNET,
- subnet->owner->name, netstr = net2str(subnet));
+ owner, netstr = net2str(subnet));
free(netstr);
cp
return x;
int add_subnet_h(connection_t *cl)
{
- char *subnetstr;
- char *name;
+ char subnetstr[MAX_STRING_SIZE];
+ char name[MAX_STRING_SIZE];
connection_t *owner, *p;
subnet_t *subnet;
- rbl_t *rbl;
+ avl_node_t *node;
cp
- if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 2)
+ if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, name, subnetstr) != 2)
{
syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
- free(name); free(subnetstr);
return -1;
}
if(check_id(name))
{
syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
- free(name); free(subnetstr);
return -1;
}
if(!(subnet = str2net(subnetstr)))
{
syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
- free(name); free(subnetstr);
return -1;
}
- free(subnetstr);
-
/* Check if somebody tries to add a subnet of ourself */
if(!strcmp(name, myself->name))
{
syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
cl->name, cl->hostname);
- free(name);
sighup = 1;
return 0;
}
{
syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
name, cl->name, cl->hostname);
- cp_trace();
- dump_connection_list();
- {
- connection_t cl;
- rbl_t *rbl;
- cl.name = name;
- rbl = rbl_search_rbl(connection_tree, &cl);
- syslog(LOG_ERR, "rbl_search_rbl: %p", rbl);
- if(rbl)
- syslog(LOG_ERR, "rbl->data->name: %s", ((connection_t *)rbl->data)->name);
- }
- free(name);
return -1;
}
/* Tell the rest */
- RBL_FOREACH(connection_tree, rbl)
+ for(node = connection_tree->head; node; node = node->next)
{
- p = (connection_t *)rbl->data;
+ p = (connection_t *)node->data;
if(p->status.meta && p->status.active && p!= cl)
send_add_subnet(p, subnet);
}
{
int x;
char *netstr;
+ char *owner;
cp
- netstr = net2str(subnet);
- x = send_request(cl, "%d %s %s", DEL_SUBNET, subnet->owner->name, netstr);
+ if(cl->options & OPTION_INDIRECT)
+ owner = myself->name;
+ else
+ owner = subnet->owner->name;
+
+ x = send_request(cl, "%d %s %s", DEL_SUBNET, owner, netstr = net2str(subnet));
free(netstr);
cp
return x;
int del_subnet_h(connection_t *cl)
{
- char *subnetstr;
- char *name;
+ char subnetstr[MAX_STRING_SIZE];
+ char name[MAX_STRING_SIZE];
connection_t *owner, *p;
subnet_t *subnet;
- rbl_t *rbl;
+ avl_node_t *node;
cp
- if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
+ if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, name, subnetstr) != 3)
{
syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
- free(name); free(subnetstr);
return -1;
}
if(check_id(name))
{
syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
- free(name); free(subnetstr);
return -1;
}
if(!(subnet = str2net(subnetstr)))
{
syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
- free(name); free(subnetstr);
return -1;
}
{
syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
cl->name, cl->hostname);
- free(name);
sighup = 1;
return 0;
}
{
syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
name, cl->name, cl->hostname);
- free(name);
return -1;
}
/* Tell the rest */
- RBL_FOREACH(connection_tree, rbl)
+ for(node = connection_tree->head; node; node = node->next)
{
- p = (connection_t *)rbl->data;
+ p = (connection_t *)node->data;
if(p->status.meta && p->status.active && p!= cl)
send_del_subnet(p, subnet);
}
int send_add_host(connection_t *cl, connection_t *other)
{
cp
- return send_request(cl, "%d %s %lx:%d %lx", ADD_HOST,
+ if(!(cl->options & OPTION_INDIRECT))
+ return send_request(cl, "%d %s %lx:%d %lx", ADD_HOST,
other->name, other->address, other->port, other->options);
}
int add_host_h(connection_t *cl)
{
connection_t *old, *new, *p;
- rbl_t *rbl;
+ char name[MAX_STRING_SIZE];
+ avl_node_t *node;
cp
new = new_connection();
- if(sscanf(cl->buffer, "%*d %as %lx:%d %lx", &new->name, &new->address, &new->port, &new->options) != 4)
+ if(sscanf(cl->buffer, "%*d "MAX_STRING" %lx:%d %lx", name, &new->address, &new->port, &new->options) != 4)
{
syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
return -1;
/* Check if identity is a valid name */
- if(check_id(new->name))
+ if(check_id(name))
{
syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
free_connection(new);
/* Check if somebody tries to add ourself */
- if(!strcmp(new->name, myself->name))
+ if(!strcmp(name, myself->name))
{
syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
sighup = 1;
/* Check if the new host already exists in the connnection list */
- if((old = lookup_id(new->name)))
+ if((old = lookup_id(name)))
{
if((new->address == old->address) && (new->port == old->port))
{
if(debug_lvl >= DEBUG_CONNECTIONS)
syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
- old->name, old->hostname, new->name, new->hostname);
+ old->name, old->hostname, name, new->hostname);
free_connection(new);
return 0;
}
/* Hook it up into the connection */
+ new->name = xstrdup(name);
connection_add(new);
id_add(new);
/* Tell the rest about the new host */
- RBL_FOREACH(connection_tree, rbl)
+ for(node = connection_tree->head; node; node = node->next)
{
- p = (connection_t *)rbl->data;
+ p = (connection_t *)node->data;
if(p->status.meta && p->status.active && p!=cl)
send_add_host(p, new);
}
new->status.active = 1;
new->cipher_pkttype = EVP_bf_cfb();
new->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
-
- /* Okay this is a bit ugly... it would be better to setup UDP sockets dynamically, or
- * perhaps just one UDP socket... but then again, this has benefits too...
- */
-
- setup_vpn_connection(new);
cp
return 0;
}
int send_del_host(connection_t *cl, connection_t *other)
{
cp
- return send_request(cl, "%d %s %lx:%d %lx", DEL_HOST,
+ if(!(cl->options & OPTION_INDIRECT))
+ return send_request(cl, "%d %s %lx:%d %lx", DEL_HOST,
other->name, other->address, other->port, other->options);
}
int del_host_h(connection_t *cl)
{
- char *name;
+ char name[MAX_STRING_SIZE];
ip_t address;
port_t port;
long int options;
connection_t *old, *p;
- rbl_t *rbl;
+ avl_node_t *node;
cp
- if(sscanf(cl->buffer, "%*d %as %lx:%d %lx", &name, &address, &port, &options) != 4)
+ if(sscanf(cl->buffer, "%*d "MAX_STRING" %lx:%d %lx", name, &address, &port, &options) != 4)
{
syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
cl->name, cl->hostname);
if(check_id(name))
{
syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
- free(name);
return -1;
}
{
syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
cl->name, cl->hostname);
- free(name);
sighup = 1;
return 0;
}
{
syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
name, cl->name, cl->hostname);
- free(name);
return -1;
}
/* Tell the rest about the new host */
- RBL_FOREACH(connection_tree, rbl)
+ for(node = connection_tree->head; node; node = node->next)
{
- p = (connection_t *)rbl->data;
+ p = (connection_t *)node->data;
if(p->status.meta && p->status.active && p!=cl)
send_del_host(p, old);
}
int status_h(connection_t *cl)
{
int statusno;
- char *statusstring;
+ char statusstring[MAX_STRING_SIZE];
cp
- if(sscanf(cl->buffer, "%*d %d %as", &statusno, &statusstring) != 2)
+ if(sscanf(cl->buffer, "%*d %d "MAX_STRING, &statusno, statusstring) != 2)
{
syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
cl->name, cl->hostname);
}
cp
- free(statusstring);
return 0;
}
int error_h(connection_t *cl)
{
int errno;
- char *errorstring;
+ char errorstring[MAX_STRING_SIZE];
cp
- if(sscanf(cl->buffer, "%*d %d %as", &errno, &errorstring) != 2)
+ if(sscanf(cl->buffer, "%*d %d "MAX_STRING, &errno, errorstring) != 2)
{
syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
cl->name, cl->hostname);
cl->name, cl->hostname, strerror(errno), errorstring);
}
- free(errorstring);
terminate_connection(cl);
cp
return 0;
return 0;
}
-/* Keepalive routines - FIXME: needs a closer look */
-
int send_ping(connection_t *cl)
{
cp
int send_key_changed(connection_t *from, connection_t *cl)
{
connection_t *p;
- rbl_t *rbl;
+ avl_node_t *node;
cp
- RBL_FOREACH(connection_tree, rbl)
+ for(node = connection_tree->head; node; node = node->next)
{
- p = (connection_t *)rbl->data;
+ p = (connection_t *)node->data;
if(p != cl && p->status.meta && p->status.active)
- send_request(p, "%d %s", KEY_CHANGED, from->name);
+ if(!(p->options & OPTION_INDIRECT) || from == myself)
+ send_request(p, "%d %s", KEY_CHANGED, from->name);
}
cp
return 0;
int key_changed_h(connection_t *cl)
{
- char *from_id;
+ char from_id[MAX_STRING_SIZE];
connection_t *from;
cp
- if(sscanf(cl->buffer, "%*d %as", &from_id) != 1)
+ if(sscanf(cl->buffer, "%*d "MAX_STRING, from_id) != 1)
{
syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
cl->name, cl->hostname);
{
syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
cl->name, cl->hostname, from_id);
- free(from_id);
return -1;
}
- free(from_id);
-
from->status.validkey = 0;
from->status.waitingforkey = 0;
int req_key_h(connection_t *cl)
{
- char *from_id, *to_id;
+ char from_id[MAX_STRING_SIZE];
+ char to_id[MAX_STRING_SIZE];
connection_t *from, *to;
char pktkey[129];
cp
- if(sscanf(cl->buffer, "%*d %as %as", &from_id, &to_id) != 2)
+ if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, from_id, to_id) != 2)
{
syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
cl->name, cl->hostname);
{
syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
cl->name, cl->hostname, from_id);
- free(from_id); free(to_id);
return -1;
}
{
syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
cl->name, cl->hostname, to_id);
- free(from_id); free(to_id);
return -1;
}
send_req_key(from, to);
}
- free(from_id); free(to_id);
cp
return 0;
}
int ans_key_h(connection_t *cl)
{
- char *from_id, *to_id, *pktkey;
+ char from_id[MAX_STRING_SIZE];
+ char to_id[MAX_STRING_SIZE];
+ char pktkey[MAX_STRING_SIZE];
int keylength;
connection_t *from, *to;
cp
- if(sscanf(cl->buffer, "%*d %as %as %as", &from_id, &to_id, &pktkey) != 3)
+ if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING, from_id, to_id, pktkey) != 3)
{
syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
cl->name, cl->hostname);
{
syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
cl->name, cl->hostname, from_id);
- free(from_id); free(to_id); free(pktkey);
return -1;
}
{
syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key length"),
cl->name, cl->hostname, from->name);
- free(from_id); free(to_id); free(pktkey);
return -1;
}
{
syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
cl->name, cl->hostname, to_id);
- free(from_id); free(to_id);
return -1;
}
send_ans_key(from, to, pktkey);
if(from->cipher_pktkey)
free(from->cipher_pktkey);
+ from->cipher_pktkey = xstrdup(pktkey);
keylength /= 2;
- hex2bin(pktkey, pktkey, keylength);
- pktkey[keylength] = '\0';
- from->cipher_pktkey = pktkey;
+ hex2bin(from->cipher_pktkey, from->cipher_pktkey, keylength);
+ from->cipher_pktkey[keylength] = '\0';
from->status.validkey = 1;
from->status.waitingforkey = 0;
-
- free(from_id); free(to_id);
+
+ flush_queue(from);
cp
return 0;
}
+int send_tcppacket(connection_t *cl, vpn_packet_t *packet)
+{
+ int x;
+
+ x = send_request(cl->nexthop, "%d %hd", PACKET, packet->len);
+
+ if(x)
+ return x;
+
+ return send_meta(cl->nexthop, packet->data, packet->len);
+}
+
+int tcppacket_h(connection_t *cl)
+{
+ vpn_packet_t packet;
+ char *p;
+ int todo, x;
+
+ if(sscanf(cl->buffer, "%*d %hd", packet.len) != 1)
+ {
+ syslog(LOG_ERR, _("Got bad PACKET from %s (%s)"), cl->name, cl->hostname);
+ return -1;
+ }
+
+ /* Evil hack. */
+
+ p = packet.data;
+ todo = packet.len;
+
+ while(todo)
+ {
+ x = read(cl->meta_socket, p, todo);
+ if(x<0)
+ {
+ syslog(LOG_ERR, _("Error during reception of PACKET from %s (%s): %m"), cl->name, cl->hostname);
+ return -1;
+ }
+
+ todo -= x;
+ p += x;
+ }
+
+ return receive_packet(cl, &packet);
+}
+
/* Jumptable for the request handlers */
int (*request_handlers[])(connection_t*) = {
add_host_h, del_host_h,
add_subnet_h, del_subnet_h,
key_changed_h, req_key_h, ans_key_h,
+ tcppacket_h,
};
/* Request names */
"ADD_HOST", "DEL_HOST",
"ADD_SUBNET", "DEL_SUBNET",
"KEY_CHANGED", "REQ_KEY", "ANS_KEY",
+ "PACKET",
};
/* Status strings */