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.46 2000/10/28 21:05:18 guus Exp $
25 #include <sys/types.h>
30 #include <sys/socket.h>
37 #include <netinet/in.h>
39 #include <openssl/sha.h>
50 int check_id(char *id)
54 for (i = 0; i < strlen(id); i++)
55 if(!isalnum(id[i]) && id[i] != '_')
61 /* Generic request routines - takes care of logging and error detection as well */
63 int send_request(conn_list_t *cl, const char *format, ...)
66 char buffer[MAXBUFSIZE];
70 /* Use vsnprintf instead of vasprintf: faster, no memory fragmentation, cleanup is automatic,
71 and there is a limit on the input buffer anyway */
73 va_start(args, format);
74 len = vsnprintf(buffer, MAXBUFSIZE, format, args);
75 request = va_arg(args, int);
78 if(len < 0 || len > MAXBUFSIZE-1)
80 syslog(LOG_ERR, _("Output buffer overflow while sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
86 if(debug_lvl >= DEBUG_PROTOCOL)
87 syslog(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
90 return send_meta(cl, buffer, len);
93 int receive_request(conn_list_t *cl)
97 if(sscanf(cl->buffer, "%d", &request) == 1)
99 if((request < 0) || (request > 255) || (request_handlers[request] == NULL))
101 syslog(LOG_ERR, _("Unknown request from %s (%s)"),
102 cl->name, cl->hostname);
107 if(debug_lvl >= DEBUG_PROTOCOL)
108 syslog(LOG_DEBUG, _("Got %s from %s (%s)"),
109 request_name[request], cl->name, cl->hostname);
111 if(request_handlers[request](cl))
112 /* Something went wrong. Probably scriptkiddies. Terminate. */
114 syslog(LOG_ERR, _("Error while processing %s from %s (%s)"),
115 request_name[request], cl->name, cl->hostname);
121 syslog(LOG_ERR, _("Bogus data received from %s (%s)"),
122 cl->name, cl->hostname);
127 /* Connection protocol:
136 ---------------------------------------
137 Any negotations about the meta protocol
138 encryption go here(u).
139 ---------------------------------------
142 ---------------------------------------
148 (E) Encrypted with symmetric cipher.
150 Part of the challenge is directly used to set the symmetric cipher key and the initial vector.
151 Since a man-in-the-middle cannot decrypt the RSA challenges, this means that he cannot get or
152 forge the key for the symmetric cipher.
155 int send_id(conn_list_t *cl)
158 cl->allow_request = CHALLENGE;
160 return send_request(cl, "%d %s %d %lx %hd", ID, myself->name, myself->protocol_version, myself->options, myself->port);
163 int id_h(conn_list_t *cl)
168 if(sscanf(cl->buffer, "%*d %as %d %lx %hd", &cl->name, &cl->protocol_version, &cl->options, &cl->port) != 4)
170 syslog(LOG_ERR, _("Got bad ID from %s"), cl->hostname);
174 /* Check if version matches */
176 if(cl->protocol_version != myself->protocol_version)
178 syslog(LOG_ERR, _("Peer %s (%s) uses incompatible version %d"),
179 cl->name, cl->hostname, cl->protocol_version);
183 /* Check if identity is a valid name */
185 if(check_id(cl->name))
187 syslog(LOG_ERR, _("Peer %s uses invalid identity name"), cl->hostname);
191 /* Load information about peer */
193 if(read_host_config(cl))
195 syslog(LOG_ERR, _("Peer %s had unknown identity (%s)"), cl->hostname, cl->name);
199 /* First check if the host we connected to is already in our
200 connection list. If so, we are probably making a loop, which
204 if(cl->status.outgoing)
206 if((old = lookup_id(cl->name)))
208 if(debug_lvl >= DEBUG_CONNECTIONS)
209 syslog(LOG_NOTICE, _("Uplink %s (%s) is already in our connection list"), cl->name, cl->hostname);
210 cl->status.outgoing = 0;
211 old->status.outgoing = 1;
212 terminate_connection(cl);
217 if(!(cfg = get_config_val(cl->config, publickey)))
219 syslog(LOG_ERR, _("No public key known for %s (%s)"), cl->name, cl->hostname);
225 cl->rsa_key = RSA_new();
226 BN_hex2bn(&cl->rsa_key->n, cfg->data.ptr);
227 BN_hex2bn(&cl->rsa_key->e, "FFFF");
231 return send_challenge(cl);
234 int send_challenge(conn_list_t *cl)
239 len = RSA_size(cl->rsa_key);
241 /* Allocate buffers for the challenge */
243 buffer = xmalloc(len*2+1);
246 free(cl->hischallenge);
248 cl->hischallenge = xmalloc(len);
250 /* Seed the PRNG with urandom (can't afford to block) */
252 RAND_load_file("/dev/urandom", 1024);
254 /* Copy random data to the buffer */
256 RAND_bytes(cl->hischallenge, len);
258 cl->hischallenge[0] &= 0x7F; /* Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
260 if(debug_lvl >= DEBUG_SCARY_THINGS)
262 bin2hex(cl->hischallenge, buffer, len);
263 buffer[len*2] = '\0';
264 syslog(LOG_DEBUG, _("Generated random challenge (unencrypted): %s"), buffer);
267 /* Encrypt the random data */
269 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 */
271 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
276 /* Convert the encrypted random data to a hexadecimal formatted string */
278 bin2hex(buffer, buffer, len);
279 buffer[len*2] = '\0';
281 /* Send the challenge */
283 cl->allow_request = CHAL_REPLY;
284 x = send_request(cl, "%d %s", CHALLENGE, buffer);
290 int challenge_h(conn_list_t *cl)
295 if(sscanf(cl->buffer, "%*d %as", &buffer) != 1)
297 syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
301 len = RSA_size(myself->rsa_key);
303 /* Check if the length of the challenge is all right */
305 if(strlen(buffer) != len*2)
307 syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
312 /* Allocate buffers for the challenge */
315 cl->mychallenge = xmalloc(len);
317 /* Convert the challenge from hexadecimal back to binary */
319 hex2bin(buffer,buffer,len);
321 /* Decrypt the challenge */
323 if(RSA_private_decrypt(len, buffer, cl->mychallenge, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
325 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
330 if(debug_lvl >= DEBUG_SCARY_THINGS)
332 bin2hex(cl->mychallenge, buffer, len);
333 buffer[len*2] = '\0';
334 syslog(LOG_DEBUG, _("Received random challenge (unencrypted): %s"), buffer);
339 /* Rest is done by send_chal_reply() */
341 return send_chal_reply(cl);
344 int send_chal_reply(conn_list_t *cl)
346 char hash[SHA_DIGEST_LENGTH*2+1];
350 syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
354 /* Calculate the hash from the challenge we received */
356 SHA1(cl->mychallenge, RSA_size(myself->rsa_key), hash);
358 /* Convert the hash to a hexadecimal formatted string */
360 bin2hex(hash,hash,SHA_DIGEST_LENGTH);
361 hash[SHA_DIGEST_LENGTH*2] = '\0';
365 if(cl->status.outgoing)
366 cl->allow_request = ID;
368 cl->allow_request = ACK;
371 return send_request(cl, "%d %s", CHAL_REPLY, hash);
374 int chal_reply_h(conn_list_t *cl)
377 char myhash[SHA_DIGEST_LENGTH];
379 if(sscanf(cl->buffer, "%*d %as", &hishash) != 1)
381 syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
386 /* Check if the length of the hash is all right */
388 if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
390 syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
395 /* Convert the hash to binary format */
397 hex2bin(hishash, hishash, SHA_DIGEST_LENGTH);
399 /* Calculate the hash from the challenge we sent */
401 SHA1(cl->hischallenge, RSA_size(cl->rsa_key), myhash);
403 /* Verify the incoming hash with the calculated hash */
405 if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
407 syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
408 if(debug_lvl >= DEBUG_SCARY_THINGS)
410 bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
411 hishash[SHA_DIGEST_LENGTH*2] = '\0';
412 syslog(LOG_DEBUG, _("Expected challenge reply: %s"), hishash);
421 /* Identity has now been positively verified.
422 If we are accepting this new connection, then send our identity,
423 if we are making this connecting, acknowledge.
426 if(cl->status.outgoing)
432 int send_ack(conn_list_t *cl)
435 cl->allow_request = ACK;
437 return send_request(cl, "%d", ACK);
440 int ack_h(conn_list_t *cl)
442 conn_list_t *old, *p;
445 /* Okay, before we active the connection, we check if there is another entry
446 in the connection list with the same name. If so, it presumably is an
447 old connection that has timed out but we don't know it yet.
450 while((old = lookup_id(cl->name)))
452 if(debug_lvl >= DEBUG_CONNECTIONS)
453 syslog(LOG_NOTICE, _("Removing old entry for %s at %s in favour of new connection from %s"),
454 cl->name, old->hostname, cl->hostname);
455 old->status.active = 0;
456 terminate_connection(old);
459 /* Notify others of this connection */
461 for(p = conn_list; p; p = p->next)
463 send_add_host(p, cl);
465 /* Activate this connection */
467 cl->allow_request = ALL;
468 cl->status.active = 1;
471 if(debug_lvl >= DEBUG_CONNECTIONS)
472 syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname);
475 if(!cl->status.outgoing)
478 /* Send him our subnets */
480 for(s = myself->subnets; s; s = s->next)
481 send_add_subnet(cl, s);
486 /* Address and subnet information exchange */
488 int send_add_subnet(conn_list_t *cl, subnet_t *subnet)
493 x = send_request(cl, "%d %s %s", ADD_SUBNET,
494 subnet->owner->name, netstr = net2str(subnet));
500 int add_subnet_h(conn_list_t *cl)
505 subnet_t *subnet, *old;
507 if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 2)
509 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
510 free(name); free(subnetstr);
514 /* Check if owner name is a valid */
518 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
519 free(name); free(subnetstr);
523 /* Check if subnet string is valid */
525 if(!(subnet = str2net(subnetstr)))
527 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
528 free(name); free(subnetstr);
534 /* Check if somebody tries to add a subnet of ourself */
536 if(!strcmp(name, myself->name))
538 syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
539 cl->name, cl->hostname);
545 /* Check if the owner of the new subnet is in the connection list */
547 if(!(owner = lookup_id(name)))
549 syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
550 name, cl->name, cl->hostname);
555 /* If everything is correct, add the subnet to the list of the owner */
557 subnet_add(owner, subnet);
562 int send_del_subnet(conn_list_t *cl, subnet_t *subnet)
567 netstr = net2str(subnet);
568 x = send_request(cl, "%d %s %s", DEL_SUBNET, subnet->owner->name, netstr);
574 int del_subnet_h(conn_list_t *cl)
579 subnet_t *subnet, *old;
581 if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
583 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
584 free(name); free(subnetstr);
588 /* Check if owner name is a valid */
592 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
593 free(name); free(subnetstr);
597 /* Check if subnet string is valid */
599 if(!(subnet = str2net(subnetstr)))
601 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
602 free(name); free(subnetstr);
608 /* Check if somebody tries to add a subnet of ourself */
610 if(!strcmp(name, myself->name))
612 syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
613 cl->name, cl->hostname);
619 /* Check if the owner of the new subnet is in the connection list */
621 if(!(owner = lookup_id(name)))
623 syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
624 name, cl->name, cl->hostname);
629 /* If everything is correct, delete the subnet from the list of the owner */
636 /* New and closed connections notification */
638 int send_add_host(conn_list_t *cl, conn_list_t *other)
641 return send_request(cl, "%d %s %s %lx:%d %lx", ADD_HOST,
642 myself->name, other->name, other->address, other->port, other->options);
645 int add_host_h(conn_list_t *cl)
648 conn_list_t *old, *new, *hisuplink;
650 new = new_conn_list();
652 if(sscanf(cl->buffer, "%*d %as %as %lx:%d %lx", &sender, &new->name, &new->address, &new->port, &new->options) != 5)
654 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
658 /* Check if identity is a valid name */
660 if(check_id(new->name) || check_id(sender))
662 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
667 /* Check if somebody tries to add ourself */
669 if(!strcmp(new->name, myself->name))
671 syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
677 /* We got an ADD_HOST from ourself!? */
679 if(!strcmp(sender, myself->name))
681 syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) from ourself, restarting"), cl->name, cl->hostname);
687 /* Lookup his uplink */
689 if(!(new->hisuplink = lookup_id(sender)))
691 syslog(LOG_ERR, _("Got ADD_HOST from %s (%s) with origin %s which is not in our connection list"),
692 sender, cl->name, cl->hostname);
699 /* Fill in more of the new conn_list structure */
701 new->hostname = hostlookup(htonl(new->address));
703 /* Check if the new host already exists in the connnection list */
705 if((old = lookup_id(new->name)))
707 if((new->address == old->address) && (new->port == old->port))
709 if(debug_lvl >= DEBUG_CONNECTIONS)
710 syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
711 old->name, old->hostname, new->name, new->hostname);
716 if(debug_lvl >= DEBUG_CONNECTIONS)
717 syslog(LOG_NOTICE, _("Removing old entry for %s (%s)"),
718 old->name, old->hostname);
719 old->status.active = 0;
720 terminate_connection(old);
724 /* Fill in rest of conn_list structure */
727 new->status.active = 1;
729 /* Hook it up into the conn_list */
731 conn_list_add(conn_list, new);
733 /* Tell the rest about the new host */
734 /* FIXME: reprogram this.
735 notify_others(new, cl, send_add_host);
741 int send_del_host(conn_list_t *cl, conn_list_t *other)
744 return send_request(cl, "%d %s %s %lx:%d %lx", DEL_HOST,
745 myself->name, other->name, other->address, other->port, other->options);
748 int del_host_h(conn_list_t *cl)
755 conn_list_t *old, *hisuplink;
758 if(sscanf(cl->buffer, "%*d %as %as %lx:%d %lx", &sender, &name, &address, &port, &options) != 5)
760 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
761 cl->name, cl->hostname);
765 /* Check if identity is a valid name */
767 if(check_id(name) || check_id(sender))
769 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
770 free(name); free(sender);
774 /* Check if somebody tries to delete ourself */
776 if(!strcmp(name, myself->name))
778 syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
779 cl->name, cl->hostname);
780 free(name); free(sender);
785 /* We got an ADD_HOST from ourself!? */
787 if(!strcmp(sender, myself->name))
789 syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) from ourself, restarting"), cl->name, cl->hostname);
791 free(name); free(sender);
795 /* Lookup his uplink */
797 if(!(hisuplink = lookup_id(sender)))
799 syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) with origin %s which is not in our connection list"),
800 cl->name, cl->hostname, sender);
801 free(name); free(sender);
807 /* Check if the new host already exists in the connnection list */
809 if(!(old = lookup_id(name)))
811 syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
812 name, cl->name, cl->hostname);
817 /* Check if the rest matches */
819 if(address!=old->address || port!=old->port || options!=old->options || hisuplink!=old->hisuplink || cl!=old->myuplink)
821 syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
825 /* Ok, since EVERYTHING seems to check out all right, delete it */
827 old->status.termreq = 1;
828 old->status.active = 0;
830 terminate_connection(old);
835 /* Status and error notification routines */
837 int send_status(conn_list_t *cl, int statusno, char *statusstring)
841 statusstring = status_text[statusno];
843 return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
846 int status_h(conn_list_t *cl)
851 if(sscanf(cl->buffer, "%*d %d %as", &statusno, &statusstring) != 2)
853 syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
854 cl->name, cl->hostname);
858 if(debug_lvl >= DEBUG_STATUS)
860 syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
861 cl->name, cl->hostname, status_text[statusno], statusstring);
869 int send_error(conn_list_t *cl, int errno, char *errstring)
873 errstring = strerror(errno);
874 return send_request(cl, "%d %d %s", ERROR, errno, errstring);
877 int error_h(conn_list_t *cl)
882 if(sscanf(cl->buffer, "%*d %d %as", &errno, &errorstring) != 2)
884 syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
885 cl->name, cl->hostname);
889 if(debug_lvl >= DEBUG_ERROR)
891 syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
892 cl->name, cl->hostname, strerror(errno), errorstring);
896 cl->status.termreq = 1;
897 terminate_connection(cl);
902 int send_termreq(conn_list_t *cl)
905 return send_request(cl, "%d", TERMREQ);
908 int termreq_h(conn_list_t *cl)
911 cl->status.termreq = 1;
912 terminate_connection(cl);
917 /* Keepalive routines - FIXME: needs a closer look */
919 int send_ping(conn_list_t *cl)
921 cl->status.pinged = 1;
923 return send_request(cl, "%d", PING);
926 int ping_h(conn_list_t *cl)
929 return send_pong(cl);
932 int send_pong(conn_list_t *cl)
935 return send_request(cl, "%d", PONG);
938 int pong_h(conn_list_t *cl)
941 cl->status.got_pong = 1;
948 int send_key_changed(conn_list_t *from, conn_list_t *cl)
952 for(p = conn_list; p != NULL; p = p->next)
954 if(p!=cl && p->status.meta && p->status.active)
955 send_request(p, "%d %s", KEY_CHANGED,
962 int key_changed_h(conn_list_t *cl)
967 if(sscanf(cl->buffer, "%*d %as", &from_id) != 1)
969 syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
970 cl->name, cl->hostname);
974 if(!(from = lookup_id(from_id)))
976 syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
977 cl->name, cl->hostname, from_id);
984 from->status.validkey = 0;
985 from->status.waitingforkey = 0;
987 send_key_changed(from, cl);
992 int send_req_key(conn_list_t *from, conn_list_t *to)
995 return send_request(to->nexthop, "%d %s %s", REQ_KEY,
996 from->name, to->name);
999 int req_key_h(conn_list_t *cl)
1001 char *from_id, *to_id;
1002 conn_list_t *from, *to;
1004 if(sscanf(cl->buffer, "%*d %as %as", &from_id, &to_id) != 2)
1006 syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
1007 cl->name, cl->hostname);
1011 if(!(from = lookup_id(from_id)))
1013 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
1014 cl->name, cl->hostname, from_id);
1015 free(from_id); free(to_id);
1019 /* Check if this key request is for us */
1021 if(!strcmp(to_id, myself->name))
1023 send_ans_key(myself, from, myself->cipher_pktkey);
1027 if(!(to = lookup_id(to_id)))
1029 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
1030 cl->name, cl->hostname, to_id);
1031 free(from_id); free(to_id);
1034 send_req_key(from, to);
1037 free(from_id); free(to_id);
1042 int send_ans_key(conn_list_t *from, conn_list_t *to, char *pktkey)
1045 return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
1046 from->name, to->name, pktkey);
1049 int ans_key_h(conn_list_t *cl)
1051 char *from_id, *to_id, *pktkey;
1053 conn_list_t *from, *to;
1055 if(sscanf(cl->buffer, "%*d %as %as %as", &from_id, &to_id, &pktkey) != 3)
1057 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
1058 cl->name, cl->hostname);
1062 if(!(from = lookup_id(from_id)))
1064 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
1065 cl->name, cl->hostname, from_id);
1066 free(from_id); free(to_id); free(pktkey);
1070 /* Check if this key request is for us */
1072 if(!strcmp(to_id, myself->name))
1074 /* It is for us, convert it to binary and set the key with it. */
1076 keylength = strlen(pktkey);
1078 /* Don't do this... yet
1079 if((keylength%2) || (keylength <= 0))
1081 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key"),
1082 cl->name, cl->hostname, from->name);
1083 free(from_id); free(to_id); free(pktkey);
1087 hex2bin(pktkey, pktkey, keylength);
1088 BF_set_key(cl->cipher_pktkey, keylength, pktkey);
1091 cl->status.validkey = 1;
1092 cl->status.waitingforkey = 0;
1096 if(!(to = lookup_id(to_id)))
1098 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1099 cl->name, cl->hostname, to_id);
1100 free(from_id); free(to_id); free(pktkey);
1103 send_ans_key(from, to, pktkey);
1106 free(from_id); free(to_id); free(pktkey);
1111 /* Jumptable for the request handlers */
1113 int (*request_handlers[])(conn_list_t*) = {
1114 id_h, challenge_h, chal_reply_h, ack_h,
1115 status_h, error_h, termreq_h,
1117 add_host_h, del_host_h,
1118 add_subnet_h, del_subnet_h,
1119 key_changed_h, req_key_h, ans_key_h,
1124 char (*request_name[]) = {
1125 "ID", "CHALLENGE", "CHAL_REPLY", "ACK",
1126 "STATUS", "ERROR", "TERMREQ",
1128 "ADD_HOST", "DEL_HOST",
1129 "ADD_SUBNET", "DEL_SUBNET",
1130 "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1133 /* Status strings */
1135 char (*status_text[]) = {
1141 char (*error_text[]) = {