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.61 2000/11/15 13:33:27 guus Exp $
25 #include <sys/types.h>
30 #include <sys/socket.h>
38 #include <netinet/in.h>
40 #ifdef HAVE_OPENSSL_SHA_H
41 # include <openssl/sha.h>
46 #ifdef HAVE_OPENSSL_RAND_H
47 # include <openssl/rand.h>
52 #ifdef HAVE_OPENSSL_EVP_H
53 # include <openssl/evp.h>
68 int check_id(char *id)
72 for (i = 0; i < strlen(id); i++)
73 if(!isalnum(id[i]) && id[i] != '_')
79 /* Generic request routines - takes care of logging and error detection as well */
81 int send_request(conn_list_t *cl, const char *format, ...)
84 char buffer[MAXBUFSIZE];
88 /* Use vsnprintf instead of vasprintf: faster, no memory fragmentation, cleanup is automatic,
89 and there is a limit on the input buffer anyway */
91 va_start(args, format);
92 len = vsnprintf(buffer, MAXBUFSIZE, format, args);
93 request = va_arg(args, int);
96 if(len < 0 || len > MAXBUFSIZE-1)
98 syslog(LOG_ERR, _("Output buffer overflow while sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
104 if(debug_lvl >= DEBUG_PROTOCOL)
105 syslog(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
108 return send_meta(cl, buffer, len);
111 int receive_request(conn_list_t *cl)
115 if(sscanf(cl->buffer, "%d", &request) == 1)
117 if((request < 0) || (request > 255) || (request_handlers[request] == NULL))
119 syslog(LOG_ERR, _("Unknown request from %s (%s)"),
120 cl->name, cl->hostname);
125 if(debug_lvl >= DEBUG_PROTOCOL)
126 syslog(LOG_DEBUG, _("Got %s from %s (%s)"),
127 request_name[request], cl->name, cl->hostname);
130 if((cl->allow_request != ALL) && (cl->allow_request != request))
132 syslog(LOG_ERR, _("Unauthorized request from %s (%s)"), cl->name, cl->hostname);
136 if(request_handlers[request](cl))
137 /* Something went wrong. Probably scriptkiddies. Terminate. */
139 syslog(LOG_ERR, _("Error while processing %s from %s (%s)"),
140 request_name[request], cl->name, cl->hostname);
146 syslog(LOG_ERR, _("Bogus data received from %s (%s)"),
147 cl->name, cl->hostname);
154 /* Connection protocol:
163 ---------------------------------------
166 ---------------------------------------
169 ---------------------------------------
175 (E) Encrypted with symmetric cipher.
177 Part of the challenge is directly used to set the symmetric cipher key and the initial vector.
178 Since a man-in-the-middle cannot decrypt the RSA challenges, this means that he cannot get or
179 forge the key for the symmetric cipher.
182 int send_id(conn_list_t *cl)
185 cl->allow_request = CHALLENGE;
187 return send_request(cl, "%d %s %d %lx %hd", ID, myself->name, myself->protocol_version, myself->options, myself->port);
190 int id_h(conn_list_t *cl)
195 if(sscanf(cl->buffer, "%*d %as %d %lx %hd", &cl->name, &cl->protocol_version, &cl->options, &cl->port) != 4)
197 syslog(LOG_ERR, _("Got bad ID from %s"), cl->hostname);
201 /* Check if version matches */
203 if(cl->protocol_version != myself->protocol_version)
205 syslog(LOG_ERR, _("Peer %s (%s) uses incompatible version %d"),
206 cl->name, cl->hostname, cl->protocol_version);
210 /* Check if identity is a valid name */
212 if(check_id(cl->name))
214 syslog(LOG_ERR, _("Peer %s uses invalid identity name"), cl->hostname);
218 /* Load information about peer */
220 if(read_host_config(cl))
222 syslog(LOG_ERR, _("Peer %s had unknown identity (%s)"), cl->hostname, cl->name);
226 /* First check if the host we connected to is already in our
227 connection list. If so, we are probably making a loop, which
231 if(cl->status.outgoing)
233 if((old = lookup_id(cl->name)))
235 if(debug_lvl >= DEBUG_CONNECTIONS)
236 syslog(LOG_NOTICE, _("Uplink %s (%s) is already in our connection list"), cl->name, cl->hostname);
237 cl->status.outgoing = 0;
238 old->status.outgoing = 1;
239 terminate_connection(cl);
244 if((cfg = get_config_val(cl->config, config_publickey)))
246 cl->rsa_key = RSA_new();
247 BN_hex2bn(&cl->rsa_key->n, cfg->data.ptr);
248 BN_hex2bn(&cl->rsa_key->e, "FFFF");
252 syslog(LOG_ERR, _("No public key known for %s (%s)"), cl->name, cl->hostname);
256 return send_challenge(cl);
259 int send_challenge(conn_list_t *cl)
264 len = RSA_size(cl->rsa_key);
266 /* Allocate buffers for the challenge */
268 buffer = xmalloc(len*2+1);
271 free(cl->hischallenge);
273 cl->hischallenge = xmalloc(len);
275 /* Copy random data to the buffer */
277 RAND_bytes(cl->hischallenge, len);
279 cl->hischallenge[0] &= 0x7F; /* Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
281 if(debug_lvl >= DEBUG_SCARY_THINGS)
283 bin2hex(cl->hischallenge, buffer, len);
284 buffer[len*2] = '\0';
285 syslog(LOG_DEBUG, _("Generated random challenge (unencrypted): %s"), buffer);
288 /* Encrypt the random data */
290 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 */
292 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
297 /* Convert the encrypted random data to a hexadecimal formatted string */
299 bin2hex(buffer, buffer, len);
300 buffer[len*2] = '\0';
302 /* Send the challenge */
304 cl->allow_request = CHAL_REPLY;
305 x = send_request(cl, "%d %s", CHALLENGE, buffer);
311 int challenge_h(conn_list_t *cl)
316 if(sscanf(cl->buffer, "%*d %as", &buffer) != 1)
318 syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
322 len = RSA_size(myself->rsa_key);
324 /* Check if the length of the challenge is all right */
326 if(strlen(buffer) != len*2)
328 syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
333 /* Allocate buffers for the challenge */
336 cl->mychallenge = xmalloc(len);
338 /* Convert the challenge from hexadecimal back to binary */
340 hex2bin(buffer,buffer,len);
342 /* Decrypt the challenge */
344 if(RSA_private_decrypt(len, buffer, cl->mychallenge, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
346 syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
351 if(debug_lvl >= DEBUG_SCARY_THINGS)
353 bin2hex(cl->mychallenge, buffer, len);
354 buffer[len*2] = '\0';
355 syslog(LOG_DEBUG, _("Received random challenge (unencrypted): %s"), buffer);
360 /* Rest is done by send_chal_reply() */
362 return send_chal_reply(cl);
365 int send_chal_reply(conn_list_t *cl)
367 char hash[SHA_DIGEST_LENGTH*2+1];
371 syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
375 /* Calculate the hash from the challenge we received */
377 SHA1(cl->mychallenge, RSA_size(myself->rsa_key), hash);
379 /* Convert the hash to a hexadecimal formatted string */
381 bin2hex(hash,hash,SHA_DIGEST_LENGTH);
382 hash[SHA_DIGEST_LENGTH*2] = '\0';
386 if(cl->status.outgoing)
387 cl->allow_request = ID;
389 cl->allow_request = METAKEY;
392 return send_request(cl, "%d %s", CHAL_REPLY, hash);
395 int chal_reply_h(conn_list_t *cl)
398 char myhash[SHA_DIGEST_LENGTH];
400 if(sscanf(cl->buffer, "%*d %as", &hishash) != 1)
402 syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
407 /* Check if the length of the hash is all right */
409 if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
411 syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
416 /* Convert the hash to binary format */
418 hex2bin(hishash, hishash, SHA_DIGEST_LENGTH);
420 /* Calculate the hash from the challenge we sent */
422 SHA1(cl->hischallenge, RSA_size(cl->rsa_key), myhash);
424 /* Verify the incoming hash with the calculated hash */
426 if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
428 syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
429 if(debug_lvl >= DEBUG_SCARY_THINGS)
431 bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
432 hishash[SHA_DIGEST_LENGTH*2] = '\0';
433 syslog(LOG_DEBUG, _("Expected challenge reply: %s"), hishash);
442 /* Identity has now been positively verified.
443 If we are accepting this new connection, then send our identity,
444 if we are making this connecting, acknowledge.
447 if(cl->status.outgoing)
448 return send_metakey(cl);
453 int send_metakey(conn_list_t *cl)
458 len = RSA_size(cl->rsa_key);
460 /* Allocate buffers for the meta key */
462 buffer = xmalloc(len*2+1);
464 if(!cl->cipher_outkey)
465 cl->cipher_outkey = xmalloc(len);
467 if(!cl->cipher_outctx)
468 cl->cipher_outctx = xmalloc(sizeof(*cl->cipher_outctx));
470 /* Copy random data to the buffer */
472 RAND_bytes(cl->cipher_outkey, len);
474 cl->cipher_outkey[0] &= 0x7F; /* FIXME: Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
476 if(debug_lvl >= DEBUG_SCARY_THINGS)
478 bin2hex(cl->cipher_outkey, buffer, len);
479 buffer[len*2] = '\0';
480 syslog(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"), buffer);
483 /* Encrypt the random data */
485 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 */
487 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
492 /* Convert the encrypted random data to a hexadecimal formatted string */
494 bin2hex(buffer, buffer, len);
495 buffer[len*2] = '\0';
497 /* Send the meta key */
499 if(cl->status.outgoing)
500 cl->allow_request = METAKEY;
502 cl->allow_request = ACK;
504 x = send_request(cl, "%d %s", METAKEY, buffer);
507 EVP_EncryptInit(cl->cipher_outctx, EVP_bf_cfb(), cl->cipher_outkey, cl->cipher_outkey + EVP_bf_cfb()->key_len);
512 int metakey_h(conn_list_t *cl)
517 if(sscanf(cl->buffer, "%*d %as", &buffer) != 1)
519 syslog(LOG_ERR, _("Got bad METAKEY from %s (%s)"), cl->name, cl->hostname);
523 len = RSA_size(myself->rsa_key);
525 /* Check if the length of the meta key is all right */
527 if(strlen(buffer) != len*2)
529 syslog(LOG_ERR, _("Intruder: wrong meta key length from %s (%s)"), cl->name, cl->hostname);
534 /* Allocate buffers for the meta key */
536 if(!cl->cipher_inkey)
537 cl->cipher_inkey = xmalloc(len);
539 if(!cl->cipher_inctx)
540 cl->cipher_inctx = xmalloc(sizeof(*cl->cipher_inctx));
542 /* Convert the challenge from hexadecimal back to binary */
544 hex2bin(buffer,buffer,len);
546 /* Decrypt the meta key */
548 if(RSA_private_decrypt(len, buffer, cl->cipher_inkey, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
550 syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname);
555 if(debug_lvl >= DEBUG_SCARY_THINGS)
557 bin2hex(cl->cipher_inkey, buffer, len);
558 buffer[len*2] = '\0';
559 syslog(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), buffer);
564 EVP_DecryptInit(cl->cipher_inctx, EVP_bf_cfb(), cl->cipher_inkey, cl->cipher_inkey + EVP_bf_cfb()->key_len);
567 if(cl->status.outgoing)
570 return send_metakey(cl);
573 int send_ack(conn_list_t *cl)
577 if(cl->status.outgoing)
578 cl->allow_request = ACK;
580 setup_vpn_connection(cl);
582 x = send_request(cl, "%d", ACK);
583 cl->status.encryptout = 1;
588 int ack_h(conn_list_t *cl)
590 conn_list_t *old, *p;
593 /* Okay, before we active the connection, we check if there is another entry
594 in the connection list with the same name. If so, it presumably is an
595 old connection that has timed out but we don't know it yet.
598 while((old = lookup_id(cl->name)))
600 if(debug_lvl >= DEBUG_CONNECTIONS)
601 syslog(LOG_NOTICE, _("Removing old entry for %s at %s in favour of new connection from %s"),
602 cl->name, old->hostname, cl->hostname);
604 terminate_connection(old);
607 /* Activate this connection */
609 cl->allow_request = ALL;
610 cl->status.active = 1;
611 cl->status.decryptin = 1;
613 cl->cipher_pkttype = EVP_bf_cfb();
614 cl->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
616 if(debug_lvl >= DEBUG_CONNECTIONS)
617 syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname);
620 if(!cl->status.outgoing)
623 /* Send him our subnets */
625 for(s = myself->subnets; s; s = s->next)
626 send_add_subnet(cl, s);
628 /* And send him all the hosts and their subnets we know... */
630 for(p = conn_list; p; p = p->next)
631 if(p != cl && p->status.active)
633 /* Notify others of this connection */
636 send_add_host(p, cl);
638 /* Notify new connection of everything we know */
640 send_add_host(cl, p);
642 for(s = p->subnets; s; s = s->next)
643 send_add_subnet(cl, s);
649 /* Address and subnet information exchange */
651 int send_add_subnet(conn_list_t *cl, subnet_t *subnet)
656 x = send_request(cl, "%d %s %s", ADD_SUBNET,
657 subnet->owner->name, netstr = net2str(subnet));
663 int add_subnet_h(conn_list_t *cl)
667 conn_list_t *owner, *p;
670 if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 2)
672 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
673 free(name); free(subnetstr);
677 /* Check if owner name is a valid */
681 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
682 free(name); free(subnetstr);
686 /* Check if subnet string is valid */
688 if(!(subnet = str2net(subnetstr)))
690 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
691 free(name); free(subnetstr);
697 /* Check if somebody tries to add a subnet of ourself */
699 if(!strcmp(name, myself->name))
701 syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
702 cl->name, cl->hostname);
708 /* Check if the owner of the new subnet is in the connection list */
710 if(!(owner = lookup_id(name)))
712 syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
713 name, cl->name, cl->hostname);
718 /* If everything is correct, add the subnet to the list of the owner */
720 subnet_add(owner, subnet);
724 for(p = conn_list; p; p = p->next)
725 if(p->status.meta && p->status.active && p!= cl)
726 send_add_subnet(p, subnet);
731 int send_del_subnet(conn_list_t *cl, subnet_t *subnet)
736 netstr = net2str(subnet);
737 x = send_request(cl, "%d %s %s", DEL_SUBNET, subnet->owner->name, netstr);
743 int del_subnet_h(conn_list_t *cl)
747 conn_list_t *owner, *p;
750 if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
752 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
753 free(name); free(subnetstr);
757 /* Check if owner name is a valid */
761 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
762 free(name); free(subnetstr);
766 /* Check if subnet string is valid */
768 if(!(subnet = str2net(subnetstr)))
770 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
771 free(name); free(subnetstr);
777 /* Check if somebody tries to add a subnet of ourself */
779 if(!strcmp(name, myself->name))
781 syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
782 cl->name, cl->hostname);
788 /* Check if the owner of the new subnet is in the connection list */
790 if(!(owner = lookup_id(name)))
792 syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
793 name, cl->name, cl->hostname);
798 /* If everything is correct, delete the subnet from the list of the owner */
804 for(p = conn_list; p; p = p->next)
805 if(p->status.meta && p->status.active && p!= cl)
806 send_del_subnet(p, subnet);
811 /* New and closed connections notification */
813 int send_add_host(conn_list_t *cl, conn_list_t *other)
816 return send_request(cl, "%d %s %lx:%d %lx", ADD_HOST,
817 other->name, other->address, other->port, other->options);
820 int add_host_h(conn_list_t *cl)
822 conn_list_t *old, *new;
826 new = new_conn_list();
828 if(sscanf(cl->buffer, "%*d %as %lx:%d %lx", &new->name, &new->address, &new->port, &new->options) != 4)
830 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
834 /* Check if identity is a valid name */
836 if(check_id(new->name))
838 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
843 /* Check if somebody tries to add ourself */
845 if(!strcmp(new->name, myself->name))
847 syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
853 /* Fill in more of the new conn_list structure */
855 new->hostname = hostlookup(htonl(new->address));
857 /* Check if the new host already exists in the connnection list */
859 if((old = lookup_id(new->name)))
861 if((new->address == old->address) && (new->port == old->port))
863 if(debug_lvl >= DEBUG_CONNECTIONS)
864 syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
865 old->name, old->hostname, new->name, new->hostname);
871 if(debug_lvl >= DEBUG_CONNECTIONS)
872 syslog(LOG_NOTICE, _("Removing old entry for %s (%s) in favour of new connection"),
873 old->name, old->hostname);
875 terminate_connection(old);
879 /* Hook it up into the conn_list */
883 /* Tell the rest about the new host */
885 for(p = conn_list; p; p = p->next)
886 if(p->status.meta && p->status.active && p!=cl)
887 send_add_host(p, new);
889 /* Fill in rest of conn_list structure */
892 new->status.active = 1;
893 new->cipher_pkttype = EVP_bf_cfb();
894 new->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len;
896 /* Okay this is a bit ugly... it would be better to setup UDP sockets dynamically, or
897 * perhaps just one UDP socket... but then again, this has benefits too...
900 setup_vpn_connection(new);
905 int send_del_host(conn_list_t *cl, conn_list_t *other)
908 return send_request(cl, "%d %s %lx:%d %lx", DEL_HOST,
909 other->name, other->address, other->port, other->options);
912 int del_host_h(conn_list_t *cl)
918 conn_list_t *old, *p;
920 if(sscanf(cl->buffer, "%*d %as %lx:%d %lx", &name, &address, &port, &options) != 4)
922 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
923 cl->name, cl->hostname);
927 /* Check if identity is a valid name */
931 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
936 /* Check if somebody tries to delete ourself */
938 if(!strcmp(name, myself->name))
940 syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
941 cl->name, cl->hostname);
947 /* Check if the new host already exists in the connnection list */
949 if(!(old = lookup_id(name)))
951 syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
952 name, cl->name, cl->hostname);
957 /* Check if the rest matches */
959 if(address!=old->address || port!=old->port || options!=old->options || cl!=old->nexthop)
961 syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
965 /* Ok, since EVERYTHING seems to check out all right, delete it */
967 old->status.active = 0;
968 terminate_connection(old);
970 /* Tell the rest about the new host */
972 for(p = conn_list; p; p = p->next)
973 if(p->status.meta && p->status.active && p!=cl)
974 send_del_host(p, old);
979 /* Status and error notification routines */
981 int send_status(conn_list_t *cl, int statusno, char *statusstring)
985 statusstring = status_text[statusno];
987 return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
990 int status_h(conn_list_t *cl)
995 if(sscanf(cl->buffer, "%*d %d %as", &statusno, &statusstring) != 2)
997 syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
998 cl->name, cl->hostname);
1002 if(debug_lvl >= DEBUG_STATUS)
1004 syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
1005 cl->name, cl->hostname, status_text[statusno], statusstring);
1013 int send_error(conn_list_t *cl, int errno, char *errstring)
1017 errstring = strerror(errno);
1018 return send_request(cl, "%d %d %s", ERROR, errno, errstring);
1021 int error_h(conn_list_t *cl)
1026 if(sscanf(cl->buffer, "%*d %d %as", &errno, &errorstring) != 2)
1028 syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
1029 cl->name, cl->hostname);
1033 if(debug_lvl >= DEBUG_ERROR)
1035 syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
1036 cl->name, cl->hostname, strerror(errno), errorstring);
1040 terminate_connection(cl);
1045 int send_termreq(conn_list_t *cl)
1048 return send_request(cl, "%d", TERMREQ);
1051 int termreq_h(conn_list_t *cl)
1054 terminate_connection(cl);
1059 /* Keepalive routines - FIXME: needs a closer look */
1061 int send_ping(conn_list_t *cl)
1064 cl->status.pinged = 1;
1065 cl->last_ping_time = time(NULL);
1067 return send_request(cl, "%d", PING);
1070 int ping_h(conn_list_t *cl)
1073 return send_pong(cl);
1076 int send_pong(conn_list_t *cl)
1079 return send_request(cl, "%d", PONG);
1082 int pong_h(conn_list_t *cl)
1085 cl->status.pinged = 0;
1092 int send_key_changed(conn_list_t *from, conn_list_t *cl)
1096 for(p = conn_list; p != NULL; p = p->next)
1098 if(p!=cl && p->status.meta && p->status.active)
1099 send_request(p, "%d %s", KEY_CHANGED,
1106 int key_changed_h(conn_list_t *cl)
1111 if(sscanf(cl->buffer, "%*d %as", &from_id) != 1)
1113 syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
1114 cl->name, cl->hostname);
1118 if(!(from = lookup_id(from_id)))
1120 syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
1121 cl->name, cl->hostname, from_id);
1128 from->status.validkey = 0;
1129 from->status.waitingforkey = 0;
1131 send_key_changed(from, cl);
1136 int send_req_key(conn_list_t *from, conn_list_t *to)
1139 return send_request(to->nexthop, "%d %s %s", REQ_KEY,
1140 from->name, to->name);
1143 int req_key_h(conn_list_t *cl)
1145 char *from_id, *to_id;
1146 conn_list_t *from, *to;
1149 if(sscanf(cl->buffer, "%*d %as %as", &from_id, &to_id) != 2)
1151 syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
1152 cl->name, cl->hostname);
1156 if(!(from = lookup_id(from_id)))
1158 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
1159 cl->name, cl->hostname, from_id);
1160 free(from_id); free(to_id);
1164 /* Check if this key request is for us */
1166 if(!strcmp(to_id, myself->name))
1168 bin2hex(myself->cipher_pktkey, pktkey, myself->cipher_pktkeylength);
1169 pktkey[myself->cipher_pktkeylength*2] = '\0';
1170 send_ans_key(myself, from, pktkey);
1174 if(!(to = lookup_id(to_id)))
1176 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
1177 cl->name, cl->hostname, to_id);
1178 free(from_id); free(to_id);
1182 if(to->status.validkey) /* Proxy keys */
1184 bin2hex(to->cipher_pktkey, pktkey, to->cipher_pktkeylength);
1185 pktkey[to->cipher_pktkeylength*2] = '\0';
1186 send_ans_key(to, from, pktkey);
1189 send_req_key(from, to);
1192 free(from_id); free(to_id);
1197 int send_ans_key(conn_list_t *from, conn_list_t *to, char *pktkey)
1200 return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
1201 from->name, to->name, pktkey);
1204 int ans_key_h(conn_list_t *cl)
1206 char *from_id, *to_id, *pktkey;
1208 conn_list_t *from, *to;
1210 if(sscanf(cl->buffer, "%*d %as %as %as", &from_id, &to_id, &pktkey) != 3)
1212 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
1213 cl->name, cl->hostname);
1217 if(!(from = lookup_id(from_id)))
1219 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
1220 cl->name, cl->hostname, from_id);
1221 free(from_id); free(to_id); free(pktkey);
1225 /* Check correctness of packet key */
1227 keylength = strlen(pktkey);
1229 if(keylength != from->cipher_pktkeylength*2)
1231 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key length"),
1232 cl->name, cl->hostname, from->name);
1233 free(from_id); free(to_id); free(pktkey);
1237 /* Forward it if necessary */
1239 if(strcmp(to_id, myself->name))
1241 if(!(to = lookup_id(to_id)))
1243 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1244 cl->name, cl->hostname, to_id);
1245 free(from_id); free(to_id);
1248 send_ans_key(from, to, pktkey);
1251 /* Update our copy of the origin's packet key */
1253 if(from->cipher_pktkey)
1254 free(from->cipher_pktkey);
1257 hex2bin(pktkey, pktkey, keylength);
1258 pktkey[keylength] = '\0';
1259 from->cipher_pktkey = pktkey;
1261 from->status.validkey = 1;
1262 from->status.waitingforkey = 0;
1264 free(from_id); free(to_id);
1269 /* Jumptable for the request handlers */
1271 int (*request_handlers[])(conn_list_t*) = {
1272 id_h, challenge_h, chal_reply_h, metakey_h, ack_h,
1273 status_h, error_h, termreq_h,
1275 add_host_h, del_host_h,
1276 add_subnet_h, del_subnet_h,
1277 key_changed_h, req_key_h, ans_key_h,
1282 char (*request_name[]) = {
1283 "ID", "CHALLENGE", "CHAL_REPLY", "METAKEY", "ACK",
1284 "STATUS", "ERROR", "TERMREQ",
1286 "ADD_HOST", "DEL_HOST",
1287 "ADD_SUBNET", "DEL_SUBNET",
1288 "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1291 /* Status strings */
1293 char (*status_text[]) = {
1299 char (*error_text[]) = {