Second round of fixes
[tinc] / src / protocol.c
1 /*
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>
5
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.
10
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.
15
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.
19
20     $Id: protocol.c,v 1.28.4.32 2000/09/15 12:58:40 zarq Exp $
21 */
22
23 #include "config.h"
24
25 #include <sys/types.h>
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include <syslog.h>
30 #include <sys/socket.h>
31 #include <unistd.h>
32 #include <stdio.h>
33
34 #include <utils.h>
35 #include <xalloc.h>
36
37 #include <netinet/in.h>
38
39 #include <openssl/sha.h>
40
41 #include "conf.h"
42 #include "encr.h"
43 #include "net.h"
44 #include "netutl.h"
45 #include "protocol.h"
46
47 #include "system.h"
48
49 int check_id(char *id)
50 {
51   int i;
52
53   for (i = 0; i < strlen(id); i++)
54     {
55       if(!isalpha(id[i]) && id[i] != '_')
56         {
57           return 0;
58         }
59     }
60
61   return 1;
62 }
63
64 /* Generic outgoing request routine - takes care of logging and error detection as well */
65
66 int send_request(conn_list_t *cl, const char *format, int request, /*args*/ ...)
67 {
68   va_list args;
69   char *buffer = NULL;
70   int len;
71   
72 cp
73   if(debug_lvl >= DEBUG_PROTOCOL)
74     syslog(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
75
76   va_start(args, request);
77   len = vasprintf(&buffer, format, args);
78   va_end(args);
79
80   if(len < 0 || !buffer)
81     {
82       syslog(LOG_ERR, _("Error during vasprintf(): %m"));
83       return -1;
84     }
85
86   if(debug_lvl >= DEBUG_META)
87     syslog(LOG_DEBUG, _("Sending meta data to %s (%s): %s"),
88            cl->name, cl->hostname, buffer);
89
90   if(cl->status.encryptin)
91     {
92       /* FIXME: Do encryption */
93     }
94
95   if((write(cl->meta_socket, buffer, len)) < 0)
96     {
97       syslog(LOG_ERR, _("Sending meta data failed:  %m"));
98       return -1;
99     }
100 cp  
101 }
102
103 /* Connection protocol:
104
105    Client               Server
106    send_id(u)
107                         send_challenge(R)
108    send_chal_reply(BH)                   
109                         send_id(B)
110    send_challenge(BR)
111                         send_chal_reply(BH)
112    send_ack(B)
113                         send_ack(B)
114
115    (u) Unencrypted,
116    (R) RSA,
117    (H) SHA1,
118    (B) Blowfish.
119
120    Part of the challenge is directly used to set the blowfish key and the initial vector.
121    (Twee vliegen in één klap!)
122 */      
123
124 int send_id(conn_list_t *cl)
125 {
126 cp
127   return send_request(cl, "%d %s %d %s", ID,
128                       myself->name, myself->protocol_version, opt2str(myself->options));
129 }
130
131 int id_h(conn_list_t *cl)
132 {
133   conn_list_t *old;
134   char *options;
135 cp
136   if(sscanf(cl->buffer, "%*d %as %d %as", &cl->name, &cl->protocol_version, &options) != 3)
137     {
138        syslog(LOG_ERR, _("Got bad ID from %s"), cl->hostname);
139        return -1;
140     }
141     
142   /* Check if version matches */
143   
144   if(cl->protocol_version != myself->protocol_version)
145     {
146       syslog(LOG_ERR, _("Peer %s (%s) uses incompatible version %d"),
147              cl->name, cl->hostname, cl->protocol_version);
148       return -1;
149     }
150
151   /* Check if option string is valid */
152   
153   if((cl->options = str2opt(options)) == -1)
154     {
155       syslog(LOG_ERR, _("Peer %s uses invalid option string"), cl->hostname);
156       return -1;
157     }
158     
159   /* Check if identity is a valid name */
160   
161   if(!check_id(cl->name))
162     {
163       syslog(LOG_ERR, _("Peer %s uses invalid identity name"), cl->hostname);
164       return -1;
165     }
166     
167   /* Load information about peer */
168   
169   if(!read_id(cl))
170     {
171       syslog(LOG_ERR, _("Peer %s had unknown identity (%s)"), cl->hostname, cl->name);
172       return -1;
173     }
174
175
176   /* First check if the host we connected to is already in our
177      connection list. If so, we are probably making a loop, which
178      is not desirable.
179    */
180
181   if(cl->status.outgoing)
182     {
183       if((old = lookup_id(cl->name)))
184         {
185           if(debug_lvl > DEBUG_CONNECTIONS)
186             syslog(LOG_NOTICE, _("Uplink %s (%s) is already in our connection list"), cl->name, cl->hostname);
187           cl->status.outgoing = 0;
188           old->status.outgoing = 1;
189           terminate_connection(cl);
190           return 0;
191         }
192     }
193
194   /* Send a challenge to verify the identity */
195
196   cl->allow_request = CHAL_REPLY;
197 cp
198   return send_challenge(cl);
199 }
200
201 int send_challenge(conn_list_t *cl)
202 {
203   char *buffer;
204   int keylength;
205   int x;
206 cp
207   if(cl->chal_answer)
208     free(cl->chal_answer);
209   
210   /* Allocate buffers for the challenge and the hash */
211   
212   cl->chal_answer = xmalloc(SHA_DIGEST_LENGTH);
213   keylength = BN_num_bytes(cl->rsakey->length);
214   buffer = xmalloc(keylength*2);
215
216   /* Copy random data and the public key to the buffer */
217   
218   RAND_bytes(buffer, keylength);
219   BN_bn2bin(cl->rsakey->length, buffer+keylength);
220
221   /* If we don't have a blowfish key set yet, use the random data from the challenge to do so. */
222   
223   if(!cl->status.encryptin)
224     {
225       set_metakey(cl, buffer, keylength);
226     }
227
228   /* Calculate the hash from that */
229
230   SHA1(buffer, keylength*2, cl->chal_answer);
231
232   /* Convert the random data to a hexadecimal formatted string */
233
234   bin2hex(buffer,buffer,keylength);
235   buffer[keylength*2] = '\0';
236
237   /* Send the challenge */
238   
239   cl->allow_request = CHAL_REPLY;
240   x = send_request(cl, "%d %s", CHALLENGE, buffer);
241   free(buffer);
242   cl->status.encryptout = 1;
243 cp
244   return x;
245 }
246
247 int challenge_h(conn_list_t *cl)
248 {
249   char *challenge;
250   int x;
251   
252 cp
253   if(sscanf(cl->buffer, "%*d %as", &cl->name, &challenge) != 1)
254     {
255        syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
256        return -1;
257     }
258
259   /* Rest is done by send_chal_reply() */
260   
261   x = send_chal_reply(cl, challenge);
262   free(challenge);
263 cp
264   return x;
265 }
266
267 int send_chal_reply(conn_list_t *cl, char *challenge)
268 {
269   char *buffer;
270   int keylength;
271   char *hash;
272   int x;
273   
274 cp
275   keylength = BN_num_bytes(myself->rsakey->length);
276
277   /* Check if the length of the challenge is all right */
278
279   if(strlen(challenge) != keylength*2)
280     {
281       syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
282       return -1;
283     }
284
285   /* Allocate buffers for the challenge and the hash */
286   
287   buffer = xmalloc(keylength*2);
288   hash = xmalloc(SHA_DIGEST_LENGTH*2+1);
289
290   /* Copy the incoming random data and our public key to the buffer */
291
292   hex2bin(challenge, buffer, keylength); 
293   BN_bn2bin(myself->rsakey->length, buffer+keylength);
294
295   /* Calculate the hash from that */
296   
297   SHA1(buffer, keylength*2, hash);
298
299   /* If we don't have a blowfish key set yet, use the random data from the challenge to do so. */
300   
301   if(!cl->status.encrypted)
302     {
303       set_metakey(cl, buffer, keylength);
304       cl->status.encrypted = 1;
305     }
306
307   free(buffer);
308
309   /* Convert the hash to a hexadecimal formatted string */
310
311   bin2hex(hash,hash,SHA_DIGEST_LENGTH);
312   hash[SHA_DIGEST_LENGTH*2] = '\0';
313
314   /* Send the reply */
315
316   if(cl->status.outgoing)
317     cl->allow_request = ID;
318   else
319     cl->allow_request = ACK;
320
321   x = send_request(cl, "%d %s", CHAL_REPLY, hash);
322   free(hash);
323 cp
324   return x;
325
326
327 int chal_reply_h(conn_list_t *cl)
328 {
329   char *hash;
330 cp
331   if(sscanf(cl->buffer, "%*d %as", &cl->name, &hash) != 2)
332     {
333        syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
334        return -1;
335     }
336
337   /* Check if the length of the hash is all right */
338   
339   if(strlen(hash) != SHA_DIGEST_LENGTH*2)
340     {
341       syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
342       return -1;
343     }
344     
345   /* Convert the hash to binary format */
346   
347   hex2bin(hash, hash, SHA_DIGEST_LENGTH);
348   
349   /* Verify the incoming hash with the calculated hash */
350   
351   if(!memcmp(hash, cl->chal_answer, SHA_DIGEST_LENGTH))
352     {
353       syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
354       return -1;
355     }
356
357   /* Identity has now been positively verified.
358      If we are accepting this new connection, then send our identity,
359      if we are making this connecting, acknowledge.
360    */
361    
362   free(hash);
363   free(cl->chal_answer);
364
365 cp
366   if(cl->status.outgoing)
367     {
368       cl->allow_request = ACK;
369       return send_ack(cl);
370     }
371   else
372     {
373       cl->allow_request = CHALLENGE;
374       return send_id(cl);
375     }
376 }
377
378 int send_ack(conn_list_t *cl)
379 {
380 cp
381   return send_request(cl, "%d", ACK);
382 }
383
384 int ack_h(conn_list_t *cl)
385 {
386   conn_list_t *old;
387   
388 cp
389   /* Okay, before we active the connection, we check if there is another entry
390      in the connection list with the same vpn_ip. If so, it presumably is an
391      old connection that has timed out but we don't know it yet.
392    */
393
394   while((old = lookup_id(cl->name))) 
395     {
396       if(debug_lvl > DEBUG_CONNECTIONS)
397         syslog(LOG_NOTICE, _("Removing old entry for %s at %s in favour of new connection from %s"),
398         cl->name, old->hostname, cl->hostname);
399       old->status.active = 0;
400       terminate_connection(old);
401     }
402
403   /* Activate this connection */
404
405   cl->allow_request = ALL;
406   cl->status.active = 1;
407
408   if(debug_lvl > DEBUG_CONNECTIONS)
409     syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname);
410
411   /* Exchange information about other tinc daemons */
412
413   notify_others(cl, NULL, send_add_host);
414   notify_one(cl);
415
416   upstreamindex = 0;
417
418 cp
419   if(cl->status.outgoing)
420     return 0;
421   else
422     return send_ack(cl);
423 }
424
425 /* Address and subnet information exchange */
426
427 int send_add_subnet(conn_list_t *cl, conn_list_t *other, subnet_t *subnet)
428 {
429 cp
430 /*  return send_request(cl, "%d %s %d %s", ADD_SUBNET,
431                       other->name, subnet->type, net2str(subnet)); */
432   return send_request(cl, "%d %s %s", ADD_SUBNET,
433                       other->name, net2str(subnet));
434 }
435
436 int add_subnet_h(conn_list_t *cl)
437 {
438 }
439
440 int send_del_subnet(conn_list_t *cl, conn_list_t *other, subnet_t *subnet)
441 {
442 cp
443   return send_request(cl, "%d %s %s", DEL_SUBNET, other->name, net2str(subnet));
444 }
445
446 int del_subnet_h(conn_list_t *cl)
447 {
448 }
449
450 /* New and closed connections notification */
451
452 int send_add_host(conn_list_t *cl, conn_list_t *other)
453 {
454 cp
455   return send_request(cl, "%d %s %lx:%d %s", ADD_HOST, other->name, other->real_ip, other->port, opt2str(other->options));
456 }
457
458 int add_host_h(conn_list_t *cl)
459 {
460   char *options;
461   conn_list_t *old, *new;
462 cp
463   new = new_conn_list();
464
465   if(sscanf(cl->buffer, "%*d %as %lx:%d %as", &new->name, &new->real_ip, &new->port, &options) != 4)
466     {
467        syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
468        return -1;
469     }  
470
471   /* Check if option string is valid */
472   
473   if((new->options = str2opt(options)) == -1)
474     {
475       syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid option string"), cl->name, cl->hostname);
476       return -1;
477     }
478
479   /* Check if identity is a valid name */
480   
481   if(!check_id(new->name))
482     {
483       syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
484       return -1;
485     }
486     
487   /* Check if somebody tries to add ourself */
488   
489   if(!strcmp(new->name, myself->name))
490     {
491       syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
492       sighup = 1;
493       return 0;
494     }
495
496   /* Fill in more of the new conn_list structure */
497
498   new->hostname = hostlookup(htonl(new->real_ip));
499   
500   /* Check if the new host already exists in the connnection list */
501
502   if((old = lookup_id(new->name)))
503     {
504       if((new->real_ip == old->real_ip) && (new->port == old->port))
505         {
506           if(debug_lvl > DEBUG_CONNECTIONS)
507             syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
508                    old->name, old->hostname, new->name, new->hostname);
509           return 0;
510         }
511       else
512         {
513           if(debug_lvl > DEBUG_CONNECTIONS)
514             syslog(LOG_NOTICE, _("Removing old entry for %s (%s)"),
515                    old->name, old->hostname);
516           old->status.active = 0;
517           terminate_connection(old);
518         }
519     }
520
521   /* Fill in rest of conn_list structure */
522
523   new->nexthop = cl;
524   new->status.active = 1;
525   
526   /* Hook it up into the conn_list */
527
528   conn_list_add(conn_list, new);
529
530   /* Tell the rest about the new host */
531   
532   notify_others(new, cl, send_add_host);
533   
534 cp
535   return 0;
536 }
537
538 int send_del_host(conn_list_t *cl, conn_list_t *other)
539 {
540 cp
541   return send_request(cl, "%d %s %lx:%d", DEL_HOST,
542                       other->name, other->real_ip, other->port);
543 }
544
545 int del_host_h(conn_list_t *cl)
546 {
547   char *id;
548   ip_t address;
549   port_t port;
550   conn_list_t *old;
551   
552 cp
553   if(sscanf(cl->buffer, "%*d %as %lx:%d", &id, &address, &port) != 3)
554     {
555       syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
556              cl->name, cl->hostname);
557       return -1;
558     }  
559
560   /* Check if somebody tries to delete ourself */
561   
562   if(!strcmp(id, myself->name))
563     {
564       syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
565              cl->name, cl->hostname);
566       sighup = 1;
567       return 0;
568     }
569
570   /* Check if the new host already exists in the connnection list */
571
572   if((old = lookup_id(id)))
573     {
574       if((address == old->real_ip) && (port == old->port))
575         {
576           notify_others(old, cl, send_del_host);
577
578           old->status.termreq = 1;
579           old->status.active = 0;
580
581           terminate_connection(old);
582 cp
583           return 0;
584         }
585     }
586
587   if(debug_lvl > DEBUG_CONNECTIONS)
588     {
589       syslog(LOG_NOTICE, _("Got DEL_HOST for %s from %s (%s) which is not in our connection list"),
590              id, cl->name, cl->hostname);
591     }
592 cp
593   return 0;
594 }
595
596 /* Status and error notification routines */
597
598 int send_status(conn_list_t *cl, int statusno, char *statusstring)
599 {
600 cp
601   if(!statusstring)
602     statusstring = status_text[statusno];
603 cp
604   return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
605 }
606
607 int status_h(conn_list_t *cl)
608 {
609   int statusno;
610   char *statusstring;
611 cp
612   if(sscanf(cl->buffer, "%*d %d %as", &statusno, &statusstring) != 2)
613     {
614        syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
615               cl->name, cl->hostname);
616        return -1;
617     }
618
619   if(debug_lvl > DEBUG_STATUS)
620     {
621       syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
622              cl->name, cl->hostname, status_text[statusno], statusstring);
623     }
624
625 cp
626   free(statusstring);
627   return 0;
628 }
629
630 int send_error(conn_list_t *cl, int errno, char *errstring)
631 {
632 cp
633   if(!errstring)
634     errstring = strerror(errno);
635   return send_request(cl, "%d %d %s", ERROR, errno, errstring);
636 }
637
638 int error_h(conn_list_t *cl)
639 {
640   int errno;
641   char *errorstring;
642 cp
643   if(sscanf(cl->buffer, "%*d %d %as", &errno, &errorstring) != 2)
644     {
645        syslog(LOG_ERR, _("Got bad error from %s (%s)"),
646               cl->name, cl->hostname);
647        return -1;
648     }
649
650   if(debug_lvl > DEBUG_error)
651     {
652       syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
653              cl->name, cl->hostname, strerror(errno), errorstring);
654     }
655
656   free(errorstring);
657   cl->status.termreq = 1;
658   terminate_connection(cl);
659 cp
660   return 0;
661 }
662
663 int send_termreq(conn_list_t *cl)
664 {
665 cp
666   return send_request(cl, "%d", TERMREQ);
667 }
668
669 int termreq_h(conn_list_t *cl)
670 {
671 cp
672   cl->status.termreq = 1;
673   terminate_connection(cl);
674 cp
675   return 0;
676 }
677
678 /* Keepalive routines - FIXME: needs a closer look */
679
680 int send_ping(conn_list_t *cl)
681 {
682   cl->status.pinged = 1;
683 cp
684   return send_request(cl, "%d", PING);
685 }
686
687 int ping_h(conn_list_t *cl)
688 {
689 cp
690   return send_pong(cl);
691 }
692
693 int send_pong(conn_list_t *cl)
694 {
695 cp
696   return send_request(cl, "%d", PONG);
697 }
698
699 int pong_h(conn_list_t *cl)
700 {
701 cp
702   cl->status.got_pong = 1;
703 cp
704   return 0;
705 }
706
707 /* Key exchange */
708
709 int send_key_changed(conn_list_t *from, conn_list_t *cl)
710 {
711   conn_list_t *p;
712 cp
713   for(p = conn_list; p != NULL; p = p->next)
714     {
715       if(p!=cl && p->status.meta && p->status.active)
716         send_request(p, "%d %s", KEY_CHANGED,
717                      from->name);
718     }
719 cp
720   return 0;
721 }
722
723 int key_changed_h(conn_list_t *cl)
724 {
725   char *from_id;
726   conn_list_t *from;
727 cp
728   if(sscanf(cl->buffer, "%*d %as", &from_id) != 1)
729     {
730       syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
731              cl->name, cl->hostname);
732       return -1;
733     }  
734
735   if(!(from = lookup_id(from_id)))
736     {
737       syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
738              cl->name, cl->hostname, from_id);
739       free(from_id);
740       return -1;
741     }
742
743   free(from_id);
744     
745   from->status.validkey = 0;
746   from->status.waitingforkey = 0;
747   
748   send_key_changed(from, cl);
749 cp
750   return 0;
751 }
752   
753 int send_req_key(conn_list_t *from, conn_list_t *to)
754 {
755 cp
756   return send_request(to->nexthop, "%d %s %s", REQ_KEY,
757                       from->name, to->name);
758 }
759
760 int req_key_h(conn_list_t *cl)
761 {
762   char *from_id, *to_id;
763   conn_list_t *from, *to;
764 cp
765   if(sscanf(cl->buffer, "%*d %as %as", &from_id, &to_id) != 2)
766     {
767        syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
768               cl->name, cl->hostname);
769        return -1;
770     }  
771
772   if(!(from = lookup_id(from_id)))
773     {
774       syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
775              cl->name, cl->hostname, from_id);
776       free(from_id); free(to_id);
777       return -1;
778     }
779
780   /* Check if this key request is for us */
781
782   if(!strcmp(to_id, myself->name))
783     {
784       send_ans_key(myself, from, myself->datakey->key);
785     }
786   else
787     {
788       if(!(to = lookup_id(to_id)))
789         {
790           syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
791                  cl->name, cl->hostname, to_id);
792           free(from_id); free(to_id);
793           return -1;
794         }
795       send_req_key(from, to);
796     }
797
798   free(from_id); free(to_id);
799 cp
800   return 0;
801 }
802
803 int send_ans_key(conn_list_t *from, conn_list_t *to, char *datakey)
804 {
805 cp
806   return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
807                       from->name, to->name, datakey);
808 }
809
810 int ans_key_h(conn_list_t *cl)
811 {
812   char *from_id, *to_id, *datakey;
813   int keylength;
814   conn_list_t *from, *to;
815 cp
816   if(sscanf(cl->buffer, "%*d %as %as %as", &from_id, &to_id, &datakey) != 3)
817     {
818        syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
819               cl->name, cl->hostname);
820        return -1;
821     }  
822
823   if(!(from = lookup_id(from_id)))
824     {
825       syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
826              cl->name, cl->hostname, from_id);
827       free(from_id); free(to_id); free(datakey);
828       return -1;
829     }
830
831   /* Check if this key request is for us */
832
833   if(!strcmp(to_id, myself->name))
834     {
835       /* It is for us, convert it to binary and set the key with it. */
836       
837       keylength = strlen(datakey);
838       
839       if((keylength%2) || (keylength <= 0))
840         {
841           syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key"),
842                  cl->name, cl->hostname, from->name);
843           free(from_id); free(to_id); free(datakey);
844           return -1;
845         }
846       keylength /= 2;
847       hex2bin(datakey, datakey, keylength);
848       BF_set_key(cl->datakey, keylength, datakey);
849     }
850   else
851     {
852       if(!(to = lookup_id(to_id)))
853         {
854           syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
855                  cl->name, cl->hostname, to_id);
856           free(from_id); free(to_id); free(datakey);
857           return -1;
858         }
859       send_ans_key(from, to, datakey);
860     }
861
862   free(from_id); free(to_id); free(datakey);
863 cp
864   return 0;
865 }
866
867 /* Old routines */
868
869 /*
870   Notify all my direct connections of a new host
871   that was added to the vpn, with the exception
872   of the source of the announcement.
873 */
874
875 int notify_others(conn_list_t *new, conn_list_t *source,
876                   int (*function)(conn_list_t*, conn_list_t*))
877 {
878   conn_list_t *p;
879 cp
880   for(p = conn_list; p != NULL; p = p->next)
881     if(p != new && p != source && p->status.meta && p->status.active)
882       function(p, new);
883 cp
884   return 0;
885 }
886
887 /*
888   Notify one connection of everything
889   I have connected
890 */
891
892 int notify_one(conn_list_t *new)
893 {
894   conn_list_t *p;
895 cp
896   for(p = conn_list; p != NULL; p = p->next)
897     if(p != new && p->status.active)
898       send_add_host(new, p);
899 cp
900   return 0;
901 }
902
903 /* "Complete overhaul". */
904
905 int (*request_handlers[])(conn_list_t*) = {
906   id_h, challenge_h, chal_reply_h, ack_h,
907   status_h, error_h, termreq_h,
908   ping_h, pong_h,
909   add_host_h, del_host_h,
910   add_subnet_h, del_subnet_h,
911   key_changed_h, req_key_h, ans_key_h,
912 };
913
914 char (*request_name[]) = {
915   "ID", "CHALLENGE", "CHAL_REPLY", "ACK",
916   "STATUS", "ERROR", "TERMREQ",
917   "PING", "PONG",
918   "ADD_HOST", "DEL_HOST",
919   "ADD_SUBNET", "DEL_SUBNET",
920   "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
921 };