2 protocol.c -- handle the meta-protocol
3 Copyright (C) 1999-2001 Ivo Timmermans <itimmermans@bigfoot.com>,
4 2000,2001 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.86 2001/03/13 21:33:31 guus Exp $
25 #include <sys/types.h>
30 #include <sys/socket.h>
41 #include <netinet/in.h>
43 #ifdef HAVE_OPENSSL_SHA_H
44 # include <openssl/sha.h>
49 #ifdef HAVE_OPENSSL_RAND_H
50 # include <openssl/rand.h>
55 #ifdef HAVE_OPENSSL_EVP_H
56 # include <openssl/evp.h>
67 #include "connection.h"
71 int check_id(char *id)
75 for (i = 0; i < strlen(id); i++)
76 if(!isalnum(id[i]) && id[i] != '_')
82 /* Generic request routines - takes care of logging and error
85 int send_request(connection_t *cl, const char *format, ...)
88 char buffer[MAXBUFSIZE];
92 /* Use vsnprintf instead of vasprintf: faster, no memory
93 fragmentation, cleanup is automatic, and there is a limit on the
94 input buffer anyway */
96 va_start(args, format);
97 len = vsnprintf(buffer, MAXBUFSIZE, format, args);
98 request = va_arg(args, int);
101 if(len < 0 || len > MAXBUFSIZE-1)
103 syslog(LOG_ERR, _("Output buffer overflow while sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
109 if(debug_lvl >= DEBUG_PROTOCOL)
110 syslog(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
113 return send_meta(cl, buffer, len);
116 int receive_request(connection_t *cl)
120 if(sscanf(cl->buffer, "%d", &request) == 1)
122 if((request < 0) || (request >= LAST) || (request_handlers[request] == NULL))
124 syslog(LOG_ERR, _("Unknown request from %s (%s)"),
125 cl->name, cl->hostname);
130 if(debug_lvl >= DEBUG_PROTOCOL)
131 syslog(LOG_DEBUG, _("Got %s from %s (%s)"),
132 request_name[request], cl->name, cl->hostname);
135 if((cl->allow_request != ALL) && (cl->allow_request != request))
137 syslog(LOG_ERR, _("Unauthorized request from %s (%s)"), cl->name, cl->hostname);
141 if(request_handlers[request](cl))
142 /* Something went wrong. Probably scriptkiddies. Terminate. */
144 syslog(LOG_ERR, _("Error while processing %s from %s (%s)"),
145 request_name[request], cl->name, cl->hostname);
151 syslog(LOG_ERR, _("Bogus data received from %s (%s)"),
152 cl->name, cl->hostname);
159 /* Connection protocol:
168 ---------------------------------------
171 ---------------------------------------
174 ---------------------------------------
180 (E) Encrypted with symmetric cipher.
182 Part of the challenge is directly used to set the symmetric cipher
183 key and the initial vector. Since a man-in-the-middle cannot
184 decrypt the RSA challenges, this means that he cannot get or forge
185 the key for the symmetric cipher.
188 int send_id(connection_t *cl)
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];
201 if(sscanf(cl->buffer, "%*d "MAX_STRING" %d %lx %hd", name, &cl->protocol_version, &cl->options, &port) != 4)
203 syslog(LOG_ERR, _("Got bad ID from %s"), cl->hostname);
207 /* Check if version matches */
209 if(cl->protocol_version != myself->protocol_version)
211 syslog(LOG_ERR, _("Peer %s (%s) uses incompatible version %d"),
212 cl->name, cl->hostname, cl->protocol_version);
216 /* Check if identity is a valid name */
220 syslog(LOG_ERR, _("Peer %s uses invalid identity name"), cl->hostname);
224 /* Copy string to cl */
226 cl->name = xstrdup(name);
228 /* Load information about peer */
230 if(read_host_config(cl))
232 syslog(LOG_ERR, _("Peer %s had unknown identity (%s)"), cl->hostname, cl->name);
236 /* First check if the host we connected to is already in our
237 connection list. If so, we are probably making a loop, which
241 if(cl->status.outgoing)
243 if((old = lookup_id(cl->name)))
245 if(debug_lvl >= DEBUG_CONNECTIONS)
246 syslog(LOG_NOTICE, _("Uplink %s (%s) is already in our connection list"), cl->name, cl->hostname);
247 cl->status.outgoing = 0;
248 old->status.outgoing = 1;
249 terminate_connection(cl);
254 /* Now we can add the name to the id tree */
258 /* And uhr... cl->port just changed so we have to unlink it from the connection tree and re-insert... */
260 node = avl_unlink(connection_tree, cl);
262 avl_insert_node(connection_tree, node);
264 /* Read in the public key, so that we can send a metakey */
266 if(read_rsa_public_key(cl))
269 cl->allow_request = METAKEY;
271 return send_metakey(cl);
274 int ack_h(connection_t *cl)
277 connection_t *old, *p;
279 avl_node_t *node, *node2;
281 /* Okay, before we active the connection, we check if there is another entry
282 in the connection list with the same name. If so, it presumably is an
283 old connection that has timed out but we don't know it yet.
286 while((old = lookup_id(cl->name)))
288 if(debug_lvl >= DEBUG_CONNECTIONS)
289 syslog(LOG_NOTICE, _("Removing old entry for %s at %s in favour of new connection from %s"),
290 cl->name, old->hostname, cl->hostname);
292 terminate_connection(old);
295 /* Activate this connection */
297 cl->allow_request = ALL;
298 cl->status.active = 1;
300 cl->cipher_pkttype = EVP_bf_cbc();
301 cl->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
303 if(debug_lvl >= DEBUG_CONNECTIONS)
304 syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname);
307 /* Check some options */
309 if((cfg = get_config_val(cl->config, config_indirectdata)))
311 if(cfg->data.val == stupid_true)
312 cl->options |= OPTION_INDIRECT;
315 if((cfg = get_config_val(cl->config, config_tcponly)))
317 if(cfg->data.val == stupid_true)
318 cl->options |= OPTION_TCPONLY;
321 /* Send him our subnets */
323 for(node = myself->subnet_tree->head; node; node = node->next)
325 subnet = (subnet_t *)node->data;
326 send_add_subnet(cl, subnet);
329 /* And send him all the hosts and their subnets we know... */
331 for(node = connection_tree->head; node; node = node->next)
333 p = (connection_t *)node->data;
335 if(p != cl && p->status.active)
337 /* Notify others of this connection */
340 send_add_host(p, cl);
342 /* Notify new connection of everything we know */
344 send_add_host(cl, p);
346 for(node2 = p->subnet_tree->head; node2; node2 = node2->next)
348 subnet = (subnet_t *)node2->data;
349 send_add_subnet(cl, subnet);
357 int send_challenge(connection_t *cl)
362 /* CHECKME: what is most reasonable value for len? */
364 len = RSA_size(cl->rsa_key);
366 /* Allocate buffers for the challenge */
368 buffer = xmalloc(len*2+1);
371 free(cl->hischallenge);
373 cl->hischallenge = xmalloc(len);
375 /* Copy random data to the buffer */
377 RAND_bytes(cl->hischallenge, len);
382 bin2hex(cl->hischallenge, buffer, len);
383 buffer[len*2] = '\0';
386 /* Send the challenge */
388 x = send_request(cl, "%d %s", CHALLENGE, buffer);
394 int challenge_h(connection_t *cl)
396 char buffer[MAX_STRING_SIZE];
399 if(sscanf(cl->buffer, "%*d "MAX_STRING, buffer) != 1)
401 syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
405 len = RSA_size(myself->rsa_key);
407 /* Check if the length of the challenge is all right */
409 if(strlen(buffer) != len*2)
411 syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
415 /* Allocate buffers for the challenge */
418 cl->mychallenge = xmalloc(len);
420 /* Convert the challenge from hexadecimal back to binary */
422 hex2bin(buffer,cl->mychallenge,len);
424 cl->allow_request = CHAL_REPLY;
426 /* Rest is done by send_chal_reply() */
428 return send_chal_reply(cl);
431 int send_chal_reply(connection_t *cl)
433 char hash[SHA_DIGEST_LENGTH*2+1];
437 syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
441 /* Calculate the hash from the challenge we received */
443 SHA1(cl->mychallenge, RSA_size(myself->rsa_key), hash);
445 /* Convert the hash to a hexadecimal formatted string */
447 bin2hex(hash,hash,SHA_DIGEST_LENGTH);
448 hash[SHA_DIGEST_LENGTH*2] = '\0';
453 return send_request(cl, "%d %s", CHAL_REPLY, hash);
456 int chal_reply_h(connection_t *cl)
458 char hishash[MAX_STRING_SIZE];
459 char myhash[SHA_DIGEST_LENGTH];
461 if(sscanf(cl->buffer, "%*d "MAX_STRING, hishash) != 1)
463 syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
467 /* Check if the length of the hash is all right */
469 if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
471 syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
475 /* Convert the hash to binary format */
477 hex2bin(hishash, hishash, SHA_DIGEST_LENGTH);
479 /* Calculate the hash from the challenge we sent */
481 SHA1(cl->hischallenge, RSA_size(cl->rsa_key), myhash);
483 /* Verify the incoming hash with the calculated hash */
485 if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
487 syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
488 if(debug_lvl >= DEBUG_SCARY_THINGS)
490 bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
491 hishash[SHA_DIGEST_LENGTH*2] = '\0';
492 syslog(LOG_DEBUG, _("Expected challenge reply: %s"), hishash);
497 /* Identity has now been positively verified.
498 ack_h() handles the rest from now on.
504 int send_metakey(connection_t *cl)
509 len = RSA_size(cl->rsa_key);
511 /* Allocate buffers for the meta key */
513 buffer = xmalloc(len*2+1);
515 if(!cl->cipher_outkey)
516 cl->cipher_outkey = xmalloc(len);
518 if(!cl->cipher_outctx)
519 cl->cipher_outctx = xmalloc(sizeof(*cl->cipher_outctx));
521 /* Copy random data to the buffer */
523 RAND_bytes(cl->cipher_outkey, len);
525 /* The message we send must be smaller than the modulus of the RSA key.
526 By definition, for a key of k bits, the following formula holds:
528 2^(k-1) <= modulus < 2^(k)
530 Where ^ means "to the power of", not "xor".
531 This means that to be sure, we must choose our message < 2^(k-1).
532 This can be done by setting the most significant bit to zero.
535 cl->cipher_outkey[0] &= 0x7F;
537 if(debug_lvl >= DEBUG_SCARY_THINGS)
539 bin2hex(cl->cipher_outkey, buffer, len);
540 buffer[len*2] = '\0';
541 syslog(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"), buffer);
544 /* Encrypt the random data
546 We do not use one of the PKCS padding schemes here.
547 This is allowed, because we encrypt a totally random string
548 with a length equal to that of the modulus of the RSA key.
551 if(RSA_public_encrypt(len, cl->cipher_outkey, buffer, cl->rsa_key, RSA_NO_PADDING) != len)
553 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
558 /* Convert the encrypted random data to a hexadecimal formatted string */
560 bin2hex(buffer, buffer, len);
561 buffer[len*2] = '\0';
563 /* Send the meta key */
565 x = send_request(cl, "%d %s", METAKEY, buffer);
568 /* Further outgoing requests are encrypted with the key we just generated */
570 EVP_EncryptInit(cl->cipher_outctx, EVP_bf_cfb(),
571 cl->cipher_outkey + len - EVP_bf_cfb()->key_len,
572 cl->cipher_outkey + len - EVP_bf_cfb()->key_len - EVP_bf_cfb()->iv_len);
574 cl->status.encryptout = 1;
579 int metakey_h(connection_t *cl)
581 char buffer[MAX_STRING_SIZE];
584 if(sscanf(cl->buffer, "%*d "MAX_STRING, buffer) != 1)
586 syslog(LOG_ERR, _("Got bad METAKEY from %s (%s)"), cl->name, cl->hostname);
590 len = RSA_size(myself->rsa_key);
592 /* Check if the length of the meta key is all right */
594 if(strlen(buffer) != len*2)
596 syslog(LOG_ERR, _("Intruder: wrong meta key length from %s (%s)"), cl->name, cl->hostname);
600 /* Allocate buffers for the meta key */
602 if(!cl->cipher_inkey)
603 cl->cipher_inkey = xmalloc(len);
605 if(!cl->cipher_inctx)
606 cl->cipher_inctx = xmalloc(sizeof(*cl->cipher_inctx));
608 /* Convert the challenge from hexadecimal back to binary */
610 hex2bin(buffer,buffer,len);
612 /* Decrypt the meta key */
614 if(RSA_private_decrypt(len, buffer, cl->cipher_inkey, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
616 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
620 if(debug_lvl >= DEBUG_SCARY_THINGS)
622 bin2hex(cl->cipher_inkey, buffer, len);
623 buffer[len*2] = '\0';
624 syslog(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), buffer);
627 /* All incoming requests will now be encrypted. */
629 EVP_DecryptInit(cl->cipher_inctx, EVP_bf_cfb(),
630 cl->cipher_inkey + len - EVP_bf_cfb()->key_len,
631 cl->cipher_inkey + len - EVP_bf_cfb()->key_len - EVP_bf_cfb()->iv_len);
633 cl->status.decryptin = 1;
635 cl->allow_request = CHALLENGE;
637 return send_challenge(cl);
640 /* Address and subnet information exchange */
642 int send_add_subnet(connection_t *cl, subnet_t *subnet)
648 if((cl->options | myself->options | subnet->owner->options) & OPTION_INDIRECT)
649 owner = myself->name;
651 owner = subnet->owner->name;
653 x = send_request(cl, "%d %s %s", ADD_SUBNET,
654 owner, netstr = net2str(subnet));
660 int add_subnet_h(connection_t *cl)
662 char subnetstr[MAX_STRING_SIZE];
663 char name[MAX_STRING_SIZE];
664 connection_t *owner, *p;
668 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, name, subnetstr) != 2)
670 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
674 /* Check if owner name is a valid */
678 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
682 /* Check if subnet string is valid */
684 if(!(subnet = str2net(subnetstr)))
686 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
690 /* Check if somebody tries to add a subnet of ourself */
692 if(!strcmp(name, myself->name))
694 syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
695 cl->name, cl->hostname);
700 /* Check if the owner of the new subnet is in the connection list */
702 if(!(owner = lookup_id(name)))
704 syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
705 name, cl->name, cl->hostname);
709 /* If everything is correct, add the subnet to the list of the owner */
711 subnet_add(owner, subnet);
715 for(node = connection_tree->head; node; node = node->next)
717 p = (connection_t *)node->data;
718 if(p->status.meta && p->status.active && p!= cl)
719 send_add_subnet(p, subnet);
725 int send_del_subnet(connection_t *cl, subnet_t *subnet)
731 if(cl->options & OPTION_INDIRECT)
732 owner = myself->name;
734 owner = subnet->owner->name;
736 x = send_request(cl, "%d %s %s", DEL_SUBNET, owner, netstr = net2str(subnet));
742 int del_subnet_h(connection_t *cl)
744 char subnetstr[MAX_STRING_SIZE];
745 char name[MAX_STRING_SIZE];
746 connection_t *owner, *p;
750 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, name, subnetstr) != 3)
752 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
756 /* Check if owner name is a valid */
760 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
764 /* Check if subnet string is valid */
766 if(!(subnet = str2net(subnetstr)))
768 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
774 /* Check if somebody tries to add a subnet of ourself */
776 if(!strcmp(name, myself->name))
778 syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
779 cl->name, cl->hostname);
784 /* Check if the owner of the new subnet is in the connection list */
786 if(!(owner = lookup_id(name)))
788 syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
789 name, cl->name, cl->hostname);
793 /* If everything is correct, delete the subnet from the list of the owner */
799 for(node = connection_tree->head; node; node = node->next)
801 p = (connection_t *)node->data;
802 if(p->status.meta && p->status.active && p!= cl)
803 send_del_subnet(p, subnet);
809 /* New and closed connections notification */
811 int send_add_host(connection_t *cl, connection_t *other)
814 if(!((cl->options | myself->options | other->options) & OPTION_INDIRECT))
815 return send_request(cl, "%d %s %lx:%d %lx", ADD_HOST,
816 other->name, other->address, other->port, other->options);
821 int add_host_h(connection_t *cl)
823 connection_t *old, *new, *p;
824 char name[MAX_STRING_SIZE];
827 new = new_connection();
829 if(sscanf(cl->buffer, "%*d "MAX_STRING" %lx:%hd %lx", name, &new->address, &new->port, &new->options) != 4)
831 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
835 /* Check if identity is a valid name */
839 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
840 free_connection(new);
844 /* Check if somebody tries to add ourself */
846 if(!strcmp(name, myself->name))
848 syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
850 free_connection(new);
854 /* Fill in more of the new connection structure */
856 new->hostname = hostlookup(htonl(new->address));
858 /* Check if the new host already exists in the connnection list */
860 if((old = lookup_id(name)))
862 if((new->address == old->address) && (new->port == old->port))
864 if(debug_lvl >= DEBUG_CONNECTIONS)
865 syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
866 old->name, old->hostname, name, new->hostname);
867 free_connection(new);
872 if(debug_lvl >= DEBUG_CONNECTIONS)
873 syslog(LOG_NOTICE, _("Removing old entry for %s (%s) in favour of new connection"),
874 old->name, old->hostname);
876 terminate_connection(old);
880 /* Hook it up into the connection */
882 new->name = xstrdup(name);
886 /* Tell the rest about the new host */
888 for(node = connection_tree->head; node; node = node->next)
890 p = (connection_t *)node->data;
891 if(p->status.meta && p->status.active && p!=cl)
892 send_add_host(p, new);
895 /* Fill in rest of connection structure */
898 new->status.active = 1;
899 new->cipher_pkttype = EVP_bf_cbc();
900 new->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
905 int send_del_host(connection_t *cl, connection_t *other)
908 if(!((cl->options | myself->options) & OPTION_INDIRECT))
909 return send_request(cl, "%d %s %lx:%d %lx", DEL_HOST,
910 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:%hd %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 err, char *errstring)
1020 errstring = strerror(err);
1021 return send_request(cl, "%d %d %s", ERROR, err, errstring);
1024 int error_h(connection_t *cl)
1027 char errorstring[MAX_STRING_SIZE];
1029 if(sscanf(cl->buffer, "%*d %d "MAX_STRING, &err, 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(err), 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 int send_ping(connection_t *cl)
1064 cl->status.pinged = 1;
1065 cl->last_ping_time = time(NULL);
1067 return send_request(cl, "%d", PING);
1070 int ping_h(connection_t *cl)
1073 return send_pong(cl);
1076 int send_pong(connection_t *cl)
1079 return send_request(cl, "%d", PONG);
1082 int pong_h(connection_t *cl)
1085 cl->status.pinged = 0;
1092 int send_key_changed(connection_t *from, connection_t *cl)
1097 for(node = connection_tree->head; node; node = node->next)
1099 p = (connection_t *)node->data;
1100 if(p != cl && p->status.meta && p->status.active)
1101 if(!(p->options & OPTION_INDIRECT) || from == myself)
1102 send_request(p, "%d %s", KEY_CHANGED, from->name);
1108 int key_changed_h(connection_t *cl)
1110 char from_id[MAX_STRING_SIZE];
1113 if(sscanf(cl->buffer, "%*d "MAX_STRING, from_id) != 1)
1115 syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
1116 cl->name, cl->hostname);
1120 if(!(from = lookup_id(from_id)))
1122 syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
1123 cl->name, cl->hostname, from_id);
1127 from->status.validkey = 0;
1128 from->status.waitingforkey = 0;
1130 if(!(from->options | cl->options | myself->options) & OPTION_INDIRECT)
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;
1266 int send_tcppacket(connection_t *cl, vpn_packet_t *packet)
1270 x = send_request(cl->nexthop, "%d %hd", PACKET, packet->len);
1275 return send_meta(cl->nexthop, packet->data, packet->len);
1278 int tcppacket_h(connection_t *cl)
1280 vpn_packet_t packet;
1284 if(sscanf(cl->buffer, "%*d %hd", &packet.len) != 1)
1286 syslog(LOG_ERR, _("Got bad PACKET from %s (%s)"), cl->name, cl->hostname);
1297 x = read(cl->meta_socket, p, todo);
1302 syslog(LOG_NOTICE, _("Connection closed by %s (%s)"), cl->name, cl->hostname);
1304 if(errno==EINTR || errno==EAGAIN) /* FIXME: select() or poll() or reimplement this evil hack */
1307 syslog(LOG_ERR, _("Error during reception of PACKET from %s (%s): %m"), cl->name, cl->hostname);
1316 receive_packet(cl, &packet);
1321 /* Jumptable for the request handlers */
1323 int (*request_handlers[])(connection_t*) = {
1324 id_h, metakey_h, challenge_h, chal_reply_h,
1325 status_h, error_h, termreq_h,
1327 add_host_h, del_host_h,
1328 add_subnet_h, del_subnet_h,
1329 key_changed_h, req_key_h, ans_key_h,
1335 char (*request_name[]) = {
1336 "ID", "METAKEY", "CHALLENGE", "CHAL_REPLY",
1337 "STATUS", "ERROR", "TERMREQ",
1339 "ADD_HOST", "DEL_HOST",
1340 "ADD_SUBNET", "DEL_SUBNET",
1341 "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1345 /* Status strings */
1347 char (*status_text[]) = {
1353 char (*error_text[]) = {