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.62 2000/11/20 19:12:13 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)
195 if(sscanf(cl->buffer, "%*d %as %d %lx %hd", &cl->name, &cl->protocol_version, &cl->options, &cl->port) != 4)
197 syslog(LOG_ERR, _("Got bad ID from %s"), cl->hostname);
201 /* Check if version matches */
203 if(cl->protocol_version != myself->protocol_version)
205 syslog(LOG_ERR, _("Peer %s (%s) uses incompatible version %d"),
206 cl->name, cl->hostname, cl->protocol_version);
210 /* Check if identity is a valid name */
212 if(check_id(cl->name))
214 syslog(LOG_ERR, _("Peer %s uses invalid identity name"), cl->hostname);
218 /* Load information about peer */
220 if(read_host_config(cl))
222 syslog(LOG_ERR, _("Peer %s had unknown identity (%s)"), cl->hostname, cl->name);
226 /* First check if the host we connected to is already in our
227 connection list. If so, we are probably making a loop, which
231 if(cl->status.outgoing)
233 if((old = lookup_id(cl->name)))
235 if(debug_lvl >= DEBUG_CONNECTIONS)
236 syslog(LOG_NOTICE, _("Uplink %s (%s) is already in our connection list"), cl->name, cl->hostname);
237 cl->status.outgoing = 0;
238 old->status.outgoing = 1;
239 terminate_connection(cl);
244 if((cfg = get_config_val(cl->config, config_publickey)))
246 cl->rsa_key = RSA_new();
247 BN_hex2bn(&cl->rsa_key->n, cfg->data.ptr);
248 BN_hex2bn(&cl->rsa_key->e, "FFFF");
252 syslog(LOG_ERR, _("No public key known for %s (%s)"), cl->name, cl->hostname);
256 return send_challenge(cl);
259 int send_challenge(connection_t *cl)
264 len = RSA_size(cl->rsa_key);
266 /* Allocate buffers for the challenge */
268 buffer = xmalloc(len*2+1);
271 free(cl->hischallenge);
273 cl->hischallenge = xmalloc(len);
275 /* Copy random data to the buffer */
277 RAND_bytes(cl->hischallenge, len);
279 cl->hischallenge[0] &= 0x7F; /* Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
281 if(debug_lvl >= DEBUG_SCARY_THINGS)
283 bin2hex(cl->hischallenge, buffer, len);
284 buffer[len*2] = '\0';
285 syslog(LOG_DEBUG, _("Generated random challenge (unencrypted): %s"), buffer);
288 /* Encrypt the random data */
290 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 */
292 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
297 /* Convert the encrypted random data to a hexadecimal formatted string */
299 bin2hex(buffer, buffer, len);
300 buffer[len*2] = '\0';
302 /* Send the challenge */
304 cl->allow_request = CHAL_REPLY;
305 x = send_request(cl, "%d %s", CHALLENGE, buffer);
311 int challenge_h(connection_t *cl)
316 if(sscanf(cl->buffer, "%*d %as", &buffer) != 1)
318 syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
322 len = RSA_size(myself->rsa_key);
324 /* Check if the length of the challenge is all right */
326 if(strlen(buffer) != len*2)
328 syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
333 /* Allocate buffers for the challenge */
336 cl->mychallenge = xmalloc(len);
338 /* Convert the challenge from hexadecimal back to binary */
340 hex2bin(buffer,buffer,len);
342 /* Decrypt the challenge */
344 if(RSA_private_decrypt(len, buffer, cl->mychallenge, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
346 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
351 if(debug_lvl >= DEBUG_SCARY_THINGS)
353 bin2hex(cl->mychallenge, buffer, len);
354 buffer[len*2] = '\0';
355 syslog(LOG_DEBUG, _("Received random challenge (unencrypted): %s"), buffer);
360 /* Rest is done by send_chal_reply() */
362 return send_chal_reply(cl);
365 int send_chal_reply(connection_t *cl)
367 char hash[SHA_DIGEST_LENGTH*2+1];
371 syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
375 /* Calculate the hash from the challenge we received */
377 SHA1(cl->mychallenge, RSA_size(myself->rsa_key), hash);
379 /* Convert the hash to a hexadecimal formatted string */
381 bin2hex(hash,hash,SHA_DIGEST_LENGTH);
382 hash[SHA_DIGEST_LENGTH*2] = '\0';
386 if(cl->status.outgoing)
387 cl->allow_request = ID;
389 cl->allow_request = METAKEY;
392 return send_request(cl, "%d %s", CHAL_REPLY, hash);
395 int chal_reply_h(connection_t *cl)
398 char myhash[SHA_DIGEST_LENGTH];
400 if(sscanf(cl->buffer, "%*d %as", &hishash) != 1)
402 syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
407 /* Check if the length of the hash is all right */
409 if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
411 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);
442 /* Identity has now been positively verified.
443 If we are accepting this new connection, then send our identity,
444 if we are making this connecting, acknowledge.
447 if(cl->status.outgoing)
448 return send_metakey(cl);
453 int send_metakey(connection_t *cl)
458 len = RSA_size(cl->rsa_key);
460 /* Allocate buffers for the meta key */
462 buffer = xmalloc(len*2+1);
464 if(!cl->cipher_outkey)
465 cl->cipher_outkey = xmalloc(len);
467 if(!cl->cipher_outctx)
468 cl->cipher_outctx = xmalloc(sizeof(*cl->cipher_outctx));
470 /* Copy random data to the buffer */
472 RAND_bytes(cl->cipher_outkey, len);
474 cl->cipher_outkey[0] &= 0x7F; /* FIXME: Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
476 if(debug_lvl >= DEBUG_SCARY_THINGS)
478 bin2hex(cl->cipher_outkey, buffer, len);
479 buffer[len*2] = '\0';
480 syslog(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"), buffer);
483 /* Encrypt the random data */
485 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 */
487 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
492 /* Convert the encrypted random data to a hexadecimal formatted string */
494 bin2hex(buffer, buffer, len);
495 buffer[len*2] = '\0';
497 /* Send the meta key */
499 if(cl->status.outgoing)
500 cl->allow_request = METAKEY;
502 cl->allow_request = ACK;
504 x = send_request(cl, "%d %s", METAKEY, buffer);
507 EVP_EncryptInit(cl->cipher_outctx, EVP_bf_cfb(), cl->cipher_outkey, cl->cipher_outkey + EVP_bf_cfb()->key_len);
512 int metakey_h(connection_t *cl)
517 if(sscanf(cl->buffer, "%*d %as", &buffer) != 1)
519 syslog(LOG_ERR, _("Got bad METAKEY from %s (%s)"), cl->name, cl->hostname);
523 len = RSA_size(myself->rsa_key);
525 /* Check if the length of the meta key is all right */
527 if(strlen(buffer) != len*2)
529 syslog(LOG_ERR, _("Intruder: wrong meta key length from %s (%s)"), cl->name, cl->hostname);
534 /* Allocate buffers for the meta key */
536 if(!cl->cipher_inkey)
537 cl->cipher_inkey = xmalloc(len);
539 if(!cl->cipher_inctx)
540 cl->cipher_inctx = xmalloc(sizeof(*cl->cipher_inctx));
542 /* Convert the challenge from hexadecimal back to binary */
544 hex2bin(buffer,buffer,len);
546 /* Decrypt the meta key */
548 if(RSA_private_decrypt(len, buffer, cl->cipher_inkey, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
550 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);
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 setup_vpn_connection(cl);
582 x = send_request(cl, "%d", ACK);
583 cl->status.encryptout = 1;
588 int ack_h(connection_t *cl)
590 connection_t *old, *p;
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 RBL_FOREACH(myself->subnet_tree, rbl)
628 subnet = (subnet_t *)rbl->data;
629 send_add_subnet(cl, subnet);
631 /* And send him all the hosts and their subnets we know... */
633 RBL_FOREACH(connection_tree, rbl)
635 p = (connection_t *)rbl->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 RBL_FOREACH(p->subnet_tree, rbl2)
650 subnet = (subnet_t *)rbl2->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)
677 connection_t *owner, *p;
681 if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 2)
683 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
684 free(name); free(subnetstr);
688 /* Check if owner name is a valid */
692 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
693 free(name); free(subnetstr);
697 /* Check if subnet string is valid */
699 if(!(subnet = str2net(subnetstr)))
701 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
702 free(name); free(subnetstr);
708 /* Check if somebody tries to add a subnet of ourself */
710 if(!strcmp(name, myself->name))
712 syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
713 cl->name, cl->hostname);
719 /* Check if the owner of the new subnet is in the connection list */
721 if(!(owner = lookup_id(name)))
723 syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
724 name, cl->name, cl->hostname);
729 /* If everything is correct, add the subnet to the list of the owner */
731 subnet_add(owner, subnet);
735 RBL_FOREACH(connection_tree, rbl)
737 p = (connection_t *)rbl->data;
738 if(p->status.meta && p->status.active && p!= cl)
739 send_add_subnet(p, subnet);
745 int send_del_subnet(connection_t *cl, subnet_t *subnet)
750 netstr = net2str(subnet);
751 x = send_request(cl, "%d %s %s", DEL_SUBNET, subnet->owner->name, netstr);
757 int del_subnet_h(connection_t *cl)
761 connection_t *owner, *p;
765 if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
767 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
768 free(name); free(subnetstr);
772 /* Check if owner name is a valid */
776 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
777 free(name); free(subnetstr);
781 /* Check if subnet string is valid */
783 if(!(subnet = str2net(subnetstr)))
785 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
786 free(name); free(subnetstr);
792 /* Check if somebody tries to add a subnet of ourself */
794 if(!strcmp(name, myself->name))
796 syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
797 cl->name, cl->hostname);
803 /* Check if the owner of the new subnet is in the connection list */
805 if(!(owner = lookup_id(name)))
807 syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
808 name, cl->name, cl->hostname);
813 /* If everything is correct, delete the subnet from the list of the owner */
819 RBL_FOREACH(connection_tree, rbl)
821 p = (connection_t *)rbl->data;
822 if(p->status.meta && p->status.active && p!= cl)
823 send_del_subnet(p, subnet);
829 /* New and closed connections notification */
831 int send_add_host(connection_t *cl, connection_t *other)
834 return send_request(cl, "%d %s %lx:%d %lx", ADD_HOST,
835 other->name, other->address, other->port, other->options);
838 int add_host_h(connection_t *cl)
840 connection_t *old, *new, *p;
843 new = new_connection();
845 if(sscanf(cl->buffer, "%*d %as %lx:%d %lx", &new->name, &new->address, &new->port, &new->options) != 4)
847 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
851 /* Check if identity is a valid name */
853 if(check_id(new->name))
855 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
856 free_connection(new);
860 /* Check if somebody tries to add ourself */
862 if(!strcmp(new->name, myself->name))
864 syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
866 free_connection(new);
870 /* Fill in more of the new connection structure */
872 new->hostname = hostlookup(htonl(new->address));
874 /* Check if the new host already exists in the connnection list */
876 if((old = lookup_id(new->name)))
878 if((new->address == old->address) && (new->port == old->port))
880 if(debug_lvl >= DEBUG_CONNECTIONS)
881 syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
882 old->name, old->hostname, new->name, new->hostname);
883 free_connection(new);
888 if(debug_lvl >= DEBUG_CONNECTIONS)
889 syslog(LOG_NOTICE, _("Removing old entry for %s (%s) in favour of new connection"),
890 old->name, old->hostname);
892 terminate_connection(old);
896 /* Hook it up into the connection */
900 /* Tell the rest about the new host */
902 RBL_FOREACH(connection_tree, rbl)
904 p = (connection_t *)rbl->data;
905 if(p->status.meta && p->status.active && p!=cl)
906 send_add_host(p, new);
909 /* Fill in rest of connection structure */
912 new->status.active = 1;
913 new->cipher_pkttype = EVP_bf_cfb();
914 new->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
916 /* Okay this is a bit ugly... it would be better to setup UDP sockets dynamically, or
917 * perhaps just one UDP socket... but then again, this has benefits too...
920 setup_vpn_connection(new);
925 int send_del_host(connection_t *cl, connection_t *other)
928 return send_request(cl, "%d %s %lx:%d %lx", DEL_HOST,
929 other->name, other->address, other->port, other->options);
932 int del_host_h(connection_t *cl)
938 connection_t *old, *p;
941 if(sscanf(cl->buffer, "%*d %as %lx:%d %lx", &name, &address, &port, &options) != 4)
943 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
944 cl->name, cl->hostname);
948 /* Check if identity is a valid name */
952 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
957 /* Check if somebody tries to delete ourself */
959 if(!strcmp(name, myself->name))
961 syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
962 cl->name, cl->hostname);
968 /* Check if the new host already exists in the connnection list */
970 if(!(old = lookup_id(name)))
972 syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
973 name, cl->name, cl->hostname);
978 /* Check if the rest matches */
980 if(address!=old->address || port!=old->port || options!=old->options || cl!=old->nexthop)
982 syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
986 /* Ok, since EVERYTHING seems to check out all right, delete it */
988 old->status.active = 0;
989 terminate_connection(old);
991 /* Tell the rest about the new host */
993 RBL_FOREACH(connection_tree, rbl)
995 p = (connection_t *)rbl->data;
996 if(p->status.meta && p->status.active && p!=cl)
997 send_del_host(p, old);
1003 /* Status and error notification routines */
1005 int send_status(connection_t *cl, int statusno, char *statusstring)
1009 statusstring = status_text[statusno];
1011 return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
1014 int status_h(connection_t *cl)
1019 if(sscanf(cl->buffer, "%*d %d %as", &statusno, &statusstring) != 2)
1021 syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
1022 cl->name, cl->hostname);
1026 if(debug_lvl >= DEBUG_STATUS)
1028 syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
1029 cl->name, cl->hostname, status_text[statusno], statusstring);
1037 int send_error(connection_t *cl, int errno, char *errstring)
1041 errstring = strerror(errno);
1042 return send_request(cl, "%d %d %s", ERROR, errno, errstring);
1045 int error_h(connection_t *cl)
1050 if(sscanf(cl->buffer, "%*d %d %as", &errno, &errorstring) != 2)
1052 syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
1053 cl->name, cl->hostname);
1057 if(debug_lvl >= DEBUG_ERROR)
1059 syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
1060 cl->name, cl->hostname, strerror(errno), errorstring);
1064 terminate_connection(cl);
1069 int send_termreq(connection_t *cl)
1072 return send_request(cl, "%d", TERMREQ);
1075 int termreq_h(connection_t *cl)
1078 terminate_connection(cl);
1083 /* Keepalive routines - FIXME: needs a closer look */
1085 int send_ping(connection_t *cl)
1088 cl->status.pinged = 1;
1089 cl->last_ping_time = time(NULL);
1091 return send_request(cl, "%d", PING);
1094 int ping_h(connection_t *cl)
1097 return send_pong(cl);
1100 int send_pong(connection_t *cl)
1103 return send_request(cl, "%d", PONG);
1106 int pong_h(connection_t *cl)
1109 cl->status.pinged = 0;
1116 int send_key_changed(connection_t *from, connection_t *cl)
1121 RBL_FOREACH(connection_tree, rbl)
1123 p = (connection_t *)rbl->data;
1124 if(p != cl && p->status.meta && p->status.active)
1125 send_request(p, "%d %s", KEY_CHANGED, from->name);
1131 int key_changed_h(connection_t *cl)
1136 if(sscanf(cl->buffer, "%*d %as", &from_id) != 1)
1138 syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
1139 cl->name, cl->hostname);
1143 if(!(from = lookup_id(from_id)))
1145 syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
1146 cl->name, cl->hostname, from_id);
1153 from->status.validkey = 0;
1154 from->status.waitingforkey = 0;
1156 send_key_changed(from, cl);
1161 int send_req_key(connection_t *from, connection_t *to)
1164 return send_request(to->nexthop, "%d %s %s", REQ_KEY,
1165 from->name, to->name);
1168 int req_key_h(connection_t *cl)
1170 char *from_id, *to_id;
1171 connection_t *from, *to;
1174 if(sscanf(cl->buffer, "%*d %as %as", &from_id, &to_id) != 2)
1176 syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
1177 cl->name, cl->hostname);
1181 if(!(from = lookup_id(from_id)))
1183 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
1184 cl->name, cl->hostname, from_id);
1185 free(from_id); free(to_id);
1189 /* Check if this key request is for us */
1191 if(!strcmp(to_id, myself->name))
1193 bin2hex(myself->cipher_pktkey, pktkey, myself->cipher_pktkeylength);
1194 pktkey[myself->cipher_pktkeylength*2] = '\0';
1195 send_ans_key(myself, from, pktkey);
1199 if(!(to = lookup_id(to_id)))
1201 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
1202 cl->name, cl->hostname, to_id);
1203 free(from_id); free(to_id);
1207 if(to->status.validkey) /* Proxy keys */
1209 bin2hex(to->cipher_pktkey, pktkey, to->cipher_pktkeylength);
1210 pktkey[to->cipher_pktkeylength*2] = '\0';
1211 send_ans_key(to, from, pktkey);
1214 send_req_key(from, to);
1217 free(from_id); free(to_id);
1222 int send_ans_key(connection_t *from, connection_t *to, char *pktkey)
1225 return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
1226 from->name, to->name, pktkey);
1229 int ans_key_h(connection_t *cl)
1231 char *from_id, *to_id, *pktkey;
1233 connection_t *from, *to;
1235 if(sscanf(cl->buffer, "%*d %as %as %as", &from_id, &to_id, &pktkey) != 3)
1237 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
1238 cl->name, cl->hostname);
1242 if(!(from = lookup_id(from_id)))
1244 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
1245 cl->name, cl->hostname, from_id);
1246 free(from_id); free(to_id); free(pktkey);
1250 /* Check correctness of packet key */
1252 keylength = strlen(pktkey);
1254 if(keylength != from->cipher_pktkeylength*2)
1256 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key length"),
1257 cl->name, cl->hostname, from->name);
1258 free(from_id); free(to_id); free(pktkey);
1262 /* Forward it if necessary */
1264 if(strcmp(to_id, myself->name))
1266 if(!(to = lookup_id(to_id)))
1268 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1269 cl->name, cl->hostname, to_id);
1270 free(from_id); free(to_id);
1273 send_ans_key(from, to, pktkey);
1276 /* Update our copy of the origin's packet key */
1278 if(from->cipher_pktkey)
1279 free(from->cipher_pktkey);
1282 hex2bin(pktkey, pktkey, keylength);
1283 pktkey[keylength] = '\0';
1284 from->cipher_pktkey = pktkey;
1286 from->status.validkey = 1;
1287 from->status.waitingforkey = 0;
1289 free(from_id); free(to_id);
1294 /* Jumptable for the request handlers */
1296 int (*request_handlers[])(connection_t*) = {
1297 id_h, challenge_h, chal_reply_h, metakey_h, ack_h,
1298 status_h, error_h, termreq_h,
1300 add_host_h, del_host_h,
1301 add_subnet_h, del_subnet_h,
1302 key_changed_h, req_key_h, ans_key_h,
1307 char (*request_name[]) = {
1308 "ID", "CHALLENGE", "CHAL_REPLY", "METAKEY", "ACK",
1309 "STATUS", "ERROR", "TERMREQ",
1311 "ADD_HOST", "DEL_HOST",
1312 "ADD_SUBNET", "DEL_SUBNET",
1313 "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1316 /* Status strings */
1318 char (*status_text[]) = {
1324 char (*error_text[]) = {