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.65 2000/11/22 20:25:27 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 detection as well */
81 int send_request(connection_t *cl, const char *format, ...)
84 char buffer[MAXBUFSIZE];
88 /* Use vsnprintf instead of vasprintf: faster, no memory fragmentation, cleanup is automatic,
89 and there is a limit on the input buffer anyway */
91 va_start(args, format);
92 len = vsnprintf(buffer, MAXBUFSIZE, format, args);
93 request = va_arg(args, int);
96 if(len < 0 || len > MAXBUFSIZE-1)
98 syslog(LOG_ERR, _("Output buffer overflow while sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
104 if(debug_lvl >= DEBUG_PROTOCOL)
105 syslog(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
108 return send_meta(cl, buffer, len);
111 int receive_request(connection_t *cl)
115 if(sscanf(cl->buffer, "%d", &request) == 1)
117 if((request < 0) || (request > 255) || (request_handlers[request] == NULL))
119 syslog(LOG_ERR, _("Unknown request from %s (%s)"),
120 cl->name, cl->hostname);
125 if(debug_lvl >= DEBUG_PROTOCOL)
126 syslog(LOG_DEBUG, _("Got %s from %s (%s)"),
127 request_name[request], cl->name, cl->hostname);
130 if((cl->allow_request != ALL) && (cl->allow_request != request))
132 syslog(LOG_ERR, _("Unauthorized request from %s (%s)"), cl->name, cl->hostname);
136 if(request_handlers[request](cl))
137 /* Something went wrong. Probably scriptkiddies. Terminate. */
139 syslog(LOG_ERR, _("Error while processing %s from %s (%s)"),
140 request_name[request], cl->name, cl->hostname);
146 syslog(LOG_ERR, _("Bogus data received from %s (%s)"),
147 cl->name, cl->hostname);
154 /* Connection protocol:
163 ---------------------------------------
166 ---------------------------------------
169 ---------------------------------------
175 (E) Encrypted with symmetric cipher.
177 Part of the challenge is directly used to set the symmetric cipher key and the initial vector.
178 Since a man-in-the-middle cannot decrypt the RSA challenges, this means that he cannot get or
179 forge the key for the symmetric cipher.
182 int send_id(connection_t *cl)
185 cl->allow_request = CHALLENGE;
187 return send_request(cl, "%d %s %d %lx %hd", ID, myself->name, myself->protocol_version, myself->options, myself->port);
190 int id_h(connection_t *cl)
194 char name[MAX_STRING_SIZE];
196 if(sscanf(cl->buffer, "%*d "MAX_STRING" %d %lx %hd", name, &cl->protocol_version, &cl->options, &cl->port) != 4)
198 syslog(LOG_ERR, _("Got bad ID from %s"), cl->hostname);
202 /* Check if version matches */
204 if(cl->protocol_version != myself->protocol_version)
206 syslog(LOG_ERR, _("Peer %s (%s) uses incompatible version %d"),
207 cl->name, cl->hostname, cl->protocol_version);
211 /* Check if identity is a valid name */
215 syslog(LOG_ERR, _("Peer %s uses invalid identity name"), cl->hostname);
219 /* Copy string to cl */
221 cl->name = xstrdup(name);
223 /* Load information about peer */
225 if(read_host_config(cl))
227 syslog(LOG_ERR, _("Peer %s had unknown identity (%s)"), cl->hostname, cl->name);
231 /* First check if the host we connected to is already in our
232 connection list. If so, we are probably making a loop, which
236 if(cl->status.outgoing)
238 if((old = lookup_id(cl->name)))
240 if(debug_lvl >= DEBUG_CONNECTIONS)
241 syslog(LOG_NOTICE, _("Uplink %s (%s) is already in our connection list"), cl->name, cl->hostname);
242 cl->status.outgoing = 0;
243 old->status.outgoing = 1;
244 terminate_connection(cl);
249 /* Now we can add the name to the id tree */
253 /* Read in the public key, so that we can send a challenge */
255 if((cfg = get_config_val(cl->config, config_publickey)))
257 cl->rsa_key = RSA_new();
258 BN_hex2bn(&cl->rsa_key->n, cfg->data.ptr);
259 BN_hex2bn(&cl->rsa_key->e, "FFFF");
263 syslog(LOG_ERR, _("No public key known for %s (%s)"), cl->name, cl->hostname);
267 return send_challenge(cl);
270 int send_challenge(connection_t *cl)
275 len = RSA_size(cl->rsa_key);
277 /* Allocate buffers for the challenge */
279 buffer = xmalloc(len*2+1);
282 free(cl->hischallenge);
284 cl->hischallenge = xmalloc(len);
286 /* Copy random data to the buffer */
288 RAND_bytes(cl->hischallenge, len);
290 cl->hischallenge[0] &= 0x7F; /* Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
292 if(debug_lvl >= DEBUG_SCARY_THINGS)
294 bin2hex(cl->hischallenge, buffer, len);
295 buffer[len*2] = '\0';
296 syslog(LOG_DEBUG, _("Generated random challenge (unencrypted): %s"), buffer);
299 /* Encrypt the random data */
301 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 */
303 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
308 /* Convert the encrypted random data to a hexadecimal formatted string */
310 bin2hex(buffer, buffer, len);
311 buffer[len*2] = '\0';
313 /* Send the challenge */
315 cl->allow_request = CHAL_REPLY;
316 x = send_request(cl, "%d %s", CHALLENGE, buffer);
322 int challenge_h(connection_t *cl)
324 char buffer[MAX_STRING_SIZE];
327 if(sscanf(cl->buffer, "%*d "MAX_STRING, buffer) != 1)
329 syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
333 len = RSA_size(myself->rsa_key);
335 /* Check if the length of the challenge is all right */
337 if(strlen(buffer) != len*2)
339 syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
343 /* Allocate buffers for the challenge */
346 cl->mychallenge = xmalloc(len);
348 /* Convert the challenge from hexadecimal back to binary */
350 hex2bin(buffer,buffer,len);
352 /* Decrypt the challenge */
354 if(RSA_private_decrypt(len, buffer, cl->mychallenge, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
356 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
360 if(debug_lvl >= DEBUG_SCARY_THINGS)
362 bin2hex(cl->mychallenge, buffer, len);
363 buffer[len*2] = '\0';
364 syslog(LOG_DEBUG, _("Received random challenge (unencrypted): %s"), buffer);
367 /* Rest is done by send_chal_reply() */
369 return send_chal_reply(cl);
372 int send_chal_reply(connection_t *cl)
374 char hash[SHA_DIGEST_LENGTH*2+1];
378 syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
382 /* Calculate the hash from the challenge we received */
384 SHA1(cl->mychallenge, RSA_size(myself->rsa_key), hash);
386 /* Convert the hash to a hexadecimal formatted string */
388 bin2hex(hash,hash,SHA_DIGEST_LENGTH);
389 hash[SHA_DIGEST_LENGTH*2] = '\0';
393 if(cl->status.outgoing)
394 cl->allow_request = ID;
396 cl->allow_request = METAKEY;
399 return send_request(cl, "%d %s", CHAL_REPLY, hash);
402 int chal_reply_h(connection_t *cl)
404 char hishash[MAX_STRING_SIZE];
405 char myhash[SHA_DIGEST_LENGTH];
407 if(sscanf(cl->buffer, "%*d "MAX_STRING, hishash) != 1)
409 syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
413 /* Check if the length of the hash is all right */
415 if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
417 syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
421 /* Convert the hash to binary format */
423 hex2bin(hishash, hishash, SHA_DIGEST_LENGTH);
425 /* Calculate the hash from the challenge we sent */
427 SHA1(cl->hischallenge, RSA_size(cl->rsa_key), myhash);
429 /* Verify the incoming hash with the calculated hash */
431 if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
433 syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
434 if(debug_lvl >= DEBUG_SCARY_THINGS)
436 bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
437 hishash[SHA_DIGEST_LENGTH*2] = '\0';
438 syslog(LOG_DEBUG, _("Expected challenge reply: %s"), hishash);
444 /* Identity has now been positively verified.
445 If we are accepting this new connection, then send our identity,
446 if we are making this connecting, acknowledge.
449 if(cl->status.outgoing)
450 return send_metakey(cl);
455 int send_metakey(connection_t *cl)
460 len = RSA_size(cl->rsa_key);
462 /* Allocate buffers for the meta key */
464 buffer = xmalloc(len*2+1);
466 if(!cl->cipher_outkey)
467 cl->cipher_outkey = xmalloc(len);
469 if(!cl->cipher_outctx)
470 cl->cipher_outctx = xmalloc(sizeof(*cl->cipher_outctx));
472 /* Copy random data to the buffer */
474 RAND_bytes(cl->cipher_outkey, len);
476 cl->cipher_outkey[0] &= 0x7F; /* FIXME: Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
478 if(debug_lvl >= DEBUG_SCARY_THINGS)
480 bin2hex(cl->cipher_outkey, buffer, len);
481 buffer[len*2] = '\0';
482 syslog(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"), buffer);
485 /* Encrypt the random data */
487 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 */
489 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
494 /* Convert the encrypted random data to a hexadecimal formatted string */
496 bin2hex(buffer, buffer, len);
497 buffer[len*2] = '\0';
499 /* Send the meta key */
501 if(cl->status.outgoing)
502 cl->allow_request = METAKEY;
504 cl->allow_request = ACK;
506 x = send_request(cl, "%d %s", METAKEY, buffer);
509 EVP_EncryptInit(cl->cipher_outctx, EVP_bf_cfb(), cl->cipher_outkey, cl->cipher_outkey + EVP_bf_cfb()->key_len);
514 int metakey_h(connection_t *cl)
516 char buffer[MAX_STRING_SIZE];
519 if(sscanf(cl->buffer, "%*d "MAX_STRING, buffer) != 1)
521 syslog(LOG_ERR, _("Got bad METAKEY from %s (%s)"), cl->name, cl->hostname);
525 len = RSA_size(myself->rsa_key);
527 /* Check if the length of the meta key is all right */
529 if(strlen(buffer) != len*2)
531 syslog(LOG_ERR, _("Intruder: wrong meta key length from %s (%s)"), cl->name, cl->hostname);
535 /* Allocate buffers for the meta key */
537 if(!cl->cipher_inkey)
538 cl->cipher_inkey = xmalloc(len);
540 if(!cl->cipher_inctx)
541 cl->cipher_inctx = xmalloc(sizeof(*cl->cipher_inctx));
543 /* Convert the challenge from hexadecimal back to binary */
545 hex2bin(buffer,buffer,len);
547 /* Decrypt the meta key */
549 if(RSA_private_decrypt(len, buffer, cl->cipher_inkey, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
551 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
555 if(debug_lvl >= DEBUG_SCARY_THINGS)
557 bin2hex(cl->cipher_inkey, buffer, len);
558 buffer[len*2] = '\0';
559 syslog(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), buffer);
562 EVP_DecryptInit(cl->cipher_inctx, EVP_bf_cfb(), cl->cipher_inkey, cl->cipher_inkey + EVP_bf_cfb()->key_len);
565 if(cl->status.outgoing)
568 return send_metakey(cl);
571 int send_ack(connection_t *cl)
575 if(cl->status.outgoing)
576 cl->allow_request = ACK;
578 setup_vpn_connection(cl);
580 x = send_request(cl, "%d", ACK);
581 cl->status.encryptout = 1;
586 int ack_h(connection_t *cl)
588 connection_t *old, *p;
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 RBL_FOREACH(myself->subnet_tree, rbl)
626 subnet = (subnet_t *)rbl->data;
627 send_add_subnet(cl, subnet);
629 /* And send him all the hosts and their subnets we know... */
631 RBL_FOREACH(connection_tree, rbl)
633 p = (connection_t *)rbl->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 RBL_FOREACH(p->subnet_tree, rbl2)
648 subnet = (subnet_t *)rbl2->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 RBL_FOREACH(connection_tree, rbl)
728 p = (connection_t *)rbl->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 RBL_FOREACH(connection_tree, rbl)
807 p = (connection_t *)rbl->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(new->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 RBL_FOREACH(connection_tree, rbl)
893 p = (connection_t *)rbl->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;
905 /* Okay this is a bit ugly... it would be better to setup UDP sockets dynamically, or
906 * perhaps just one UDP socket... but then again, this has benefits too...
909 setup_vpn_connection(new);
914 int send_del_host(connection_t *cl, connection_t *other)
917 return send_request(cl, "%d %s %lx:%d %lx", DEL_HOST,
918 other->name, other->address, other->port, other->options);
921 int del_host_h(connection_t *cl)
923 char name[MAX_STRING_SIZE];
927 connection_t *old, *p;
930 if(sscanf(cl->buffer, "%*d "MAX_STRING" %lx:%d %lx", name, &address, &port, &options) != 4)
932 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
933 cl->name, cl->hostname);
937 /* Check if identity is a valid name */
941 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
945 /* Check if somebody tries to delete ourself */
947 if(!strcmp(name, myself->name))
949 syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
950 cl->name, cl->hostname);
955 /* Check if the new host already exists in the connnection list */
957 if(!(old = lookup_id(name)))
959 syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
960 name, cl->name, cl->hostname);
964 /* Check if the rest matches */
966 if(address!=old->address || port!=old->port || options!=old->options || cl!=old->nexthop)
968 syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
972 /* Ok, since EVERYTHING seems to check out all right, delete it */
974 old->status.active = 0;
975 terminate_connection(old);
977 /* Tell the rest about the new host */
979 RBL_FOREACH(connection_tree, rbl)
981 p = (connection_t *)rbl->data;
982 if(p->status.meta && p->status.active && p!=cl)
983 send_del_host(p, old);
989 /* Status and error notification routines */
991 int send_status(connection_t *cl, int statusno, char *statusstring)
995 statusstring = status_text[statusno];
997 return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
1000 int status_h(connection_t *cl)
1003 char statusstring[MAX_STRING_SIZE];
1005 if(sscanf(cl->buffer, "%*d %d "MAX_STRING, &statusno, statusstring) != 2)
1007 syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
1008 cl->name, cl->hostname);
1012 if(debug_lvl >= DEBUG_STATUS)
1014 syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
1015 cl->name, cl->hostname, status_text[statusno], statusstring);
1022 int send_error(connection_t *cl, int errno, char *errstring)
1026 errstring = strerror(errno);
1027 return send_request(cl, "%d %d %s", ERROR, errno, errstring);
1030 int error_h(connection_t *cl)
1033 char errorstring[MAX_STRING_SIZE];
1035 if(sscanf(cl->buffer, "%*d %d "MAX_STRING, &errno, errorstring) != 2)
1037 syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
1038 cl->name, cl->hostname);
1042 if(debug_lvl >= DEBUG_ERROR)
1044 syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
1045 cl->name, cl->hostname, strerror(errno), errorstring);
1048 terminate_connection(cl);
1053 int send_termreq(connection_t *cl)
1056 return send_request(cl, "%d", TERMREQ);
1059 int termreq_h(connection_t *cl)
1062 terminate_connection(cl);
1067 /* Keepalive routines - FIXME: needs a closer look */
1069 int send_ping(connection_t *cl)
1072 cl->status.pinged = 1;
1073 cl->last_ping_time = time(NULL);
1075 return send_request(cl, "%d", PING);
1078 int ping_h(connection_t *cl)
1081 return send_pong(cl);
1084 int send_pong(connection_t *cl)
1087 return send_request(cl, "%d", PONG);
1090 int pong_h(connection_t *cl)
1093 cl->status.pinged = 0;
1100 int send_key_changed(connection_t *from, connection_t *cl)
1105 RBL_FOREACH(connection_tree, rbl)
1107 p = (connection_t *)rbl->data;
1108 if(p != cl && p->status.meta && p->status.active)
1109 send_request(p, "%d %s", KEY_CHANGED, from->name);
1115 int key_changed_h(connection_t *cl)
1117 char from_id[MAX_STRING_SIZE];
1120 if(sscanf(cl->buffer, "%*d "MAX_STRING, from_id) != 1)
1122 syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
1123 cl->name, cl->hostname);
1127 if(!(from = lookup_id(from_id)))
1129 syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
1130 cl->name, cl->hostname, from_id);
1134 from->status.validkey = 0;
1135 from->status.waitingforkey = 0;
1137 send_key_changed(from, cl);
1142 int send_req_key(connection_t *from, connection_t *to)
1145 return send_request(to->nexthop, "%d %s %s", REQ_KEY,
1146 from->name, to->name);
1149 int req_key_h(connection_t *cl)
1151 char from_id[MAX_STRING_SIZE];
1152 char to_id[MAX_STRING_SIZE];
1153 connection_t *from, *to;
1156 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, from_id, to_id) != 2)
1158 syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
1159 cl->name, cl->hostname);
1163 if(!(from = lookup_id(from_id)))
1165 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
1166 cl->name, cl->hostname, from_id);
1170 /* Check if this key request is for us */
1172 if(!strcmp(to_id, myself->name))
1174 bin2hex(myself->cipher_pktkey, pktkey, myself->cipher_pktkeylength);
1175 pktkey[myself->cipher_pktkeylength*2] = '\0';
1176 send_ans_key(myself, from, pktkey);
1180 if(!(to = lookup_id(to_id)))
1182 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
1183 cl->name, cl->hostname, to_id);
1187 if(to->status.validkey) /* Proxy keys */
1189 bin2hex(to->cipher_pktkey, pktkey, to->cipher_pktkeylength);
1190 pktkey[to->cipher_pktkeylength*2] = '\0';
1191 send_ans_key(to, from, pktkey);
1194 send_req_key(from, to);
1201 int send_ans_key(connection_t *from, connection_t *to, char *pktkey)
1204 return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
1205 from->name, to->name, pktkey);
1208 int ans_key_h(connection_t *cl)
1210 char from_id[MAX_STRING_SIZE];
1211 char to_id[MAX_STRING_SIZE];
1212 char pktkey[MAX_STRING_SIZE];
1214 connection_t *from, *to;
1216 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING, from_id, to_id, pktkey) != 3)
1218 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
1219 cl->name, cl->hostname);
1223 if(!(from = lookup_id(from_id)))
1225 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
1226 cl->name, cl->hostname, from_id);
1230 /* Check correctness of packet key */
1232 keylength = strlen(pktkey);
1234 if(keylength != from->cipher_pktkeylength*2)
1236 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key length"),
1237 cl->name, cl->hostname, from->name);
1241 /* Forward it if necessary */
1243 if(strcmp(to_id, myself->name))
1245 if(!(to = lookup_id(to_id)))
1247 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1248 cl->name, cl->hostname, to_id);
1251 send_ans_key(from, to, pktkey);
1254 /* Update our copy of the origin's packet key */
1256 if(from->cipher_pktkey)
1257 free(from->cipher_pktkey);
1259 from->cipher_pktkey = xstrdup(pktkey);
1261 hex2bin(from->cipher_pktkey, from->cipher_pktkey, keylength);
1262 from->cipher_pktkey[keylength] = '\0';
1264 from->status.validkey = 1;
1265 from->status.waitingforkey = 0;
1270 /* Jumptable for the request handlers */
1272 int (*request_handlers[])(connection_t*) = {
1273 id_h, challenge_h, chal_reply_h, metakey_h, ack_h,
1274 status_h, error_h, termreq_h,
1276 add_host_h, del_host_h,
1277 add_subnet_h, del_subnet_h,
1278 key_changed_h, req_key_h, ans_key_h,
1283 char (*request_name[]) = {
1284 "ID", "CHALLENGE", "CHAL_REPLY", "METAKEY", "ACK",
1285 "STATUS", "ERROR", "TERMREQ",
1287 "ADD_HOST", "DEL_HOST",
1288 "ADD_SUBNET", "DEL_SUBNET",
1289 "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1292 /* Status strings */
1294 char (*status_text[]) = {
1300 char (*error_text[]) = {