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.70 2000/12/22 21:34:24 guus 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(read_rsa_public_key(cl))
262 return send_challenge(cl);
265 int send_challenge(connection_t *cl)
270 len = RSA_size(cl->rsa_key);
272 /* Allocate buffers for the challenge */
274 buffer = xmalloc(len*2+1);
277 free(cl->hischallenge);
279 cl->hischallenge = xmalloc(len);
281 /* Copy random data to the buffer */
283 RAND_bytes(cl->hischallenge, len);
285 cl->hischallenge[0] &= 0x7F; /* Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
287 if(debug_lvl >= DEBUG_SCARY_THINGS)
289 bin2hex(cl->hischallenge, buffer, len);
290 buffer[len*2] = '\0';
291 syslog(LOG_DEBUG, _("Generated random challenge (unencrypted): %s"), buffer);
294 /* Encrypt the random data */
296 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 */
298 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
303 /* Convert the encrypted random data to a hexadecimal formatted string */
305 bin2hex(buffer, buffer, len);
306 buffer[len*2] = '\0';
308 /* Send the challenge */
310 cl->allow_request = CHAL_REPLY;
311 x = send_request(cl, "%d %s", CHALLENGE, buffer);
317 int challenge_h(connection_t *cl)
319 char buffer[MAX_STRING_SIZE];
322 if(sscanf(cl->buffer, "%*d "MAX_STRING, buffer) != 1)
324 syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
328 len = RSA_size(myself->rsa_key);
330 /* Check if the length of the challenge is all right */
332 if(strlen(buffer) != len*2)
334 syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
338 /* Allocate buffers for the challenge */
341 cl->mychallenge = xmalloc(len);
343 /* Convert the challenge from hexadecimal back to binary */
345 hex2bin(buffer,buffer,len);
347 /* Decrypt the challenge */
349 if(RSA_private_decrypt(len, buffer, cl->mychallenge, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
351 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
355 if(debug_lvl >= DEBUG_SCARY_THINGS)
357 bin2hex(cl->mychallenge, buffer, len);
358 buffer[len*2] = '\0';
359 syslog(LOG_DEBUG, _("Received random challenge (unencrypted): %s"), buffer);
362 /* Rest is done by send_chal_reply() */
364 return send_chal_reply(cl);
367 int send_chal_reply(connection_t *cl)
369 char hash[SHA_DIGEST_LENGTH*2+1];
373 syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
377 /* Calculate the hash from the challenge we received */
379 SHA1(cl->mychallenge, RSA_size(myself->rsa_key), hash);
381 /* Convert the hash to a hexadecimal formatted string */
383 bin2hex(hash,hash,SHA_DIGEST_LENGTH);
384 hash[SHA_DIGEST_LENGTH*2] = '\0';
388 if(cl->status.outgoing)
389 cl->allow_request = ID;
391 cl->allow_request = METAKEY;
394 return send_request(cl, "%d %s", CHAL_REPLY, hash);
397 int chal_reply_h(connection_t *cl)
399 char hishash[MAX_STRING_SIZE];
400 char myhash[SHA_DIGEST_LENGTH];
402 if(sscanf(cl->buffer, "%*d "MAX_STRING, hishash) != 1)
404 syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
408 /* Check if the length of the hash is all right */
410 if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
412 syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
416 /* Convert the hash to binary format */
418 hex2bin(hishash, hishash, SHA_DIGEST_LENGTH);
420 /* Calculate the hash from the challenge we sent */
422 SHA1(cl->hischallenge, RSA_size(cl->rsa_key), myhash);
424 /* Verify the incoming hash with the calculated hash */
426 if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
428 syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
429 if(debug_lvl >= DEBUG_SCARY_THINGS)
431 bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
432 hishash[SHA_DIGEST_LENGTH*2] = '\0';
433 syslog(LOG_DEBUG, _("Expected challenge reply: %s"), hishash);
439 /* Identity has now been positively verified.
440 If we are accepting this new connection, then send our identity,
441 if we are making this connecting, acknowledge.
444 if(cl->status.outgoing)
445 return send_metakey(cl);
450 int send_metakey(connection_t *cl)
455 len = RSA_size(cl->rsa_key);
457 /* Allocate buffers for the meta key */
459 buffer = xmalloc(len*2+1);
461 if(!cl->cipher_outkey)
462 cl->cipher_outkey = xmalloc(len);
464 if(!cl->cipher_outctx)
465 cl->cipher_outctx = xmalloc(sizeof(*cl->cipher_outctx));
467 /* Copy random data to the buffer */
469 RAND_bytes(cl->cipher_outkey, len);
471 cl->cipher_outkey[0] &= 0x7F; /* FIXME: Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
473 if(debug_lvl >= DEBUG_SCARY_THINGS)
475 bin2hex(cl->cipher_outkey, buffer, len);
476 buffer[len*2] = '\0';
477 syslog(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"), buffer);
480 /* Encrypt the random data */
482 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 */
484 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
489 /* Convert the encrypted random data to a hexadecimal formatted string */
491 bin2hex(buffer, buffer, len);
492 buffer[len*2] = '\0';
494 /* Send the meta key */
496 if(cl->status.outgoing)
497 cl->allow_request = METAKEY;
499 cl->allow_request = ACK;
501 x = send_request(cl, "%d %s", METAKEY, buffer);
504 EVP_EncryptInit(cl->cipher_outctx, EVP_bf_cfb(), cl->cipher_outkey, cl->cipher_outkey + EVP_bf_cfb()->key_len);
509 int metakey_h(connection_t *cl)
511 char buffer[MAX_STRING_SIZE];
514 if(sscanf(cl->buffer, "%*d "MAX_STRING, buffer) != 1)
516 syslog(LOG_ERR, _("Got bad METAKEY from %s (%s)"), cl->name, cl->hostname);
520 len = RSA_size(myself->rsa_key);
522 /* Check if the length of the meta key is all right */
524 if(strlen(buffer) != len*2)
526 syslog(LOG_ERR, _("Intruder: wrong meta key length from %s (%s)"), cl->name, cl->hostname);
530 /* Allocate buffers for the meta key */
532 if(!cl->cipher_inkey)
533 cl->cipher_inkey = xmalloc(len);
535 if(!cl->cipher_inctx)
536 cl->cipher_inctx = xmalloc(sizeof(*cl->cipher_inctx));
538 /* Convert the challenge from hexadecimal back to binary */
540 hex2bin(buffer,buffer,len);
542 /* Decrypt the meta key */
544 if(RSA_private_decrypt(len, buffer, cl->cipher_inkey, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
546 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
550 if(debug_lvl >= DEBUG_SCARY_THINGS)
552 bin2hex(cl->cipher_inkey, buffer, len);
553 buffer[len*2] = '\0';
554 syslog(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), buffer);
557 EVP_DecryptInit(cl->cipher_inctx, EVP_bf_cfb(), cl->cipher_inkey, cl->cipher_inkey + EVP_bf_cfb()->key_len);
560 if(cl->status.outgoing)
563 return send_metakey(cl);
566 int send_ack(connection_t *cl)
570 if(cl->status.outgoing)
571 cl->allow_request = ACK;
573 x = send_request(cl, "%d", ACK);
574 cl->status.encryptout = 1;
579 int ack_h(connection_t *cl)
581 connection_t *old, *p;
585 /* Okay, before we active the connection, we check if there is another entry
586 in the connection list with the same name. If so, it presumably is an
587 old connection that has timed out but we don't know it yet.
590 while((old = lookup_id(cl->name)))
592 if(debug_lvl >= DEBUG_CONNECTIONS)
593 syslog(LOG_NOTICE, _("Removing old entry for %s at %s in favour of new connection from %s"),
594 cl->name, old->hostname, cl->hostname);
596 terminate_connection(old);
599 /* Activate this connection */
601 cl->allow_request = ALL;
602 cl->status.active = 1;
603 cl->status.decryptin = 1;
605 cl->cipher_pkttype = EVP_bf_cfb();
606 cl->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
608 if(debug_lvl >= DEBUG_CONNECTIONS)
609 syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname);
612 if(!cl->status.outgoing)
615 /* Send him our subnets */
617 RBL_FOREACH(myself->subnet_tree, rbl)
619 subnet = (subnet_t *)rbl->data;
620 send_add_subnet(cl, subnet);
622 /* And send him all the hosts and their subnets we know... */
624 RBL_FOREACH(connection_tree, rbl)
626 p = (connection_t *)rbl->data;
628 if(p != cl && p->status.active)
630 /* Notify others of this connection */
633 send_add_host(p, cl);
635 /* Notify new connection of everything we know */
637 send_add_host(cl, p);
639 RBL_FOREACH(p->subnet_tree, rbl2)
641 subnet = (subnet_t *)rbl2->data;
642 send_add_subnet(cl, subnet);
650 /* Address and subnet information exchange */
652 int send_add_subnet(connection_t *cl, subnet_t *subnet)
657 x = send_request(cl, "%d %s %s", ADD_SUBNET,
658 subnet->owner->name, netstr = net2str(subnet));
664 int add_subnet_h(connection_t *cl)
666 char subnetstr[MAX_STRING_SIZE];
667 char name[MAX_STRING_SIZE];
668 connection_t *owner, *p;
672 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, name, subnetstr) != 2)
674 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
678 /* Check if owner name is a valid */
682 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
686 /* Check if subnet string is valid */
688 if(!(subnet = str2net(subnetstr)))
690 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
694 /* Check if somebody tries to add a subnet of ourself */
696 if(!strcmp(name, myself->name))
698 syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
699 cl->name, cl->hostname);
704 /* Check if the owner of the new subnet is in the connection list */
706 if(!(owner = lookup_id(name)))
708 syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
709 name, cl->name, cl->hostname);
713 /* If everything is correct, add the subnet to the list of the owner */
715 subnet_add(owner, subnet);
719 RBL_FOREACH(connection_tree, rbl)
721 p = (connection_t *)rbl->data;
722 if(p->status.meta && p->status.active && p!= cl)
723 send_add_subnet(p, subnet);
729 int send_del_subnet(connection_t *cl, subnet_t *subnet)
734 netstr = net2str(subnet);
735 x = send_request(cl, "%d %s %s", DEL_SUBNET, subnet->owner->name, netstr);
741 int del_subnet_h(connection_t *cl)
743 char subnetstr[MAX_STRING_SIZE];
744 char name[MAX_STRING_SIZE];
745 connection_t *owner, *p;
749 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, name, subnetstr) != 3)
751 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
755 /* Check if owner name is a valid */
759 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
763 /* Check if subnet string is valid */
765 if(!(subnet = str2net(subnetstr)))
767 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
773 /* Check if somebody tries to add a subnet of ourself */
775 if(!strcmp(name, myself->name))
777 syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
778 cl->name, cl->hostname);
783 /* Check if the owner of the new subnet is in the connection list */
785 if(!(owner = lookup_id(name)))
787 syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
788 name, cl->name, cl->hostname);
792 /* If everything is correct, delete the subnet from the list of the owner */
798 RBL_FOREACH(connection_tree, rbl)
800 p = (connection_t *)rbl->data;
801 if(p->status.meta && p->status.active && p!= cl)
802 send_del_subnet(p, subnet);
808 /* New and closed connections notification */
810 int send_add_host(connection_t *cl, connection_t *other)
813 return send_request(cl, "%d %s %lx:%d %lx", ADD_HOST,
814 other->name, other->address, other->port, other->options);
817 int add_host_h(connection_t *cl)
819 connection_t *old, *new, *p;
820 char name[MAX_STRING_SIZE];
823 new = new_connection();
825 if(sscanf(cl->buffer, "%*d "MAX_STRING" %lx:%d %lx", name, &new->address, &new->port, &new->options) != 4)
827 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
831 /* Check if identity is a valid name */
835 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
836 free_connection(new);
840 /* Check if somebody tries to add ourself */
842 if(!strcmp(name, myself->name))
844 syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
846 free_connection(new);
850 /* Fill in more of the new connection structure */
852 new->hostname = hostlookup(htonl(new->address));
854 /* Check if the new host already exists in the connnection list */
856 if((old = lookup_id(name)))
858 if((new->address == old->address) && (new->port == old->port))
860 if(debug_lvl >= DEBUG_CONNECTIONS)
861 syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
862 old->name, old->hostname, name, new->hostname);
863 free_connection(new);
868 if(debug_lvl >= DEBUG_CONNECTIONS)
869 syslog(LOG_NOTICE, _("Removing old entry for %s (%s) in favour of new connection"),
870 old->name, old->hostname);
872 terminate_connection(old);
876 /* Hook it up into the connection */
878 new->name = xstrdup(name);
882 /* Tell the rest about the new host */
884 RBL_FOREACH(connection_tree, rbl)
886 p = (connection_t *)rbl->data;
887 if(p->status.meta && p->status.active && p!=cl)
888 send_add_host(p, new);
891 /* Fill in rest of connection structure */
894 new->status.active = 1;
895 new->cipher_pkttype = EVP_bf_cfb();
896 new->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
901 int send_del_host(connection_t *cl, connection_t *other)
904 return send_request(cl, "%d %s %lx:%d %lx", DEL_HOST,
905 other->name, other->address, other->port, other->options);
908 int del_host_h(connection_t *cl)
910 char name[MAX_STRING_SIZE];
914 connection_t *old, *p;
917 if(sscanf(cl->buffer, "%*d "MAX_STRING" %lx:%d %lx", name, &address, &port, &options) != 4)
919 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
920 cl->name, cl->hostname);
924 /* Check if identity is a valid name */
928 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
932 /* Check if somebody tries to delete ourself */
934 if(!strcmp(name, myself->name))
936 syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
937 cl->name, cl->hostname);
942 /* Check if the new host already exists in the connnection list */
944 if(!(old = lookup_id(name)))
946 syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
947 name, cl->name, cl->hostname);
951 /* Check if the rest matches */
953 if(address!=old->address || port!=old->port || options!=old->options || cl!=old->nexthop)
955 syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
959 /* Ok, since EVERYTHING seems to check out all right, delete it */
961 old->status.active = 0;
962 terminate_connection(old);
964 /* Tell the rest about the new host */
966 RBL_FOREACH(connection_tree, rbl)
968 p = (connection_t *)rbl->data;
969 if(p->status.meta && p->status.active && p!=cl)
970 send_del_host(p, old);
976 /* Status and error notification routines */
978 int send_status(connection_t *cl, int statusno, char *statusstring)
982 statusstring = status_text[statusno];
984 return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
987 int status_h(connection_t *cl)
990 char statusstring[MAX_STRING_SIZE];
992 if(sscanf(cl->buffer, "%*d %d "MAX_STRING, &statusno, statusstring) != 2)
994 syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
995 cl->name, cl->hostname);
999 if(debug_lvl >= DEBUG_STATUS)
1001 syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
1002 cl->name, cl->hostname, status_text[statusno], statusstring);
1009 int send_error(connection_t *cl, int errno, char *errstring)
1013 errstring = strerror(errno);
1014 return send_request(cl, "%d %d %s", ERROR, errno, errstring);
1017 int error_h(connection_t *cl)
1020 char errorstring[MAX_STRING_SIZE];
1022 if(sscanf(cl->buffer, "%*d %d "MAX_STRING, &errno, errorstring) != 2)
1024 syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
1025 cl->name, cl->hostname);
1029 if(debug_lvl >= DEBUG_ERROR)
1031 syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
1032 cl->name, cl->hostname, strerror(errno), errorstring);
1035 terminate_connection(cl);
1040 int send_termreq(connection_t *cl)
1043 return send_request(cl, "%d", TERMREQ);
1046 int termreq_h(connection_t *cl)
1049 terminate_connection(cl);
1054 /* Keepalive routines - FIXME: needs a closer look */
1056 int send_ping(connection_t *cl)
1059 cl->status.pinged = 1;
1060 cl->last_ping_time = time(NULL);
1062 return send_request(cl, "%d", PING);
1065 int ping_h(connection_t *cl)
1068 return send_pong(cl);
1071 int send_pong(connection_t *cl)
1074 return send_request(cl, "%d", PONG);
1077 int pong_h(connection_t *cl)
1080 cl->status.pinged = 0;
1087 int send_key_changed(connection_t *from, connection_t *cl)
1092 RBL_FOREACH(connection_tree, rbl)
1094 p = (connection_t *)rbl->data;
1095 if(p != cl && p->status.meta && p->status.active)
1096 send_request(p, "%d %s", KEY_CHANGED, from->name);
1102 int key_changed_h(connection_t *cl)
1104 char from_id[MAX_STRING_SIZE];
1107 if(sscanf(cl->buffer, "%*d "MAX_STRING, from_id) != 1)
1109 syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
1110 cl->name, cl->hostname);
1114 if(!(from = lookup_id(from_id)))
1116 syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
1117 cl->name, cl->hostname, from_id);
1121 from->status.validkey = 0;
1122 from->status.waitingforkey = 0;
1124 send_key_changed(from, cl);
1129 int send_req_key(connection_t *from, connection_t *to)
1132 return send_request(to->nexthop, "%d %s %s", REQ_KEY,
1133 from->name, to->name);
1136 int req_key_h(connection_t *cl)
1138 char from_id[MAX_STRING_SIZE];
1139 char to_id[MAX_STRING_SIZE];
1140 connection_t *from, *to;
1143 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, from_id, to_id) != 2)
1145 syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
1146 cl->name, cl->hostname);
1150 if(!(from = lookup_id(from_id)))
1152 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
1153 cl->name, cl->hostname, from_id);
1157 /* Check if this key request is for us */
1159 if(!strcmp(to_id, myself->name))
1161 bin2hex(myself->cipher_pktkey, pktkey, myself->cipher_pktkeylength);
1162 pktkey[myself->cipher_pktkeylength*2] = '\0';
1163 send_ans_key(myself, from, pktkey);
1167 if(!(to = lookup_id(to_id)))
1169 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
1170 cl->name, cl->hostname, to_id);
1174 if(to->status.validkey) /* Proxy keys */
1176 bin2hex(to->cipher_pktkey, pktkey, to->cipher_pktkeylength);
1177 pktkey[to->cipher_pktkeylength*2] = '\0';
1178 send_ans_key(to, from, pktkey);
1181 send_req_key(from, to);
1188 int send_ans_key(connection_t *from, connection_t *to, char *pktkey)
1191 return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
1192 from->name, to->name, pktkey);
1195 int ans_key_h(connection_t *cl)
1197 char from_id[MAX_STRING_SIZE];
1198 char to_id[MAX_STRING_SIZE];
1199 char pktkey[MAX_STRING_SIZE];
1201 connection_t *from, *to;
1203 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING, from_id, to_id, pktkey) != 3)
1205 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
1206 cl->name, cl->hostname);
1210 if(!(from = lookup_id(from_id)))
1212 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
1213 cl->name, cl->hostname, from_id);
1217 /* Check correctness of packet key */
1219 keylength = strlen(pktkey);
1221 if(keylength != from->cipher_pktkeylength*2)
1223 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key length"),
1224 cl->name, cl->hostname, from->name);
1228 /* Forward it if necessary */
1230 if(strcmp(to_id, myself->name))
1232 if(!(to = lookup_id(to_id)))
1234 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1235 cl->name, cl->hostname, to_id);
1238 send_ans_key(from, to, pktkey);
1241 /* Update our copy of the origin's packet key */
1243 if(from->cipher_pktkey)
1244 free(from->cipher_pktkey);
1246 from->cipher_pktkey = xstrdup(pktkey);
1248 hex2bin(from->cipher_pktkey, from->cipher_pktkey, keylength);
1249 from->cipher_pktkey[keylength] = '\0';
1251 from->status.validkey = 1;
1252 from->status.waitingforkey = 0;
1257 /* Jumptable for the request handlers */
1259 int (*request_handlers[])(connection_t*) = {
1260 id_h, challenge_h, chal_reply_h, metakey_h, ack_h,
1261 status_h, error_h, termreq_h,
1263 add_host_h, del_host_h,
1264 add_subnet_h, del_subnet_h,
1265 key_changed_h, req_key_h, ans_key_h,
1270 char (*request_name[]) = {
1271 "ID", "CHALLENGE", "CHAL_REPLY", "METAKEY", "ACK",
1272 "STATUS", "ERROR", "TERMREQ",
1274 "ADD_HOST", "DEL_HOST",
1275 "ADD_SUBNET", "DEL_SUBNET",
1276 "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1279 /* Status strings */
1281 char (*status_text[]) = {
1287 char (*error_text[]) = {