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.63 2000/11/22 18:54:08 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 /* Now we can add the name to the id tree */
248 /* Read in the public key, so that we can send a challenge */
250 if((cfg = get_config_val(cl->config, config_publickey)))
252 cl->rsa_key = RSA_new();
253 BN_hex2bn(&cl->rsa_key->n, cfg->data.ptr);
254 BN_hex2bn(&cl->rsa_key->e, "FFFF");
258 syslog(LOG_ERR, _("No public key known for %s (%s)"), cl->name, cl->hostname);
262 return send_challenge(cl);
265 int send_challenge(connection_t *cl)
270 len = RSA_size(cl->rsa_key);
272 /* Allocate buffers for the challenge */
274 buffer = xmalloc(len*2+1);
277 free(cl->hischallenge);
279 cl->hischallenge = xmalloc(len);
281 /* Copy random data to the buffer */
283 RAND_bytes(cl->hischallenge, len);
285 cl->hischallenge[0] &= 0x7F; /* Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
287 if(debug_lvl >= DEBUG_SCARY_THINGS)
289 bin2hex(cl->hischallenge, buffer, len);
290 buffer[len*2] = '\0';
291 syslog(LOG_DEBUG, _("Generated random challenge (unencrypted): %s"), buffer);
294 /* Encrypt the random data */
296 if(RSA_public_encrypt(len, cl->hischallenge, buffer, cl->rsa_key, RSA_NO_PADDING) != len) /* NO_PADDING because the message size equals the RSA key size and it is totally random */
298 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
303 /* Convert the encrypted random data to a hexadecimal formatted string */
305 bin2hex(buffer, buffer, len);
306 buffer[len*2] = '\0';
308 /* Send the challenge */
310 cl->allow_request = CHAL_REPLY;
311 x = send_request(cl, "%d %s", CHALLENGE, buffer);
317 int challenge_h(connection_t *cl)
322 if(sscanf(cl->buffer, "%*d %as", &buffer) != 1)
324 syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
328 len = RSA_size(myself->rsa_key);
330 /* Check if the length of the challenge is all right */
332 if(strlen(buffer) != len*2)
334 syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
339 /* Allocate buffers for the challenge */
342 cl->mychallenge = xmalloc(len);
344 /* Convert the challenge from hexadecimal back to binary */
346 hex2bin(buffer,buffer,len);
348 /* Decrypt the challenge */
350 if(RSA_private_decrypt(len, buffer, cl->mychallenge, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
352 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
357 if(debug_lvl >= DEBUG_SCARY_THINGS)
359 bin2hex(cl->mychallenge, buffer, len);
360 buffer[len*2] = '\0';
361 syslog(LOG_DEBUG, _("Received random challenge (unencrypted): %s"), buffer);
366 /* Rest is done by send_chal_reply() */
368 return send_chal_reply(cl);
371 int send_chal_reply(connection_t *cl)
373 char hash[SHA_DIGEST_LENGTH*2+1];
377 syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
381 /* Calculate the hash from the challenge we received */
383 SHA1(cl->mychallenge, RSA_size(myself->rsa_key), hash);
385 /* Convert the hash to a hexadecimal formatted string */
387 bin2hex(hash,hash,SHA_DIGEST_LENGTH);
388 hash[SHA_DIGEST_LENGTH*2] = '\0';
392 if(cl->status.outgoing)
393 cl->allow_request = ID;
395 cl->allow_request = METAKEY;
398 return send_request(cl, "%d %s", CHAL_REPLY, hash);
401 int chal_reply_h(connection_t *cl)
404 char myhash[SHA_DIGEST_LENGTH];
406 if(sscanf(cl->buffer, "%*d %as", &hishash) != 1)
408 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);
422 /* Convert the hash to binary format */
424 hex2bin(hishash, hishash, SHA_DIGEST_LENGTH);
426 /* Calculate the hash from the challenge we sent */
428 SHA1(cl->hischallenge, RSA_size(cl->rsa_key), myhash);
430 /* Verify the incoming hash with the calculated hash */
432 if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
434 syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
435 if(debug_lvl >= DEBUG_SCARY_THINGS)
437 bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
438 hishash[SHA_DIGEST_LENGTH*2] = '\0';
439 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)
523 if(sscanf(cl->buffer, "%*d %as", &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);
540 /* Allocate buffers for the meta key */
542 if(!cl->cipher_inkey)
543 cl->cipher_inkey = xmalloc(len);
545 if(!cl->cipher_inctx)
546 cl->cipher_inctx = xmalloc(sizeof(*cl->cipher_inctx));
548 /* Convert the challenge from hexadecimal back to binary */
550 hex2bin(buffer,buffer,len);
552 /* Decrypt the meta key */
554 if(RSA_private_decrypt(len, buffer, cl->cipher_inkey, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
556 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
561 if(debug_lvl >= DEBUG_SCARY_THINGS)
563 bin2hex(cl->cipher_inkey, buffer, len);
564 buffer[len*2] = '\0';
565 syslog(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), buffer);
570 EVP_DecryptInit(cl->cipher_inctx, EVP_bf_cfb(), cl->cipher_inkey, cl->cipher_inkey + EVP_bf_cfb()->key_len);
573 if(cl->status.outgoing)
576 return send_metakey(cl);
579 int send_ack(connection_t *cl)
583 if(cl->status.outgoing)
584 cl->allow_request = ACK;
586 setup_vpn_connection(cl);
588 x = send_request(cl, "%d", ACK);
589 cl->status.encryptout = 1;
594 int ack_h(connection_t *cl)
596 connection_t *old, *p;
600 /* Okay, before we active the connection, we check if there is another entry
601 in the connection list with the same name. If so, it presumably is an
602 old connection that has timed out but we don't know it yet.
605 while((old = lookup_id(cl->name)))
607 if(debug_lvl >= DEBUG_CONNECTIONS)
608 syslog(LOG_NOTICE, _("Removing old entry for %s at %s in favour of new connection from %s"),
609 cl->name, old->hostname, cl->hostname);
611 terminate_connection(old);
614 /* Activate this connection */
616 cl->allow_request = ALL;
617 cl->status.active = 1;
618 cl->status.decryptin = 1;
620 cl->cipher_pkttype = EVP_bf_cfb();
621 cl->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
623 if(debug_lvl >= DEBUG_CONNECTIONS)
624 syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname);
627 if(!cl->status.outgoing)
630 /* Send him our subnets */
632 RBL_FOREACH(myself->subnet_tree, rbl)
634 subnet = (subnet_t *)rbl->data;
635 send_add_subnet(cl, subnet);
637 /* And send him all the hosts and their subnets we know... */
639 RBL_FOREACH(connection_tree, rbl)
641 p = (connection_t *)rbl->data;
643 if(p != cl && p->status.active)
645 /* Notify others of this connection */
648 send_add_host(p, cl);
650 /* Notify new connection of everything we know */
652 send_add_host(cl, p);
654 RBL_FOREACH(p->subnet_tree, rbl2)
656 subnet = (subnet_t *)rbl2->data;
657 send_add_subnet(cl, subnet);
665 /* Address and subnet information exchange */
667 int send_add_subnet(connection_t *cl, subnet_t *subnet)
672 x = send_request(cl, "%d %s %s", ADD_SUBNET,
673 subnet->owner->name, netstr = net2str(subnet));
679 int add_subnet_h(connection_t *cl)
683 connection_t *owner, *p;
687 if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 2)
689 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
690 free(name); free(subnetstr);
694 /* Check if owner name is a valid */
698 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
699 free(name); free(subnetstr);
703 /* Check if subnet string is valid */
705 if(!(subnet = str2net(subnetstr)))
707 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
708 free(name); free(subnetstr);
714 /* Check if somebody tries to add a subnet of ourself */
716 if(!strcmp(name, myself->name))
718 syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
719 cl->name, cl->hostname);
725 /* Check if the owner of the new subnet is in the connection list */
727 if(!(owner = lookup_id(name)))
729 syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
730 name, cl->name, cl->hostname);
732 dump_connection_list();
737 rbl = rbl_search_rbl(connection_tree, &cl);
738 syslog(LOG_ERR, "rbl_search_rbl: %p", rbl);
740 syslog(LOG_ERR, "rbl->data->name: %s", ((connection_t *)rbl->data)->name);
746 /* If everything is correct, add the subnet to the list of the owner */
748 subnet_add(owner, subnet);
752 RBL_FOREACH(connection_tree, rbl)
754 p = (connection_t *)rbl->data;
755 if(p->status.meta && p->status.active && p!= cl)
756 send_add_subnet(p, subnet);
762 int send_del_subnet(connection_t *cl, subnet_t *subnet)
767 netstr = net2str(subnet);
768 x = send_request(cl, "%d %s %s", DEL_SUBNET, subnet->owner->name, netstr);
774 int del_subnet_h(connection_t *cl)
778 connection_t *owner, *p;
782 if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
784 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
785 free(name); free(subnetstr);
789 /* Check if owner name is a valid */
793 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
794 free(name); free(subnetstr);
798 /* Check if subnet string is valid */
800 if(!(subnet = str2net(subnetstr)))
802 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
803 free(name); free(subnetstr);
809 /* Check if somebody tries to add a subnet of ourself */
811 if(!strcmp(name, myself->name))
813 syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
814 cl->name, cl->hostname);
820 /* Check if the owner of the new subnet is in the connection list */
822 if(!(owner = lookup_id(name)))
824 syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
825 name, cl->name, cl->hostname);
830 /* If everything is correct, delete the subnet from the list of the owner */
836 RBL_FOREACH(connection_tree, rbl)
838 p = (connection_t *)rbl->data;
839 if(p->status.meta && p->status.active && p!= cl)
840 send_del_subnet(p, subnet);
846 /* New and closed connections notification */
848 int send_add_host(connection_t *cl, connection_t *other)
851 return send_request(cl, "%d %s %lx:%d %lx", ADD_HOST,
852 other->name, other->address, other->port, other->options);
855 int add_host_h(connection_t *cl)
857 connection_t *old, *new, *p;
860 new = new_connection();
862 if(sscanf(cl->buffer, "%*d %as %lx:%d %lx", &new->name, &new->address, &new->port, &new->options) != 4)
864 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
868 /* Check if identity is a valid name */
870 if(check_id(new->name))
872 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
873 free_connection(new);
877 /* Check if somebody tries to add ourself */
879 if(!strcmp(new->name, myself->name))
881 syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
883 free_connection(new);
887 /* Fill in more of the new connection structure */
889 new->hostname = hostlookup(htonl(new->address));
891 /* Check if the new host already exists in the connnection list */
893 if((old = lookup_id(new->name)))
895 if((new->address == old->address) && (new->port == old->port))
897 if(debug_lvl >= DEBUG_CONNECTIONS)
898 syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
899 old->name, old->hostname, new->name, new->hostname);
900 free_connection(new);
905 if(debug_lvl >= DEBUG_CONNECTIONS)
906 syslog(LOG_NOTICE, _("Removing old entry for %s (%s) in favour of new connection"),
907 old->name, old->hostname);
909 terminate_connection(old);
913 /* Hook it up into the connection */
918 /* Tell the rest about the new host */
920 RBL_FOREACH(connection_tree, rbl)
922 p = (connection_t *)rbl->data;
923 if(p->status.meta && p->status.active && p!=cl)
924 send_add_host(p, new);
927 /* Fill in rest of connection structure */
930 new->status.active = 1;
931 new->cipher_pkttype = EVP_bf_cfb();
932 new->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
934 /* Okay this is a bit ugly... it would be better to setup UDP sockets dynamically, or
935 * perhaps just one UDP socket... but then again, this has benefits too...
938 setup_vpn_connection(new);
943 int send_del_host(connection_t *cl, connection_t *other)
946 return send_request(cl, "%d %s %lx:%d %lx", DEL_HOST,
947 other->name, other->address, other->port, other->options);
950 int del_host_h(connection_t *cl)
956 connection_t *old, *p;
959 if(sscanf(cl->buffer, "%*d %as %lx:%d %lx", &name, &address, &port, &options) != 4)
961 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
962 cl->name, cl->hostname);
966 /* Check if identity is a valid name */
970 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
975 /* Check if somebody tries to delete ourself */
977 if(!strcmp(name, myself->name))
979 syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
980 cl->name, cl->hostname);
986 /* Check if the new host already exists in the connnection list */
988 if(!(old = lookup_id(name)))
990 syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
991 name, cl->name, cl->hostname);
996 /* Check if the rest matches */
998 if(address!=old->address || port!=old->port || options!=old->options || cl!=old->nexthop)
1000 syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
1004 /* Ok, since EVERYTHING seems to check out all right, delete it */
1006 old->status.active = 0;
1007 terminate_connection(old);
1009 /* Tell the rest about the new host */
1011 RBL_FOREACH(connection_tree, rbl)
1013 p = (connection_t *)rbl->data;
1014 if(p->status.meta && p->status.active && p!=cl)
1015 send_del_host(p, old);
1021 /* Status and error notification routines */
1023 int send_status(connection_t *cl, int statusno, char *statusstring)
1027 statusstring = status_text[statusno];
1029 return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
1032 int status_h(connection_t *cl)
1037 if(sscanf(cl->buffer, "%*d %d %as", &statusno, &statusstring) != 2)
1039 syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
1040 cl->name, cl->hostname);
1044 if(debug_lvl >= DEBUG_STATUS)
1046 syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
1047 cl->name, cl->hostname, status_text[statusno], statusstring);
1055 int send_error(connection_t *cl, int errno, char *errstring)
1059 errstring = strerror(errno);
1060 return send_request(cl, "%d %d %s", ERROR, errno, errstring);
1063 int error_h(connection_t *cl)
1068 if(sscanf(cl->buffer, "%*d %d %as", &errno, &errorstring) != 2)
1070 syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
1071 cl->name, cl->hostname);
1075 if(debug_lvl >= DEBUG_ERROR)
1077 syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
1078 cl->name, cl->hostname, strerror(errno), errorstring);
1082 terminate_connection(cl);
1087 int send_termreq(connection_t *cl)
1090 return send_request(cl, "%d", TERMREQ);
1093 int termreq_h(connection_t *cl)
1096 terminate_connection(cl);
1101 /* Keepalive routines - FIXME: needs a closer look */
1103 int send_ping(connection_t *cl)
1106 cl->status.pinged = 1;
1107 cl->last_ping_time = time(NULL);
1109 return send_request(cl, "%d", PING);
1112 int ping_h(connection_t *cl)
1115 return send_pong(cl);
1118 int send_pong(connection_t *cl)
1121 return send_request(cl, "%d", PONG);
1124 int pong_h(connection_t *cl)
1127 cl->status.pinged = 0;
1134 int send_key_changed(connection_t *from, connection_t *cl)
1139 RBL_FOREACH(connection_tree, rbl)
1141 p = (connection_t *)rbl->data;
1142 if(p != cl && p->status.meta && p->status.active)
1143 send_request(p, "%d %s", KEY_CHANGED, from->name);
1149 int key_changed_h(connection_t *cl)
1154 if(sscanf(cl->buffer, "%*d %as", &from_id) != 1)
1156 syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
1157 cl->name, cl->hostname);
1161 if(!(from = lookup_id(from_id)))
1163 syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
1164 cl->name, cl->hostname, from_id);
1171 from->status.validkey = 0;
1172 from->status.waitingforkey = 0;
1174 send_key_changed(from, cl);
1179 int send_req_key(connection_t *from, connection_t *to)
1182 return send_request(to->nexthop, "%d %s %s", REQ_KEY,
1183 from->name, to->name);
1186 int req_key_h(connection_t *cl)
1188 char *from_id, *to_id;
1189 connection_t *from, *to;
1192 if(sscanf(cl->buffer, "%*d %as %as", &from_id, &to_id) != 2)
1194 syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
1195 cl->name, cl->hostname);
1199 if(!(from = lookup_id(from_id)))
1201 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
1202 cl->name, cl->hostname, from_id);
1203 free(from_id); free(to_id);
1207 /* Check if this key request is for us */
1209 if(!strcmp(to_id, myself->name))
1211 bin2hex(myself->cipher_pktkey, pktkey, myself->cipher_pktkeylength);
1212 pktkey[myself->cipher_pktkeylength*2] = '\0';
1213 send_ans_key(myself, from, pktkey);
1217 if(!(to = lookup_id(to_id)))
1219 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
1220 cl->name, cl->hostname, to_id);
1221 free(from_id); free(to_id);
1225 if(to->status.validkey) /* Proxy keys */
1227 bin2hex(to->cipher_pktkey, pktkey, to->cipher_pktkeylength);
1228 pktkey[to->cipher_pktkeylength*2] = '\0';
1229 send_ans_key(to, from, pktkey);
1232 send_req_key(from, to);
1235 free(from_id); free(to_id);
1240 int send_ans_key(connection_t *from, connection_t *to, char *pktkey)
1243 return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
1244 from->name, to->name, pktkey);
1247 int ans_key_h(connection_t *cl)
1249 char *from_id, *to_id, *pktkey;
1251 connection_t *from, *to;
1253 if(sscanf(cl->buffer, "%*d %as %as %as", &from_id, &to_id, &pktkey) != 3)
1255 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
1256 cl->name, cl->hostname);
1260 if(!(from = lookup_id(from_id)))
1262 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
1263 cl->name, cl->hostname, from_id);
1264 free(from_id); free(to_id); free(pktkey);
1268 /* Check correctness of packet key */
1270 keylength = strlen(pktkey);
1272 if(keylength != from->cipher_pktkeylength*2)
1274 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key length"),
1275 cl->name, cl->hostname, from->name);
1276 free(from_id); free(to_id); free(pktkey);
1280 /* Forward it if necessary */
1282 if(strcmp(to_id, myself->name))
1284 if(!(to = lookup_id(to_id)))
1286 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1287 cl->name, cl->hostname, to_id);
1288 free(from_id); free(to_id);
1291 send_ans_key(from, to, pktkey);
1294 /* Update our copy of the origin's packet key */
1296 if(from->cipher_pktkey)
1297 free(from->cipher_pktkey);
1300 hex2bin(pktkey, pktkey, keylength);
1301 pktkey[keylength] = '\0';
1302 from->cipher_pktkey = pktkey;
1304 from->status.validkey = 1;
1305 from->status.waitingforkey = 0;
1307 free(from_id); free(to_id);
1312 /* Jumptable for the request handlers */
1314 int (*request_handlers[])(connection_t*) = {
1315 id_h, challenge_h, chal_reply_h, metakey_h, ack_h,
1316 status_h, error_h, termreq_h,
1318 add_host_h, del_host_h,
1319 add_subnet_h, del_subnet_h,
1320 key_changed_h, req_key_h, ans_key_h,
1325 char (*request_name[]) = {
1326 "ID", "CHALLENGE", "CHAL_REPLY", "METAKEY", "ACK",
1327 "STATUS", "ERROR", "TERMREQ",
1329 "ADD_HOST", "DEL_HOST",
1330 "ADD_SUBNET", "DEL_SUBNET",
1331 "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1334 /* Status strings */
1336 char (*status_text[]) = {
1342 char (*error_text[]) = {