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.73 2001/01/07 15:25:45 guus Exp $
25 #include <sys/types.h>
30 #include <sys/socket.h>
40 #include <netinet/in.h>
42 #ifdef HAVE_OPENSSL_SHA_H
43 # include <openssl/sha.h>
48 #ifdef HAVE_OPENSSL_RAND_H
49 # include <openssl/rand.h>
54 #ifdef HAVE_OPENSSL_EVP_H
55 # include <openssl/evp.h>
66 #include "connection.h"
70 int check_id(char *id)
74 for (i = 0; i < strlen(id); i++)
75 if(!isalnum(id[i]) && id[i] != '_')
81 /* Generic request routines - takes care of logging and error
84 int send_request(connection_t *cl, const char *format, ...)
87 char buffer[MAXBUFSIZE];
91 /* Use vsnprintf instead of vasprintf: faster, no memory
92 fragmentation, cleanup is automatic, and there is a limit on the
93 input buffer anyway */
95 va_start(args, format);
96 len = vsnprintf(buffer, MAXBUFSIZE, format, args);
97 request = va_arg(args, int);
100 if(len < 0 || len > MAXBUFSIZE-1)
102 syslog(LOG_ERR, _("Output buffer overflow while sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
108 if(debug_lvl >= DEBUG_PROTOCOL)
109 syslog(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
112 return send_meta(cl, buffer, len);
115 int receive_request(connection_t *cl)
119 if(sscanf(cl->buffer, "%d", &request) == 1)
121 if((request < 0) || (request > 255) || (request_handlers[request] == NULL))
123 syslog(LOG_ERR, _("Unknown request from %s (%s)"),
124 cl->name, cl->hostname);
129 if(debug_lvl >= DEBUG_PROTOCOL)
130 syslog(LOG_DEBUG, _("Got %s from %s (%s)"),
131 request_name[request], cl->name, cl->hostname);
134 if((cl->allow_request != ALL) && (cl->allow_request != request))
136 syslog(LOG_ERR, _("Unauthorized request from %s (%s)"), cl->name, cl->hostname);
140 if(request_handlers[request](cl))
141 /* Something went wrong. Probably scriptkiddies. Terminate. */
143 syslog(LOG_ERR, _("Error while processing %s from %s (%s)"),
144 request_name[request], cl->name, cl->hostname);
150 syslog(LOG_ERR, _("Bogus data received from %s (%s)"),
151 cl->name, cl->hostname);
158 /* Connection protocol:
167 ---------------------------------------
170 ---------------------------------------
173 ---------------------------------------
179 (E) Encrypted with symmetric cipher.
181 Part of the challenge is directly used to set the symmetric cipher
182 key and the initial vector. Since a man-in-the-middle cannot
183 decrypt the RSA challenges, this means that he cannot get or forge
184 the key for the symmetric cipher.
187 int send_id(connection_t *cl)
190 cl->allow_request = CHALLENGE;
192 return send_request(cl, "%d %s %d %lx %hd", ID, myself->name, myself->protocol_version, myself->options, myself->port);
195 int id_h(connection_t *cl)
198 unsigned short int port;
199 char name[MAX_STRING_SIZE];
202 if(sscanf(cl->buffer, "%*d "MAX_STRING" %d %lx %hd", name, &cl->protocol_version, &cl->options, &port) != 4)
204 syslog(LOG_ERR, _("Got bad ID from %s"), cl->hostname);
208 /* Check if version matches */
210 if(cl->protocol_version != myself->protocol_version)
212 syslog(LOG_ERR, _("Peer %s (%s) uses incompatible version %d"),
213 cl->name, cl->hostname, cl->protocol_version);
217 /* Check if identity is a valid name */
221 syslog(LOG_ERR, _("Peer %s uses invalid identity name"), cl->hostname);
225 /* Copy string to cl */
227 cl->name = xstrdup(name);
229 /* Load information about peer */
231 if(read_host_config(cl))
233 syslog(LOG_ERR, _("Peer %s had unknown identity (%s)"), cl->hostname, cl->name);
237 /* First check if the host we connected to is already in our
238 connection list. If so, we are probably making a loop, which
242 if(cl->status.outgoing)
244 if((old = lookup_id(cl->name)))
246 if(debug_lvl >= DEBUG_CONNECTIONS)
247 syslog(LOG_NOTICE, _("Uplink %s (%s) is already in our connection list"), cl->name, cl->hostname);
248 cl->status.outgoing = 0;
249 old->status.outgoing = 1;
250 terminate_connection(cl);
255 /* Now we can add the name to the id tree */
259 /* And uhr... cl->port just changed so we have to unlink it from the connection tree and re-insert... */
261 node = avl_unlink(connection_tree, cl);
263 avl_insert_node(connection_tree, node);
265 /* Read in the public key, so that we can send a challenge */
267 if(read_rsa_public_key(cl))
271 return send_challenge(cl);
274 int send_challenge(connection_t *cl)
279 len = RSA_size(cl->rsa_key);
281 /* Allocate buffers for the challenge */
283 buffer = xmalloc(len*2+1);
286 free(cl->hischallenge);
288 cl->hischallenge = xmalloc(len);
290 /* Copy random data to the buffer */
292 RAND_bytes(cl->hischallenge, len);
294 cl->hischallenge[0] &= 0x7F; /* Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
296 if(debug_lvl >= DEBUG_SCARY_THINGS)
298 bin2hex(cl->hischallenge, buffer, len);
299 buffer[len*2] = '\0';
300 syslog(LOG_DEBUG, _("Generated random challenge (unencrypted): %s"), buffer);
303 /* Encrypt the random data */
305 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 */
307 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
312 /* Convert the encrypted random data to a hexadecimal formatted string */
314 bin2hex(buffer, buffer, len);
315 buffer[len*2] = '\0';
317 /* Send the challenge */
319 cl->allow_request = CHAL_REPLY;
320 x = send_request(cl, "%d %s", CHALLENGE, buffer);
326 int challenge_h(connection_t *cl)
328 char buffer[MAX_STRING_SIZE];
331 if(sscanf(cl->buffer, "%*d "MAX_STRING, buffer) != 1)
333 syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
337 len = RSA_size(myself->rsa_key);
339 /* Check if the length of the challenge is all right */
341 if(strlen(buffer) != len*2)
343 syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
347 /* Allocate buffers for the challenge */
350 cl->mychallenge = xmalloc(len);
352 /* Convert the challenge from hexadecimal back to binary */
354 hex2bin(buffer,buffer,len);
356 /* Decrypt the challenge */
358 if(RSA_private_decrypt(len, buffer, cl->mychallenge, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
360 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
364 if(debug_lvl >= DEBUG_SCARY_THINGS)
366 bin2hex(cl->mychallenge, buffer, len);
367 buffer[len*2] = '\0';
368 syslog(LOG_DEBUG, _("Received random challenge (unencrypted): %s"), buffer);
371 /* Rest is done by send_chal_reply() */
373 return send_chal_reply(cl);
376 int send_chal_reply(connection_t *cl)
378 char hash[SHA_DIGEST_LENGTH*2+1];
382 syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
386 /* Calculate the hash from the challenge we received */
388 SHA1(cl->mychallenge, RSA_size(myself->rsa_key), hash);
390 /* Convert the hash to a hexadecimal formatted string */
392 bin2hex(hash,hash,SHA_DIGEST_LENGTH);
393 hash[SHA_DIGEST_LENGTH*2] = '\0';
397 if(cl->status.outgoing)
398 cl->allow_request = ID;
400 cl->allow_request = METAKEY;
403 return send_request(cl, "%d %s", CHAL_REPLY, hash);
406 int chal_reply_h(connection_t *cl)
408 char hishash[MAX_STRING_SIZE];
409 char myhash[SHA_DIGEST_LENGTH];
411 if(sscanf(cl->buffer, "%*d "MAX_STRING, hishash) != 1)
413 syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
417 /* Check if the length of the hash is all right */
419 if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
421 syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
425 /* Convert the hash to binary format */
427 hex2bin(hishash, hishash, SHA_DIGEST_LENGTH);
429 /* Calculate the hash from the challenge we sent */
431 SHA1(cl->hischallenge, RSA_size(cl->rsa_key), myhash);
433 /* Verify the incoming hash with the calculated hash */
435 if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
437 syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
438 if(debug_lvl >= DEBUG_SCARY_THINGS)
440 bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
441 hishash[SHA_DIGEST_LENGTH*2] = '\0';
442 syslog(LOG_DEBUG, _("Expected challenge reply: %s"), hishash);
448 /* Identity has now been positively verified.
449 If we are accepting this new connection, then send our identity,
450 if we are making this connecting, acknowledge.
453 if(cl->status.outgoing)
454 return send_metakey(cl);
459 int send_metakey(connection_t *cl)
464 len = RSA_size(cl->rsa_key);
466 /* Allocate buffers for the meta key */
468 buffer = xmalloc(len*2+1);
470 if(!cl->cipher_outkey)
471 cl->cipher_outkey = xmalloc(len);
473 if(!cl->cipher_outctx)
474 cl->cipher_outctx = xmalloc(sizeof(*cl->cipher_outctx));
476 /* Copy random data to the buffer */
478 RAND_bytes(cl->cipher_outkey, len);
480 cl->cipher_outkey[0] &= 0x7F; /* FIXME: Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
482 if(debug_lvl >= DEBUG_SCARY_THINGS)
484 bin2hex(cl->cipher_outkey, buffer, len);
485 buffer[len*2] = '\0';
486 syslog(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"), buffer);
489 /* Encrypt the random data */
491 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 */
493 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
498 /* Convert the encrypted random data to a hexadecimal formatted string */
500 bin2hex(buffer, buffer, len);
501 buffer[len*2] = '\0';
503 /* Send the meta key */
505 if(cl->status.outgoing)
506 cl->allow_request = METAKEY;
508 cl->allow_request = ACK;
510 x = send_request(cl, "%d %s", METAKEY, buffer);
513 EVP_EncryptInit(cl->cipher_outctx, EVP_bf_cfb(), cl->cipher_outkey, cl->cipher_outkey + EVP_bf_cfb()->key_len);
518 int metakey_h(connection_t *cl)
520 char buffer[MAX_STRING_SIZE];
523 if(sscanf(cl->buffer, "%*d "MAX_STRING, buffer) != 1)
525 syslog(LOG_ERR, _("Got bad METAKEY from %s (%s)"), cl->name, cl->hostname);
529 len = RSA_size(myself->rsa_key);
531 /* Check if the length of the meta key is all right */
533 if(strlen(buffer) != len*2)
535 syslog(LOG_ERR, _("Intruder: wrong meta key length from %s (%s)"), cl->name, cl->hostname);
539 /* Allocate buffers for the meta key */
541 if(!cl->cipher_inkey)
542 cl->cipher_inkey = xmalloc(len);
544 if(!cl->cipher_inctx)
545 cl->cipher_inctx = xmalloc(sizeof(*cl->cipher_inctx));
547 /* Convert the challenge from hexadecimal back to binary */
549 hex2bin(buffer,buffer,len);
551 /* Decrypt the meta key */
553 if(RSA_private_decrypt(len, buffer, cl->cipher_inkey, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
555 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
559 if(debug_lvl >= DEBUG_SCARY_THINGS)
561 bin2hex(cl->cipher_inkey, buffer, len);
562 buffer[len*2] = '\0';
563 syslog(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), buffer);
566 EVP_DecryptInit(cl->cipher_inctx, EVP_bf_cfb(), cl->cipher_inkey, cl->cipher_inkey + EVP_bf_cfb()->key_len);
569 if(cl->status.outgoing)
572 return send_metakey(cl);
575 int send_ack(connection_t *cl)
579 if(cl->status.outgoing)
580 cl->allow_request = ACK;
582 x = send_request(cl, "%d", ACK);
583 cl->status.encryptout = 1;
588 int ack_h(connection_t *cl)
590 connection_t *old, *p;
592 avl_node_t *node, *node2;
594 /* Okay, before we active the connection, we check if there is another entry
595 in the connection list with the same name. If so, it presumably is an
596 old connection that has timed out but we don't know it yet.
599 while((old = lookup_id(cl->name)))
601 if(debug_lvl >= DEBUG_CONNECTIONS)
602 syslog(LOG_NOTICE, _("Removing old entry for %s at %s in favour of new connection from %s"),
603 cl->name, old->hostname, cl->hostname);
605 terminate_connection(old);
608 /* Activate this connection */
610 cl->allow_request = ALL;
611 cl->status.active = 1;
612 cl->status.decryptin = 1;
614 cl->cipher_pkttype = EVP_bf_cfb();
615 cl->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
617 if(debug_lvl >= DEBUG_CONNECTIONS)
618 syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname);
621 if(!cl->status.outgoing)
624 /* Send him our subnets */
626 for(node = myself->subnet_tree->head; node; node = node->next)
628 subnet = (subnet_t *)node->data;
629 send_add_subnet(cl, subnet);
631 /* And send him all the hosts and their subnets we know... */
633 for(node = connection_tree->head; node; node = node->next)
635 p = (connection_t *)node->data;
637 if(p != cl && p->status.active)
639 /* Notify others of this connection */
642 send_add_host(p, cl);
644 /* Notify new connection of everything we know */
646 send_add_host(cl, p);
648 for(node2 = p->subnet_tree->head; node2; node2 = node2->next)
650 subnet = (subnet_t *)node2->data;
651 send_add_subnet(cl, subnet);
659 /* Address and subnet information exchange */
661 int send_add_subnet(connection_t *cl, subnet_t *subnet)
666 x = send_request(cl, "%d %s %s", ADD_SUBNET,
667 subnet->owner->name, netstr = net2str(subnet));
673 int add_subnet_h(connection_t *cl)
675 char subnetstr[MAX_STRING_SIZE];
676 char name[MAX_STRING_SIZE];
677 connection_t *owner, *p;
681 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, name, subnetstr) != 2)
683 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
687 /* Check if owner name is a valid */
691 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
695 /* Check if subnet string is valid */
697 if(!(subnet = str2net(subnetstr)))
699 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
703 /* Check if somebody tries to add a subnet of ourself */
705 if(!strcmp(name, myself->name))
707 syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
708 cl->name, cl->hostname);
713 /* Check if the owner of the new subnet is in the connection list */
715 if(!(owner = lookup_id(name)))
717 syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
718 name, cl->name, cl->hostname);
722 /* If everything is correct, add the subnet to the list of the owner */
724 subnet_add(owner, subnet);
728 for(node = connection_tree->head; node; node = node->next)
730 p = (connection_t *)node->data;
731 if(p->status.meta && p->status.active && p!= cl)
732 send_add_subnet(p, subnet);
738 int send_del_subnet(connection_t *cl, subnet_t *subnet)
743 netstr = net2str(subnet);
744 x = send_request(cl, "%d %s %s", DEL_SUBNET, subnet->owner->name, netstr);
750 int del_subnet_h(connection_t *cl)
752 char subnetstr[MAX_STRING_SIZE];
753 char name[MAX_STRING_SIZE];
754 connection_t *owner, *p;
758 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, name, subnetstr) != 3)
760 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
764 /* Check if owner name is a valid */
768 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
772 /* Check if subnet string is valid */
774 if(!(subnet = str2net(subnetstr)))
776 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
782 /* Check if somebody tries to add a subnet of ourself */
784 if(!strcmp(name, myself->name))
786 syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
787 cl->name, cl->hostname);
792 /* Check if the owner of the new subnet is in the connection list */
794 if(!(owner = lookup_id(name)))
796 syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
797 name, cl->name, cl->hostname);
801 /* If everything is correct, delete the subnet from the list of the owner */
807 for(node = connection_tree->head; node; node = node->next)
809 p = (connection_t *)node->data;
810 if(p->status.meta && p->status.active && p!= cl)
811 send_del_subnet(p, subnet);
817 /* New and closed connections notification */
819 int send_add_host(connection_t *cl, connection_t *other)
822 return send_request(cl, "%d %s %lx:%d %lx", ADD_HOST,
823 other->name, other->address, other->port, other->options);
826 int add_host_h(connection_t *cl)
828 connection_t *old, *new, *p;
829 char name[MAX_STRING_SIZE];
832 new = new_connection();
834 if(sscanf(cl->buffer, "%*d "MAX_STRING" %lx:%d %lx", name, &new->address, &new->port, &new->options) != 4)
836 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
840 /* Check if identity is a valid name */
844 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
845 free_connection(new);
849 /* Check if somebody tries to add ourself */
851 if(!strcmp(name, myself->name))
853 syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
855 free_connection(new);
859 /* Fill in more of the new connection structure */
861 new->hostname = hostlookup(htonl(new->address));
863 /* Check if the new host already exists in the connnection list */
865 if((old = lookup_id(name)))
867 if((new->address == old->address) && (new->port == old->port))
869 if(debug_lvl >= DEBUG_CONNECTIONS)
870 syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
871 old->name, old->hostname, name, new->hostname);
872 free_connection(new);
877 if(debug_lvl >= DEBUG_CONNECTIONS)
878 syslog(LOG_NOTICE, _("Removing old entry for %s (%s) in favour of new connection"),
879 old->name, old->hostname);
881 terminate_connection(old);
885 /* Hook it up into the connection */
887 new->name = xstrdup(name);
891 /* Tell the rest about the new host */
893 for(node = connection_tree->head; node; node = node->next)
895 p = (connection_t *)node->data;
896 if(p->status.meta && p->status.active && p!=cl)
897 send_add_host(p, new);
900 /* Fill in rest of connection structure */
903 new->status.active = 1;
904 new->cipher_pkttype = EVP_bf_cfb();
905 new->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
910 int send_del_host(connection_t *cl, connection_t *other)
913 return send_request(cl, "%d %s %lx:%d %lx", DEL_HOST,
914 other->name, other->address, other->port, other->options);
917 int del_host_h(connection_t *cl)
919 char name[MAX_STRING_SIZE];
923 connection_t *old, *p;
926 if(sscanf(cl->buffer, "%*d "MAX_STRING" %lx:%d %lx", name, &address, &port, &options) != 4)
928 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
929 cl->name, cl->hostname);
933 /* Check if identity is a valid name */
937 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
941 /* Check if somebody tries to delete ourself */
943 if(!strcmp(name, myself->name))
945 syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
946 cl->name, cl->hostname);
951 /* Check if the new host already exists in the connnection list */
953 if(!(old = lookup_id(name)))
955 syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
956 name, cl->name, cl->hostname);
960 /* Check if the rest matches */
962 if(address!=old->address || port!=old->port || options!=old->options || cl!=old->nexthop)
964 syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
968 /* Ok, since EVERYTHING seems to check out all right, delete it */
970 old->status.active = 0;
971 terminate_connection(old);
973 /* Tell the rest about the new host */
975 for(node = connection_tree->head; node; node = node->next)
977 p = (connection_t *)node->data;
978 if(p->status.meta && p->status.active && p!=cl)
979 send_del_host(p, old);
985 /* Status and error notification routines */
987 int send_status(connection_t *cl, int statusno, char *statusstring)
991 statusstring = status_text[statusno];
993 return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
996 int status_h(connection_t *cl)
999 char statusstring[MAX_STRING_SIZE];
1001 if(sscanf(cl->buffer, "%*d %d "MAX_STRING, &statusno, statusstring) != 2)
1003 syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
1004 cl->name, cl->hostname);
1008 if(debug_lvl >= DEBUG_STATUS)
1010 syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
1011 cl->name, cl->hostname, status_text[statusno], statusstring);
1018 int send_error(connection_t *cl, int errno, char *errstring)
1022 errstring = strerror(errno);
1023 return send_request(cl, "%d %d %s", ERROR, errno, errstring);
1026 int error_h(connection_t *cl)
1029 char errorstring[MAX_STRING_SIZE];
1031 if(sscanf(cl->buffer, "%*d %d "MAX_STRING, &errno, errorstring) != 2)
1033 syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
1034 cl->name, cl->hostname);
1038 if(debug_lvl >= DEBUG_ERROR)
1040 syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
1041 cl->name, cl->hostname, strerror(errno), errorstring);
1044 terminate_connection(cl);
1049 int send_termreq(connection_t *cl)
1052 return send_request(cl, "%d", TERMREQ);
1055 int termreq_h(connection_t *cl)
1058 terminate_connection(cl);
1063 /* Keepalive routines - FIXME: needs a closer look */
1065 int send_ping(connection_t *cl)
1068 cl->status.pinged = 1;
1069 cl->last_ping_time = time(NULL);
1071 return send_request(cl, "%d", PING);
1074 int ping_h(connection_t *cl)
1077 return send_pong(cl);
1080 int send_pong(connection_t *cl)
1083 return send_request(cl, "%d", PONG);
1086 int pong_h(connection_t *cl)
1089 cl->status.pinged = 0;
1096 int send_key_changed(connection_t *from, connection_t *cl)
1101 for(node = connection_tree->head; node; node = node->next)
1103 p = (connection_t *)node->data;
1104 if(p != cl && p->status.meta && p->status.active)
1105 send_request(p, "%d %s", KEY_CHANGED, from->name);
1111 int key_changed_h(connection_t *cl)
1113 char from_id[MAX_STRING_SIZE];
1116 if(sscanf(cl->buffer, "%*d "MAX_STRING, from_id) != 1)
1118 syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
1119 cl->name, cl->hostname);
1123 if(!(from = lookup_id(from_id)))
1125 syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
1126 cl->name, cl->hostname, from_id);
1130 from->status.validkey = 0;
1131 from->status.waitingforkey = 0;
1133 send_key_changed(from, cl);
1138 int send_req_key(connection_t *from, connection_t *to)
1141 return send_request(to->nexthop, "%d %s %s", REQ_KEY,
1142 from->name, to->name);
1145 int req_key_h(connection_t *cl)
1147 char from_id[MAX_STRING_SIZE];
1148 char to_id[MAX_STRING_SIZE];
1149 connection_t *from, *to;
1152 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, from_id, to_id) != 2)
1154 syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
1155 cl->name, cl->hostname);
1159 if(!(from = lookup_id(from_id)))
1161 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
1162 cl->name, cl->hostname, from_id);
1166 /* Check if this key request is for us */
1168 if(!strcmp(to_id, myself->name))
1170 bin2hex(myself->cipher_pktkey, pktkey, myself->cipher_pktkeylength);
1171 pktkey[myself->cipher_pktkeylength*2] = '\0';
1172 send_ans_key(myself, from, pktkey);
1176 if(!(to = lookup_id(to_id)))
1178 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
1179 cl->name, cl->hostname, to_id);
1183 if(to->status.validkey) /* Proxy keys */
1185 bin2hex(to->cipher_pktkey, pktkey, to->cipher_pktkeylength);
1186 pktkey[to->cipher_pktkeylength*2] = '\0';
1187 send_ans_key(to, from, pktkey);
1190 send_req_key(from, to);
1197 int send_ans_key(connection_t *from, connection_t *to, char *pktkey)
1200 return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
1201 from->name, to->name, pktkey);
1204 int ans_key_h(connection_t *cl)
1206 char from_id[MAX_STRING_SIZE];
1207 char to_id[MAX_STRING_SIZE];
1208 char pktkey[MAX_STRING_SIZE];
1210 connection_t *from, *to;
1212 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING, from_id, to_id, pktkey) != 3)
1214 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
1215 cl->name, cl->hostname);
1219 if(!(from = lookup_id(from_id)))
1221 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
1222 cl->name, cl->hostname, from_id);
1226 /* Check correctness of packet key */
1228 keylength = strlen(pktkey);
1230 if(keylength != from->cipher_pktkeylength*2)
1232 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key length"),
1233 cl->name, cl->hostname, from->name);
1237 /* Forward it if necessary */
1239 if(strcmp(to_id, myself->name))
1241 if(!(to = lookup_id(to_id)))
1243 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1244 cl->name, cl->hostname, to_id);
1247 send_ans_key(from, to, pktkey);
1250 /* Update our copy of the origin's packet key */
1252 if(from->cipher_pktkey)
1253 free(from->cipher_pktkey);
1255 from->cipher_pktkey = xstrdup(pktkey);
1257 hex2bin(from->cipher_pktkey, from->cipher_pktkey, keylength);
1258 from->cipher_pktkey[keylength] = '\0';
1260 from->status.validkey = 1;
1261 from->status.waitingforkey = 0;
1268 /* Jumptable for the request handlers */
1270 int (*request_handlers[])(connection_t*) = {
1271 id_h, challenge_h, chal_reply_h, metakey_h, ack_h,
1272 status_h, error_h, termreq_h,
1274 add_host_h, del_host_h,
1275 add_subnet_h, del_subnet_h,
1276 key_changed_h, req_key_h, ans_key_h,
1281 char (*request_name[]) = {
1282 "ID", "CHALLENGE", "CHAL_REPLY", "METAKEY", "ACK",
1283 "STATUS", "ERROR", "TERMREQ",
1285 "ADD_HOST", "DEL_HOST",
1286 "ADD_SUBNET", "DEL_SUBNET",
1287 "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1290 /* Status strings */
1292 char (*status_text[]) = {
1298 char (*error_text[]) = {