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.59 2000/11/07 22:02:14 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 ---------------------------------------
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, 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 /* Copy random data to the buffer */
261 RAND_bytes(cl->hischallenge, len);
263 cl->hischallenge[0] &= 0x7F; /* Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
265 if(debug_lvl >= DEBUG_SCARY_THINGS)
267 bin2hex(cl->hischallenge, buffer, len);
268 buffer[len*2] = '\0';
269 syslog(LOG_DEBUG, _("Generated random challenge (unencrypted): %s"), buffer);
272 /* Encrypt the random data */
274 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 */
276 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
281 /* Convert the encrypted random data to a hexadecimal formatted string */
283 bin2hex(buffer, buffer, len);
284 buffer[len*2] = '\0';
286 /* Send the challenge */
288 cl->allow_request = CHAL_REPLY;
289 x = send_request(cl, "%d %s", CHALLENGE, buffer);
295 int challenge_h(conn_list_t *cl)
300 if(sscanf(cl->buffer, "%*d %as", &buffer) != 1)
302 syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
306 len = RSA_size(myself->rsa_key);
308 /* Check if the length of the challenge is all right */
310 if(strlen(buffer) != len*2)
312 syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
317 /* Allocate buffers for the challenge */
320 cl->mychallenge = xmalloc(len);
322 /* Convert the challenge from hexadecimal back to binary */
324 hex2bin(buffer,buffer,len);
326 /* Decrypt the challenge */
328 if(RSA_private_decrypt(len, buffer, cl->mychallenge, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
330 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
335 if(debug_lvl >= DEBUG_SCARY_THINGS)
337 bin2hex(cl->mychallenge, buffer, len);
338 buffer[len*2] = '\0';
339 syslog(LOG_DEBUG, _("Received random challenge (unencrypted): %s"), buffer);
344 /* Rest is done by send_chal_reply() */
346 return send_chal_reply(cl);
349 int send_chal_reply(conn_list_t *cl)
351 char hash[SHA_DIGEST_LENGTH*2+1];
355 syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
359 /* Calculate the hash from the challenge we received */
361 SHA1(cl->mychallenge, RSA_size(myself->rsa_key), hash);
363 /* Convert the hash to a hexadecimal formatted string */
365 bin2hex(hash,hash,SHA_DIGEST_LENGTH);
366 hash[SHA_DIGEST_LENGTH*2] = '\0';
370 if(cl->status.outgoing)
371 cl->allow_request = ID;
373 cl->allow_request = METAKEY;
376 return send_request(cl, "%d %s", CHAL_REPLY, hash);
379 int chal_reply_h(conn_list_t *cl)
382 char myhash[SHA_DIGEST_LENGTH];
384 if(sscanf(cl->buffer, "%*d %as", &hishash) != 1)
386 syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
391 /* Check if the length of the hash is all right */
393 if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
395 syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
400 /* Convert the hash to binary format */
402 hex2bin(hishash, hishash, SHA_DIGEST_LENGTH);
404 /* Calculate the hash from the challenge we sent */
406 SHA1(cl->hischallenge, RSA_size(cl->rsa_key), myhash);
408 /* Verify the incoming hash with the calculated hash */
410 if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
412 syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
413 if(debug_lvl >= DEBUG_SCARY_THINGS)
415 bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
416 hishash[SHA_DIGEST_LENGTH*2] = '\0';
417 syslog(LOG_DEBUG, _("Expected challenge reply: %s"), hishash);
426 /* Identity has now been positively verified.
427 If we are accepting this new connection, then send our identity,
428 if we are making this connecting, acknowledge.
431 if(cl->status.outgoing)
432 return send_metakey(cl);
437 int send_metakey(conn_list_t *cl)
442 len = RSA_size(cl->rsa_key);
444 /* Allocate buffers for the meta key */
446 buffer = xmalloc(len*2+1);
448 if(!cl->cipher_outkey)
449 cl->cipher_outkey = xmalloc(len);
451 if(!cl->cipher_outctx)
452 cl->cipher_outctx = xmalloc(sizeof(*cl->cipher_outctx));
454 /* Copy random data to the buffer */
456 RAND_bytes(cl->cipher_outkey, len);
458 cl->cipher_outkey[0] &= 0x7F; /* FIXME: Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
460 if(debug_lvl >= DEBUG_SCARY_THINGS)
462 bin2hex(cl->cipher_outkey, buffer, len);
463 buffer[len*2] = '\0';
464 syslog(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"), buffer);
467 /* Encrypt the random data */
469 if(RSA_public_encrypt(len, cl->cipher_outkey, buffer, cl->rsa_key, RSA_NO_PADDING) != len) /* NO_PADDING because the message size equals the RSA key size and it is totally random */
471 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
476 /* Convert the encrypted random data to a hexadecimal formatted string */
478 bin2hex(buffer, buffer, len);
479 buffer[len*2] = '\0';
481 /* Send the meta key */
483 if(cl->status.outgoing)
484 cl->allow_request = METAKEY;
486 cl->allow_request = ACK;
488 x = send_request(cl, "%d %s", METAKEY, buffer);
491 EVP_EncryptInit(cl->cipher_outctx, EVP_bf_cfb(), cl->cipher_outkey, cl->cipher_outkey + EVP_bf_cfb()->key_len);
496 int metakey_h(conn_list_t *cl)
501 if(sscanf(cl->buffer, "%*d %as", &buffer) != 1)
503 syslog(LOG_ERR, _("Got bad METAKEY from %s (%s)"), cl->name, cl->hostname);
507 len = RSA_size(myself->rsa_key);
509 /* Check if the length of the meta key is all right */
511 if(strlen(buffer) != len*2)
513 syslog(LOG_ERR, _("Intruder: wrong meta key length from %s (%s)"), cl->name, cl->hostname);
518 /* Allocate buffers for the meta key */
520 if(!cl->cipher_inkey)
521 cl->cipher_inkey = xmalloc(len);
523 if(!cl->cipher_inctx)
524 cl->cipher_inctx = xmalloc(sizeof(*cl->cipher_inctx));
526 /* Convert the challenge from hexadecimal back to binary */
528 hex2bin(buffer,buffer,len);
530 /* Decrypt the meta key */
532 if(RSA_private_decrypt(len, buffer, cl->cipher_inkey, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
534 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
539 if(debug_lvl >= DEBUG_SCARY_THINGS)
541 bin2hex(cl->cipher_inkey, buffer, len);
542 buffer[len*2] = '\0';
543 syslog(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), buffer);
548 EVP_DecryptInit(cl->cipher_inctx, EVP_bf_cfb(), cl->cipher_inkey, cl->cipher_inkey + EVP_bf_cfb()->key_len);
551 if(cl->status.outgoing)
554 return send_metakey(cl);
557 int send_ack(conn_list_t *cl)
561 if(cl->status.outgoing)
562 cl->allow_request = ACK;
564 setup_vpn_connection(cl);
566 x = send_request(cl, "%d", ACK);
567 cl->status.encryptout = 1;
572 int ack_h(conn_list_t *cl)
574 conn_list_t *old, *p;
577 /* Okay, before we active the connection, we check if there is another entry
578 in the connection list with the same name. If so, it presumably is an
579 old connection that has timed out but we don't know it yet.
582 while((old = lookup_id(cl->name)))
584 if(debug_lvl >= DEBUG_CONNECTIONS)
585 syslog(LOG_NOTICE, _("Removing old entry for %s at %s in favour of new connection from %s"),
586 cl->name, old->hostname, cl->hostname);
588 terminate_connection(old);
591 /* Activate this connection */
593 cl->allow_request = ALL;
594 cl->status.active = 1;
595 cl->status.decryptin = 1;
597 cl->cipher_pkttype = EVP_bf_cfb();
598 cl->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
600 if(debug_lvl >= DEBUG_CONNECTIONS)
601 syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname);
604 if(!cl->status.outgoing)
607 /* Send him our subnets */
609 for(s = myself->subnets; s; s = s->next)
610 send_add_subnet(cl, s);
612 /* And send him all the hosts and their subnets we know... */
614 for(p = conn_list; p; p = p->next)
615 if(p != cl && p->status.active)
617 /* Notify others of this connection */
620 send_add_host(p, cl);
622 /* Notify new connection of everything we know */
624 send_add_host(cl, p);
626 for(s = p->subnets; s; s = s->next)
627 send_add_subnet(cl, s);
633 /* Address and subnet information exchange */
635 int send_add_subnet(conn_list_t *cl, subnet_t *subnet)
640 x = send_request(cl, "%d %s %s", ADD_SUBNET,
641 subnet->owner->name, netstr = net2str(subnet));
647 int add_subnet_h(conn_list_t *cl)
651 conn_list_t *owner, *p;
654 if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 2)
656 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
657 free(name); free(subnetstr);
661 /* Check if owner name is a valid */
665 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
666 free(name); free(subnetstr);
670 /* Check if subnet string is valid */
672 if(!(subnet = str2net(subnetstr)))
674 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
675 free(name); free(subnetstr);
681 /* Check if somebody tries to add a subnet of ourself */
683 if(!strcmp(name, myself->name))
685 syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
686 cl->name, cl->hostname);
692 /* Check if the owner of the new subnet is in the connection list */
694 if(!(owner = lookup_id(name)))
696 syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
697 name, cl->name, cl->hostname);
702 /* If everything is correct, add the subnet to the list of the owner */
704 subnet_add(owner, subnet);
708 for(p = conn_list; p; p = p->next)
709 if(p->status.meta && p->status.active && p!= cl)
710 send_add_subnet(p, subnet);
715 int send_del_subnet(conn_list_t *cl, subnet_t *subnet)
720 netstr = net2str(subnet);
721 x = send_request(cl, "%d %s %s", DEL_SUBNET, subnet->owner->name, netstr);
727 int del_subnet_h(conn_list_t *cl)
731 conn_list_t *owner, *p;
734 if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
736 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
737 free(name); free(subnetstr);
741 /* Check if owner name is a valid */
745 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
746 free(name); free(subnetstr);
750 /* Check if subnet string is valid */
752 if(!(subnet = str2net(subnetstr)))
754 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
755 free(name); free(subnetstr);
761 /* Check if somebody tries to add a subnet of ourself */
763 if(!strcmp(name, myself->name))
765 syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
766 cl->name, cl->hostname);
772 /* Check if the owner of the new subnet is in the connection list */
774 if(!(owner = lookup_id(name)))
776 syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
777 name, cl->name, cl->hostname);
782 /* If everything is correct, delete the subnet from the list of the owner */
788 for(p = conn_list; p; p = p->next)
789 if(p->status.meta && p->status.active && p!= cl)
790 send_del_subnet(p, subnet);
795 /* New and closed connections notification */
797 int send_add_host(conn_list_t *cl, conn_list_t *other)
800 return send_request(cl, "%d %s %lx:%d %lx", ADD_HOST,
801 other->name, other->address, other->port, other->options);
804 int add_host_h(conn_list_t *cl)
806 conn_list_t *old, *new;
810 new = new_conn_list();
812 if(sscanf(cl->buffer, "%*d %as %lx:%d %lx", &new->name, &new->address, &new->port, &new->options) != 4)
814 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
818 /* Check if identity is a valid name */
820 if(check_id(new->name))
822 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
827 /* Check if somebody tries to add ourself */
829 if(!strcmp(new->name, myself->name))
831 syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
837 /* Fill in more of the new conn_list structure */
839 new->hostname = hostlookup(htonl(new->address));
841 /* Check if the new host already exists in the connnection list */
843 if((old = lookup_id(new->name)))
845 if((new->address == old->address) && (new->port == old->port))
847 if(debug_lvl >= DEBUG_CONNECTIONS)
848 syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
849 old->name, old->hostname, new->name, new->hostname);
855 if(debug_lvl >= DEBUG_CONNECTIONS)
856 syslog(LOG_NOTICE, _("Removing old entry for %s (%s) in favour of new connection"),
857 old->name, old->hostname);
859 terminate_connection(old);
863 /* Hook it up into the conn_list */
867 /* Tell the rest about the new host */
869 for(p = conn_list; p; p = p->next)
870 if(p->status.meta && p->status.active && p!=cl)
871 send_add_host(p, new);
873 /* Fill in rest of conn_list structure */
876 new->status.active = 1;
877 new->cipher_pkttype = EVP_bf_cfb();
878 new->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
880 /* Okay this is a bit ugly... it would be better to setup UDP sockets dynamically, or
881 * perhaps just one UDP socket... but then again, this has benefits too...
884 setup_vpn_connection(new);
889 int send_del_host(conn_list_t *cl, conn_list_t *other)
892 return send_request(cl, "%d %s %lx:%d %lx", DEL_HOST,
893 other->name, other->address, other->port, other->options);
896 int del_host_h(conn_list_t *cl)
902 conn_list_t *old, *p;
904 if(sscanf(cl->buffer, "%*d %as %lx:%d %lx", &name, &address, &port, &options) != 4)
906 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
907 cl->name, cl->hostname);
911 /* Check if identity is a valid name */
915 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
920 /* Check if somebody tries to delete ourself */
922 if(!strcmp(name, myself->name))
924 syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
925 cl->name, cl->hostname);
931 /* Check if the new host already exists in the connnection list */
933 if(!(old = lookup_id(name)))
935 syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
936 name, cl->name, cl->hostname);
941 /* Check if the rest matches */
943 if(address!=old->address || port!=old->port || options!=old->options || cl!=old->nexthop)
945 syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
949 /* Ok, since EVERYTHING seems to check out all right, delete it */
951 old->status.active = 0;
952 terminate_connection(old);
954 /* Tell the rest about the new host */
956 for(p = conn_list; p; p = p->next)
957 if(p->status.meta && p->status.active && p!=cl)
958 send_del_host(p, old);
963 /* Status and error notification routines */
965 int send_status(conn_list_t *cl, int statusno, char *statusstring)
969 statusstring = status_text[statusno];
971 return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
974 int status_h(conn_list_t *cl)
979 if(sscanf(cl->buffer, "%*d %d %as", &statusno, &statusstring) != 2)
981 syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
982 cl->name, cl->hostname);
986 if(debug_lvl >= DEBUG_STATUS)
988 syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
989 cl->name, cl->hostname, status_text[statusno], statusstring);
997 int send_error(conn_list_t *cl, int errno, char *errstring)
1001 errstring = strerror(errno);
1002 return send_request(cl, "%d %d %s", ERROR, errno, errstring);
1005 int error_h(conn_list_t *cl)
1010 if(sscanf(cl->buffer, "%*d %d %as", &errno, &errorstring) != 2)
1012 syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
1013 cl->name, cl->hostname);
1017 if(debug_lvl >= DEBUG_ERROR)
1019 syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
1020 cl->name, cl->hostname, strerror(errno), errorstring);
1024 terminate_connection(cl);
1029 int send_termreq(conn_list_t *cl)
1032 return send_request(cl, "%d", TERMREQ);
1035 int termreq_h(conn_list_t *cl)
1038 terminate_connection(cl);
1043 /* Keepalive routines - FIXME: needs a closer look */
1045 int send_ping(conn_list_t *cl)
1048 cl->status.pinged = 1;
1049 cl->last_ping_time = time(NULL);
1051 return send_request(cl, "%d", PING);
1054 int ping_h(conn_list_t *cl)
1057 return send_pong(cl);
1060 int send_pong(conn_list_t *cl)
1063 return send_request(cl, "%d", PONG);
1066 int pong_h(conn_list_t *cl)
1069 cl->status.pinged = 0;
1076 int send_key_changed(conn_list_t *from, conn_list_t *cl)
1080 for(p = conn_list; p != NULL; p = p->next)
1082 if(p!=cl && p->status.meta && p->status.active)
1083 send_request(p, "%d %s", KEY_CHANGED,
1090 int key_changed_h(conn_list_t *cl)
1095 if(sscanf(cl->buffer, "%*d %as", &from_id) != 1)
1097 syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
1098 cl->name, cl->hostname);
1102 if(!(from = lookup_id(from_id)))
1104 syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
1105 cl->name, cl->hostname, from_id);
1112 from->status.validkey = 0;
1113 from->status.waitingforkey = 0;
1115 send_key_changed(from, cl);
1120 int send_req_key(conn_list_t *from, conn_list_t *to)
1123 return send_request(to->nexthop, "%d %s %s", REQ_KEY,
1124 from->name, to->name);
1127 int req_key_h(conn_list_t *cl)
1129 char *from_id, *to_id;
1130 conn_list_t *from, *to;
1133 if(sscanf(cl->buffer, "%*d %as %as", &from_id, &to_id) != 2)
1135 syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
1136 cl->name, cl->hostname);
1140 if(!(from = lookup_id(from_id)))
1142 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
1143 cl->name, cl->hostname, from_id);
1144 free(from_id); free(to_id);
1148 /* Check if this key request is for us */
1150 if(!strcmp(to_id, myself->name))
1152 bin2hex(myself->cipher_pktkey, pktkey, myself->cipher_pktkeylength);
1153 pktkey[myself->cipher_pktkeylength*2] = '\0';
1154 send_ans_key(myself, from, pktkey);
1158 if(!(to = lookup_id(to_id)))
1160 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
1161 cl->name, cl->hostname, to_id);
1162 free(from_id); free(to_id);
1166 if(to->status.validkey) /* Proxy keys */
1168 bin2hex(to->cipher_pktkey, pktkey, to->cipher_pktkeylength);
1169 pktkey[to->cipher_pktkeylength*2] = '\0';
1170 send_ans_key(to, from, pktkey);
1173 send_req_key(from, to);
1176 free(from_id); free(to_id);
1181 int send_ans_key(conn_list_t *from, conn_list_t *to, char *pktkey)
1184 return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
1185 from->name, to->name, pktkey);
1188 int ans_key_h(conn_list_t *cl)
1190 char *from_id, *to_id, *pktkey;
1192 conn_list_t *from, *to;
1194 if(sscanf(cl->buffer, "%*d %as %as %as", &from_id, &to_id, &pktkey) != 3)
1196 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
1197 cl->name, cl->hostname);
1201 if(!(from = lookup_id(from_id)))
1203 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
1204 cl->name, cl->hostname, from_id);
1205 free(from_id); free(to_id); free(pktkey);
1209 /* Check correctness of packet key */
1211 keylength = strlen(pktkey);
1213 if(keylength != from->cipher_pktkeylength*2)
1215 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key length"),
1216 cl->name, cl->hostname, from->name);
1217 free(from_id); free(to_id); free(pktkey);
1221 /* Forward it if necessary */
1223 if(strcmp(to_id, myself->name))
1225 if(!(to = lookup_id(to_id)))
1227 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1228 cl->name, cl->hostname, to_id);
1229 free(from_id); free(to_id);
1232 send_ans_key(from, to, pktkey);
1235 /* Update our copy of the origin's packet key */
1237 if(from->cipher_pktkey)
1238 free(from->cipher_pktkey);
1241 hex2bin(pktkey, pktkey, keylength);
1242 pktkey[keylength] = '\0';
1243 from->cipher_pktkey = pktkey;
1245 from->status.validkey = 1;
1246 from->status.waitingforkey = 0;
1248 free(from_id); free(to_id);
1253 /* Jumptable for the request handlers */
1255 int (*request_handlers[])(conn_list_t*) = {
1256 id_h, challenge_h, chal_reply_h, metakey_h, ack_h,
1257 status_h, error_h, termreq_h,
1259 add_host_h, del_host_h,
1260 add_subnet_h, del_subnet_h,
1261 key_changed_h, req_key_h, ans_key_h,
1266 char (*request_name[]) = {
1267 "ID", "CHALLENGE", "CHAL_REPLY", "METAKEY", "ACK",
1268 "STATUS", "ERROR", "TERMREQ",
1270 "ADD_HOST", "DEL_HOST",
1271 "ADD_SUBNET", "DEL_SUBNET",
1272 "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1275 /* Status strings */
1277 char (*status_text[]) = {
1283 char (*error_text[]) = {