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.60 2000/11/15 01:06:11 zarq Exp $
25 #include <sys/types.h>
30 #include <sys/socket.h>
37 #include <netinet/in.h>
39 #ifdef HAVE_OPENSSL_SHA_H
40 # include <openssl/sha.h>
45 #ifdef HAVE_OPENSSL_RAND_H
46 # include <openssl/rand.h>
51 #ifdef HAVE_OPENSSL_EVP_H
52 # include <openssl/evp.h>
67 int check_id(char *id)
71 for (i = 0; i < strlen(id); i++)
72 if(!isalnum(id[i]) && id[i] != '_')
78 /* Generic request routines - takes care of logging and error detection as well */
80 int send_request(conn_list_t *cl, const char *format, ...)
83 char buffer[MAXBUFSIZE];
87 /* Use vsnprintf instead of vasprintf: faster, no memory fragmentation, cleanup is automatic,
88 and there is a limit on the input buffer anyway */
90 va_start(args, format);
91 len = vsnprintf(buffer, MAXBUFSIZE, format, args);
92 request = va_arg(args, int);
95 if(len < 0 || len > MAXBUFSIZE-1)
97 syslog(LOG_ERR, _("Output buffer overflow while sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
103 if(debug_lvl >= DEBUG_PROTOCOL)
104 syslog(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
107 return send_meta(cl, buffer, len);
110 int receive_request(conn_list_t *cl)
114 if(sscanf(cl->buffer, "%d", &request) == 1)
116 if((request < 0) || (request > 255) || (request_handlers[request] == NULL))
118 syslog(LOG_ERR, _("Unknown request from %s (%s)"),
119 cl->name, cl->hostname);
124 if(debug_lvl >= DEBUG_PROTOCOL)
125 syslog(LOG_DEBUG, _("Got %s from %s (%s)"),
126 request_name[request], cl->name, cl->hostname);
129 if((cl->allow_request != ALL) && (cl->allow_request != request))
131 syslog(LOG_ERR, _("Unauthorized request from %s (%s)"), cl->name, cl->hostname);
135 if(request_handlers[request](cl))
136 /* Something went wrong. Probably scriptkiddies. Terminate. */
138 syslog(LOG_ERR, _("Error while processing %s from %s (%s)"),
139 request_name[request], cl->name, cl->hostname);
145 syslog(LOG_ERR, _("Bogus data received from %s (%s)"),
146 cl->name, cl->hostname);
153 /* Connection protocol:
162 ---------------------------------------
165 ---------------------------------------
168 ---------------------------------------
174 (E) Encrypted with symmetric cipher.
176 Part of the challenge is directly used to set the symmetric cipher key and the initial vector.
177 Since a man-in-the-middle cannot decrypt the RSA challenges, this means that he cannot get or
178 forge the key for the symmetric cipher.
181 int send_id(conn_list_t *cl)
184 cl->allow_request = CHALLENGE;
186 return send_request(cl, "%d %s %d %lx %hd", ID, myself->name, myself->protocol_version, myself->options, myself->port);
189 int id_h(conn_list_t *cl)
194 if(sscanf(cl->buffer, "%*d %as %d %lx %hd", &cl->name, &cl->protocol_version, &cl->options, &cl->port) != 4)
196 syslog(LOG_ERR, _("Got bad ID from %s"), cl->hostname);
200 /* Check if version matches */
202 if(cl->protocol_version != myself->protocol_version)
204 syslog(LOG_ERR, _("Peer %s (%s) uses incompatible version %d"),
205 cl->name, cl->hostname, cl->protocol_version);
209 /* Check if identity is a valid name */
211 if(check_id(cl->name))
213 syslog(LOG_ERR, _("Peer %s uses invalid identity name"), cl->hostname);
217 /* Load information about peer */
219 if(read_host_config(cl))
221 syslog(LOG_ERR, _("Peer %s had unknown identity (%s)"), cl->hostname, cl->name);
225 /* First check if the host we connected to is already in our
226 connection list. If so, we are probably making a loop, which
230 if(cl->status.outgoing)
232 if((old = lookup_id(cl->name)))
234 if(debug_lvl >= DEBUG_CONNECTIONS)
235 syslog(LOG_NOTICE, _("Uplink %s (%s) is already in our connection list"), cl->name, cl->hostname);
236 cl->status.outgoing = 0;
237 old->status.outgoing = 1;
238 terminate_connection(cl);
243 if((cfg = get_config_val(cl->config, config_publickey)))
245 cl->rsa_key = RSA_new();
246 BN_hex2bn(&cl->rsa_key->n, cfg->data.ptr);
247 BN_hex2bn(&cl->rsa_key->e, "FFFF");
251 syslog(LOG_ERR, _("No public key known for %s (%s)"), cl->name, cl->hostname);
255 return send_challenge(cl);
258 int send_challenge(conn_list_t *cl)
263 len = RSA_size(cl->rsa_key);
265 /* Allocate buffers for the challenge */
267 buffer = xmalloc(len*2+1);
270 free(cl->hischallenge);
272 cl->hischallenge = xmalloc(len);
274 /* Copy random data to the buffer */
276 RAND_bytes(cl->hischallenge, len);
278 cl->hischallenge[0] &= 0x7F; /* Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
280 if(debug_lvl >= DEBUG_SCARY_THINGS)
282 bin2hex(cl->hischallenge, buffer, len);
283 buffer[len*2] = '\0';
284 syslog(LOG_DEBUG, _("Generated random challenge (unencrypted): %s"), buffer);
287 /* Encrypt the random data */
289 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 */
291 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
296 /* Convert the encrypted random data to a hexadecimal formatted string */
298 bin2hex(buffer, buffer, len);
299 buffer[len*2] = '\0';
301 /* Send the challenge */
303 cl->allow_request = CHAL_REPLY;
304 x = send_request(cl, "%d %s", CHALLENGE, buffer);
310 int challenge_h(conn_list_t *cl)
315 if(sscanf(cl->buffer, "%*d %as", &buffer) != 1)
317 syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
321 len = RSA_size(myself->rsa_key);
323 /* Check if the length of the challenge is all right */
325 if(strlen(buffer) != len*2)
327 syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
332 /* Allocate buffers for the challenge */
335 cl->mychallenge = xmalloc(len);
337 /* Convert the challenge from hexadecimal back to binary */
339 hex2bin(buffer,buffer,len);
341 /* Decrypt the challenge */
343 if(RSA_private_decrypt(len, buffer, cl->mychallenge, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
345 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
350 if(debug_lvl >= DEBUG_SCARY_THINGS)
352 bin2hex(cl->mychallenge, buffer, len);
353 buffer[len*2] = '\0';
354 syslog(LOG_DEBUG, _("Received random challenge (unencrypted): %s"), buffer);
359 /* Rest is done by send_chal_reply() */
361 return send_chal_reply(cl);
364 int send_chal_reply(conn_list_t *cl)
366 char hash[SHA_DIGEST_LENGTH*2+1];
370 syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
374 /* Calculate the hash from the challenge we received */
376 SHA1(cl->mychallenge, RSA_size(myself->rsa_key), hash);
378 /* Convert the hash to a hexadecimal formatted string */
380 bin2hex(hash,hash,SHA_DIGEST_LENGTH);
381 hash[SHA_DIGEST_LENGTH*2] = '\0';
385 if(cl->status.outgoing)
386 cl->allow_request = ID;
388 cl->allow_request = METAKEY;
391 return send_request(cl, "%d %s", CHAL_REPLY, hash);
394 int chal_reply_h(conn_list_t *cl)
397 char myhash[SHA_DIGEST_LENGTH];
399 if(sscanf(cl->buffer, "%*d %as", &hishash) != 1)
401 syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
406 /* Check if the length of the hash is all right */
408 if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
410 syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
415 /* Convert the hash to binary format */
417 hex2bin(hishash, hishash, SHA_DIGEST_LENGTH);
419 /* Calculate the hash from the challenge we sent */
421 SHA1(cl->hischallenge, RSA_size(cl->rsa_key), myhash);
423 /* Verify the incoming hash with the calculated hash */
425 if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
427 syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
428 if(debug_lvl >= DEBUG_SCARY_THINGS)
430 bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
431 hishash[SHA_DIGEST_LENGTH*2] = '\0';
432 syslog(LOG_DEBUG, _("Expected challenge reply: %s"), hishash);
441 /* Identity has now been positively verified.
442 If we are accepting this new connection, then send our identity,
443 if we are making this connecting, acknowledge.
446 if(cl->status.outgoing)
447 return send_metakey(cl);
452 int send_metakey(conn_list_t *cl)
457 len = RSA_size(cl->rsa_key);
459 /* Allocate buffers for the meta key */
461 buffer = xmalloc(len*2+1);
463 if(!cl->cipher_outkey)
464 cl->cipher_outkey = xmalloc(len);
466 if(!cl->cipher_outctx)
467 cl->cipher_outctx = xmalloc(sizeof(*cl->cipher_outctx));
469 /* Copy random data to the buffer */
471 RAND_bytes(cl->cipher_outkey, len);
473 cl->cipher_outkey[0] &= 0x7F; /* FIXME: Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
475 if(debug_lvl >= DEBUG_SCARY_THINGS)
477 bin2hex(cl->cipher_outkey, buffer, len);
478 buffer[len*2] = '\0';
479 syslog(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"), buffer);
482 /* Encrypt the random data */
484 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 */
486 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
491 /* Convert the encrypted random data to a hexadecimal formatted string */
493 bin2hex(buffer, buffer, len);
494 buffer[len*2] = '\0';
496 /* Send the meta key */
498 if(cl->status.outgoing)
499 cl->allow_request = METAKEY;
501 cl->allow_request = ACK;
503 x = send_request(cl, "%d %s", METAKEY, buffer);
506 EVP_EncryptInit(cl->cipher_outctx, EVP_bf_cfb(), cl->cipher_outkey, cl->cipher_outkey + EVP_bf_cfb()->key_len);
511 int metakey_h(conn_list_t *cl)
516 if(sscanf(cl->buffer, "%*d %as", &buffer) != 1)
518 syslog(LOG_ERR, _("Got bad METAKEY from %s (%s)"), cl->name, cl->hostname);
522 len = RSA_size(myself->rsa_key);
524 /* Check if the length of the meta key is all right */
526 if(strlen(buffer) != len*2)
528 syslog(LOG_ERR, _("Intruder: wrong meta key length from %s (%s)"), cl->name, cl->hostname);
533 /* Allocate buffers for the meta key */
535 if(!cl->cipher_inkey)
536 cl->cipher_inkey = xmalloc(len);
538 if(!cl->cipher_inctx)
539 cl->cipher_inctx = xmalloc(sizeof(*cl->cipher_inctx));
541 /* Convert the challenge from hexadecimal back to binary */
543 hex2bin(buffer,buffer,len);
545 /* Decrypt the meta key */
547 if(RSA_private_decrypt(len, buffer, cl->cipher_inkey, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
549 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
554 if(debug_lvl >= DEBUG_SCARY_THINGS)
556 bin2hex(cl->cipher_inkey, buffer, len);
557 buffer[len*2] = '\0';
558 syslog(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), buffer);
563 EVP_DecryptInit(cl->cipher_inctx, EVP_bf_cfb(), cl->cipher_inkey, cl->cipher_inkey + EVP_bf_cfb()->key_len);
566 if(cl->status.outgoing)
569 return send_metakey(cl);
572 int send_ack(conn_list_t *cl)
576 if(cl->status.outgoing)
577 cl->allow_request = ACK;
579 setup_vpn_connection(cl);
581 x = send_request(cl, "%d", ACK);
582 cl->status.encryptout = 1;
587 int ack_h(conn_list_t *cl)
589 conn_list_t *old, *p;
592 /* Okay, before we active the connection, we check if there is another entry
593 in the connection list with the same name. If so, it presumably is an
594 old connection that has timed out but we don't know it yet.
597 while((old = lookup_id(cl->name)))
599 if(debug_lvl >= DEBUG_CONNECTIONS)
600 syslog(LOG_NOTICE, _("Removing old entry for %s at %s in favour of new connection from %s"),
601 cl->name, old->hostname, cl->hostname);
603 terminate_connection(old);
606 /* Activate this connection */
608 cl->allow_request = ALL;
609 cl->status.active = 1;
610 cl->status.decryptin = 1;
612 cl->cipher_pkttype = EVP_bf_cfb();
613 cl->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
615 if(debug_lvl >= DEBUG_CONNECTIONS)
616 syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname);
619 if(!cl->status.outgoing)
622 /* Send him our subnets */
624 for(s = myself->subnets; s; s = s->next)
625 send_add_subnet(cl, s);
627 /* And send him all the hosts and their subnets we know... */
629 for(p = conn_list; p; p = p->next)
630 if(p != cl && p->status.active)
632 /* Notify others of this connection */
635 send_add_host(p, cl);
637 /* Notify new connection of everything we know */
639 send_add_host(cl, p);
641 for(s = p->subnets; s; s = s->next)
642 send_add_subnet(cl, s);
648 /* Address and subnet information exchange */
650 int send_add_subnet(conn_list_t *cl, subnet_t *subnet)
655 x = send_request(cl, "%d %s %s", ADD_SUBNET,
656 subnet->owner->name, netstr = net2str(subnet));
662 int add_subnet_h(conn_list_t *cl)
666 conn_list_t *owner, *p;
669 if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 2)
671 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
672 free(name); free(subnetstr);
676 /* Check if owner name is a valid */
680 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
681 free(name); free(subnetstr);
685 /* Check if subnet string is valid */
687 if(!(subnet = str2net(subnetstr)))
689 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
690 free(name); free(subnetstr);
696 /* Check if somebody tries to add a subnet of ourself */
698 if(!strcmp(name, myself->name))
700 syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
701 cl->name, cl->hostname);
707 /* Check if the owner of the new subnet is in the connection list */
709 if(!(owner = lookup_id(name)))
711 syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
712 name, cl->name, cl->hostname);
717 /* If everything is correct, add the subnet to the list of the owner */
719 subnet_add(owner, subnet);
723 for(p = conn_list; p; p = p->next)
724 if(p->status.meta && p->status.active && p!= cl)
725 send_add_subnet(p, subnet);
730 int send_del_subnet(conn_list_t *cl, subnet_t *subnet)
735 netstr = net2str(subnet);
736 x = send_request(cl, "%d %s %s", DEL_SUBNET, subnet->owner->name, netstr);
742 int del_subnet_h(conn_list_t *cl)
746 conn_list_t *owner, *p;
749 if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
751 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
752 free(name); free(subnetstr);
756 /* Check if owner name is a valid */
760 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
761 free(name); free(subnetstr);
765 /* Check if subnet string is valid */
767 if(!(subnet = str2net(subnetstr)))
769 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
770 free(name); free(subnetstr);
776 /* Check if somebody tries to add a subnet of ourself */
778 if(!strcmp(name, myself->name))
780 syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
781 cl->name, cl->hostname);
787 /* Check if the owner of the new subnet is in the connection list */
789 if(!(owner = lookup_id(name)))
791 syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
792 name, cl->name, cl->hostname);
797 /* If everything is correct, delete the subnet from the list of the owner */
803 for(p = conn_list; p; p = p->next)
804 if(p->status.meta && p->status.active && p!= cl)
805 send_del_subnet(p, subnet);
810 /* New and closed connections notification */
812 int send_add_host(conn_list_t *cl, conn_list_t *other)
815 return send_request(cl, "%d %s %lx:%d %lx", ADD_HOST,
816 other->name, other->address, other->port, other->options);
819 int add_host_h(conn_list_t *cl)
821 conn_list_t *old, *new;
825 new = new_conn_list();
827 if(sscanf(cl->buffer, "%*d %as %lx:%d %lx", &new->name, &new->address, &new->port, &new->options) != 4)
829 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
833 /* Check if identity is a valid name */
835 if(check_id(new->name))
837 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
842 /* Check if somebody tries to add ourself */
844 if(!strcmp(new->name, myself->name))
846 syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
852 /* Fill in more of the new conn_list structure */
854 new->hostname = hostlookup(htonl(new->address));
856 /* Check if the new host already exists in the connnection list */
858 if((old = lookup_id(new->name)))
860 if((new->address == old->address) && (new->port == old->port))
862 if(debug_lvl >= DEBUG_CONNECTIONS)
863 syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
864 old->name, old->hostname, new->name, new->hostname);
870 if(debug_lvl >= DEBUG_CONNECTIONS)
871 syslog(LOG_NOTICE, _("Removing old entry for %s (%s) in favour of new connection"),
872 old->name, old->hostname);
874 terminate_connection(old);
878 /* Hook it up into the conn_list */
882 /* Tell the rest about the new host */
884 for(p = conn_list; p; p = p->next)
885 if(p->status.meta && p->status.active && p!=cl)
886 send_add_host(p, new);
888 /* Fill in rest of conn_list structure */
891 new->status.active = 1;
892 new->cipher_pkttype = EVP_bf_cfb();
893 new->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
895 /* Okay this is a bit ugly... it would be better to setup UDP sockets dynamically, or
896 * perhaps just one UDP socket... but then again, this has benefits too...
899 setup_vpn_connection(new);
904 int send_del_host(conn_list_t *cl, conn_list_t *other)
907 return send_request(cl, "%d %s %lx:%d %lx", DEL_HOST,
908 other->name, other->address, other->port, other->options);
911 int del_host_h(conn_list_t *cl)
917 conn_list_t *old, *p;
919 if(sscanf(cl->buffer, "%*d %as %lx:%d %lx", &name, &address, &port, &options) != 4)
921 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
922 cl->name, cl->hostname);
926 /* Check if identity is a valid name */
930 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
935 /* Check if somebody tries to delete ourself */
937 if(!strcmp(name, myself->name))
939 syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
940 cl->name, cl->hostname);
946 /* Check if the new host already exists in the connnection list */
948 if(!(old = lookup_id(name)))
950 syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
951 name, cl->name, cl->hostname);
956 /* Check if the rest matches */
958 if(address!=old->address || port!=old->port || options!=old->options || cl!=old->nexthop)
960 syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
964 /* Ok, since EVERYTHING seems to check out all right, delete it */
966 old->status.active = 0;
967 terminate_connection(old);
969 /* Tell the rest about the new host */
971 for(p = conn_list; p; p = p->next)
972 if(p->status.meta && p->status.active && p!=cl)
973 send_del_host(p, old);
978 /* Status and error notification routines */
980 int send_status(conn_list_t *cl, int statusno, char *statusstring)
984 statusstring = status_text[statusno];
986 return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
989 int status_h(conn_list_t *cl)
994 if(sscanf(cl->buffer, "%*d %d %as", &statusno, &statusstring) != 2)
996 syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
997 cl->name, cl->hostname);
1001 if(debug_lvl >= DEBUG_STATUS)
1003 syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
1004 cl->name, cl->hostname, status_text[statusno], statusstring);
1012 int send_error(conn_list_t *cl, int errno, char *errstring)
1016 errstring = strerror(errno);
1017 return send_request(cl, "%d %d %s", ERROR, errno, errstring);
1020 int error_h(conn_list_t *cl)
1025 if(sscanf(cl->buffer, "%*d %d %as", &errno, &errorstring) != 2)
1027 syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
1028 cl->name, cl->hostname);
1032 if(debug_lvl >= DEBUG_ERROR)
1034 syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
1035 cl->name, cl->hostname, strerror(errno), errorstring);
1039 terminate_connection(cl);
1044 int send_termreq(conn_list_t *cl)
1047 return send_request(cl, "%d", TERMREQ);
1050 int termreq_h(conn_list_t *cl)
1053 terminate_connection(cl);
1058 /* Keepalive routines - FIXME: needs a closer look */
1060 int send_ping(conn_list_t *cl)
1063 cl->status.pinged = 1;
1064 cl->last_ping_time = time(NULL);
1066 return send_request(cl, "%d", PING);
1069 int ping_h(conn_list_t *cl)
1072 return send_pong(cl);
1075 int send_pong(conn_list_t *cl)
1078 return send_request(cl, "%d", PONG);
1081 int pong_h(conn_list_t *cl)
1084 cl->status.pinged = 0;
1091 int send_key_changed(conn_list_t *from, conn_list_t *cl)
1095 for(p = conn_list; p != NULL; p = p->next)
1097 if(p!=cl && p->status.meta && p->status.active)
1098 send_request(p, "%d %s", KEY_CHANGED,
1105 int key_changed_h(conn_list_t *cl)
1110 if(sscanf(cl->buffer, "%*d %as", &from_id) != 1)
1112 syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
1113 cl->name, cl->hostname);
1117 if(!(from = lookup_id(from_id)))
1119 syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
1120 cl->name, cl->hostname, from_id);
1127 from->status.validkey = 0;
1128 from->status.waitingforkey = 0;
1130 send_key_changed(from, cl);
1135 int send_req_key(conn_list_t *from, conn_list_t *to)
1138 return send_request(to->nexthop, "%d %s %s", REQ_KEY,
1139 from->name, to->name);
1142 int req_key_h(conn_list_t *cl)
1144 char *from_id, *to_id;
1145 conn_list_t *from, *to;
1148 if(sscanf(cl->buffer, "%*d %as %as", &from_id, &to_id) != 2)
1150 syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
1151 cl->name, cl->hostname);
1155 if(!(from = lookup_id(from_id)))
1157 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
1158 cl->name, cl->hostname, from_id);
1159 free(from_id); free(to_id);
1163 /* Check if this key request is for us */
1165 if(!strcmp(to_id, myself->name))
1167 bin2hex(myself->cipher_pktkey, pktkey, myself->cipher_pktkeylength);
1168 pktkey[myself->cipher_pktkeylength*2] = '\0';
1169 send_ans_key(myself, from, pktkey);
1173 if(!(to = lookup_id(to_id)))
1175 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
1176 cl->name, cl->hostname, to_id);
1177 free(from_id); free(to_id);
1181 if(to->status.validkey) /* Proxy keys */
1183 bin2hex(to->cipher_pktkey, pktkey, to->cipher_pktkeylength);
1184 pktkey[to->cipher_pktkeylength*2] = '\0';
1185 send_ans_key(to, from, pktkey);
1188 send_req_key(from, to);
1191 free(from_id); free(to_id);
1196 int send_ans_key(conn_list_t *from, conn_list_t *to, char *pktkey)
1199 return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
1200 from->name, to->name, pktkey);
1203 int ans_key_h(conn_list_t *cl)
1205 char *from_id, *to_id, *pktkey;
1207 conn_list_t *from, *to;
1209 if(sscanf(cl->buffer, "%*d %as %as %as", &from_id, &to_id, &pktkey) != 3)
1211 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
1212 cl->name, cl->hostname);
1216 if(!(from = lookup_id(from_id)))
1218 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
1219 cl->name, cl->hostname, from_id);
1220 free(from_id); free(to_id); free(pktkey);
1224 /* Check correctness of packet key */
1226 keylength = strlen(pktkey);
1228 if(keylength != from->cipher_pktkeylength*2)
1230 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key length"),
1231 cl->name, cl->hostname, from->name);
1232 free(from_id); free(to_id); free(pktkey);
1236 /* Forward it if necessary */
1238 if(strcmp(to_id, myself->name))
1240 if(!(to = lookup_id(to_id)))
1242 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1243 cl->name, cl->hostname, to_id);
1244 free(from_id); free(to_id);
1247 send_ans_key(from, to, pktkey);
1250 /* Update our copy of the origin's packet key */
1252 if(from->cipher_pktkey)
1253 free(from->cipher_pktkey);
1256 hex2bin(pktkey, pktkey, keylength);
1257 pktkey[keylength] = '\0';
1258 from->cipher_pktkey = pktkey;
1260 from->status.validkey = 1;
1261 from->status.waitingforkey = 0;
1263 free(from_id); free(to_id);
1268 /* Jumptable for the request handlers */
1270 int (*request_handlers[])(conn_list_t*) = {
1271 id_h, challenge_h, chal_reply_h, metakey_h, ack_h,
1272 status_h, error_h, termreq_h,
1274 add_host_h, del_host_h,
1275 add_subnet_h, del_subnet_h,
1276 key_changed_h, req_key_h, ans_key_h,
1281 char (*request_name[]) = {
1282 "ID", "CHALLENGE", "CHAL_REPLY", "METAKEY", "ACK",
1283 "STATUS", "ERROR", "TERMREQ",
1285 "ADD_HOST", "DEL_HOST",
1286 "ADD_SUBNET", "DEL_SUBNET",
1287 "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1290 /* Status strings */
1292 char (*status_text[]) = {
1298 char (*error_text[]) = {