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.43 2000/10/20 15:34:37 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 /* Copy random data to the buffer */
252 RAND_bytes(cl->hischallenge, len);
254 /* Encrypt the random data */
256 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 */
258 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
263 /* Convert the encrypted random data to a hexadecimal formatted string */
265 bin2hex(buffer, buffer, len);
266 buffer[len*2] = '\0';
268 /* Send the challenge */
270 cl->allow_request = CHAL_REPLY;
271 x = send_request(cl, "%d %s", CHALLENGE, buffer);
277 int challenge_h(conn_list_t *cl)
282 if(sscanf(cl->buffer, "%*d %as", &buffer) != 1)
284 syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
288 len = RSA_size(myself->rsa_key);
290 /* Check if the length of the challenge is all right */
292 if(strlen(buffer) != len*2)
294 syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
299 /* Allocate buffers for the challenge */
302 cl->mychallenge = xmalloc(len);
304 /* Convert the challenge from hexadecimal back to binary */
306 hex2bin(buffer,buffer,len);
308 /* Decrypt the challenge */
310 if(RSA_private_decrypt(len, buffer, cl->mychallenge, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
312 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
319 /* Rest is done by send_chal_reply() */
321 return send_chal_reply(cl);
324 int send_chal_reply(conn_list_t *cl)
326 char hash[SHA_DIGEST_LENGTH*2+1];
330 syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
334 /* Calculate the hash from the challenge we received */
336 SHA1(cl->mychallenge, RSA_size(myself->rsa_key), hash);
338 /* Convert the hash to a hexadecimal formatted string */
340 bin2hex(hash,hash,SHA_DIGEST_LENGTH);
341 hash[SHA_DIGEST_LENGTH*2] = '\0';
345 if(cl->status.outgoing)
346 cl->allow_request = ID;
348 cl->allow_request = ACK;
351 return send_request(cl, "%d %s", CHAL_REPLY, hash);
354 int chal_reply_h(conn_list_t *cl)
357 char myhash[SHA_DIGEST_LENGTH];
359 if(sscanf(cl->buffer, "%*d %as", &hishash) != 1)
361 syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
366 /* Check if the length of the hash is all right */
368 if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
370 syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
375 /* Convert the hash to binary format */
377 hex2bin(hishash, hishash, SHA_DIGEST_LENGTH);
379 /* Calculate the hash from the challenge we sent */
381 SHA1(cl->hischallenge, RSA_size(cl->rsa_key), myhash);
383 /* Verify the incoming hash with the calculated hash */
385 if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
387 syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
394 /* Identity has now been positively verified.
395 If we are accepting this new connection, then send our identity,
396 if we are making this connecting, acknowledge.
399 if(cl->status.outgoing)
405 int send_ack(conn_list_t *cl)
408 cl->allow_request = ACK;
410 return send_request(cl, "%d", ACK);
413 int ack_h(conn_list_t *cl)
417 /* Okay, before we active the connection, we check if there is another entry
418 in the connection list with the same name. If so, it presumably is an
419 old connection that has timed out but we don't know it yet.
422 while((old = lookup_id(cl->name)))
424 if(debug_lvl > DEBUG_CONNECTIONS)
425 syslog(LOG_NOTICE, _("Removing old entry for %s at %s in favour of new connection from %s"),
426 cl->name, old->hostname, cl->hostname);
427 old->status.active = 0;
428 terminate_connection(old);
431 /* Activate this connection */
433 cl->allow_request = ALL;
434 cl->status.active = 1;
436 if(debug_lvl > DEBUG_CONNECTIONS)
437 syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname);
439 /* Exchange information about other tinc daemons */
441 /* FIXME: reprogram this.
442 notify_others(cl, NULL, send_add_host);
448 if(cl->status.outgoing)
454 /* Address and subnet information exchange */
456 int send_add_subnet(conn_list_t *cl, conn_list_t *other, subnet_t *subnet)
461 x = send_request(cl, "%d %s %s", ADD_SUBNET,
462 other->name, netstr = net2str(subnet));
468 int add_subnet_h(conn_list_t *cl)
473 subnet_t *subnet, *old;
475 if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
477 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
478 free(name); free(subnetstr);
482 /* Check if owner name is a valid */
486 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
487 free(name); free(subnetstr);
491 /* Check if subnet string is valid */
493 if(!(subnet = str2net(subnetstr)))
495 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
496 free(name); free(subnetstr);
502 /* Check if somebody tries to add a subnet of ourself */
504 if(!strcmp(name, myself->name))
506 syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
507 cl->name, cl->hostname);
513 /* Check if the owner of the new subnet is in the connection list */
515 if(!(owner = lookup_id(name)))
517 syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
518 name, cl->name, cl->hostname);
523 /* If everything is correct, add the subnet to the list of the owner */
525 subnet_add(owner, subnet);
530 int send_del_subnet(conn_list_t *cl, conn_list_t *other, subnet_t *subnet)
533 return send_request(cl, "%d %s %s", DEL_SUBNET, other->name, net2str(subnet));
536 int del_subnet_h(conn_list_t *cl)
541 subnet_t *subnet, *old;
543 if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
545 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
546 free(name); free(subnetstr);
550 /* Check if owner name is a valid */
554 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
555 free(name); free(subnetstr);
559 /* Check if subnet string is valid */
561 if(!(subnet = str2net(subnetstr)))
563 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
564 free(name); free(subnetstr);
570 /* Check if somebody tries to add a subnet of ourself */
572 if(!strcmp(name, myself->name))
574 syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
575 cl->name, cl->hostname);
581 /* Check if the owner of the new subnet is in the connection list */
583 if(!(owner = lookup_id(name)))
585 syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
586 name, cl->name, cl->hostname);
591 /* If everything is correct, delete the subnet from the list of the owner */
598 /* New and closed connections notification */
600 int send_add_host(conn_list_t *cl, conn_list_t *other)
603 return send_request(cl, "%d %s %s %lx:%d %lx", ADD_HOST,
604 myself->name, other->name, other->address, other->port, other->options);
607 int add_host_h(conn_list_t *cl)
610 conn_list_t *old, *new, *hisuplink;
612 new = new_conn_list();
614 if(sscanf(cl->buffer, "%*d %as %as %lx:%d %lx", &sender, &new->name, &new->address, &new->port, &new->options) != 5)
616 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
620 /* Check if identity is a valid name */
622 if(check_id(new->name) || check_id(sender))
624 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
629 /* Check if somebody tries to add ourself */
631 if(!strcmp(new->name, myself->name))
633 syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
639 /* We got an ADD_HOST from ourself!? */
641 if(!strcmp(sender, myself->name))
643 syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) from ourself, restarting"), cl->name, cl->hostname);
649 /* Lookup his uplink */
651 if(!(new->hisuplink = lookup_id(sender)))
653 syslog(LOG_ERR, _("Got ADD_HOST from %s (%s) with origin %s which is not in our connection list"),
654 sender, cl->name, cl->hostname);
661 /* Fill in more of the new conn_list structure */
663 new->hostname = hostlookup(htonl(new->address));
665 /* Check if the new host already exists in the connnection list */
667 if((old = lookup_id(new->name)))
669 if((new->address == old->address) && (new->port == old->port))
671 if(debug_lvl > DEBUG_CONNECTIONS)
672 syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
673 old->name, old->hostname, new->name, new->hostname);
678 if(debug_lvl > DEBUG_CONNECTIONS)
679 syslog(LOG_NOTICE, _("Removing old entry for %s (%s)"),
680 old->name, old->hostname);
681 old->status.active = 0;
682 terminate_connection(old);
686 /* Fill in rest of conn_list structure */
689 new->status.active = 1;
691 /* Hook it up into the conn_list */
693 conn_list_add(conn_list, new);
695 /* Tell the rest about the new host */
696 /* FIXME: reprogram this.
697 notify_others(new, cl, send_add_host);
703 int send_del_host(conn_list_t *cl, conn_list_t *other)
706 return send_request(cl, "%d %s %s %lx:%d %lx", DEL_HOST,
707 myself->name, other->name, other->address, other->port, other->options);
710 int del_host_h(conn_list_t *cl)
717 conn_list_t *old, *hisuplink;
720 if(sscanf(cl->buffer, "%*d %as %as %lx:%d %lx", &sender, &name, &address, &port, &options) != 5)
722 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
723 cl->name, cl->hostname);
727 /* Check if identity is a valid name */
729 if(check_id(name) || check_id(sender))
731 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
732 free(name); free(sender);
736 /* Check if somebody tries to delete ourself */
738 if(!strcmp(name, myself->name))
740 syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
741 cl->name, cl->hostname);
742 free(name); free(sender);
747 /* We got an ADD_HOST from ourself!? */
749 if(!strcmp(sender, myself->name))
751 syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) from ourself, restarting"), cl->name, cl->hostname);
753 free(name); free(sender);
757 /* Lookup his uplink */
759 if(!(hisuplink = lookup_id(sender)))
761 syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) with origin %s which is not in our connection list"),
762 cl->name, cl->hostname, sender);
763 free(name); free(sender);
769 /* Check if the new host already exists in the connnection list */
771 if(!(old = lookup_id(name)))
773 syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
774 name, cl->name, cl->hostname);
779 /* Check if the rest matches */
781 if(address!=old->address || port!=old->port || options!=old->options || hisuplink!=old->hisuplink || cl!=old->myuplink)
783 syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
787 /* Ok, since EVERYTHING seems to check out all right, delete it */
789 old->status.termreq = 1;
790 old->status.active = 0;
792 terminate_connection(old);
797 /* Status and error notification routines */
799 int send_status(conn_list_t *cl, int statusno, char *statusstring)
803 statusstring = status_text[statusno];
805 return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
808 int status_h(conn_list_t *cl)
813 if(sscanf(cl->buffer, "%*d %d %as", &statusno, &statusstring) != 2)
815 syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
816 cl->name, cl->hostname);
820 if(debug_lvl > DEBUG_STATUS)
822 syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
823 cl->name, cl->hostname, status_text[statusno], statusstring);
831 int send_error(conn_list_t *cl, int errno, char *errstring)
835 errstring = strerror(errno);
836 return send_request(cl, "%d %d %s", ERROR, errno, errstring);
839 int error_h(conn_list_t *cl)
844 if(sscanf(cl->buffer, "%*d %d %as", &errno, &errorstring) != 2)
846 syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
847 cl->name, cl->hostname);
851 if(debug_lvl > DEBUG_ERROR)
853 syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
854 cl->name, cl->hostname, strerror(errno), errorstring);
858 cl->status.termreq = 1;
859 terminate_connection(cl);
864 int send_termreq(conn_list_t *cl)
867 return send_request(cl, "%d", TERMREQ);
870 int termreq_h(conn_list_t *cl)
873 cl->status.termreq = 1;
874 terminate_connection(cl);
879 /* Keepalive routines - FIXME: needs a closer look */
881 int send_ping(conn_list_t *cl)
883 cl->status.pinged = 1;
885 return send_request(cl, "%d", PING);
888 int ping_h(conn_list_t *cl)
891 return send_pong(cl);
894 int send_pong(conn_list_t *cl)
897 return send_request(cl, "%d", PONG);
900 int pong_h(conn_list_t *cl)
903 cl->status.got_pong = 1;
910 int send_key_changed(conn_list_t *from, conn_list_t *cl)
914 for(p = conn_list; p != NULL; p = p->next)
916 if(p!=cl && p->status.meta && p->status.active)
917 send_request(p, "%d %s", KEY_CHANGED,
924 int key_changed_h(conn_list_t *cl)
929 if(sscanf(cl->buffer, "%*d %as", &from_id) != 1)
931 syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
932 cl->name, cl->hostname);
936 if(!(from = lookup_id(from_id)))
938 syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
939 cl->name, cl->hostname, from_id);
946 from->status.validkey = 0;
947 from->status.waitingforkey = 0;
949 send_key_changed(from, cl);
954 int send_req_key(conn_list_t *from, conn_list_t *to)
957 return send_request(to->nexthop, "%d %s %s", REQ_KEY,
958 from->name, to->name);
961 int req_key_h(conn_list_t *cl)
963 char *from_id, *to_id;
964 conn_list_t *from, *to;
966 if(sscanf(cl->buffer, "%*d %as %as", &from_id, &to_id) != 2)
968 syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
969 cl->name, cl->hostname);
973 if(!(from = lookup_id(from_id)))
975 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
976 cl->name, cl->hostname, from_id);
977 free(from_id); free(to_id);
981 /* Check if this key request is for us */
983 if(!strcmp(to_id, myself->name))
985 send_ans_key(myself, from, myself->cipher_pktkey);
989 if(!(to = lookup_id(to_id)))
991 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
992 cl->name, cl->hostname, to_id);
993 free(from_id); free(to_id);
996 send_req_key(from, to);
999 free(from_id); free(to_id);
1004 int send_ans_key(conn_list_t *from, conn_list_t *to, char *pktkey)
1007 return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
1008 from->name, to->name, pktkey);
1011 int ans_key_h(conn_list_t *cl)
1013 char *from_id, *to_id, *pktkey;
1015 conn_list_t *from, *to;
1017 if(sscanf(cl->buffer, "%*d %as %as %as", &from_id, &to_id, &pktkey) != 3)
1019 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
1020 cl->name, cl->hostname);
1024 if(!(from = lookup_id(from_id)))
1026 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
1027 cl->name, cl->hostname, from_id);
1028 free(from_id); free(to_id); free(pktkey);
1032 /* Check if this key request is for us */
1034 if(!strcmp(to_id, myself->name))
1036 /* It is for us, convert it to binary and set the key with it. */
1038 keylength = strlen(pktkey);
1040 if((keylength%2) || (keylength <= 0))
1042 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key"),
1043 cl->name, cl->hostname, from->name);
1044 free(from_id); free(to_id); free(pktkey);
1048 hex2bin(pktkey, pktkey, keylength);
1049 BF_set_key(cl->cipher_pktkey, keylength, pktkey);
1053 if(!(to = lookup_id(to_id)))
1055 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1056 cl->name, cl->hostname, to_id);
1057 free(from_id); free(to_id); free(pktkey);
1060 send_ans_key(from, to, pktkey);
1063 free(from_id); free(to_id); free(pktkey);
1068 /* Jumptable for the request handlers */
1070 int (*request_handlers[])(conn_list_t*) = {
1071 id_h, challenge_h, chal_reply_h, ack_h,
1072 status_h, error_h, termreq_h,
1074 add_host_h, del_host_h,
1075 add_subnet_h, del_subnet_h,
1076 key_changed_h, req_key_h, ans_key_h,
1081 char (*request_name[]) = {
1082 "ID", "CHALLENGE", "CHAL_REPLY", "ACK",
1083 "STATUS", "ERROR", "TERMREQ",
1085 "ADD_HOST", "DEL_HOST",
1086 "ADD_SUBNET", "DEL_SUBNET",
1087 "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1090 /* Status strings */
1092 char (*status_text[]) = {
1098 char (*error_text[]) = {