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.71 2001/01/05 23:53:51 guus Exp $
25 #include <sys/types.h>
30 #include <sys/socket.h>
39 #include <netinet/in.h>
41 #ifdef HAVE_OPENSSL_SHA_H
42 # include <openssl/sha.h>
47 #ifdef HAVE_OPENSSL_RAND_H
48 # include <openssl/rand.h>
53 #ifdef HAVE_OPENSSL_EVP_H
54 # include <openssl/evp.h>
65 #include "connection.h"
69 int check_id(char *id)
73 for (i = 0; i < strlen(id); i++)
74 if(!isalnum(id[i]) && id[i] != '_')
80 /* Generic request routines - takes care of logging and error
83 int send_request(connection_t *cl, const char *format, ...)
86 char buffer[MAXBUFSIZE];
90 /* Use vsnprintf instead of vasprintf: faster, no memory
91 fragmentation, cleanup is automatic, and there is a limit on the
92 input buffer anyway */
94 va_start(args, format);
95 len = vsnprintf(buffer, MAXBUFSIZE, format, args);
96 request = va_arg(args, int);
99 if(len < 0 || len > MAXBUFSIZE-1)
101 syslog(LOG_ERR, _("Output buffer overflow while sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
107 if(debug_lvl >= DEBUG_PROTOCOL)
108 syslog(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
111 return send_meta(cl, buffer, len);
114 int receive_request(connection_t *cl)
118 if(sscanf(cl->buffer, "%d", &request) == 1)
120 if((request < 0) || (request > 255) || (request_handlers[request] == NULL))
122 syslog(LOG_ERR, _("Unknown request from %s (%s)"),
123 cl->name, cl->hostname);
128 if(debug_lvl >= DEBUG_PROTOCOL)
129 syslog(LOG_DEBUG, _("Got %s from %s (%s)"),
130 request_name[request], cl->name, cl->hostname);
133 if((cl->allow_request != ALL) && (cl->allow_request != request))
135 syslog(LOG_ERR, _("Unauthorized request from %s (%s)"), cl->name, cl->hostname);
139 if(request_handlers[request](cl))
140 /* Something went wrong. Probably scriptkiddies. Terminate. */
142 syslog(LOG_ERR, _("Error while processing %s from %s (%s)"),
143 request_name[request], cl->name, cl->hostname);
149 syslog(LOG_ERR, _("Bogus data received from %s (%s)"),
150 cl->name, cl->hostname);
157 /* Connection protocol:
166 ---------------------------------------
169 ---------------------------------------
172 ---------------------------------------
178 (E) Encrypted with symmetric cipher.
180 Part of the challenge is directly used to set the symmetric cipher
181 key and the initial vector. Since a man-in-the-middle cannot
182 decrypt the RSA challenges, this means that he cannot get or forge
183 the key for the symmetric cipher.
186 int send_id(connection_t *cl)
189 cl->allow_request = CHALLENGE;
191 return send_request(cl, "%d %s %d %lx %hd", ID, myself->name, myself->protocol_version, myself->options, myself->port);
194 int id_h(connection_t *cl)
197 unsigned short int port;
198 char name[MAX_STRING_SIZE];
200 if(sscanf(cl->buffer, "%*d "MAX_STRING" %d %lx %hd", name, &cl->protocol_version, &cl->options, &port) != 4)
202 syslog(LOG_ERR, _("Got bad ID from %s"), cl->hostname);
206 /* Check if version matches */
208 if(cl->protocol_version != myself->protocol_version)
210 syslog(LOG_ERR, _("Peer %s (%s) uses incompatible version %d"),
211 cl->name, cl->hostname, cl->protocol_version);
215 /* Check if identity is a valid name */
219 syslog(LOG_ERR, _("Peer %s uses invalid identity name"), cl->hostname);
223 /* Copy string to cl */
225 cl->name = xstrdup(name);
227 /* Load information about peer */
229 if(read_host_config(cl))
231 syslog(LOG_ERR, _("Peer %s had unknown identity (%s)"), cl->hostname, cl->name);
235 /* First check if the host we connected to is already in our
236 connection list. If so, we are probably making a loop, which
240 if(cl->status.outgoing)
242 if((old = lookup_id(cl->name)))
244 if(debug_lvl >= DEBUG_CONNECTIONS)
245 syslog(LOG_NOTICE, _("Uplink %s (%s) is already in our connection list"), cl->name, cl->hostname);
246 cl->status.outgoing = 0;
247 old->status.outgoing = 1;
248 terminate_connection(cl);
253 /* Now we can add the name to the id tree */
257 /* And uhr... cl->port just changed so we have to unlink it from the connection tree and re-insert... */
259 avl_unlink(connection_tree, cl);
261 avl_insert(connection_tree, cl);
263 /* Read in the public key, so that we can send a challenge */
265 if(read_rsa_public_key(cl))
269 return send_challenge(cl);
272 int send_challenge(connection_t *cl)
277 len = RSA_size(cl->rsa_key);
279 /* Allocate buffers for the challenge */
281 buffer = xmalloc(len*2+1);
284 free(cl->hischallenge);
286 cl->hischallenge = xmalloc(len);
288 /* Copy random data to the buffer */
290 RAND_bytes(cl->hischallenge, len);
292 cl->hischallenge[0] &= 0x7F; /* Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
294 if(debug_lvl >= DEBUG_SCARY_THINGS)
296 bin2hex(cl->hischallenge, buffer, len);
297 buffer[len*2] = '\0';
298 syslog(LOG_DEBUG, _("Generated random challenge (unencrypted): %s"), buffer);
301 /* Encrypt the random data */
303 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 */
305 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
310 /* Convert the encrypted random data to a hexadecimal formatted string */
312 bin2hex(buffer, buffer, len);
313 buffer[len*2] = '\0';
315 /* Send the challenge */
317 cl->allow_request = CHAL_REPLY;
318 x = send_request(cl, "%d %s", CHALLENGE, buffer);
324 int challenge_h(connection_t *cl)
326 char buffer[MAX_STRING_SIZE];
329 if(sscanf(cl->buffer, "%*d "MAX_STRING, buffer) != 1)
331 syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
335 len = RSA_size(myself->rsa_key);
337 /* Check if the length of the challenge is all right */
339 if(strlen(buffer) != len*2)
341 syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
345 /* Allocate buffers for the challenge */
348 cl->mychallenge = xmalloc(len);
350 /* Convert the challenge from hexadecimal back to binary */
352 hex2bin(buffer,buffer,len);
354 /* Decrypt the challenge */
356 if(RSA_private_decrypt(len, buffer, cl->mychallenge, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
358 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
362 if(debug_lvl >= DEBUG_SCARY_THINGS)
364 bin2hex(cl->mychallenge, buffer, len);
365 buffer[len*2] = '\0';
366 syslog(LOG_DEBUG, _("Received random challenge (unencrypted): %s"), buffer);
369 /* Rest is done by send_chal_reply() */
371 return send_chal_reply(cl);
374 int send_chal_reply(connection_t *cl)
376 char hash[SHA_DIGEST_LENGTH*2+1];
380 syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
384 /* Calculate the hash from the challenge we received */
386 SHA1(cl->mychallenge, RSA_size(myself->rsa_key), hash);
388 /* Convert the hash to a hexadecimal formatted string */
390 bin2hex(hash,hash,SHA_DIGEST_LENGTH);
391 hash[SHA_DIGEST_LENGTH*2] = '\0';
395 if(cl->status.outgoing)
396 cl->allow_request = ID;
398 cl->allow_request = METAKEY;
401 return send_request(cl, "%d %s", CHAL_REPLY, hash);
404 int chal_reply_h(connection_t *cl)
406 char hishash[MAX_STRING_SIZE];
407 char myhash[SHA_DIGEST_LENGTH];
409 if(sscanf(cl->buffer, "%*d "MAX_STRING, hishash) != 1)
411 syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
415 /* Check if the length of the hash is all right */
417 if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
419 syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
423 /* Convert the hash to binary format */
425 hex2bin(hishash, hishash, SHA_DIGEST_LENGTH);
427 /* Calculate the hash from the challenge we sent */
429 SHA1(cl->hischallenge, RSA_size(cl->rsa_key), myhash);
431 /* Verify the incoming hash with the calculated hash */
433 if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
435 syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
436 if(debug_lvl >= DEBUG_SCARY_THINGS)
438 bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
439 hishash[SHA_DIGEST_LENGTH*2] = '\0';
440 syslog(LOG_DEBUG, _("Expected challenge reply: %s"), hishash);
446 /* Identity has now been positively verified.
447 If we are accepting this new connection, then send our identity,
448 if we are making this connecting, acknowledge.
451 if(cl->status.outgoing)
452 return send_metakey(cl);
457 int send_metakey(connection_t *cl)
462 len = RSA_size(cl->rsa_key);
464 /* Allocate buffers for the meta key */
466 buffer = xmalloc(len*2+1);
468 if(!cl->cipher_outkey)
469 cl->cipher_outkey = xmalloc(len);
471 if(!cl->cipher_outctx)
472 cl->cipher_outctx = xmalloc(sizeof(*cl->cipher_outctx));
474 /* Copy random data to the buffer */
476 RAND_bytes(cl->cipher_outkey, len);
478 cl->cipher_outkey[0] &= 0x7F; /* FIXME: Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
480 if(debug_lvl >= DEBUG_SCARY_THINGS)
482 bin2hex(cl->cipher_outkey, buffer, len);
483 buffer[len*2] = '\0';
484 syslog(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"), buffer);
487 /* Encrypt the random data */
489 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 */
491 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
496 /* Convert the encrypted random data to a hexadecimal formatted string */
498 bin2hex(buffer, buffer, len);
499 buffer[len*2] = '\0';
501 /* Send the meta key */
503 if(cl->status.outgoing)
504 cl->allow_request = METAKEY;
506 cl->allow_request = ACK;
508 x = send_request(cl, "%d %s", METAKEY, buffer);
511 EVP_EncryptInit(cl->cipher_outctx, EVP_bf_cfb(), cl->cipher_outkey, cl->cipher_outkey + EVP_bf_cfb()->key_len);
516 int metakey_h(connection_t *cl)
518 char buffer[MAX_STRING_SIZE];
521 if(sscanf(cl->buffer, "%*d "MAX_STRING, buffer) != 1)
523 syslog(LOG_ERR, _("Got bad METAKEY from %s (%s)"), cl->name, cl->hostname);
527 len = RSA_size(myself->rsa_key);
529 /* Check if the length of the meta key is all right */
531 if(strlen(buffer) != len*2)
533 syslog(LOG_ERR, _("Intruder: wrong meta key length from %s (%s)"), cl->name, cl->hostname);
537 /* Allocate buffers for the meta key */
539 if(!cl->cipher_inkey)
540 cl->cipher_inkey = xmalloc(len);
542 if(!cl->cipher_inctx)
543 cl->cipher_inctx = xmalloc(sizeof(*cl->cipher_inctx));
545 /* Convert the challenge from hexadecimal back to binary */
547 hex2bin(buffer,buffer,len);
549 /* Decrypt the meta key */
551 if(RSA_private_decrypt(len, buffer, cl->cipher_inkey, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
553 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
557 if(debug_lvl >= DEBUG_SCARY_THINGS)
559 bin2hex(cl->cipher_inkey, buffer, len);
560 buffer[len*2] = '\0';
561 syslog(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), buffer);
564 EVP_DecryptInit(cl->cipher_inctx, EVP_bf_cfb(), cl->cipher_inkey, cl->cipher_inkey + EVP_bf_cfb()->key_len);
567 if(cl->status.outgoing)
570 return send_metakey(cl);
573 int send_ack(connection_t *cl)
577 if(cl->status.outgoing)
578 cl->allow_request = ACK;
580 x = send_request(cl, "%d", ACK);
581 cl->status.encryptout = 1;
586 int ack_h(connection_t *cl)
588 connection_t *old, *p;
590 avl_node_t *node, *node2;
592 /* Okay, before we active the connection, we check if there is another entry
593 in the connection list with the same name. If so, it presumably is an
594 old connection that has timed out but we don't know it yet.
597 while((old = lookup_id(cl->name)))
599 if(debug_lvl >= DEBUG_CONNECTIONS)
600 syslog(LOG_NOTICE, _("Removing old entry for %s at %s in favour of new connection from %s"),
601 cl->name, old->hostname, cl->hostname);
603 terminate_connection(old);
606 /* Activate this connection */
608 cl->allow_request = ALL;
609 cl->status.active = 1;
610 cl->status.decryptin = 1;
612 cl->cipher_pkttype = EVP_bf_cfb();
613 cl->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
615 if(debug_lvl >= DEBUG_CONNECTIONS)
616 syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname);
619 if(!cl->status.outgoing)
622 /* Send him our subnets */
624 for(node = myself->subnet_tree->head; node; node = node->next)
626 subnet = (subnet_t *)node->data;
627 send_add_subnet(cl, subnet);
629 /* And send him all the hosts and their subnets we know... */
631 for(node = connection_tree->head; node; node = node->next)
633 p = (connection_t *)node->data;
635 if(p != cl && p->status.active)
637 /* Notify others of this connection */
640 send_add_host(p, cl);
642 /* Notify new connection of everything we know */
644 send_add_host(cl, p);
646 for(node2 = p->subnet_tree->head; node2; node2 = node2->next)
648 subnet = (subnet_t *)node2->data;
649 send_add_subnet(cl, subnet);
657 /* Address and subnet information exchange */
659 int send_add_subnet(connection_t *cl, subnet_t *subnet)
664 x = send_request(cl, "%d %s %s", ADD_SUBNET,
665 subnet->owner->name, netstr = net2str(subnet));
671 int add_subnet_h(connection_t *cl)
673 char subnetstr[MAX_STRING_SIZE];
674 char name[MAX_STRING_SIZE];
675 connection_t *owner, *p;
679 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, name, subnetstr) != 2)
681 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
685 /* Check if owner name is a valid */
689 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
693 /* Check if subnet string is valid */
695 if(!(subnet = str2net(subnetstr)))
697 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
701 /* Check if somebody tries to add a subnet of ourself */
703 if(!strcmp(name, myself->name))
705 syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
706 cl->name, cl->hostname);
711 /* Check if the owner of the new subnet is in the connection list */
713 if(!(owner = lookup_id(name)))
715 syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
716 name, cl->name, cl->hostname);
720 /* If everything is correct, add the subnet to the list of the owner */
722 subnet_add(owner, subnet);
726 for(node = connection_tree->head; node; node = node->next)
728 p = (connection_t *)node->data;
729 if(p->status.meta && p->status.active && p!= cl)
730 send_add_subnet(p, subnet);
736 int send_del_subnet(connection_t *cl, subnet_t *subnet)
741 netstr = net2str(subnet);
742 x = send_request(cl, "%d %s %s", DEL_SUBNET, subnet->owner->name, netstr);
748 int del_subnet_h(connection_t *cl)
750 char subnetstr[MAX_STRING_SIZE];
751 char name[MAX_STRING_SIZE];
752 connection_t *owner, *p;
756 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, name, subnetstr) != 3)
758 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
762 /* Check if owner name is a valid */
766 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
770 /* Check if subnet string is valid */
772 if(!(subnet = str2net(subnetstr)))
774 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
780 /* Check if somebody tries to add a subnet of ourself */
782 if(!strcmp(name, myself->name))
784 syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
785 cl->name, cl->hostname);
790 /* Check if the owner of the new subnet is in the connection list */
792 if(!(owner = lookup_id(name)))
794 syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
795 name, cl->name, cl->hostname);
799 /* If everything is correct, delete the subnet from the list of the owner */
805 for(node = connection_tree->head; node; node = node->next)
807 p = (connection_t *)node->data;
808 if(p->status.meta && p->status.active && p!= cl)
809 send_del_subnet(p, subnet);
815 /* New and closed connections notification */
817 int send_add_host(connection_t *cl, connection_t *other)
820 return send_request(cl, "%d %s %lx:%d %lx", ADD_HOST,
821 other->name, other->address, other->port, other->options);
824 int add_host_h(connection_t *cl)
826 connection_t *old, *new, *p;
827 char name[MAX_STRING_SIZE];
830 new = new_connection();
832 if(sscanf(cl->buffer, "%*d "MAX_STRING" %lx:%d %lx", name, &new->address, &new->port, &new->options) != 4)
834 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
838 /* Check if identity is a valid name */
842 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
843 free_connection(new);
847 /* Check if somebody tries to add ourself */
849 if(!strcmp(name, myself->name))
851 syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
853 free_connection(new);
857 /* Fill in more of the new connection structure */
859 new->hostname = hostlookup(htonl(new->address));
861 /* Check if the new host already exists in the connnection list */
863 if((old = lookup_id(name)))
865 if((new->address == old->address) && (new->port == old->port))
867 if(debug_lvl >= DEBUG_CONNECTIONS)
868 syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
869 old->name, old->hostname, name, new->hostname);
870 free_connection(new);
875 if(debug_lvl >= DEBUG_CONNECTIONS)
876 syslog(LOG_NOTICE, _("Removing old entry for %s (%s) in favour of new connection"),
877 old->name, old->hostname);
879 terminate_connection(old);
883 /* Hook it up into the connection */
885 new->name = xstrdup(name);
889 /* Tell the rest about the new host */
891 for(node = connection_tree->head; node; node = node->next)
893 p = (connection_t *)node->data;
894 if(p->status.meta && p->status.active && p!=cl)
895 send_add_host(p, new);
898 /* Fill in rest of connection structure */
901 new->status.active = 1;
902 new->cipher_pkttype = EVP_bf_cfb();
903 new->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
908 int send_del_host(connection_t *cl, connection_t *other)
911 return send_request(cl, "%d %s %lx:%d %lx", DEL_HOST,
912 other->name, other->address, other->port, other->options);
915 int del_host_h(connection_t *cl)
917 char name[MAX_STRING_SIZE];
921 connection_t *old, *p;
924 if(sscanf(cl->buffer, "%*d "MAX_STRING" %lx:%d %lx", name, &address, &port, &options) != 4)
926 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
927 cl->name, cl->hostname);
931 /* Check if identity is a valid name */
935 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
939 /* Check if somebody tries to delete ourself */
941 if(!strcmp(name, myself->name))
943 syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
944 cl->name, cl->hostname);
949 /* Check if the new host already exists in the connnection list */
951 if(!(old = lookup_id(name)))
953 syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
954 name, cl->name, cl->hostname);
958 /* Check if the rest matches */
960 if(address!=old->address || port!=old->port || options!=old->options || cl!=old->nexthop)
962 syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
966 /* Ok, since EVERYTHING seems to check out all right, delete it */
968 old->status.active = 0;
969 terminate_connection(old);
971 /* Tell the rest about the new host */
973 for(node = connection_tree->head; node; node = node->next)
975 p = (connection_t *)node->data;
976 if(p->status.meta && p->status.active && p!=cl)
977 send_del_host(p, old);
983 /* Status and error notification routines */
985 int send_status(connection_t *cl, int statusno, char *statusstring)
989 statusstring = status_text[statusno];
991 return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
994 int status_h(connection_t *cl)
997 char statusstring[MAX_STRING_SIZE];
999 if(sscanf(cl->buffer, "%*d %d "MAX_STRING, &statusno, statusstring) != 2)
1001 syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
1002 cl->name, cl->hostname);
1006 if(debug_lvl >= DEBUG_STATUS)
1008 syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
1009 cl->name, cl->hostname, status_text[statusno], statusstring);
1016 int send_error(connection_t *cl, int errno, char *errstring)
1020 errstring = strerror(errno);
1021 return send_request(cl, "%d %d %s", ERROR, errno, errstring);
1024 int error_h(connection_t *cl)
1027 char errorstring[MAX_STRING_SIZE];
1029 if(sscanf(cl->buffer, "%*d %d "MAX_STRING, &errno, errorstring) != 2)
1031 syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
1032 cl->name, cl->hostname);
1036 if(debug_lvl >= DEBUG_ERROR)
1038 syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
1039 cl->name, cl->hostname, strerror(errno), errorstring);
1042 terminate_connection(cl);
1047 int send_termreq(connection_t *cl)
1050 return send_request(cl, "%d", TERMREQ);
1053 int termreq_h(connection_t *cl)
1056 terminate_connection(cl);
1061 /* Keepalive routines - FIXME: needs a closer look */
1063 int send_ping(connection_t *cl)
1066 cl->status.pinged = 1;
1067 cl->last_ping_time = time(NULL);
1069 return send_request(cl, "%d", PING);
1072 int ping_h(connection_t *cl)
1075 return send_pong(cl);
1078 int send_pong(connection_t *cl)
1081 return send_request(cl, "%d", PONG);
1084 int pong_h(connection_t *cl)
1087 cl->status.pinged = 0;
1094 int send_key_changed(connection_t *from, connection_t *cl)
1099 for(node = connection_tree->head; node; node = node->next)
1101 p = (connection_t *)node->data;
1102 if(p != cl && p->status.meta && p->status.active)
1103 send_request(p, "%d %s", KEY_CHANGED, from->name);
1109 int key_changed_h(connection_t *cl)
1111 char from_id[MAX_STRING_SIZE];
1114 if(sscanf(cl->buffer, "%*d "MAX_STRING, from_id) != 1)
1116 syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
1117 cl->name, cl->hostname);
1121 if(!(from = lookup_id(from_id)))
1123 syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
1124 cl->name, cl->hostname, from_id);
1128 from->status.validkey = 0;
1129 from->status.waitingforkey = 0;
1131 send_key_changed(from, cl);
1136 int send_req_key(connection_t *from, connection_t *to)
1139 return send_request(to->nexthop, "%d %s %s", REQ_KEY,
1140 from->name, to->name);
1143 int req_key_h(connection_t *cl)
1145 char from_id[MAX_STRING_SIZE];
1146 char to_id[MAX_STRING_SIZE];
1147 connection_t *from, *to;
1150 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, from_id, to_id) != 2)
1152 syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
1153 cl->name, cl->hostname);
1157 if(!(from = lookup_id(from_id)))
1159 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
1160 cl->name, cl->hostname, from_id);
1164 /* Check if this key request is for us */
1166 if(!strcmp(to_id, myself->name))
1168 bin2hex(myself->cipher_pktkey, pktkey, myself->cipher_pktkeylength);
1169 pktkey[myself->cipher_pktkeylength*2] = '\0';
1170 send_ans_key(myself, from, pktkey);
1174 if(!(to = lookup_id(to_id)))
1176 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
1177 cl->name, cl->hostname, to_id);
1181 if(to->status.validkey) /* Proxy keys */
1183 bin2hex(to->cipher_pktkey, pktkey, to->cipher_pktkeylength);
1184 pktkey[to->cipher_pktkeylength*2] = '\0';
1185 send_ans_key(to, from, pktkey);
1188 send_req_key(from, to);
1195 int send_ans_key(connection_t *from, connection_t *to, char *pktkey)
1198 return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
1199 from->name, to->name, pktkey);
1202 int ans_key_h(connection_t *cl)
1204 char from_id[MAX_STRING_SIZE];
1205 char to_id[MAX_STRING_SIZE];
1206 char pktkey[MAX_STRING_SIZE];
1208 connection_t *from, *to;
1210 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING, from_id, to_id, pktkey) != 3)
1212 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
1213 cl->name, cl->hostname);
1217 if(!(from = lookup_id(from_id)))
1219 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
1220 cl->name, cl->hostname, from_id);
1224 /* Check correctness of packet key */
1226 keylength = strlen(pktkey);
1228 if(keylength != from->cipher_pktkeylength*2)
1230 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key length"),
1231 cl->name, cl->hostname, from->name);
1235 /* Forward it if necessary */
1237 if(strcmp(to_id, myself->name))
1239 if(!(to = lookup_id(to_id)))
1241 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1242 cl->name, cl->hostname, to_id);
1245 send_ans_key(from, to, pktkey);
1248 /* Update our copy of the origin's packet key */
1250 if(from->cipher_pktkey)
1251 free(from->cipher_pktkey);
1253 from->cipher_pktkey = xstrdup(pktkey);
1255 hex2bin(from->cipher_pktkey, from->cipher_pktkey, keylength);
1256 from->cipher_pktkey[keylength] = '\0';
1258 from->status.validkey = 1;
1259 from->status.waitingforkey = 0;
1264 /* Jumptable for the request handlers */
1266 int (*request_handlers[])(connection_t*) = {
1267 id_h, challenge_h, chal_reply_h, metakey_h, ack_h,
1268 status_h, error_h, termreq_h,
1270 add_host_h, del_host_h,
1271 add_subnet_h, del_subnet_h,
1272 key_changed_h, req_key_h, ans_key_h,
1277 char (*request_name[]) = {
1278 "ID", "CHALLENGE", "CHAL_REPLY", "METAKEY", "ACK",
1279 "STATUS", "ERROR", "TERMREQ",
1281 "ADD_HOST", "DEL_HOST",
1282 "ADD_SUBNET", "DEL_SUBNET",
1283 "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1286 /* Status strings */
1288 char (*status_text[]) = {
1294 char (*error_text[]) = {