2 protocol.c -- handle the meta-protocol
3 Copyright (C) 1999,2000 Ivo Timmermans <itimmermans@bigfoot.com>,
4 2000 Guus Sliepen <guus@sliepen.warande.net>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 $Id: protocol.c,v 1.28.4.69 2000/12/05 08:59:30 zarq Exp $
25 #include <sys/types.h>
30 #include <sys/socket.h>
38 #include <netinet/in.h>
40 #ifdef HAVE_OPENSSL_SHA_H
41 # include <openssl/sha.h>
46 #ifdef HAVE_OPENSSL_RAND_H
47 # include <openssl/rand.h>
52 #ifdef HAVE_OPENSSL_EVP_H
53 # include <openssl/evp.h>
64 #include "connection.h"
68 int check_id(char *id)
72 for (i = 0; i < strlen(id); i++)
73 if(!isalnum(id[i]) && id[i] != '_')
79 /* Generic request routines - takes care of logging and error
82 int send_request(connection_t *cl, const char *format, ...)
85 char buffer[MAXBUFSIZE];
89 /* Use vsnprintf instead of vasprintf: faster, no memory
90 fragmentation, cleanup is automatic, and there is a limit on the
91 input buffer anyway */
93 va_start(args, format);
94 len = vsnprintf(buffer, MAXBUFSIZE, format, args);
95 request = va_arg(args, int);
98 if(len < 0 || len > MAXBUFSIZE-1)
100 syslog(LOG_ERR, _("Output buffer overflow while sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
106 if(debug_lvl >= DEBUG_PROTOCOL)
107 syslog(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
110 return send_meta(cl, buffer, len);
113 int receive_request(connection_t *cl)
117 if(sscanf(cl->buffer, "%d", &request) == 1)
119 if((request < 0) || (request > 255) || (request_handlers[request] == NULL))
121 syslog(LOG_ERR, _("Unknown request from %s (%s)"),
122 cl->name, cl->hostname);
127 if(debug_lvl >= DEBUG_PROTOCOL)
128 syslog(LOG_DEBUG, _("Got %s from %s (%s)"),
129 request_name[request], cl->name, cl->hostname);
132 if((cl->allow_request != ALL) && (cl->allow_request != request))
134 syslog(LOG_ERR, _("Unauthorized request from %s (%s)"), cl->name, cl->hostname);
138 if(request_handlers[request](cl))
139 /* Something went wrong. Probably scriptkiddies. Terminate. */
141 syslog(LOG_ERR, _("Error while processing %s from %s (%s)"),
142 request_name[request], cl->name, cl->hostname);
148 syslog(LOG_ERR, _("Bogus data received from %s (%s)"),
149 cl->name, cl->hostname);
156 /* Connection protocol:
165 ---------------------------------------
168 ---------------------------------------
171 ---------------------------------------
177 (E) Encrypted with symmetric cipher.
179 Part of the challenge is directly used to set the symmetric cipher
180 key and the initial vector. Since a man-in-the-middle cannot
181 decrypt the RSA challenges, this means that he cannot get or forge
182 the key for the symmetric cipher.
185 int send_id(connection_t *cl)
188 cl->allow_request = CHALLENGE;
190 return send_request(cl, "%d %s %d %lx %hd", ID, myself->name, myself->protocol_version, myself->options, myself->port);
193 int id_h(connection_t *cl)
197 char name[MAX_STRING_SIZE];
199 if(sscanf(cl->buffer, "%*d "MAX_STRING" %d %lx %hd", name, &cl->protocol_version, &cl->options, &cl->port) != 4)
201 syslog(LOG_ERR, _("Got bad ID from %s"), cl->hostname);
205 /* Check if version matches */
207 if(cl->protocol_version != myself->protocol_version)
209 syslog(LOG_ERR, _("Peer %s (%s) uses incompatible version %d"),
210 cl->name, cl->hostname, cl->protocol_version);
214 /* Check if identity is a valid name */
218 syslog(LOG_ERR, _("Peer %s uses invalid identity name"), cl->hostname);
222 /* Copy string to cl */
224 cl->name = xstrdup(name);
226 /* Load information about peer */
228 if(read_host_config(cl))
230 syslog(LOG_ERR, _("Peer %s had unknown identity (%s)"), cl->hostname, cl->name);
234 /* First check if the host we connected to is already in our
235 connection list. If so, we are probably making a loop, which
239 if(cl->status.outgoing)
241 if((old = lookup_id(cl->name)))
243 if(debug_lvl >= DEBUG_CONNECTIONS)
244 syslog(LOG_NOTICE, _("Uplink %s (%s) is already in our connection list"), cl->name, cl->hostname);
245 cl->status.outgoing = 0;
246 old->status.outgoing = 1;
247 terminate_connection(cl);
252 /* Now we can add the name to the id tree */
256 /* Read in the public key, so that we can send a challenge */
258 if((cfg = get_config_val(cl->config, config_publickey)))
260 cl->rsa_key = RSA_new();
261 if(read_rsa_public_key(&(cl->rsa_key), cfg->data.ptr) < 0)
266 syslog(LOG_ERR, _("No public key known for %s (%s)"), cl->name, cl->hostname);
270 return send_challenge(cl);
273 int send_challenge(connection_t *cl)
278 len = RSA_size(cl->rsa_key);
280 /* Allocate buffers for the challenge */
282 buffer = xmalloc(len*2+1);
285 free(cl->hischallenge);
287 cl->hischallenge = xmalloc(len);
289 /* Copy random data to the buffer */
291 RAND_bytes(cl->hischallenge, len);
293 cl->hischallenge[0] &= 0x7F; /* Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
295 if(debug_lvl >= DEBUG_SCARY_THINGS)
297 bin2hex(cl->hischallenge, buffer, len);
298 buffer[len*2] = '\0';
299 syslog(LOG_DEBUG, _("Generated random challenge (unencrypted): %s"), buffer);
302 /* Encrypt the random data */
304 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 */
306 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
311 /* Convert the encrypted random data to a hexadecimal formatted string */
313 bin2hex(buffer, buffer, len);
314 buffer[len*2] = '\0';
316 /* Send the challenge */
318 cl->allow_request = CHAL_REPLY;
319 x = send_request(cl, "%d %s", CHALLENGE, buffer);
325 int challenge_h(connection_t *cl)
327 char buffer[MAX_STRING_SIZE];
330 if(sscanf(cl->buffer, "%*d "MAX_STRING, buffer) != 1)
332 syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
336 len = RSA_size(myself->rsa_key);
338 /* Check if the length of the challenge is all right */
340 if(strlen(buffer) != len*2)
342 syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
346 /* Allocate buffers for the challenge */
349 cl->mychallenge = xmalloc(len);
351 /* Convert the challenge from hexadecimal back to binary */
353 hex2bin(buffer,buffer,len);
355 /* Decrypt the challenge */
357 if(RSA_private_decrypt(len, buffer, cl->mychallenge, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
359 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
363 if(debug_lvl >= DEBUG_SCARY_THINGS)
365 bin2hex(cl->mychallenge, buffer, len);
366 buffer[len*2] = '\0';
367 syslog(LOG_DEBUG, _("Received random challenge (unencrypted): %s"), buffer);
370 /* Rest is done by send_chal_reply() */
372 return send_chal_reply(cl);
375 int send_chal_reply(connection_t *cl)
377 char hash[SHA_DIGEST_LENGTH*2+1];
381 syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
385 /* Calculate the hash from the challenge we received */
387 SHA1(cl->mychallenge, RSA_size(myself->rsa_key), hash);
389 /* Convert the hash to a hexadecimal formatted string */
391 bin2hex(hash,hash,SHA_DIGEST_LENGTH);
392 hash[SHA_DIGEST_LENGTH*2] = '\0';
396 if(cl->status.outgoing)
397 cl->allow_request = ID;
399 cl->allow_request = METAKEY;
402 return send_request(cl, "%d %s", CHAL_REPLY, hash);
405 int chal_reply_h(connection_t *cl)
407 char hishash[MAX_STRING_SIZE];
408 char myhash[SHA_DIGEST_LENGTH];
410 if(sscanf(cl->buffer, "%*d "MAX_STRING, hishash) != 1)
412 syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
416 /* Check if the length of the hash is all right */
418 if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
420 syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
424 /* Convert the hash to binary format */
426 hex2bin(hishash, hishash, SHA_DIGEST_LENGTH);
428 /* Calculate the hash from the challenge we sent */
430 SHA1(cl->hischallenge, RSA_size(cl->rsa_key), myhash);
432 /* Verify the incoming hash with the calculated hash */
434 if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
436 syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
437 if(debug_lvl >= DEBUG_SCARY_THINGS)
439 bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
440 hishash[SHA_DIGEST_LENGTH*2] = '\0';
441 syslog(LOG_DEBUG, _("Expected challenge reply: %s"), hishash);
447 /* Identity has now been positively verified.
448 If we are accepting this new connection, then send our identity,
449 if we are making this connecting, acknowledge.
452 if(cl->status.outgoing)
453 return send_metakey(cl);
458 int send_metakey(connection_t *cl)
463 len = RSA_size(cl->rsa_key);
465 /* Allocate buffers for the meta key */
467 buffer = xmalloc(len*2+1);
469 if(!cl->cipher_outkey)
470 cl->cipher_outkey = xmalloc(len);
472 if(!cl->cipher_outctx)
473 cl->cipher_outctx = xmalloc(sizeof(*cl->cipher_outctx));
475 /* Copy random data to the buffer */
477 RAND_bytes(cl->cipher_outkey, len);
479 cl->cipher_outkey[0] &= 0x7F; /* FIXME: Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
481 if(debug_lvl >= DEBUG_SCARY_THINGS)
483 bin2hex(cl->cipher_outkey, buffer, len);
484 buffer[len*2] = '\0';
485 syslog(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"), buffer);
488 /* Encrypt the random data */
490 if(RSA_public_encrypt(len, cl->cipher_outkey, buffer, cl->rsa_key, RSA_NO_PADDING) != len) /* NO_PADDING because the message size equals the RSA key size and it is totally random */
492 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
497 /* Convert the encrypted random data to a hexadecimal formatted string */
499 bin2hex(buffer, buffer, len);
500 buffer[len*2] = '\0';
502 /* Send the meta key */
504 if(cl->status.outgoing)
505 cl->allow_request = METAKEY;
507 cl->allow_request = ACK;
509 x = send_request(cl, "%d %s", METAKEY, buffer);
512 EVP_EncryptInit(cl->cipher_outctx, EVP_bf_cfb(), cl->cipher_outkey, cl->cipher_outkey + EVP_bf_cfb()->key_len);
517 int metakey_h(connection_t *cl)
519 char buffer[MAX_STRING_SIZE];
522 if(sscanf(cl->buffer, "%*d "MAX_STRING, buffer) != 1)
524 syslog(LOG_ERR, _("Got bad METAKEY from %s (%s)"), cl->name, cl->hostname);
528 len = RSA_size(myself->rsa_key);
530 /* Check if the length of the meta key is all right */
532 if(strlen(buffer) != len*2)
534 syslog(LOG_ERR, _("Intruder: wrong meta key length from %s (%s)"), cl->name, cl->hostname);
538 /* Allocate buffers for the meta key */
540 if(!cl->cipher_inkey)
541 cl->cipher_inkey = xmalloc(len);
543 if(!cl->cipher_inctx)
544 cl->cipher_inctx = xmalloc(sizeof(*cl->cipher_inctx));
546 /* Convert the challenge from hexadecimal back to binary */
548 hex2bin(buffer,buffer,len);
550 /* Decrypt the meta key */
552 if(RSA_private_decrypt(len, buffer, cl->cipher_inkey, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
554 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
558 if(debug_lvl >= DEBUG_SCARY_THINGS)
560 bin2hex(cl->cipher_inkey, buffer, len);
561 buffer[len*2] = '\0';
562 syslog(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), buffer);
565 EVP_DecryptInit(cl->cipher_inctx, EVP_bf_cfb(), cl->cipher_inkey, cl->cipher_inkey + EVP_bf_cfb()->key_len);
568 if(cl->status.outgoing)
571 return send_metakey(cl);
574 int send_ack(connection_t *cl)
578 if(cl->status.outgoing)
579 cl->allow_request = ACK;
581 x = send_request(cl, "%d", ACK);
582 cl->status.encryptout = 1;
587 int ack_h(connection_t *cl)
589 connection_t *old, *p;
593 /* Okay, before we active the connection, we check if there is another entry
594 in the connection list with the same name. If so, it presumably is an
595 old connection that has timed out but we don't know it yet.
598 while((old = lookup_id(cl->name)))
600 if(debug_lvl >= DEBUG_CONNECTIONS)
601 syslog(LOG_NOTICE, _("Removing old entry for %s at %s in favour of new connection from %s"),
602 cl->name, old->hostname, cl->hostname);
604 terminate_connection(old);
607 /* Activate this connection */
609 cl->allow_request = ALL;
610 cl->status.active = 1;
611 cl->status.decryptin = 1;
613 cl->cipher_pkttype = EVP_bf_cfb();
614 cl->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
616 if(debug_lvl >= DEBUG_CONNECTIONS)
617 syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname);
620 if(!cl->status.outgoing)
623 /* Send him our subnets */
625 RBL_FOREACH(myself->subnet_tree, rbl)
627 subnet = (subnet_t *)rbl->data;
628 send_add_subnet(cl, subnet);
630 /* And send him all the hosts and their subnets we know... */
632 RBL_FOREACH(connection_tree, rbl)
634 p = (connection_t *)rbl->data;
636 if(p != cl && p->status.active)
638 /* Notify others of this connection */
641 send_add_host(p, cl);
643 /* Notify new connection of everything we know */
645 send_add_host(cl, p);
647 RBL_FOREACH(p->subnet_tree, rbl2)
649 subnet = (subnet_t *)rbl2->data;
650 send_add_subnet(cl, subnet);
658 /* Address and subnet information exchange */
660 int send_add_subnet(connection_t *cl, subnet_t *subnet)
665 x = send_request(cl, "%d %s %s", ADD_SUBNET,
666 subnet->owner->name, netstr = net2str(subnet));
672 int add_subnet_h(connection_t *cl)
674 char subnetstr[MAX_STRING_SIZE];
675 char name[MAX_STRING_SIZE];
676 connection_t *owner, *p;
680 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, name, subnetstr) != 2)
682 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
686 /* Check if owner name is a valid */
690 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
694 /* Check if subnet string is valid */
696 if(!(subnet = str2net(subnetstr)))
698 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
702 /* Check if somebody tries to add a subnet of ourself */
704 if(!strcmp(name, myself->name))
706 syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
707 cl->name, cl->hostname);
712 /* Check if the owner of the new subnet is in the connection list */
714 if(!(owner = lookup_id(name)))
716 syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
717 name, cl->name, cl->hostname);
721 /* If everything is correct, add the subnet to the list of the owner */
723 subnet_add(owner, subnet);
727 RBL_FOREACH(connection_tree, rbl)
729 p = (connection_t *)rbl->data;
730 if(p->status.meta && p->status.active && p!= cl)
731 send_add_subnet(p, subnet);
737 int send_del_subnet(connection_t *cl, subnet_t *subnet)
742 netstr = net2str(subnet);
743 x = send_request(cl, "%d %s %s", DEL_SUBNET, subnet->owner->name, netstr);
749 int del_subnet_h(connection_t *cl)
751 char subnetstr[MAX_STRING_SIZE];
752 char name[MAX_STRING_SIZE];
753 connection_t *owner, *p;
757 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, name, subnetstr) != 3)
759 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
763 /* Check if owner name is a valid */
767 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
771 /* Check if subnet string is valid */
773 if(!(subnet = str2net(subnetstr)))
775 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
781 /* Check if somebody tries to add a subnet of ourself */
783 if(!strcmp(name, myself->name))
785 syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
786 cl->name, cl->hostname);
791 /* Check if the owner of the new subnet is in the connection list */
793 if(!(owner = lookup_id(name)))
795 syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
796 name, cl->name, cl->hostname);
800 /* If everything is correct, delete the subnet from the list of the owner */
806 RBL_FOREACH(connection_tree, rbl)
808 p = (connection_t *)rbl->data;
809 if(p->status.meta && p->status.active && p!= cl)
810 send_del_subnet(p, subnet);
816 /* New and closed connections notification */
818 int send_add_host(connection_t *cl, connection_t *other)
821 return send_request(cl, "%d %s %lx:%d %lx", ADD_HOST,
822 other->name, other->address, other->port, other->options);
825 int add_host_h(connection_t *cl)
827 connection_t *old, *new, *p;
828 char name[MAX_STRING_SIZE];
831 new = new_connection();
833 if(sscanf(cl->buffer, "%*d "MAX_STRING" %lx:%d %lx", name, &new->address, &new->port, &new->options) != 4)
835 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
839 /* Check if identity is a valid name */
843 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
844 free_connection(new);
848 /* Check if somebody tries to add ourself */
850 if(!strcmp(name, myself->name))
852 syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
854 free_connection(new);
858 /* Fill in more of the new connection structure */
860 new->hostname = hostlookup(htonl(new->address));
862 /* Check if the new host already exists in the connnection list */
864 if((old = lookup_id(name)))
866 if((new->address == old->address) && (new->port == old->port))
868 if(debug_lvl >= DEBUG_CONNECTIONS)
869 syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
870 old->name, old->hostname, name, new->hostname);
871 free_connection(new);
876 if(debug_lvl >= DEBUG_CONNECTIONS)
877 syslog(LOG_NOTICE, _("Removing old entry for %s (%s) in favour of new connection"),
878 old->name, old->hostname);
880 terminate_connection(old);
884 /* Hook it up into the connection */
886 new->name = xstrdup(name);
890 /* Tell the rest about the new host */
892 RBL_FOREACH(connection_tree, rbl)
894 p = (connection_t *)rbl->data;
895 if(p->status.meta && p->status.active && p!=cl)
896 send_add_host(p, new);
899 /* Fill in rest of connection structure */
902 new->status.active = 1;
903 new->cipher_pkttype = EVP_bf_cfb();
904 new->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
909 int send_del_host(connection_t *cl, connection_t *other)
912 return send_request(cl, "%d %s %lx:%d %lx", DEL_HOST,
913 other->name, other->address, other->port, other->options);
916 int del_host_h(connection_t *cl)
918 char name[MAX_STRING_SIZE];
922 connection_t *old, *p;
925 if(sscanf(cl->buffer, "%*d "MAX_STRING" %lx:%d %lx", name, &address, &port, &options) != 4)
927 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
928 cl->name, cl->hostname);
932 /* Check if identity is a valid name */
936 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
940 /* Check if somebody tries to delete ourself */
942 if(!strcmp(name, myself->name))
944 syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
945 cl->name, cl->hostname);
950 /* Check if the new host already exists in the connnection list */
952 if(!(old = lookup_id(name)))
954 syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
955 name, cl->name, cl->hostname);
959 /* Check if the rest matches */
961 if(address!=old->address || port!=old->port || options!=old->options || cl!=old->nexthop)
963 syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
967 /* Ok, since EVERYTHING seems to check out all right, delete it */
969 old->status.active = 0;
970 terminate_connection(old);
972 /* Tell the rest about the new host */
974 RBL_FOREACH(connection_tree, rbl)
976 p = (connection_t *)rbl->data;
977 if(p->status.meta && p->status.active && p!=cl)
978 send_del_host(p, old);
984 /* Status and error notification routines */
986 int send_status(connection_t *cl, int statusno, char *statusstring)
990 statusstring = status_text[statusno];
992 return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
995 int status_h(connection_t *cl)
998 char statusstring[MAX_STRING_SIZE];
1000 if(sscanf(cl->buffer, "%*d %d "MAX_STRING, &statusno, statusstring) != 2)
1002 syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
1003 cl->name, cl->hostname);
1007 if(debug_lvl >= DEBUG_STATUS)
1009 syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
1010 cl->name, cl->hostname, status_text[statusno], statusstring);
1017 int send_error(connection_t *cl, int errno, char *errstring)
1021 errstring = strerror(errno);
1022 return send_request(cl, "%d %d %s", ERROR, errno, errstring);
1025 int error_h(connection_t *cl)
1028 char errorstring[MAX_STRING_SIZE];
1030 if(sscanf(cl->buffer, "%*d %d "MAX_STRING, &errno, errorstring) != 2)
1032 syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
1033 cl->name, cl->hostname);
1037 if(debug_lvl >= DEBUG_ERROR)
1039 syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
1040 cl->name, cl->hostname, strerror(errno), errorstring);
1043 terminate_connection(cl);
1048 int send_termreq(connection_t *cl)
1051 return send_request(cl, "%d", TERMREQ);
1054 int termreq_h(connection_t *cl)
1057 terminate_connection(cl);
1062 /* Keepalive routines - FIXME: needs a closer look */
1064 int send_ping(connection_t *cl)
1067 cl->status.pinged = 1;
1068 cl->last_ping_time = time(NULL);
1070 return send_request(cl, "%d", PING);
1073 int ping_h(connection_t *cl)
1076 return send_pong(cl);
1079 int send_pong(connection_t *cl)
1082 return send_request(cl, "%d", PONG);
1085 int pong_h(connection_t *cl)
1088 cl->status.pinged = 0;
1095 int send_key_changed(connection_t *from, connection_t *cl)
1100 RBL_FOREACH(connection_tree, rbl)
1102 p = (connection_t *)rbl->data;
1103 if(p != cl && p->status.meta && p->status.active)
1104 send_request(p, "%d %s", KEY_CHANGED, from->name);
1110 int key_changed_h(connection_t *cl)
1112 char from_id[MAX_STRING_SIZE];
1115 if(sscanf(cl->buffer, "%*d "MAX_STRING, from_id) != 1)
1117 syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
1118 cl->name, cl->hostname);
1122 if(!(from = lookup_id(from_id)))
1124 syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
1125 cl->name, cl->hostname, from_id);
1129 from->status.validkey = 0;
1130 from->status.waitingforkey = 0;
1132 send_key_changed(from, cl);
1137 int send_req_key(connection_t *from, connection_t *to)
1140 return send_request(to->nexthop, "%d %s %s", REQ_KEY,
1141 from->name, to->name);
1144 int req_key_h(connection_t *cl)
1146 char from_id[MAX_STRING_SIZE];
1147 char to_id[MAX_STRING_SIZE];
1148 connection_t *from, *to;
1151 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, from_id, to_id) != 2)
1153 syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
1154 cl->name, cl->hostname);
1158 if(!(from = lookup_id(from_id)))
1160 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
1161 cl->name, cl->hostname, from_id);
1165 /* Check if this key request is for us */
1167 if(!strcmp(to_id, myself->name))
1169 bin2hex(myself->cipher_pktkey, pktkey, myself->cipher_pktkeylength);
1170 pktkey[myself->cipher_pktkeylength*2] = '\0';
1171 send_ans_key(myself, from, pktkey);
1175 if(!(to = lookup_id(to_id)))
1177 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
1178 cl->name, cl->hostname, to_id);
1182 if(to->status.validkey) /* Proxy keys */
1184 bin2hex(to->cipher_pktkey, pktkey, to->cipher_pktkeylength);
1185 pktkey[to->cipher_pktkeylength*2] = '\0';
1186 send_ans_key(to, from, pktkey);
1189 send_req_key(from, to);
1196 int send_ans_key(connection_t *from, connection_t *to, char *pktkey)
1199 return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
1200 from->name, to->name, pktkey);
1203 int ans_key_h(connection_t *cl)
1205 char from_id[MAX_STRING_SIZE];
1206 char to_id[MAX_STRING_SIZE];
1207 char pktkey[MAX_STRING_SIZE];
1209 connection_t *from, *to;
1211 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING, from_id, to_id, pktkey) != 3)
1213 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
1214 cl->name, cl->hostname);
1218 if(!(from = lookup_id(from_id)))
1220 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
1221 cl->name, cl->hostname, from_id);
1225 /* Check correctness of packet key */
1227 keylength = strlen(pktkey);
1229 if(keylength != from->cipher_pktkeylength*2)
1231 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key length"),
1232 cl->name, cl->hostname, from->name);
1236 /* Forward it if necessary */
1238 if(strcmp(to_id, myself->name))
1240 if(!(to = lookup_id(to_id)))
1242 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1243 cl->name, cl->hostname, to_id);
1246 send_ans_key(from, to, pktkey);
1249 /* Update our copy of the origin's packet key */
1251 if(from->cipher_pktkey)
1252 free(from->cipher_pktkey);
1254 from->cipher_pktkey = xstrdup(pktkey);
1256 hex2bin(from->cipher_pktkey, from->cipher_pktkey, keylength);
1257 from->cipher_pktkey[keylength] = '\0';
1259 from->status.validkey = 1;
1260 from->status.waitingforkey = 0;
1265 /* Jumptable for the request handlers */
1267 int (*request_handlers[])(connection_t*) = {
1268 id_h, challenge_h, chal_reply_h, metakey_h, ack_h,
1269 status_h, error_h, termreq_h,
1271 add_host_h, del_host_h,
1272 add_subnet_h, del_subnet_h,
1273 key_changed_h, req_key_h, ans_key_h,
1278 char (*request_name[]) = {
1279 "ID", "CHALLENGE", "CHAL_REPLY", "METAKEY", "ACK",
1280 "STATUS", "ERROR", "TERMREQ",
1282 "ADD_HOST", "DEL_HOST",
1283 "ADD_SUBNET", "DEL_SUBNET",
1284 "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1287 /* Status strings */
1289 char (*status_text[]) = {
1295 char (*error_text[]) = {