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.52 2000/10/29 22:10:43 guus Exp $
25 #include <sys/types.h>
30 #include <sys/socket.h>
37 #include <netinet/in.h>
39 #include <openssl/sha.h>
40 #include <openssl/rand.h>
41 #include <openssl/evp.h>
52 int check_id(char *id)
56 for (i = 0; i < strlen(id); i++)
57 if(!isalnum(id[i]) && id[i] != '_')
63 /* Generic request routines - takes care of logging and error detection as well */
65 int send_request(conn_list_t *cl, const char *format, ...)
68 char buffer[MAXBUFSIZE];
72 /* Use vsnprintf instead of vasprintf: faster, no memory fragmentation, cleanup is automatic,
73 and there is a limit on the input buffer anyway */
75 va_start(args, format);
76 len = vsnprintf(buffer, MAXBUFSIZE, format, args);
77 request = va_arg(args, int);
80 if(len < 0 || len > MAXBUFSIZE-1)
82 syslog(LOG_ERR, _("Output buffer overflow while sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
88 if(debug_lvl >= DEBUG_PROTOCOL)
89 syslog(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
92 return send_meta(cl, buffer, len);
95 int receive_request(conn_list_t *cl)
99 if(sscanf(cl->buffer, "%d", &request) == 1)
101 if((request < 0) || (request > 255) || (request_handlers[request] == NULL))
103 syslog(LOG_ERR, _("Unknown request from %s (%s)"),
104 cl->name, cl->hostname);
109 if(debug_lvl >= DEBUG_PROTOCOL)
110 syslog(LOG_DEBUG, _("Got %s from %s (%s)"),
111 request_name[request], cl->name, cl->hostname);
114 if((cl->allow_request != ALL) && (cl->allow_request != request))
116 syslog(LOG_ERR, _("Unauthorized request from %s (%s)"), cl->name, cl->hostname);
120 if(request_handlers[request](cl))
121 /* Something went wrong. Probably scriptkiddies. Terminate. */
123 syslog(LOG_ERR, _("Error while processing %s from %s (%s)"),
124 request_name[request], cl->name, cl->hostname);
130 syslog(LOG_ERR, _("Bogus data received from %s (%s)"),
131 cl->name, cl->hostname);
138 /* Connection protocol:
147 ---------------------------------------
148 Any negotations about the meta protocol
149 encryption go here(u).
150 ---------------------------------------
153 ---------------------------------------
159 (E) Encrypted with symmetric cipher.
161 Part of the challenge is directly used to set the symmetric cipher key and the initial vector.
162 Since a man-in-the-middle cannot decrypt the RSA challenges, this means that he cannot get or
163 forge the key for the symmetric cipher.
166 int send_id(conn_list_t *cl)
169 cl->allow_request = CHALLENGE;
171 return send_request(cl, "%d %s %d %lx %hd", ID, myself->name, myself->protocol_version, myself->options, myself->port);
174 int id_h(conn_list_t *cl)
179 if(sscanf(cl->buffer, "%*d %as %d %lx %hd", &cl->name, &cl->protocol_version, &cl->options, &cl->port) != 4)
181 syslog(LOG_ERR, _("Got bad ID from %s"), cl->hostname);
185 /* Check if version matches */
187 if(cl->protocol_version != myself->protocol_version)
189 syslog(LOG_ERR, _("Peer %s (%s) uses incompatible version %d"),
190 cl->name, cl->hostname, cl->protocol_version);
194 /* Check if identity is a valid name */
196 if(check_id(cl->name))
198 syslog(LOG_ERR, _("Peer %s uses invalid identity name"), cl->hostname);
202 /* Load information about peer */
204 if(read_host_config(cl))
206 syslog(LOG_ERR, _("Peer %s had unknown identity (%s)"), cl->hostname, cl->name);
210 /* First check if the host we connected to is already in our
211 connection list. If so, we are probably making a loop, which
215 if(cl->status.outgoing)
217 if((old = lookup_id(cl->name)))
219 if(debug_lvl >= DEBUG_CONNECTIONS)
220 syslog(LOG_NOTICE, _("Uplink %s (%s) is already in our connection list"), cl->name, cl->hostname);
221 cl->status.outgoing = 0;
222 old->status.outgoing = 1;
223 terminate_connection(cl);
228 if((cfg = get_config_val(cl->config, publickey)))
230 cl->rsa_key = RSA_new();
231 BN_hex2bn(&cl->rsa_key->n, cfg->data.ptr);
232 BN_hex2bn(&cl->rsa_key->e, "FFFF");
236 syslog(LOG_ERR, _("No public key known for %s (%s)"), cl->name, cl->hostname);
240 return send_challenge(cl);
243 int send_challenge(conn_list_t *cl)
248 len = RSA_size(cl->rsa_key);
250 /* Allocate buffers for the challenge */
252 buffer = xmalloc(len*2+1);
255 free(cl->hischallenge);
257 cl->hischallenge = xmalloc(len);
259 /* Seed the PRNG with urandom (can't afford to block) */
261 RAND_load_file("/dev/urandom", 1024);
263 /* Copy random data to the buffer */
265 RAND_bytes(cl->hischallenge, len);
267 cl->hischallenge[0] &= 0x7F; /* Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
269 if(debug_lvl >= DEBUG_SCARY_THINGS)
271 bin2hex(cl->hischallenge, buffer, len);
272 buffer[len*2] = '\0';
273 syslog(LOG_DEBUG, _("Generated random challenge (unencrypted): %s"), buffer);
276 /* Encrypt the random data */
278 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 */
280 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
285 /* Convert the encrypted random data to a hexadecimal formatted string */
287 bin2hex(buffer, buffer, len);
288 buffer[len*2] = '\0';
290 /* Send the challenge */
292 cl->allow_request = CHAL_REPLY;
293 x = send_request(cl, "%d %s", CHALLENGE, buffer);
299 int challenge_h(conn_list_t *cl)
304 if(sscanf(cl->buffer, "%*d %as", &buffer) != 1)
306 syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
310 len = RSA_size(myself->rsa_key);
312 /* Check if the length of the challenge is all right */
314 if(strlen(buffer) != len*2)
316 syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
321 /* Allocate buffers for the challenge */
324 cl->mychallenge = xmalloc(len);
326 /* Convert the challenge from hexadecimal back to binary */
328 hex2bin(buffer,buffer,len);
330 /* Decrypt the challenge */
332 if(RSA_private_decrypt(len, buffer, cl->mychallenge, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
334 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
339 if(debug_lvl >= DEBUG_SCARY_THINGS)
341 bin2hex(cl->mychallenge, buffer, len);
342 buffer[len*2] = '\0';
343 syslog(LOG_DEBUG, _("Received random challenge (unencrypted): %s"), buffer);
348 /* Rest is done by send_chal_reply() */
350 return send_chal_reply(cl);
353 int send_chal_reply(conn_list_t *cl)
355 char hash[SHA_DIGEST_LENGTH*2+1];
359 syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
363 /* Calculate the hash from the challenge we received */
365 SHA1(cl->mychallenge, RSA_size(myself->rsa_key), hash);
367 /* Convert the hash to a hexadecimal formatted string */
369 bin2hex(hash,hash,SHA_DIGEST_LENGTH);
370 hash[SHA_DIGEST_LENGTH*2] = '\0';
374 if(cl->status.outgoing)
375 cl->allow_request = ID;
377 cl->allow_request = ACK;
380 return send_request(cl, "%d %s", CHAL_REPLY, hash);
383 int chal_reply_h(conn_list_t *cl)
386 char myhash[SHA_DIGEST_LENGTH];
388 if(sscanf(cl->buffer, "%*d %as", &hishash) != 1)
390 syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
395 /* Check if the length of the hash is all right */
397 if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
399 syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
404 /* Convert the hash to binary format */
406 hex2bin(hishash, hishash, SHA_DIGEST_LENGTH);
408 /* Calculate the hash from the challenge we sent */
410 SHA1(cl->hischallenge, RSA_size(cl->rsa_key), myhash);
412 /* Verify the incoming hash with the calculated hash */
414 if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
416 syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
417 if(debug_lvl >= DEBUG_SCARY_THINGS)
419 bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
420 hishash[SHA_DIGEST_LENGTH*2] = '\0';
421 syslog(LOG_DEBUG, _("Expected challenge reply: %s"), hishash);
430 /* Identity has now been positively verified.
431 If we are accepting this new connection, then send our identity,
432 if we are making this connecting, acknowledge.
435 if(cl->status.outgoing)
441 int send_ack(conn_list_t *cl)
444 if(cl->status.outgoing)
445 cl->allow_request = ACK;
447 return send_request(cl, "%d", ACK);
450 int ack_h(conn_list_t *cl)
452 conn_list_t *old, *p;
455 /* Okay, before we active the connection, we check if there is another entry
456 in the connection list with the same name. If so, it presumably is an
457 old connection that has timed out but we don't know it yet.
460 while((old = lookup_id(cl->name)))
462 if(debug_lvl >= DEBUG_CONNECTIONS)
463 syslog(LOG_NOTICE, _("Removing old entry for %s at %s in favour of new connection from %s"),
464 cl->name, old->hostname, cl->hostname);
466 terminate_connection(old);
469 /* Activate this connection */
471 cl->allow_request = ALL;
472 cl->status.active = 1;
474 cl->cipher_pkttype = EVP_bf_cfb();
475 cl->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
477 if(debug_lvl >= DEBUG_CONNECTIONS)
478 syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname);
481 if(!cl->status.outgoing)
484 /* Send him our subnets */
486 for(s = myself->subnets; s; s = s->next)
487 send_add_subnet(cl, s);
489 /* And send him all the hosts and their subnets we know... */
491 for(p = conn_list; p; p = p->next)
492 if(p != cl && p->status.active)
494 /* Notify others of this connection */
497 send_add_host(p, cl);
499 /* Notify new connection of everything we know */
501 send_add_host(cl, p);
503 for(s = p->subnets; s; s = s->next)
504 send_add_subnet(cl, s);
510 /* Address and subnet information exchange */
512 int send_add_subnet(conn_list_t *cl, subnet_t *subnet)
517 x = send_request(cl, "%d %s %s", ADD_SUBNET,
518 subnet->owner->name, netstr = net2str(subnet));
524 int add_subnet_h(conn_list_t *cl)
528 conn_list_t *owner, *p;
531 if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 2)
533 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
534 free(name); free(subnetstr);
538 /* Check if owner name is a valid */
542 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
543 free(name); free(subnetstr);
547 /* Check if subnet string is valid */
549 if(!(subnet = str2net(subnetstr)))
551 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
552 free(name); free(subnetstr);
558 /* Check if somebody tries to add a subnet of ourself */
560 if(!strcmp(name, myself->name))
562 syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
563 cl->name, cl->hostname);
569 /* Check if the owner of the new subnet is in the connection list */
571 if(!(owner = lookup_id(name)))
573 syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
574 name, cl->name, cl->hostname);
579 /* If everything is correct, add the subnet to the list of the owner */
581 subnet_add(owner, subnet);
585 for(p = conn_list; p; p = p->next)
586 if(p->status.meta && p->status.active && p!= cl)
587 send_add_subnet(p, subnet);
592 int send_del_subnet(conn_list_t *cl, subnet_t *subnet)
597 netstr = net2str(subnet);
598 x = send_request(cl, "%d %s %s", DEL_SUBNET, subnet->owner->name, netstr);
604 int del_subnet_h(conn_list_t *cl)
608 conn_list_t *owner, *p;
611 if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
613 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
614 free(name); free(subnetstr);
618 /* Check if owner name is a valid */
622 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
623 free(name); free(subnetstr);
627 /* Check if subnet string is valid */
629 if(!(subnet = str2net(subnetstr)))
631 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
632 free(name); free(subnetstr);
638 /* Check if somebody tries to add a subnet of ourself */
640 if(!strcmp(name, myself->name))
642 syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
643 cl->name, cl->hostname);
649 /* Check if the owner of the new subnet is in the connection list */
651 if(!(owner = lookup_id(name)))
653 syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
654 name, cl->name, cl->hostname);
659 /* If everything is correct, delete the subnet from the list of the owner */
665 for(p = conn_list; p; p = p->next)
666 if(p->status.meta && p->status.active && p!= cl)
667 send_del_subnet(p, subnet);
672 /* New and closed connections notification */
674 int send_add_host(conn_list_t *cl, conn_list_t *other)
677 return send_request(cl, "%d %s %lx:%d %lx", ADD_HOST,
678 other->name, other->address, other->port, other->options);
681 int add_host_h(conn_list_t *cl)
683 conn_list_t *old, *new;
686 new = new_conn_list();
688 if(sscanf(cl->buffer, "%*d %as %lx:%d %lx", &new->name, &new->address, &new->port, &new->options) != 4)
690 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
694 /* Check if identity is a valid name */
696 if(check_id(new->name))
698 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
703 /* Check if somebody tries to add ourself */
705 if(!strcmp(new->name, myself->name))
707 syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
713 /* Fill in more of the new conn_list structure */
715 new->hostname = hostlookup(htonl(new->address));
717 /* Check if the new host already exists in the connnection list */
719 if((old = lookup_id(new->name)))
721 if((new->address == old->address) && (new->port == old->port))
723 if(debug_lvl >= DEBUG_CONNECTIONS)
724 syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
725 old->name, old->hostname, new->name, new->hostname);
731 if(debug_lvl >= DEBUG_CONNECTIONS)
732 syslog(LOG_NOTICE, _("Removing old entry for %s (%s) in favour of new connection"),
733 old->name, old->hostname);
735 terminate_connection(old);
739 /* Hook it up into the conn_list */
743 /* Tell the rest about the new host */
745 for(p = conn_list; p; p = p->next)
746 if(p->status.meta && p->status.active && p!=cl)
747 send_add_host(p, new);
749 /* Fill in rest of conn_list structure */
752 new->status.active = 1;
758 int send_del_host(conn_list_t *cl, conn_list_t *other)
761 return send_request(cl, "%d %s %lx:%d %lx", DEL_HOST,
762 other->name, other->address, other->port, other->options);
765 int del_host_h(conn_list_t *cl)
771 conn_list_t *old, *p;
773 if(sscanf(cl->buffer, "%*d %as %lx:%d %lx", &name, &address, &port, &options) != 4)
775 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
776 cl->name, cl->hostname);
780 /* Check if identity is a valid name */
784 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
789 /* Check if somebody tries to delete ourself */
791 if(!strcmp(name, myself->name))
793 syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
794 cl->name, cl->hostname);
800 /* Check if the new host already exists in the connnection list */
802 if(!(old = lookup_id(name)))
804 syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
805 name, cl->name, cl->hostname);
810 /* Check if the rest matches */
812 if(address!=old->address || port!=old->port || options!=old->options || cl!=old->nexthop)
814 syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
818 /* Ok, since EVERYTHING seems to check out all right, delete it */
820 old->status.active = 0;
821 terminate_connection(old);
823 /* Tell the rest about the new host */
825 for(p = conn_list; p; p = p->next)
826 if(p->status.meta && p->status.active && p!=cl)
827 send_del_host(p, old);
832 /* Status and error notification routines */
834 int send_status(conn_list_t *cl, int statusno, char *statusstring)
838 statusstring = status_text[statusno];
840 return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
843 int status_h(conn_list_t *cl)
848 if(sscanf(cl->buffer, "%*d %d %as", &statusno, &statusstring) != 2)
850 syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
851 cl->name, cl->hostname);
855 if(debug_lvl >= DEBUG_STATUS)
857 syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
858 cl->name, cl->hostname, status_text[statusno], statusstring);
866 int send_error(conn_list_t *cl, int errno, char *errstring)
870 errstring = strerror(errno);
871 return send_request(cl, "%d %d %s", ERROR, errno, errstring);
874 int error_h(conn_list_t *cl)
879 if(sscanf(cl->buffer, "%*d %d %as", &errno, &errorstring) != 2)
881 syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
882 cl->name, cl->hostname);
886 if(debug_lvl >= DEBUG_ERROR)
888 syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
889 cl->name, cl->hostname, strerror(errno), errorstring);
893 terminate_connection(cl);
898 int send_termreq(conn_list_t *cl)
901 return send_request(cl, "%d", TERMREQ);
904 int termreq_h(conn_list_t *cl)
907 terminate_connection(cl);
912 /* Keepalive routines - FIXME: needs a closer look */
914 int send_ping(conn_list_t *cl)
916 cl->status.pinged = 1;
918 return send_request(cl, "%d", PING);
921 int ping_h(conn_list_t *cl)
924 return send_pong(cl);
927 int send_pong(conn_list_t *cl)
930 return send_request(cl, "%d", PONG);
933 int pong_h(conn_list_t *cl)
936 cl->status.got_pong = 1;
943 int send_key_changed(conn_list_t *from, conn_list_t *cl)
947 for(p = conn_list; p != NULL; p = p->next)
949 if(p!=cl && p->status.meta && p->status.active)
950 send_request(p, "%d %s", KEY_CHANGED,
957 int key_changed_h(conn_list_t *cl)
962 if(sscanf(cl->buffer, "%*d %as", &from_id) != 1)
964 syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
965 cl->name, cl->hostname);
969 if(!(from = lookup_id(from_id)))
971 syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
972 cl->name, cl->hostname, from_id);
979 from->status.validkey = 0;
980 from->status.waitingforkey = 0;
982 send_key_changed(from, cl);
987 int send_req_key(conn_list_t *from, conn_list_t *to)
990 return send_request(to->nexthop, "%d %s %s", REQ_KEY,
991 from->name, to->name);
994 int req_key_h(conn_list_t *cl)
996 char *from_id, *to_id;
997 conn_list_t *from, *to;
1000 if(sscanf(cl->buffer, "%*d %as %as", &from_id, &to_id) != 2)
1002 syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
1003 cl->name, cl->hostname);
1007 if(!(from = lookup_id(from_id)))
1009 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
1010 cl->name, cl->hostname, from_id);
1011 free(from_id); free(to_id);
1015 /* Check if this key request is for us */
1017 if(!strcmp(to_id, myself->name))
1019 bin2hex(myself->cipher_pktkey, pktkey, myself->cipher_pktkeylength);
1020 pktkey[myself->cipher_pktkeylength*2] = '\0';
1021 send_ans_key(myself, from, pktkey);
1025 if(!(to = lookup_id(to_id)))
1027 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
1028 cl->name, cl->hostname, to_id);
1029 free(from_id); free(to_id);
1033 if(to->status.validkey) /* Proxy keys */
1035 bin2hex(to->cipher_pktkey, pktkey, to->cipher_pktkeylength);
1036 pktkey[to->cipher_pktkeylength*2] = '\0';
1037 send_ans_key(to, from, pktkey);
1040 send_req_key(from, to);
1043 free(from_id); free(to_id);
1048 int send_ans_key(conn_list_t *from, conn_list_t *to, char *pktkey)
1051 return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
1052 from->name, to->name, pktkey);
1055 int ans_key_h(conn_list_t *cl)
1057 char *from_id, *to_id, *pktkey;
1059 conn_list_t *from, *to;
1061 if(sscanf(cl->buffer, "%*d %as %as %as", &from_id, &to_id, &pktkey) != 3)
1063 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
1064 cl->name, cl->hostname);
1068 if(!(from = lookup_id(from_id)))
1070 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
1071 cl->name, cl->hostname, from_id);
1072 free(from_id); free(to_id); free(pktkey);
1076 /* Update origin's packet key */
1078 keylength = strlen(pktkey);
1080 if(keylength != from->cipher_pktkeylength*2)
1082 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key length"),
1083 cl->name, cl->hostname, from->name);
1084 free(from_id); free(to_id); free(pktkey);
1088 if(from->cipher_pktkey)
1089 free(from->cipher_pktkey);
1092 hex2bin(pktkey, pktkey, keylength);
1093 pktkey[keylength] = '\0';
1094 from->cipher_pktkey = pktkey;
1096 from->status.validkey = 1;
1097 from->status.waitingforkey = 0;
1099 if(strcmp(to_id, myself->name))
1101 if(!(to = lookup_id(to_id)))
1103 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1104 cl->name, cl->hostname, to_id);
1105 free(from_id); free(to_id);
1108 send_ans_key(from, to, pktkey);
1111 free(from_id); free(to_id);
1116 /* Jumptable for the request handlers */
1118 int (*request_handlers[])(conn_list_t*) = {
1119 id_h, challenge_h, chal_reply_h, ack_h,
1120 status_h, error_h, termreq_h,
1122 add_host_h, del_host_h,
1123 add_subnet_h, del_subnet_h,
1124 key_changed_h, req_key_h, ans_key_h,
1129 char (*request_name[]) = {
1130 "ID", "CHALLENGE", "CHAL_REPLY", "ACK",
1131 "STATUS", "ERROR", "TERMREQ",
1133 "ADD_HOST", "DEL_HOST",
1134 "ADD_SUBNET", "DEL_SUBNET",
1135 "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1138 /* Status strings */
1140 char (*status_text[]) = {
1146 char (*error_text[]) = {