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.49 2000/10/29 01:08:09 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>
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;
475 if(debug_lvl >= DEBUG_CONNECTIONS)
476 syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname);
479 if(!cl->status.outgoing)
482 /* Send him our subnets */
484 for(s = myself->subnets; s; s = s->next)
485 send_add_subnet(cl, s);
487 /* And send him all the hosts and their subnets we know... */
489 for(p = conn_list; p; p = p->next)
490 if(p != cl && p->status.active)
492 /* Notify others of this connection */
495 send_add_host(p, cl);
497 /* Notify new connection of everything we know */
499 send_add_host(cl, p);
501 for(s = p->subnets; s; s = s->next)
502 send_add_subnet(cl, s);
508 /* Address and subnet information exchange */
510 int send_add_subnet(conn_list_t *cl, subnet_t *subnet)
515 x = send_request(cl, "%d %s %s", ADD_SUBNET,
516 subnet->owner->name, netstr = net2str(subnet));
522 int add_subnet_h(conn_list_t *cl)
526 conn_list_t *owner, *p;
529 if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 2)
531 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
532 free(name); free(subnetstr);
536 /* Check if owner name is a valid */
540 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
541 free(name); free(subnetstr);
545 /* Check if subnet string is valid */
547 if(!(subnet = str2net(subnetstr)))
549 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
550 free(name); free(subnetstr);
556 /* Check if somebody tries to add a subnet of ourself */
558 if(!strcmp(name, myself->name))
560 syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
561 cl->name, cl->hostname);
567 /* Check if the owner of the new subnet is in the connection list */
569 if(!(owner = lookup_id(name)))
571 syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
572 name, cl->name, cl->hostname);
577 /* If everything is correct, add the subnet to the list of the owner */
579 subnet_add(owner, subnet);
583 for(p = conn_list; p; p = p->next)
584 if(p->status.meta && p->status.active && p!= cl)
585 send_add_subnet(p, subnet);
590 int send_del_subnet(conn_list_t *cl, subnet_t *subnet)
595 netstr = net2str(subnet);
596 x = send_request(cl, "%d %s %s", DEL_SUBNET, subnet->owner->name, netstr);
602 int del_subnet_h(conn_list_t *cl)
606 conn_list_t *owner, *p;
609 if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
611 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
612 free(name); free(subnetstr);
616 /* Check if owner name is a valid */
620 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
621 free(name); free(subnetstr);
625 /* Check if subnet string is valid */
627 if(!(subnet = str2net(subnetstr)))
629 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
630 free(name); free(subnetstr);
636 /* Check if somebody tries to add a subnet of ourself */
638 if(!strcmp(name, myself->name))
640 syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
641 cl->name, cl->hostname);
647 /* Check if the owner of the new subnet is in the connection list */
649 if(!(owner = lookup_id(name)))
651 syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
652 name, cl->name, cl->hostname);
657 /* If everything is correct, delete the subnet from the list of the owner */
663 for(p = conn_list; p; p = p->next)
664 if(p->status.meta && p->status.active && p!= cl)
665 send_del_subnet(p, subnet);
670 /* New and closed connections notification */
672 int send_add_host(conn_list_t *cl, conn_list_t *other)
675 return send_request(cl, "%d %s %lx:%d %lx", ADD_HOST,
676 other->name, other->address, other->port, other->options);
679 int add_host_h(conn_list_t *cl)
681 conn_list_t *old, *new;
684 new = new_conn_list();
686 if(sscanf(cl->buffer, "%*d %as %lx:%d %lx", &new->name, &new->address, &new->port, &new->options) != 4)
688 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
692 /* Check if identity is a valid name */
694 if(check_id(new->name))
696 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
701 /* Check if somebody tries to add ourself */
703 if(!strcmp(new->name, myself->name))
705 syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
711 /* Fill in more of the new conn_list structure */
713 new->hostname = hostlookup(htonl(new->address));
715 /* Check if the new host already exists in the connnection list */
717 if((old = lookup_id(new->name)))
719 if((new->address == old->address) && (new->port == old->port))
721 if(debug_lvl >= DEBUG_CONNECTIONS)
722 syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
723 old->name, old->hostname, new->name, new->hostname);
729 if(debug_lvl >= DEBUG_CONNECTIONS)
730 syslog(LOG_NOTICE, _("Removing old entry for %s (%s) in favour of new connection"),
731 old->name, old->hostname);
733 terminate_connection(old);
737 /* Hook it up into the conn_list */
741 /* Tell the rest about the new host */
743 for(p = conn_list; p; p = p->next)
744 if(p->status.meta && p->status.active && p!=cl)
745 send_add_host(p, new);
747 /* Fill in rest of conn_list structure */
750 new->status.active = 1;
756 int send_del_host(conn_list_t *cl, conn_list_t *other)
759 return send_request(cl, "%d %s %lx:%d %lx", DEL_HOST,
760 other->name, other->address, other->port, other->options);
763 int del_host_h(conn_list_t *cl)
769 conn_list_t *old, *p;
771 if(sscanf(cl->buffer, "%*d %as %lx:%d %lx", &name, &address, &port, &options) != 4)
773 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
774 cl->name, cl->hostname);
778 /* Check if identity is a valid name */
782 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
787 /* Check if somebody tries to delete ourself */
789 if(!strcmp(name, myself->name))
791 syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
792 cl->name, cl->hostname);
798 /* Check if the new host already exists in the connnection list */
800 if(!(old = lookup_id(name)))
802 syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
803 name, cl->name, cl->hostname);
808 /* Check if the rest matches */
810 if(address!=old->address || port!=old->port || options!=old->options || cl!=old->nexthop)
812 syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
816 /* Ok, since EVERYTHING seems to check out all right, delete it */
818 old->status.active = 0;
819 terminate_connection(old);
821 /* Tell the rest about the new host */
823 for(p = conn_list; p; p = p->next)
824 if(p->status.meta && p->status.active && p!=cl)
825 send_del_host(p, old);
830 /* Status and error notification routines */
832 int send_status(conn_list_t *cl, int statusno, char *statusstring)
836 statusstring = status_text[statusno];
838 return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
841 int status_h(conn_list_t *cl)
846 if(sscanf(cl->buffer, "%*d %d %as", &statusno, &statusstring) != 2)
848 syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
849 cl->name, cl->hostname);
853 if(debug_lvl >= DEBUG_STATUS)
855 syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
856 cl->name, cl->hostname, status_text[statusno], statusstring);
864 int send_error(conn_list_t *cl, int errno, char *errstring)
868 errstring = strerror(errno);
869 return send_request(cl, "%d %d %s", ERROR, errno, errstring);
872 int error_h(conn_list_t *cl)
877 if(sscanf(cl->buffer, "%*d %d %as", &errno, &errorstring) != 2)
879 syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
880 cl->name, cl->hostname);
884 if(debug_lvl >= DEBUG_ERROR)
886 syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
887 cl->name, cl->hostname, strerror(errno), errorstring);
891 terminate_connection(cl);
896 int send_termreq(conn_list_t *cl)
899 return send_request(cl, "%d", TERMREQ);
902 int termreq_h(conn_list_t *cl)
905 terminate_connection(cl);
910 /* Keepalive routines - FIXME: needs a closer look */
912 int send_ping(conn_list_t *cl)
914 cl->status.pinged = 1;
916 return send_request(cl, "%d", PING);
919 int ping_h(conn_list_t *cl)
922 return send_pong(cl);
925 int send_pong(conn_list_t *cl)
928 return send_request(cl, "%d", PONG);
931 int pong_h(conn_list_t *cl)
934 cl->status.got_pong = 1;
941 int send_key_changed(conn_list_t *from, conn_list_t *cl)
945 for(p = conn_list; p != NULL; p = p->next)
947 if(p!=cl && p->status.meta && p->status.active)
948 send_request(p, "%d %s", KEY_CHANGED,
955 int key_changed_h(conn_list_t *cl)
960 if(sscanf(cl->buffer, "%*d %as", &from_id) != 1)
962 syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
963 cl->name, cl->hostname);
967 if(!(from = lookup_id(from_id)))
969 syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
970 cl->name, cl->hostname, from_id);
977 from->status.validkey = 0;
978 from->status.waitingforkey = 0;
980 send_key_changed(from, cl);
985 int send_req_key(conn_list_t *from, conn_list_t *to)
988 return send_request(to->nexthop, "%d %s %s", REQ_KEY,
989 from->name, to->name);
992 int req_key_h(conn_list_t *cl)
994 char *from_id, *to_id;
995 conn_list_t *from, *to;
997 if(sscanf(cl->buffer, "%*d %as %as", &from_id, &to_id) != 2)
999 syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
1000 cl->name, cl->hostname);
1004 if(!(from = lookup_id(from_id)))
1006 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
1007 cl->name, cl->hostname, from_id);
1008 free(from_id); free(to_id);
1012 /* Check if this key request is for us */
1014 if(!strcmp(to_id, myself->name))
1016 send_ans_key(myself, from, myself->cipher_pktkey);
1020 if(!(to = lookup_id(to_id)))
1022 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
1023 cl->name, cl->hostname, to_id);
1024 free(from_id); free(to_id);
1027 send_req_key(from, to);
1030 free(from_id); free(to_id);
1035 int send_ans_key(conn_list_t *from, conn_list_t *to, char *pktkey)
1038 return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
1039 from->name, to->name, pktkey);
1042 int ans_key_h(conn_list_t *cl)
1044 char *from_id, *to_id, *pktkey;
1046 conn_list_t *from, *to;
1048 if(sscanf(cl->buffer, "%*d %as %as %as", &from_id, &to_id, &pktkey) != 3)
1050 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
1051 cl->name, cl->hostname);
1055 if(!(from = lookup_id(from_id)))
1057 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
1058 cl->name, cl->hostname, from_id);
1059 free(from_id); free(to_id); free(pktkey);
1063 /* Check if this key request is for us */
1065 if(!strcmp(to_id, myself->name))
1067 /* It is for us, convert it to binary and set the key with it. */
1069 keylength = strlen(pktkey);
1071 /* Don't do this... yet
1072 if((keylength%2) || (keylength <= 0))
1074 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key"),
1075 cl->name, cl->hostname, from->name);
1076 free(from_id); free(to_id); free(pktkey);
1080 hex2bin(pktkey, pktkey, keylength);
1081 BF_set_key(cl->cipher_pktkey, keylength, pktkey);
1084 from->status.validkey = 1;
1085 from->status.waitingforkey = 0;
1089 if(!(to = lookup_id(to_id)))
1091 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1092 cl->name, cl->hostname, to_id);
1093 free(from_id); free(to_id); free(pktkey);
1096 send_ans_key(from, to, pktkey);
1099 free(from_id); free(to_id); free(pktkey);
1104 /* Jumptable for the request handlers */
1106 int (*request_handlers[])(conn_list_t*) = {
1107 id_h, challenge_h, chal_reply_h, ack_h,
1108 status_h, error_h, termreq_h,
1110 add_host_h, del_host_h,
1111 add_subnet_h, del_subnet_h,
1112 key_changed_h, req_key_h, ans_key_h,
1117 char (*request_name[]) = {
1118 "ID", "CHALLENGE", "CHAL_REPLY", "ACK",
1119 "STATUS", "ERROR", "TERMREQ",
1121 "ADD_HOST", "DEL_HOST",
1122 "ADD_SUBNET", "DEL_SUBNET",
1123 "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1126 /* Status strings */
1128 char (*status_text[]) = {
1134 char (*error_text[]) = {