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.82 2001/02/26 11:37:20 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 > 255) || (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 send_challenge(connection_t *cl)
279 /* CHECKME: what is most reasonable value for len? */
281 len = RSA_size(cl->rsa_key);
283 /* Allocate buffers for the challenge */
285 buffer = xmalloc(len*2+1);
288 free(cl->hischallenge);
290 cl->hischallenge = xmalloc(len);
292 /* Copy random data to the buffer */
294 RAND_bytes(cl->hischallenge, len);
299 bin2hex(cl->hischallenge, buffer, len);
300 buffer[len*2] = '\0';
303 /* Send the challenge */
305 x = send_request(cl, "%d %s", CHALLENGE, buffer);
311 int challenge_h(connection_t *cl)
313 char buffer[MAX_STRING_SIZE];
316 if(sscanf(cl->buffer, "%*d "MAX_STRING, 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);
332 /* Allocate buffers for the challenge */
335 cl->mychallenge = xmalloc(len);
337 /* Convert the challenge from hexadecimal back to binary */
339 hex2bin(buffer,cl->mychallenge,len);
341 cl->allow_request = CHAL_REPLY;
343 /* Rest is done by send_chal_reply() */
345 return send_chal_reply(cl);
348 int send_chal_reply(connection_t *cl)
350 char hash[SHA_DIGEST_LENGTH*2+1];
354 syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
358 /* Calculate the hash from the challenge we received */
360 SHA1(cl->mychallenge, RSA_size(myself->rsa_key), hash);
362 /* Convert the hash to a hexadecimal formatted string */
364 bin2hex(hash,hash,SHA_DIGEST_LENGTH);
365 hash[SHA_DIGEST_LENGTH*2] = '\0';
370 return send_request(cl, "%d %s", CHAL_REPLY, hash);
373 int chal_reply_h(connection_t *cl)
375 char hishash[MAX_STRING_SIZE];
376 char myhash[SHA_DIGEST_LENGTH];
378 if(sscanf(cl->buffer, "%*d "MAX_STRING, hishash) != 1)
380 syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
384 /* Check if the length of the hash is all right */
386 if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
388 syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
392 /* Convert the hash to binary format */
394 hex2bin(hishash, hishash, SHA_DIGEST_LENGTH);
396 /* Calculate the hash from the challenge we sent */
398 SHA1(cl->hischallenge, RSA_size(cl->rsa_key), myhash);
400 /* Verify the incoming hash with the calculated hash */
402 if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
404 syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
405 if(debug_lvl >= DEBUG_SCARY_THINGS)
407 bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
408 hishash[SHA_DIGEST_LENGTH*2] = '\0';
409 syslog(LOG_DEBUG, _("Expected challenge reply: %s"), hishash);
414 /* Identity has now been positively verified.
415 ack_h() handles the rest from now on.
421 int send_metakey(connection_t *cl)
426 len = RSA_size(cl->rsa_key);
428 /* Allocate buffers for the meta key */
430 buffer = xmalloc(len*2+1);
432 if(!cl->cipher_outkey)
433 cl->cipher_outkey = xmalloc(len);
435 if(!cl->cipher_outctx)
436 cl->cipher_outctx = xmalloc(sizeof(*cl->cipher_outctx));
438 /* Copy random data to the buffer */
440 RAND_bytes(cl->cipher_outkey, len);
442 cl->cipher_outkey[0] &= 0x0F; /* Make sure that the random data is smaller than the modulus of the RSA key */
444 if(debug_lvl >= DEBUG_SCARY_THINGS)
446 bin2hex(cl->cipher_outkey, buffer, len);
447 buffer[len*2] = '\0';
448 syslog(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"), buffer);
451 /* Encrypt the random data */
453 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 */
455 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
460 /* Convert the encrypted random data to a hexadecimal formatted string */
462 bin2hex(buffer, buffer, len);
463 buffer[len*2] = '\0';
465 /* Send the meta key */
467 x = send_request(cl, "%d %s", METAKEY, buffer);
470 /* Further outgoing requests are encrypted with the key we just generated */
472 EVP_EncryptInit(cl->cipher_outctx, EVP_bf_cfb(),
473 cl->cipher_outkey + len - EVP_bf_cfb()->key_len,
474 cl->cipher_outkey + len - EVP_bf_cfb()->key_len - EVP_bf_cfb()->iv_len);
476 cl->status.encryptout = 1;
481 int metakey_h(connection_t *cl)
483 char buffer[MAX_STRING_SIZE];
486 if(sscanf(cl->buffer, "%*d "MAX_STRING, buffer) != 1)
488 syslog(LOG_ERR, _("Got bad METAKEY from %s (%s)"), cl->name, cl->hostname);
492 len = RSA_size(myself->rsa_key);
494 /* Check if the length of the meta key is all right */
496 if(strlen(buffer) != len*2)
498 syslog(LOG_ERR, _("Intruder: wrong meta key length from %s (%s)"), cl->name, cl->hostname);
502 /* Allocate buffers for the meta key */
504 if(!cl->cipher_inkey)
505 cl->cipher_inkey = xmalloc(len);
507 if(!cl->cipher_inctx)
508 cl->cipher_inctx = xmalloc(sizeof(*cl->cipher_inctx));
510 /* Convert the challenge from hexadecimal back to binary */
512 hex2bin(buffer,buffer,len);
514 /* Decrypt the meta key */
516 if(RSA_private_decrypt(len, buffer, cl->cipher_inkey, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
518 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
522 if(debug_lvl >= DEBUG_SCARY_THINGS)
524 bin2hex(cl->cipher_inkey, buffer, len);
525 buffer[len*2] = '\0';
526 syslog(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), buffer);
529 /* All incoming requests will now be encrypted. */
531 EVP_DecryptInit(cl->cipher_inctx, EVP_bf_cfb(),
532 cl->cipher_inkey + len - EVP_bf_cfb()->key_len,
533 cl->cipher_inkey + len - EVP_bf_cfb()->key_len - EVP_bf_cfb()->iv_len);
535 cl->status.decryptin = 1;
537 cl->allow_request = CHALLENGE;
539 return send_challenge(cl);
542 int ack_h(connection_t *cl)
545 connection_t *old, *p;
547 avl_node_t *node, *node2;
549 /* Okay, before we active the connection, we check if there is another entry
550 in the connection list with the same name. If so, it presumably is an
551 old connection that has timed out but we don't know it yet.
554 while((old = lookup_id(cl->name)))
556 if(debug_lvl >= DEBUG_CONNECTIONS)
557 syslog(LOG_NOTICE, _("Removing old entry for %s at %s in favour of new connection from %s"),
558 cl->name, old->hostname, cl->hostname);
560 terminate_connection(old);
563 /* Activate this connection */
565 cl->allow_request = ALL;
566 cl->status.active = 1;
568 cl->cipher_pkttype = EVP_bf_cbc();
569 cl->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
571 if(debug_lvl >= DEBUG_CONNECTIONS)
572 syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname);
575 /* Check some options */
577 if((cfg = get_config_val(cl->config, config_indirectdata)))
579 if(cfg->data.val == stupid_true)
580 cl->options |= OPTION_INDIRECT;
583 if((cfg = get_config_val(cl->config, config_tcponly)))
585 if(cfg->data.val == stupid_true)
586 cl->options |= OPTION_TCPONLY;
589 /* Send him our subnets */
591 for(node = myself->subnet_tree->head; node; node = node->next)
593 subnet = (subnet_t *)node->data;
594 send_add_subnet(cl, subnet);
596 /* And send him all the hosts and their subnets we know... */
598 for(node = connection_tree->head; node; node = node->next)
600 p = (connection_t *)node->data;
602 if(p != cl && p->status.active)
604 /* Notify others of this connection */
607 send_add_host(p, cl);
609 /* Notify new connection of everything we know */
611 send_add_host(cl, p);
613 for(node2 = p->subnet_tree->head; node2; node2 = node2->next)
615 subnet = (subnet_t *)node2->data;
616 send_add_subnet(cl, subnet);
624 /* Address and subnet information exchange */
626 int send_add_subnet(connection_t *cl, subnet_t *subnet)
632 if(cl->options & OPTION_INDIRECT)
633 owner = myself->name;
635 owner = subnet->owner->name;
637 x = send_request(cl, "%d %s %s", ADD_SUBNET,
638 owner, netstr = net2str(subnet));
644 int add_subnet_h(connection_t *cl)
646 char subnetstr[MAX_STRING_SIZE];
647 char name[MAX_STRING_SIZE];
648 connection_t *owner, *p;
652 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, name, subnetstr) != 2)
654 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
658 /* Check if owner name is a valid */
662 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
666 /* Check if subnet string is valid */
668 if(!(subnet = str2net(subnetstr)))
670 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
674 /* Check if somebody tries to add a subnet of ourself */
676 if(!strcmp(name, myself->name))
678 syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
679 cl->name, cl->hostname);
684 /* Check if the owner of the new subnet is in the connection list */
686 if(!(owner = lookup_id(name)))
688 syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
689 name, cl->name, cl->hostname);
693 /* If everything is correct, add the subnet to the list of the owner */
695 subnet_add(owner, subnet);
699 for(node = connection_tree->head; node; node = node->next)
701 p = (connection_t *)node->data;
702 if(p->status.meta && p->status.active && p!= cl)
703 send_add_subnet(p, subnet);
709 int send_del_subnet(connection_t *cl, subnet_t *subnet)
715 if(cl->options & OPTION_INDIRECT)
716 owner = myself->name;
718 owner = subnet->owner->name;
720 x = send_request(cl, "%d %s %s", DEL_SUBNET, owner, netstr = net2str(subnet));
726 int del_subnet_h(connection_t *cl)
728 char subnetstr[MAX_STRING_SIZE];
729 char name[MAX_STRING_SIZE];
730 connection_t *owner, *p;
734 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, name, subnetstr) != 3)
736 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
740 /* Check if owner name is a valid */
744 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
748 /* Check if subnet string is valid */
750 if(!(subnet = str2net(subnetstr)))
752 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
758 /* Check if somebody tries to add a subnet of ourself */
760 if(!strcmp(name, myself->name))
762 syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
763 cl->name, cl->hostname);
768 /* Check if the owner of the new subnet is in the connection list */
770 if(!(owner = lookup_id(name)))
772 syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
773 name, cl->name, cl->hostname);
777 /* If everything is correct, delete the subnet from the list of the owner */
783 for(node = connection_tree->head; node; node = node->next)
785 p = (connection_t *)node->data;
786 if(p->status.meta && p->status.active && p!= cl)
787 send_del_subnet(p, subnet);
793 /* New and closed connections notification */
795 int send_add_host(connection_t *cl, connection_t *other)
798 if(!(cl->options & OPTION_INDIRECT))
799 return send_request(cl, "%d %s %lx:%d %lx", ADD_HOST,
800 other->name, other->address, other->port, other->options);
803 int add_host_h(connection_t *cl)
805 connection_t *old, *new, *p;
806 char name[MAX_STRING_SIZE];
809 new = new_connection();
811 if(sscanf(cl->buffer, "%*d "MAX_STRING" %lx:%d %lx", name, &new->address, &new->port, &new->options) != 4)
813 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
817 /* Check if identity is a valid name */
821 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
822 free_connection(new);
826 /* Check if somebody tries to add ourself */
828 if(!strcmp(name, myself->name))
830 syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
832 free_connection(new);
836 /* Fill in more of the new connection structure */
838 new->hostname = hostlookup(htonl(new->address));
840 /* Check if the new host already exists in the connnection list */
842 if((old = lookup_id(name)))
844 if((new->address == old->address) && (new->port == old->port))
846 if(debug_lvl >= DEBUG_CONNECTIONS)
847 syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
848 old->name, old->hostname, name, new->hostname);
849 free_connection(new);
854 if(debug_lvl >= DEBUG_CONNECTIONS)
855 syslog(LOG_NOTICE, _("Removing old entry for %s (%s) in favour of new connection"),
856 old->name, old->hostname);
858 terminate_connection(old);
862 /* Hook it up into the connection */
864 new->name = xstrdup(name);
868 /* Tell the rest about the new host */
870 for(node = connection_tree->head; node; node = node->next)
872 p = (connection_t *)node->data;
873 if(p->status.meta && p->status.active && p!=cl)
874 send_add_host(p, new);
877 /* Fill in rest of connection structure */
880 new->status.active = 1;
881 new->cipher_pkttype = EVP_bf_cbc();
882 new->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
887 int send_del_host(connection_t *cl, connection_t *other)
890 if(!(cl->options & OPTION_INDIRECT))
891 return send_request(cl, "%d %s %lx:%d %lx", DEL_HOST,
892 other->name, other->address, other->port, other->options);
895 int del_host_h(connection_t *cl)
897 char name[MAX_STRING_SIZE];
901 connection_t *old, *p;
904 if(sscanf(cl->buffer, "%*d "MAX_STRING" %lx:%d %lx", name, &address, &port, &options) != 4)
906 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
907 cl->name, cl->hostname);
911 /* Check if identity is a valid name */
915 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
919 /* Check if somebody tries to delete ourself */
921 if(!strcmp(name, myself->name))
923 syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
924 cl->name, cl->hostname);
929 /* Check if the new host already exists in the connnection list */
931 if(!(old = lookup_id(name)))
933 syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
934 name, cl->name, cl->hostname);
938 /* Check if the rest matches */
940 if(address!=old->address || port!=old->port || options!=old->options || cl!=old->nexthop)
942 syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
946 /* Ok, since EVERYTHING seems to check out all right, delete it */
948 old->status.active = 0;
949 terminate_connection(old);
951 /* Tell the rest about the new host */
953 for(node = connection_tree->head; node; node = node->next)
955 p = (connection_t *)node->data;
956 if(p->status.meta && p->status.active && p!=cl)
957 send_del_host(p, old);
963 /* Status and error notification routines */
965 int send_status(connection_t *cl, int statusno, char *statusstring)
969 statusstring = status_text[statusno];
971 return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
974 int status_h(connection_t *cl)
977 char statusstring[MAX_STRING_SIZE];
979 if(sscanf(cl->buffer, "%*d %d "MAX_STRING, &statusno, statusstring) != 2)
981 syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
982 cl->name, cl->hostname);
986 if(debug_lvl >= DEBUG_STATUS)
988 syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
989 cl->name, cl->hostname, status_text[statusno], statusstring);
996 int send_error(connection_t *cl, int err, char *errstring)
1000 errstring = strerror(err);
1001 return send_request(cl, "%d %d %s", ERROR, err, errstring);
1004 int error_h(connection_t *cl)
1007 char errorstring[MAX_STRING_SIZE];
1009 if(sscanf(cl->buffer, "%*d %d "MAX_STRING, &err, errorstring) != 2)
1011 syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
1012 cl->name, cl->hostname);
1016 if(debug_lvl >= DEBUG_ERROR)
1018 syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
1019 cl->name, cl->hostname, strerror(err), errorstring);
1022 terminate_connection(cl);
1027 int send_termreq(connection_t *cl)
1030 return send_request(cl, "%d", TERMREQ);
1033 int termreq_h(connection_t *cl)
1036 terminate_connection(cl);
1041 int send_ping(connection_t *cl)
1044 cl->status.pinged = 1;
1045 cl->last_ping_time = time(NULL);
1047 return send_request(cl, "%d", PING);
1050 int ping_h(connection_t *cl)
1053 return send_pong(cl);
1056 int send_pong(connection_t *cl)
1059 return send_request(cl, "%d", PONG);
1062 int pong_h(connection_t *cl)
1065 cl->status.pinged = 0;
1072 int send_key_changed(connection_t *from, connection_t *cl)
1077 for(node = connection_tree->head; node; node = node->next)
1079 p = (connection_t *)node->data;
1080 if(p != cl && p->status.meta && p->status.active)
1081 if(!(p->options & OPTION_INDIRECT) || from == myself)
1082 send_request(p, "%d %s", KEY_CHANGED, from->name);
1088 int key_changed_h(connection_t *cl)
1090 char from_id[MAX_STRING_SIZE];
1093 if(sscanf(cl->buffer, "%*d "MAX_STRING, from_id) != 1)
1095 syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
1096 cl->name, cl->hostname);
1100 if(!(from = lookup_id(from_id)))
1102 syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
1103 cl->name, cl->hostname, from_id);
1107 from->status.validkey = 0;
1108 from->status.waitingforkey = 0;
1110 send_key_changed(from, cl);
1115 int send_req_key(connection_t *from, connection_t *to)
1118 return send_request(to->nexthop, "%d %s %s", REQ_KEY,
1119 from->name, to->name);
1122 int req_key_h(connection_t *cl)
1124 char from_id[MAX_STRING_SIZE];
1125 char to_id[MAX_STRING_SIZE];
1126 connection_t *from, *to;
1129 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, from_id, to_id) != 2)
1131 syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
1132 cl->name, cl->hostname);
1136 if(!(from = lookup_id(from_id)))
1138 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
1139 cl->name, cl->hostname, from_id);
1143 /* Check if this key request is for us */
1145 if(!strcmp(to_id, myself->name))
1147 bin2hex(myself->cipher_pktkey, pktkey, myself->cipher_pktkeylength);
1148 pktkey[myself->cipher_pktkeylength*2] = '\0';
1149 send_ans_key(myself, from, pktkey);
1153 if(!(to = lookup_id(to_id)))
1155 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
1156 cl->name, cl->hostname, to_id);
1160 if(to->status.validkey) /* Proxy keys */
1162 bin2hex(to->cipher_pktkey, pktkey, to->cipher_pktkeylength);
1163 pktkey[to->cipher_pktkeylength*2] = '\0';
1164 send_ans_key(to, from, pktkey);
1167 send_req_key(from, to);
1174 int send_ans_key(connection_t *from, connection_t *to, char *pktkey)
1177 return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
1178 from->name, to->name, pktkey);
1181 int ans_key_h(connection_t *cl)
1183 char from_id[MAX_STRING_SIZE];
1184 char to_id[MAX_STRING_SIZE];
1185 char pktkey[MAX_STRING_SIZE];
1187 connection_t *from, *to;
1189 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING, from_id, to_id, pktkey) != 3)
1191 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
1192 cl->name, cl->hostname);
1196 if(!(from = lookup_id(from_id)))
1198 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
1199 cl->name, cl->hostname, from_id);
1203 /* Check correctness of packet key */
1205 keylength = strlen(pktkey);
1207 if(keylength != from->cipher_pktkeylength*2)
1209 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key length"),
1210 cl->name, cl->hostname, from->name);
1214 /* Forward it if necessary */
1216 if(strcmp(to_id, myself->name))
1218 if(!(to = lookup_id(to_id)))
1220 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1221 cl->name, cl->hostname, to_id);
1224 send_ans_key(from, to, pktkey);
1227 /* Update our copy of the origin's packet key */
1229 if(from->cipher_pktkey)
1230 free(from->cipher_pktkey);
1232 from->cipher_pktkey = xstrdup(pktkey);
1234 hex2bin(from->cipher_pktkey, from->cipher_pktkey, keylength);
1235 from->cipher_pktkey[keylength] = '\0';
1237 from->status.validkey = 1;
1238 from->status.waitingforkey = 0;
1245 int send_tcppacket(connection_t *cl, vpn_packet_t *packet)
1249 x = send_request(cl->nexthop, "%d %hd", PACKET, packet->len);
1254 return send_meta(cl->nexthop, packet->data, packet->len);
1257 int tcppacket_h(connection_t *cl)
1259 vpn_packet_t packet;
1263 if(sscanf(cl->buffer, "%*d %hd", packet.len) != 1)
1265 syslog(LOG_ERR, _("Got bad PACKET from %s (%s)"), cl->name, cl->hostname);
1276 x = read(cl->meta_socket, p, todo);
1281 syslog(LOG_NOTICE, _("Connection closed by %s (%s)"), cl->name, cl->hostname);
1286 syslog(LOG_ERR, _("Error during reception of PACKET from %s (%s): %m"), cl->name, cl->hostname);
1295 return receive_packet(cl, &packet);
1298 /* Jumptable for the request handlers */
1300 int (*request_handlers[])(connection_t*) = {
1301 id_h, metakey_h, challenge_h, chal_reply_h,
1302 status_h, error_h, termreq_h,
1304 add_host_h, del_host_h,
1305 add_subnet_h, del_subnet_h,
1306 key_changed_h, req_key_h, ans_key_h,
1312 char (*request_name[]) = {
1313 "ID", "METAKEY", "CHALLENGE", "CHAL_REPLY",
1314 "STATUS", "ERROR", "TERMREQ",
1316 "ADD_HOST", "DEL_HOST",
1317 "ADD_SUBNET", "DEL_SUBNET",
1318 "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1322 /* Status strings */
1324 char (*status_text[]) = {
1330 char (*error_text[]) = {