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.50 2000/10/29 09:19:25 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>
51 int check_id(char *id)
55 for (i = 0; i < strlen(id); i++)
56 if(!isalnum(id[i]) && id[i] != '_')
62 /* Generic request routines - takes care of logging and error detection as well */
64 int send_request(conn_list_t *cl, const char *format, ...)
67 char buffer[MAXBUFSIZE];
71 /* Use vsnprintf instead of vasprintf: faster, no memory fragmentation, cleanup is automatic,
72 and there is a limit on the input buffer anyway */
74 va_start(args, format);
75 len = vsnprintf(buffer, MAXBUFSIZE, format, args);
76 request = va_arg(args, int);
79 if(len < 0 || len > MAXBUFSIZE-1)
81 syslog(LOG_ERR, _("Output buffer overflow while sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
87 if(debug_lvl >= DEBUG_PROTOCOL)
88 syslog(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
91 return send_meta(cl, buffer, len);
94 int receive_request(conn_list_t *cl)
98 if(sscanf(cl->buffer, "%d", &request) == 1)
100 if((request < 0) || (request > 255) || (request_handlers[request] == NULL))
102 syslog(LOG_ERR, _("Unknown request from %s (%s)"),
103 cl->name, cl->hostname);
108 if(debug_lvl >= DEBUG_PROTOCOL)
109 syslog(LOG_DEBUG, _("Got %s from %s (%s)"),
110 request_name[request], cl->name, cl->hostname);
113 if((cl->allow_request != ALL) && (cl->allow_request != request))
115 syslog(LOG_ERR, _("Unauthorized request from %s (%s)"), cl->name, cl->hostname);
119 if(request_handlers[request](cl))
120 /* Something went wrong. Probably scriptkiddies. Terminate. */
122 syslog(LOG_ERR, _("Error while processing %s from %s (%s)"),
123 request_name[request], cl->name, cl->hostname);
129 syslog(LOG_ERR, _("Bogus data received from %s (%s)"),
130 cl->name, cl->hostname);
137 /* Connection protocol:
146 ---------------------------------------
147 Any negotations about the meta protocol
148 encryption go here(u).
149 ---------------------------------------
152 ---------------------------------------
158 (E) Encrypted with symmetric cipher.
160 Part of the challenge is directly used to set the symmetric cipher key and the initial vector.
161 Since a man-in-the-middle cannot decrypt the RSA challenges, this means that he cannot get or
162 forge the key for the symmetric cipher.
165 int send_id(conn_list_t *cl)
168 cl->allow_request = CHALLENGE;
170 return send_request(cl, "%d %s %d %lx %hd", ID, myself->name, myself->protocol_version, myself->options, myself->port);
173 int id_h(conn_list_t *cl)
178 if(sscanf(cl->buffer, "%*d %as %d %lx %hd", &cl->name, &cl->protocol_version, &cl->options, &cl->port) != 4)
180 syslog(LOG_ERR, _("Got bad ID from %s"), cl->hostname);
184 /* Check if version matches */
186 if(cl->protocol_version != myself->protocol_version)
188 syslog(LOG_ERR, _("Peer %s (%s) uses incompatible version %d"),
189 cl->name, cl->hostname, cl->protocol_version);
193 /* Check if identity is a valid name */
195 if(check_id(cl->name))
197 syslog(LOG_ERR, _("Peer %s uses invalid identity name"), cl->hostname);
201 /* Load information about peer */
203 if(read_host_config(cl))
205 syslog(LOG_ERR, _("Peer %s had unknown identity (%s)"), cl->hostname, cl->name);
209 /* First check if the host we connected to is already in our
210 connection list. If so, we are probably making a loop, which
214 if(cl->status.outgoing)
216 if((old = lookup_id(cl->name)))
218 if(debug_lvl >= DEBUG_CONNECTIONS)
219 syslog(LOG_NOTICE, _("Uplink %s (%s) is already in our connection list"), cl->name, cl->hostname);
220 cl->status.outgoing = 0;
221 old->status.outgoing = 1;
222 terminate_connection(cl);
227 if((cfg = get_config_val(cl->config, publickey)))
229 cl->rsa_key = RSA_new();
230 BN_hex2bn(&cl->rsa_key->n, cfg->data.ptr);
231 BN_hex2bn(&cl->rsa_key->e, "FFFF");
235 syslog(LOG_ERR, _("No public key known for %s (%s)"), cl->name, cl->hostname);
239 return send_challenge(cl);
242 int send_challenge(conn_list_t *cl)
247 len = RSA_size(cl->rsa_key);
249 /* Allocate buffers for the challenge */
251 buffer = xmalloc(len*2+1);
254 free(cl->hischallenge);
256 cl->hischallenge = xmalloc(len);
258 /* Seed the PRNG with urandom (can't afford to block) */
260 RAND_load_file("/dev/urandom", 1024);
262 /* Copy random data to the buffer */
264 RAND_bytes(cl->hischallenge, len);
266 cl->hischallenge[0] &= 0x7F; /* Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
268 if(debug_lvl >= DEBUG_SCARY_THINGS)
270 bin2hex(cl->hischallenge, buffer, len);
271 buffer[len*2] = '\0';
272 syslog(LOG_DEBUG, _("Generated random challenge (unencrypted): %s"), buffer);
275 /* Encrypt the random data */
277 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 */
279 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
284 /* Convert the encrypted random data to a hexadecimal formatted string */
286 bin2hex(buffer, buffer, len);
287 buffer[len*2] = '\0';
289 /* Send the challenge */
291 cl->allow_request = CHAL_REPLY;
292 x = send_request(cl, "%d %s", CHALLENGE, buffer);
298 int challenge_h(conn_list_t *cl)
303 if(sscanf(cl->buffer, "%*d %as", &buffer) != 1)
305 syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
309 len = RSA_size(myself->rsa_key);
311 /* Check if the length of the challenge is all right */
313 if(strlen(buffer) != len*2)
315 syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
320 /* Allocate buffers for the challenge */
323 cl->mychallenge = xmalloc(len);
325 /* Convert the challenge from hexadecimal back to binary */
327 hex2bin(buffer,buffer,len);
329 /* Decrypt the challenge */
331 if(RSA_private_decrypt(len, buffer, cl->mychallenge, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
333 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
338 if(debug_lvl >= DEBUG_SCARY_THINGS)
340 bin2hex(cl->mychallenge, buffer, len);
341 buffer[len*2] = '\0';
342 syslog(LOG_DEBUG, _("Received random challenge (unencrypted): %s"), buffer);
347 /* Rest is done by send_chal_reply() */
349 return send_chal_reply(cl);
352 int send_chal_reply(conn_list_t *cl)
354 char hash[SHA_DIGEST_LENGTH*2+1];
358 syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
362 /* Calculate the hash from the challenge we received */
364 SHA1(cl->mychallenge, RSA_size(myself->rsa_key), hash);
366 /* Convert the hash to a hexadecimal formatted string */
368 bin2hex(hash,hash,SHA_DIGEST_LENGTH);
369 hash[SHA_DIGEST_LENGTH*2] = '\0';
373 if(cl->status.outgoing)
374 cl->allow_request = ID;
376 cl->allow_request = ACK;
379 return send_request(cl, "%d %s", CHAL_REPLY, hash);
382 int chal_reply_h(conn_list_t *cl)
385 char myhash[SHA_DIGEST_LENGTH];
387 if(sscanf(cl->buffer, "%*d %as", &hishash) != 1)
389 syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
394 /* Check if the length of the hash is all right */
396 if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
398 syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
403 /* Convert the hash to binary format */
405 hex2bin(hishash, hishash, SHA_DIGEST_LENGTH);
407 /* Calculate the hash from the challenge we sent */
409 SHA1(cl->hischallenge, RSA_size(cl->rsa_key), myhash);
411 /* Verify the incoming hash with the calculated hash */
413 if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
415 syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
416 if(debug_lvl >= DEBUG_SCARY_THINGS)
418 bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
419 hishash[SHA_DIGEST_LENGTH*2] = '\0';
420 syslog(LOG_DEBUG, _("Expected challenge reply: %s"), hishash);
429 /* Identity has now been positively verified.
430 If we are accepting this new connection, then send our identity,
431 if we are making this connecting, acknowledge.
434 if(cl->status.outgoing)
440 int send_ack(conn_list_t *cl)
443 if(cl->status.outgoing)
444 cl->allow_request = ACK;
446 return send_request(cl, "%d", ACK);
449 int ack_h(conn_list_t *cl)
451 conn_list_t *old, *p;
454 /* Okay, before we active the connection, we check if there is another entry
455 in the connection list with the same name. If so, it presumably is an
456 old connection that has timed out but we don't know it yet.
459 while((old = lookup_id(cl->name)))
461 if(debug_lvl >= DEBUG_CONNECTIONS)
462 syslog(LOG_NOTICE, _("Removing old entry for %s at %s in favour of new connection from %s"),
463 cl->name, old->hostname, cl->hostname);
465 terminate_connection(old);
468 /* Activate this connection */
470 cl->allow_request = ALL;
471 cl->status.active = 1;
474 if(debug_lvl >= DEBUG_CONNECTIONS)
475 syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname);
478 if(!cl->status.outgoing)
481 /* Send him our subnets */
483 for(s = myself->subnets; s; s = s->next)
484 send_add_subnet(cl, s);
486 /* And send him all the hosts and their subnets we know... */
488 for(p = conn_list; p; p = p->next)
489 if(p != cl && p->status.active)
491 /* Notify others of this connection */
494 send_add_host(p, cl);
496 /* Notify new connection of everything we know */
498 send_add_host(cl, p);
500 for(s = p->subnets; s; s = s->next)
501 send_add_subnet(cl, s);
507 /* Address and subnet information exchange */
509 int send_add_subnet(conn_list_t *cl, subnet_t *subnet)
514 x = send_request(cl, "%d %s %s", ADD_SUBNET,
515 subnet->owner->name, netstr = net2str(subnet));
521 int add_subnet_h(conn_list_t *cl)
525 conn_list_t *owner, *p;
528 if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 2)
530 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
531 free(name); free(subnetstr);
535 /* Check if owner name is a valid */
539 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
540 free(name); free(subnetstr);
544 /* Check if subnet string is valid */
546 if(!(subnet = str2net(subnetstr)))
548 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
549 free(name); free(subnetstr);
555 /* Check if somebody tries to add a subnet of ourself */
557 if(!strcmp(name, myself->name))
559 syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
560 cl->name, cl->hostname);
566 /* Check if the owner of the new subnet is in the connection list */
568 if(!(owner = lookup_id(name)))
570 syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
571 name, cl->name, cl->hostname);
576 /* If everything is correct, add the subnet to the list of the owner */
578 subnet_add(owner, subnet);
582 for(p = conn_list; p; p = p->next)
583 if(p->status.meta && p->status.active && p!= cl)
584 send_add_subnet(p, subnet);
589 int send_del_subnet(conn_list_t *cl, subnet_t *subnet)
594 netstr = net2str(subnet);
595 x = send_request(cl, "%d %s %s", DEL_SUBNET, subnet->owner->name, netstr);
601 int del_subnet_h(conn_list_t *cl)
605 conn_list_t *owner, *p;
608 if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
610 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
611 free(name); free(subnetstr);
615 /* Check if owner name is a valid */
619 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
620 free(name); free(subnetstr);
624 /* Check if subnet string is valid */
626 if(!(subnet = str2net(subnetstr)))
628 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
629 free(name); free(subnetstr);
635 /* Check if somebody tries to add a subnet of ourself */
637 if(!strcmp(name, myself->name))
639 syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
640 cl->name, cl->hostname);
646 /* Check if the owner of the new subnet is in the connection list */
648 if(!(owner = lookup_id(name)))
650 syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
651 name, cl->name, cl->hostname);
656 /* If everything is correct, delete the subnet from the list of the owner */
662 for(p = conn_list; p; p = p->next)
663 if(p->status.meta && p->status.active && p!= cl)
664 send_del_subnet(p, subnet);
669 /* New and closed connections notification */
671 int send_add_host(conn_list_t *cl, conn_list_t *other)
674 return send_request(cl, "%d %s %lx:%d %lx", ADD_HOST,
675 other->name, other->address, other->port, other->options);
678 int add_host_h(conn_list_t *cl)
680 conn_list_t *old, *new;
683 new = new_conn_list();
685 if(sscanf(cl->buffer, "%*d %as %lx:%d %lx", &new->name, &new->address, &new->port, &new->options) != 4)
687 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
691 /* Check if identity is a valid name */
693 if(check_id(new->name))
695 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
700 /* Check if somebody tries to add ourself */
702 if(!strcmp(new->name, myself->name))
704 syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
710 /* Fill in more of the new conn_list structure */
712 new->hostname = hostlookup(htonl(new->address));
714 /* Check if the new host already exists in the connnection list */
716 if((old = lookup_id(new->name)))
718 if((new->address == old->address) && (new->port == old->port))
720 if(debug_lvl >= DEBUG_CONNECTIONS)
721 syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
722 old->name, old->hostname, new->name, new->hostname);
728 if(debug_lvl >= DEBUG_CONNECTIONS)
729 syslog(LOG_NOTICE, _("Removing old entry for %s (%s) in favour of new connection"),
730 old->name, old->hostname);
732 terminate_connection(old);
736 /* Hook it up into the conn_list */
740 /* Tell the rest about the new host */
742 for(p = conn_list; p; p = p->next)
743 if(p->status.meta && p->status.active && p!=cl)
744 send_add_host(p, new);
746 /* Fill in rest of conn_list structure */
749 new->status.active = 1;
755 int send_del_host(conn_list_t *cl, conn_list_t *other)
758 return send_request(cl, "%d %s %lx:%d %lx", DEL_HOST,
759 other->name, other->address, other->port, other->options);
762 int del_host_h(conn_list_t *cl)
768 conn_list_t *old, *p;
770 if(sscanf(cl->buffer, "%*d %as %lx:%d %lx", &name, &address, &port, &options) != 4)
772 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
773 cl->name, cl->hostname);
777 /* Check if identity is a valid name */
781 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
786 /* Check if somebody tries to delete ourself */
788 if(!strcmp(name, myself->name))
790 syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
791 cl->name, cl->hostname);
797 /* Check if the new host already exists in the connnection list */
799 if(!(old = lookup_id(name)))
801 syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
802 name, cl->name, cl->hostname);
807 /* Check if the rest matches */
809 if(address!=old->address || port!=old->port || options!=old->options || cl!=old->nexthop)
811 syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
815 /* Ok, since EVERYTHING seems to check out all right, delete it */
817 old->status.active = 0;
818 terminate_connection(old);
820 /* Tell the rest about the new host */
822 for(p = conn_list; p; p = p->next)
823 if(p->status.meta && p->status.active && p!=cl)
824 send_del_host(p, old);
829 /* Status and error notification routines */
831 int send_status(conn_list_t *cl, int statusno, char *statusstring)
835 statusstring = status_text[statusno];
837 return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
840 int status_h(conn_list_t *cl)
845 if(sscanf(cl->buffer, "%*d %d %as", &statusno, &statusstring) != 2)
847 syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
848 cl->name, cl->hostname);
852 if(debug_lvl >= DEBUG_STATUS)
854 syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
855 cl->name, cl->hostname, status_text[statusno], statusstring);
863 int send_error(conn_list_t *cl, int errno, char *errstring)
867 errstring = strerror(errno);
868 return send_request(cl, "%d %d %s", ERROR, errno, errstring);
871 int error_h(conn_list_t *cl)
876 if(sscanf(cl->buffer, "%*d %d %as", &errno, &errorstring) != 2)
878 syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
879 cl->name, cl->hostname);
883 if(debug_lvl >= DEBUG_ERROR)
885 syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
886 cl->name, cl->hostname, strerror(errno), errorstring);
890 terminate_connection(cl);
895 int send_termreq(conn_list_t *cl)
898 return send_request(cl, "%d", TERMREQ);
901 int termreq_h(conn_list_t *cl)
904 terminate_connection(cl);
909 /* Keepalive routines - FIXME: needs a closer look */
911 int send_ping(conn_list_t *cl)
913 cl->status.pinged = 1;
915 return send_request(cl, "%d", PING);
918 int ping_h(conn_list_t *cl)
921 return send_pong(cl);
924 int send_pong(conn_list_t *cl)
927 return send_request(cl, "%d", PONG);
930 int pong_h(conn_list_t *cl)
933 cl->status.got_pong = 1;
940 int send_key_changed(conn_list_t *from, conn_list_t *cl)
944 for(p = conn_list; p != NULL; p = p->next)
946 if(p!=cl && p->status.meta && p->status.active)
947 send_request(p, "%d %s", KEY_CHANGED,
954 int key_changed_h(conn_list_t *cl)
959 if(sscanf(cl->buffer, "%*d %as", &from_id) != 1)
961 syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
962 cl->name, cl->hostname);
966 if(!(from = lookup_id(from_id)))
968 syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
969 cl->name, cl->hostname, from_id);
976 from->status.validkey = 0;
977 from->status.waitingforkey = 0;
979 send_key_changed(from, cl);
984 int send_req_key(conn_list_t *from, conn_list_t *to)
987 return send_request(to->nexthop, "%d %s %s", REQ_KEY,
988 from->name, to->name);
991 int req_key_h(conn_list_t *cl)
993 char *from_id, *to_id;
994 conn_list_t *from, *to;
996 if(sscanf(cl->buffer, "%*d %as %as", &from_id, &to_id) != 2)
998 syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
999 cl->name, cl->hostname);
1003 if(!(from = lookup_id(from_id)))
1005 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
1006 cl->name, cl->hostname, from_id);
1007 free(from_id); free(to_id);
1011 /* Check if this key request is for us */
1013 if(!strcmp(to_id, myself->name))
1015 send_ans_key(myself, from, myself->cipher_pktkey);
1019 if(!(to = lookup_id(to_id)))
1021 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
1022 cl->name, cl->hostname, to_id);
1023 free(from_id); free(to_id);
1026 send_req_key(from, to);
1029 free(from_id); free(to_id);
1034 int send_ans_key(conn_list_t *from, conn_list_t *to, char *pktkey)
1037 return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
1038 from->name, to->name, pktkey);
1041 int ans_key_h(conn_list_t *cl)
1043 char *from_id, *to_id, *pktkey;
1045 conn_list_t *from, *to;
1047 if(sscanf(cl->buffer, "%*d %as %as %as", &from_id, &to_id, &pktkey) != 3)
1049 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
1050 cl->name, cl->hostname);
1054 if(!(from = lookup_id(from_id)))
1056 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
1057 cl->name, cl->hostname, from_id);
1058 free(from_id); free(to_id); free(pktkey);
1062 /* Check if this key request is for us */
1064 if(!strcmp(to_id, myself->name))
1066 /* It is for us, convert it to binary and set the key with it. */
1068 keylength = strlen(pktkey);
1070 if((keylength%2)!=0 || (keylength <= 0))
1072 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key"),
1073 cl->name, cl->hostname, from->name);
1074 free(from_id); free(to_id); free(pktkey);
1078 if(from->cipher_pktkey)
1079 free(from->cipher_pktkey);
1082 hex2bin(pktkey, pktkey, keylength);
1083 pktkey[keylength] = '\0';
1084 from->cipher_pktkey = pktkey;
1086 from->status.validkey = 1;
1087 from->status.waitingforkey = 0;
1091 if(!(to = lookup_id(to_id)))
1093 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1094 cl->name, cl->hostname, to_id);
1095 free(from_id); free(to_id); free(pktkey);
1098 send_ans_key(from, to, pktkey);
1101 free(from_id); free(to_id); free(pktkey);
1106 /* Jumptable for the request handlers */
1108 int (*request_handlers[])(conn_list_t*) = {
1109 id_h, challenge_h, chal_reply_h, ack_h,
1110 status_h, error_h, termreq_h,
1112 add_host_h, del_host_h,
1113 add_subnet_h, del_subnet_h,
1114 key_changed_h, req_key_h, ans_key_h,
1119 char (*request_name[]) = {
1120 "ID", "CHALLENGE", "CHAL_REPLY", "ACK",
1121 "STATUS", "ERROR", "TERMREQ",
1123 "ADD_HOST", "DEL_HOST",
1124 "ADD_SUBNET", "DEL_SUBNET",
1125 "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1128 /* Status strings */
1130 char (*status_text[]) = {
1136 char (*error_text[]) = {