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.83 2001/02/27 16:37:28 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 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);
328 /* And send him all the hosts and their subnets we know... */
330 for(node = connection_tree->head; node; node = node->next)
332 p = (connection_t *)node->data;
334 if(p != cl && p->status.active)
336 /* Notify others of this connection */
339 send_add_host(p, cl);
341 /* Notify new connection of everything we know */
343 send_add_host(cl, p);
345 for(node2 = p->subnet_tree->head; node2; node2 = node2->next)
347 subnet = (subnet_t *)node2->data;
348 send_add_subnet(cl, subnet);
356 int send_challenge(connection_t *cl)
361 /* CHECKME: what is most reasonable value for len? */
363 len = RSA_size(cl->rsa_key);
365 /* Allocate buffers for the challenge */
367 buffer = xmalloc(len*2+1);
370 free(cl->hischallenge);
372 cl->hischallenge = xmalloc(len);
374 /* Copy random data to the buffer */
376 RAND_bytes(cl->hischallenge, len);
381 bin2hex(cl->hischallenge, buffer, len);
382 buffer[len*2] = '\0';
385 /* Send the challenge */
387 x = send_request(cl, "%d %s", CHALLENGE, buffer);
393 int challenge_h(connection_t *cl)
395 char buffer[MAX_STRING_SIZE];
398 if(sscanf(cl->buffer, "%*d "MAX_STRING, buffer) != 1)
400 syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
404 len = RSA_size(myself->rsa_key);
406 /* Check if the length of the challenge is all right */
408 if(strlen(buffer) != len*2)
410 syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
414 /* Allocate buffers for the challenge */
417 cl->mychallenge = xmalloc(len);
419 /* Convert the challenge from hexadecimal back to binary */
421 hex2bin(buffer,cl->mychallenge,len);
423 cl->allow_request = CHAL_REPLY;
425 /* Rest is done by send_chal_reply() */
427 return send_chal_reply(cl);
430 int send_chal_reply(connection_t *cl)
432 char hash[SHA_DIGEST_LENGTH*2+1];
436 syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
440 /* Calculate the hash from the challenge we received */
442 SHA1(cl->mychallenge, RSA_size(myself->rsa_key), hash);
444 /* Convert the hash to a hexadecimal formatted string */
446 bin2hex(hash,hash,SHA_DIGEST_LENGTH);
447 hash[SHA_DIGEST_LENGTH*2] = '\0';
452 return send_request(cl, "%d %s", CHAL_REPLY, hash);
455 int chal_reply_h(connection_t *cl)
457 char hishash[MAX_STRING_SIZE];
458 char myhash[SHA_DIGEST_LENGTH];
460 if(sscanf(cl->buffer, "%*d "MAX_STRING, hishash) != 1)
462 syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
466 /* Check if the length of the hash is all right */
468 if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
470 syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
474 /* Convert the hash to binary format */
476 hex2bin(hishash, hishash, SHA_DIGEST_LENGTH);
478 /* Calculate the hash from the challenge we sent */
480 SHA1(cl->hischallenge, RSA_size(cl->rsa_key), myhash);
482 /* Verify the incoming hash with the calculated hash */
484 if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
486 syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
487 if(debug_lvl >= DEBUG_SCARY_THINGS)
489 bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
490 hishash[SHA_DIGEST_LENGTH*2] = '\0';
491 syslog(LOG_DEBUG, _("Expected challenge reply: %s"), hishash);
496 /* Identity has now been positively verified.
497 ack_h() handles the rest from now on.
503 int send_metakey(connection_t *cl)
508 len = RSA_size(cl->rsa_key);
510 /* Allocate buffers for the meta key */
512 buffer = xmalloc(len*2+1);
514 if(!cl->cipher_outkey)
515 cl->cipher_outkey = xmalloc(len);
517 if(!cl->cipher_outctx)
518 cl->cipher_outctx = xmalloc(sizeof(*cl->cipher_outctx));
520 /* Copy random data to the buffer */
522 RAND_bytes(cl->cipher_outkey, len);
524 cl->cipher_outkey[0] &= 0x0F; /* Make sure that the random data is smaller than the modulus of the RSA key */
526 if(debug_lvl >= DEBUG_SCARY_THINGS)
528 bin2hex(cl->cipher_outkey, buffer, len);
529 buffer[len*2] = '\0';
530 syslog(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"), buffer);
533 /* Encrypt the random data */
535 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 */
537 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
542 /* Convert the encrypted random data to a hexadecimal formatted string */
544 bin2hex(buffer, buffer, len);
545 buffer[len*2] = '\0';
547 /* Send the meta key */
549 x = send_request(cl, "%d %s", METAKEY, buffer);
552 /* Further outgoing requests are encrypted with the key we just generated */
554 EVP_EncryptInit(cl->cipher_outctx, EVP_bf_cfb(),
555 cl->cipher_outkey + len - EVP_bf_cfb()->key_len,
556 cl->cipher_outkey + len - EVP_bf_cfb()->key_len - EVP_bf_cfb()->iv_len);
558 cl->status.encryptout = 1;
563 int metakey_h(connection_t *cl)
565 char buffer[MAX_STRING_SIZE];
568 if(sscanf(cl->buffer, "%*d "MAX_STRING, buffer) != 1)
570 syslog(LOG_ERR, _("Got bad METAKEY from %s (%s)"), cl->name, cl->hostname);
574 len = RSA_size(myself->rsa_key);
576 /* Check if the length of the meta key is all right */
578 if(strlen(buffer) != len*2)
580 syslog(LOG_ERR, _("Intruder: wrong meta key length from %s (%s)"), cl->name, cl->hostname);
584 /* Allocate buffers for the meta key */
586 if(!cl->cipher_inkey)
587 cl->cipher_inkey = xmalloc(len);
589 if(!cl->cipher_inctx)
590 cl->cipher_inctx = xmalloc(sizeof(*cl->cipher_inctx));
592 /* Convert the challenge from hexadecimal back to binary */
594 hex2bin(buffer,buffer,len);
596 /* Decrypt the meta key */
598 if(RSA_private_decrypt(len, buffer, cl->cipher_inkey, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
600 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
604 if(debug_lvl >= DEBUG_SCARY_THINGS)
606 bin2hex(cl->cipher_inkey, buffer, len);
607 buffer[len*2] = '\0';
608 syslog(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), buffer);
611 /* All incoming requests will now be encrypted. */
613 EVP_DecryptInit(cl->cipher_inctx, EVP_bf_cfb(),
614 cl->cipher_inkey + len - EVP_bf_cfb()->key_len,
615 cl->cipher_inkey + len - EVP_bf_cfb()->key_len - EVP_bf_cfb()->iv_len);
617 cl->status.decryptin = 1;
619 cl->allow_request = CHALLENGE;
621 return send_challenge(cl);
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);
805 int add_host_h(connection_t *cl)
807 connection_t *old, *new, *p;
808 char name[MAX_STRING_SIZE];
811 new = new_connection();
813 if(sscanf(cl->buffer, "%*d "MAX_STRING" %lx:%hd %lx", name, &new->address, &new->port, &new->options) != 4)
815 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
819 /* Check if identity is a valid name */
823 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
824 free_connection(new);
828 /* Check if somebody tries to add ourself */
830 if(!strcmp(name, myself->name))
832 syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
834 free_connection(new);
838 /* Fill in more of the new connection structure */
840 new->hostname = hostlookup(htonl(new->address));
842 /* Check if the new host already exists in the connnection list */
844 if((old = lookup_id(name)))
846 if((new->address == old->address) && (new->port == old->port))
848 if(debug_lvl >= DEBUG_CONNECTIONS)
849 syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
850 old->name, old->hostname, name, new->hostname);
851 free_connection(new);
856 if(debug_lvl >= DEBUG_CONNECTIONS)
857 syslog(LOG_NOTICE, _("Removing old entry for %s (%s) in favour of new connection"),
858 old->name, old->hostname);
860 terminate_connection(old);
864 /* Hook it up into the connection */
866 new->name = xstrdup(name);
870 /* Tell the rest about the new host */
872 for(node = connection_tree->head; node; node = node->next)
874 p = (connection_t *)node->data;
875 if(p->status.meta && p->status.active && p!=cl)
876 send_add_host(p, new);
879 /* Fill in rest of connection structure */
882 new->status.active = 1;
883 new->cipher_pkttype = EVP_bf_cbc();
884 new->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
889 int send_del_host(connection_t *cl, connection_t *other)
892 if(!(cl->options & OPTION_INDIRECT))
893 return send_request(cl, "%d %s %lx:%d %lx", DEL_HOST,
894 other->name, other->address, other->port, other->options);
899 int del_host_h(connection_t *cl)
901 char name[MAX_STRING_SIZE];
905 connection_t *old, *p;
908 if(sscanf(cl->buffer, "%*d "MAX_STRING" %lx:%hd %lx", name, &address, &port, &options) != 4)
910 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
911 cl->name, cl->hostname);
915 /* Check if identity is a valid name */
919 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
923 /* Check if somebody tries to delete ourself */
925 if(!strcmp(name, myself->name))
927 syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
928 cl->name, cl->hostname);
933 /* Check if the new host already exists in the connnection list */
935 if(!(old = lookup_id(name)))
937 syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
938 name, cl->name, cl->hostname);
942 /* Check if the rest matches */
944 if(address!=old->address || port!=old->port || options!=old->options || cl!=old->nexthop)
946 syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
950 /* Ok, since EVERYTHING seems to check out all right, delete it */
952 old->status.active = 0;
953 terminate_connection(old);
955 /* Tell the rest about the new host */
957 for(node = connection_tree->head; node; node = node->next)
959 p = (connection_t *)node->data;
960 if(p->status.meta && p->status.active && p!=cl)
961 send_del_host(p, old);
967 /* Status and error notification routines */
969 int send_status(connection_t *cl, int statusno, char *statusstring)
973 statusstring = status_text[statusno];
975 return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
978 int status_h(connection_t *cl)
981 char statusstring[MAX_STRING_SIZE];
983 if(sscanf(cl->buffer, "%*d %d "MAX_STRING, &statusno, statusstring) != 2)
985 syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
986 cl->name, cl->hostname);
990 if(debug_lvl >= DEBUG_STATUS)
992 syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
993 cl->name, cl->hostname, status_text[statusno], statusstring);
1000 int send_error(connection_t *cl, int err, char *errstring)
1004 errstring = strerror(err);
1005 return send_request(cl, "%d %d %s", ERROR, err, errstring);
1008 int error_h(connection_t *cl)
1011 char errorstring[MAX_STRING_SIZE];
1013 if(sscanf(cl->buffer, "%*d %d "MAX_STRING, &err, errorstring) != 2)
1015 syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
1016 cl->name, cl->hostname);
1020 if(debug_lvl >= DEBUG_ERROR)
1022 syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
1023 cl->name, cl->hostname, strerror(err), errorstring);
1026 terminate_connection(cl);
1031 int send_termreq(connection_t *cl)
1034 return send_request(cl, "%d", TERMREQ);
1037 int termreq_h(connection_t *cl)
1040 terminate_connection(cl);
1045 int send_ping(connection_t *cl)
1048 cl->status.pinged = 1;
1049 cl->last_ping_time = time(NULL);
1051 return send_request(cl, "%d", PING);
1054 int ping_h(connection_t *cl)
1057 return send_pong(cl);
1060 int send_pong(connection_t *cl)
1063 return send_request(cl, "%d", PONG);
1066 int pong_h(connection_t *cl)
1069 cl->status.pinged = 0;
1076 int send_key_changed(connection_t *from, connection_t *cl)
1081 for(node = connection_tree->head; node; node = node->next)
1083 p = (connection_t *)node->data;
1084 if(p != cl && p->status.meta && p->status.active)
1085 if(!(p->options & OPTION_INDIRECT) || from == myself)
1086 send_request(p, "%d %s", KEY_CHANGED, from->name);
1092 int key_changed_h(connection_t *cl)
1094 char from_id[MAX_STRING_SIZE];
1097 if(sscanf(cl->buffer, "%*d "MAX_STRING, from_id) != 1)
1099 syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
1100 cl->name, cl->hostname);
1104 if(!(from = lookup_id(from_id)))
1106 syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
1107 cl->name, cl->hostname, from_id);
1111 from->status.validkey = 0;
1112 from->status.waitingforkey = 0;
1114 send_key_changed(from, cl);
1119 int send_req_key(connection_t *from, connection_t *to)
1122 return send_request(to->nexthop, "%d %s %s", REQ_KEY,
1123 from->name, to->name);
1126 int req_key_h(connection_t *cl)
1128 char from_id[MAX_STRING_SIZE];
1129 char to_id[MAX_STRING_SIZE];
1130 connection_t *from, *to;
1133 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING, from_id, to_id) != 2)
1135 syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
1136 cl->name, cl->hostname);
1140 if(!(from = lookup_id(from_id)))
1142 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
1143 cl->name, cl->hostname, from_id);
1147 /* Check if this key request is for us */
1149 if(!strcmp(to_id, myself->name))
1151 bin2hex(myself->cipher_pktkey, pktkey, myself->cipher_pktkeylength);
1152 pktkey[myself->cipher_pktkeylength*2] = '\0';
1153 send_ans_key(myself, from, pktkey);
1157 if(!(to = lookup_id(to_id)))
1159 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
1160 cl->name, cl->hostname, to_id);
1164 if(to->status.validkey) /* Proxy keys */
1166 bin2hex(to->cipher_pktkey, pktkey, to->cipher_pktkeylength);
1167 pktkey[to->cipher_pktkeylength*2] = '\0';
1168 send_ans_key(to, from, pktkey);
1171 send_req_key(from, to);
1178 int send_ans_key(connection_t *from, connection_t *to, char *pktkey)
1181 return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
1182 from->name, to->name, pktkey);
1185 int ans_key_h(connection_t *cl)
1187 char from_id[MAX_STRING_SIZE];
1188 char to_id[MAX_STRING_SIZE];
1189 char pktkey[MAX_STRING_SIZE];
1191 connection_t *from, *to;
1193 if(sscanf(cl->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING, from_id, to_id, pktkey) != 3)
1195 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
1196 cl->name, cl->hostname);
1200 if(!(from = lookup_id(from_id)))
1202 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
1203 cl->name, cl->hostname, from_id);
1207 /* Check correctness of packet key */
1209 keylength = strlen(pktkey);
1211 if(keylength != from->cipher_pktkeylength*2)
1213 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key length"),
1214 cl->name, cl->hostname, from->name);
1218 /* Forward it if necessary */
1220 if(strcmp(to_id, myself->name))
1222 if(!(to = lookup_id(to_id)))
1224 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1225 cl->name, cl->hostname, to_id);
1228 send_ans_key(from, to, pktkey);
1231 /* Update our copy of the origin's packet key */
1233 if(from->cipher_pktkey)
1234 free(from->cipher_pktkey);
1236 from->cipher_pktkey = xstrdup(pktkey);
1238 hex2bin(from->cipher_pktkey, from->cipher_pktkey, keylength);
1239 from->cipher_pktkey[keylength] = '\0';
1241 from->status.validkey = 1;
1242 from->status.waitingforkey = 0;
1249 int send_tcppacket(connection_t *cl, vpn_packet_t *packet)
1253 x = send_request(cl->nexthop, "%d %hd", PACKET, packet->len);
1258 return send_meta(cl->nexthop, packet->data, packet->len);
1261 int tcppacket_h(connection_t *cl)
1263 vpn_packet_t packet;
1267 if(sscanf(cl->buffer, "%*d %hd", packet.len) != 1)
1269 syslog(LOG_ERR, _("Got bad PACKET from %s (%s)"), cl->name, cl->hostname);
1280 x = read(cl->meta_socket, p, todo);
1285 syslog(LOG_NOTICE, _("Connection closed by %s (%s)"), cl->name, cl->hostname);
1290 syslog(LOG_ERR, _("Error during reception of PACKET from %s (%s): %m"), cl->name, cl->hostname);
1299 return receive_packet(cl, &packet);
1302 /* Jumptable for the request handlers */
1304 int (*request_handlers[])(connection_t*) = {
1305 id_h, metakey_h, challenge_h, chal_reply_h,
1306 status_h, error_h, termreq_h,
1308 add_host_h, del_host_h,
1309 add_subnet_h, del_subnet_h,
1310 key_changed_h, req_key_h, ans_key_h,
1316 char (*request_name[]) = {
1317 "ID", "METAKEY", "CHALLENGE", "CHAL_REPLY",
1318 "STATUS", "ERROR", "TERMREQ",
1320 "ADD_HOST", "DEL_HOST",
1321 "ADD_SUBNET", "DEL_SUBNET",
1322 "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1326 /* Status strings */
1328 char (*status_text[]) = {
1334 char (*error_text[]) = {