78ab00d79a36cdb25da34255f338bd29574cb56a
[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.34 2000/09/22 15:06:28 guus 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[MAXBUFSIZE+1];
70   int len;
71
72 cp
73   /* Use vsnprintf instead of vasprintf: faster, no memory fragmentation, cleanup is automatic,
74      and there is a limit on the input buffer anyway */
75
76   va_start(args, request);
77   len = vsnprintf(buffer, MAXBUFSIZE+1, format, args);
78   va_end(args);
79
80   if(len < 0 || len > MAXBUFSIZE)
81     {
82       syslog(LOG_ERR, _("Output buffer overflow while sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
83       return -1;
84     }
85
86   if(debug_lvl >= DEBUG_META)
87     syslog(LOG_DEBUG, _("Sending %s to %s (%s): %s"), request_name[request],
88            cl->name, cl->hostname, buffer);
89   else if(debug_lvl >= DEBUG_PROTOCOL)
90     syslog(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
91
92
93   if(cl->status.encryptin)
94     {
95       /* FIXME: Do encryption */
96     }
97
98   if((write(cl->meta_socket, buffer, len)) < 0)
99     {
100       syslog(LOG_ERR, _("Sending meta data failed:  %m"));
101       return -1;
102     }
103 cp
104 }
105
106 /* Connection protocol:
107
108    Client               Server
109    send_id(u)
110                         send_challenge(R)
111    send_chal_reply(H)
112                         send_id(u)
113    send_challenge(R)
114                         send_chal_reply(H)
115    ---------------------------------------
116    Any negotations about the meta protocol
117    encryption go here(u).
118    ---------------------------------------
119    send_ack(u)
120                         send_ack(u)
121    ---------------------------------------
122    Other requests(E)...
123
124    (u) Unencrypted,
125    (R) RSA,
126    (H) SHA1,
127    (E) Encrypted with symmetric cipher.
128
129    Part of the challenge is directly used to set the symmetric cipher key and the initial vector.
130    Since a man-in-the-middle cannot decrypt the RSA challenges, this means that he cannot get or
131    forge the key for the symmetric cipher.
132 */
133
134 int send_id(conn_list_t *cl)
135 {
136   int x;
137   char *optstr;
138 cp
139   x = send_request(cl, "%d %s %d %s", ID, myself->name, myself->protocol_version, optstr=opt2str(myself->options));
140   free(optstr);
141 cp
142   return x;
143 }
144
145 int id_h(conn_list_t *cl)
146 {
147   conn_list_t *old;
148   char *optstr;
149 cp
150   if(sscanf(cl->buffer, "%*d %as %d %as", &cl->name, &cl->protocol_version, &optstr) != 3)
151     {
152        syslog(LOG_ERR, _("Got bad ID from %s"), cl->hostname);
153        return -1;
154     }
155
156   /* Check if version matches */
157
158   if(cl->protocol_version != myself->protocol_version)
159     {
160       syslog(LOG_ERR, _("Peer %s (%s) uses incompatible version %d"),
161              cl->name, cl->hostname, cl->protocol_version);
162       return -1;
163     }
164
165   /* Check if option string is valid */
166
167   if((cl->options = str2opt(optstr)) == -1)
168     {
169       syslog(LOG_ERR, _("Peer %s uses invalid option string"), cl->hostname);
170       free(optstr);
171       return -1;
172     }
173
174   free(optstr);
175
176   /* Check if identity is a valid name */
177
178   if(!check_id(cl->name))
179     {
180       syslog(LOG_ERR, _("Peer %s uses invalid identity name"), cl->hostname);
181       return -1;
182     }
183
184   /* Load information about peer */
185
186   if(!read_id(cl))
187     {
188       syslog(LOG_ERR, _("Peer %s had unknown identity (%s)"), cl->hostname, cl->name);
189       return -1;
190     }
191
192
193   /* First check if the host we connected to is already in our
194      connection list. If so, we are probably making a loop, which
195      is not desirable.
196    */
197
198   if(cl->status.outgoing)
199     {
200       if((old = lookup_id(cl->name)))
201         {
202           if(debug_lvl > DEBUG_CONNECTIONS)
203             syslog(LOG_NOTICE, _("Uplink %s (%s) is already in our connection list"), cl->name, cl->hostname);
204           cl->status.outgoing = 0;
205           old->status.outgoing = 1;
206           terminate_connection(cl);
207           return 0;
208         }
209     }
210
211   /* Send a challenge to verify the identity */
212
213   cl->allow_request = CHAL_REPLY;
214 cp
215   return send_challenge(cl);
216 }
217
218 int send_challenge(conn_list_t *cl)
219 {
220   char buffer[CHAL_LENGTH*2+1];
221 cp
222   /* Allocate buffers for the challenge */
223
224   if(!cl->hischallenge)
225     cl->hischallenge = xmalloc(CHAL_LENGTH);
226
227   /* Copy random data to the buffer */
228
229   RAND_bytes(cl->hischallenge, CHAL_LENGTH);
230
231   /* Convert the random data to a hexadecimal formatted string */
232
233   bin2hex(cl->hischallenge,buffer,CHAL_LENGTH);
234   buffer[keylength*2] = '\0';
235
236   /* Send the challenge */
237
238   cl->allow_request = CHAL_REPLY;
239 cp
240   return send_request(cl, "%d %s", CHALLENGE, buffer);
241 }
242
243 int challenge_h(conn_list_t *cl)
244 {
245   char *buffer;
246 cp
247   if(sscanf(cl->buffer, "%*d %as", &buffer) != 1)
248     {
249        syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
250        return -1;
251     }
252
253   /* Check if the length of the challenge is all right */
254
255   if(strlen(buffer) != CHAL_LENGTH*2)
256     {
257       syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
258       free(buffer);
259       return -1;
260     }
261
262   /* Allocate buffers for the challenge */
263
264   if(!cl->mychallenge)
265     cl->mychallenge = xmalloc(CHAL_LENGTH);
266
267   /* Convert the challenge from hexadecimal back to binary */
268
269   hex2bin(buffer,cl->mychallenge,CHAL_LENGTH);
270   free(buffer);
271     
272   /* Rest is done by send_chal_reply() */
273 cp
274   return send_chal_reply(cl);
275 }
276
277 int send_chal_reply(conn_list_t *cl)
278 {
279   char hash[SHA_DIGEST_LENGTH*2+1];
280 cp
281   if(!cl->mychallenge)
282     {
283       syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
284       return -1;
285     }
286      
287   /* Calculate the hash from the challenge we received */
288
289   SHA1(cl->mychallenge, CHAL_LENGTH, hash);
290
291   /* Convert the hash to a hexadecimal formatted string */
292
293   bin2hex(hash,hash,SHA_DIGEST_LENGTH);
294   hash[SHA_DIGEST_LENGTH*2] = '\0';
295
296   /* Send the reply */
297
298   if(cl->status.outgoing)
299     cl->allow_request = ID;
300   else
301     cl->allow_request = ACK;
302
303 cp
304   return send_request(cl, "%d %s", CHAL_REPLY, hash);
305 }
306
307 int chal_reply_h(conn_list_t *cl)
308 {
309   char *hishash;
310   char myhash[SHA_DIGEST_LENGTH];
311 cp
312   if(sscanf(cl->buffer, "%*d %as", &hishash) != 2)
313     {
314        syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
315        return -1;
316     }
317
318   /* Check if the length of the hash is all right */
319
320   if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
321     {
322       syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
323       return -1;
324     }
325
326   /* Convert the hash to binary format */
327
328   hex2bin(hishash, hishash, SHA_DIGEST_LENGTH);
329
330   /* Calculate the hash from the challenge we sent */
331
332   SHA1(cl->hischallenge, CHAL_LENGTH, myhash);
333
334   /* Verify the incoming hash with the calculated hash */
335
336   if(!memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
337     {
338       syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
339       free(hishash);
340       return -1;
341     }
342
343   free(hishash);
344
345   /* Identity has now been positively verified.
346      If we are accepting this new connection, then send our identity,
347      if we are making this connecting, acknowledge.
348    */
349 cp
350   if(cl->status.outgoing)
351     {
352       cl->allow_request = ACK;
353       return send_ack(cl);
354     }
355   else
356     {
357       cl->allow_request = CHALLENGE;
358       return send_id(cl);
359     }
360 }
361
362 int send_ack(conn_list_t *cl)
363 {
364 cp
365   return send_request(cl, "%d", ACK);
366 }
367
368 int ack_h(conn_list_t *cl)
369 {
370   conn_list_t *old;
371 cp
372   /* Okay, before we active the connection, we check if there is another entry
373      in the connection list with the same name. If so, it presumably is an
374      old connection that has timed out but we don't know it yet.
375    */
376
377   while((old = lookup_id(cl->name)))
378     {
379       if(debug_lvl > DEBUG_CONNECTIONS)
380         syslog(LOG_NOTICE, _("Removing old entry for %s at %s in favour of new connection from %s"),
381         cl->name, old->hostname, cl->hostname);
382       old->status.active = 0;
383       terminate_connection(old);
384     }
385
386   /* Activate this connection */
387
388   cl->allow_request = ALL;
389   cl->status.active = 1;
390
391   if(debug_lvl > DEBUG_CONNECTIONS)
392     syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname);
393
394   /* Exchange information about other tinc daemons */
395
396   notify_others(cl, NULL, send_add_host);
397   notify_one(cl);
398
399   upstreamindex = 0;
400
401 cp
402   if(cl->status.outgoing)
403     return 0;
404   else
405     return send_ack(cl);
406 }
407
408 /* Address and subnet information exchange */
409
410 int send_add_subnet(conn_list_t *cl, conn_list_t *other, subnet_t *subnet)
411 {
412   int x;
413   char *netstr;
414 cp
415   x = send_request(cl, "%d %s %s", ADD_SUBNET,
416                       other->name, netstr = net2str(subnet));
417   free(netstr);
418 cp
419   return x;
420 }
421
422 int add_subnet_h(conn_list_t *cl)
423 {
424   char *subnetstr;
425   char *name;
426   conn_list_t *owner;
427   subnet_t *subnet, *old;
428 cp
429   if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
430     {
431       syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
432       free(name); free(subnetstr);
433       return -1;
434     }
435
436   /* Check if owner name is a valid */
437
438   if(!check_id(name))
439     {
440       syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
441       free(name); free(subnetstr);
442       return -1;
443     }
444
445   /* Check if subnet string is valid */
446
447   if((subnet = str2net(subnetstr)) == -1)
448     {
449       syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
450       free(name); free(subnetstr);
451       return -1;
452     }
453
454   free(subnetstr);
455   
456   /* Check if somebody tries to add a subnet of ourself */
457
458   if(!strcmp(name, myself->name))
459     {
460       syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
461              cl->name, cl->hostname);
462       free(name);
463       sighup = 1;
464       return 0;
465     }
466
467   /* Check if the owner of the new subnet is in the connection list */
468
469   if(!(owner = lookup_id(name))
470     {
471       syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
472              name, cl->name, cl->hostname);
473       free(name);
474       return -1;
475     }
476
477   /* If everything is correct, add the subnet to the list of the owner */
478 cp
479   return subnet_add(owner, subnet);
480 }
481
482 int send_del_subnet(conn_list_t *cl, conn_list_t *other, subnet_t *subnet)
483 {
484 cp
485   return send_request(cl, "%d %s %s", DEL_SUBNET, other->name, net2str(subnet));
486 }
487
488 int del_subnet_h(conn_list_t *cl)
489 {
490   char *subnetstr;
491   char *name;
492   conn_list_t *owner;
493   subnet_t *subnet, *old;
494 cp
495   if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
496     {
497       syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
498       free(name); free(subnetstr);
499       return -1;
500     }
501
502   /* Check if owner name is a valid */
503
504   if(!check_id(name))
505     {
506       syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
507       free(name); free(subnetstr);
508       return -1;
509     }
510
511   /* Check if subnet string is valid */
512
513   if((subnet = str2net(subnetstr)) == -1)
514     {
515       syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
516       free(name); free(subnetstr);
517       return -1;
518     }
519
520   free(subnetstr);
521   
522   /* Check if somebody tries to add a subnet of ourself */
523
524   if(!strcmp(name, myself->name))
525     {
526       syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
527              cl->name, cl->hostname);
528       free(name);
529       sighup = 1;
530       return 0;
531     }
532
533   /* Check if the owner of the new subnet is in the connection list */
534
535   if(!(owner = lookup_id(name))
536     {
537       syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
538              name, cl->name, cl->hostname);
539       free(name);
540       return -1;
541     }
542
543   /* If everything is correct, add the subnet to the list of the owner */
544 cp
545   return subnet_del(owner, subnet);
546 }
547
548 /* New and closed connections notification */
549
550 int send_add_host(conn_list_t *cl, conn_list_t *other)
551 {
552   char *optstr;
553   int x;
554 cp
555   x = send_request(cl, "%d %s %s %lx:%d %s", ADD_HOST,
556                       myself->name, other->name, other->real_ip, other->port, optstr = opt2str(other->options));
557   free(optstr);
558 cp
559   return x;
560 }
561
562 int add_host_h(conn_list_t *cl)
563 {
564   char *optstr;
565   char *sender;
566   conn_list_t *old, *new, *hisuplink;
567 cp
568   new = new_conn_list();
569
570   if(sscanf(cl->buffer, "%*d %as %as %lx:%d %as", &sender, &new->name, &new->address, &new->port, &optstr) != 5)
571     {
572        syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
573        return -1;
574     }
575
576   /* Check if option string is valid */
577
578   if((new->options = str2opt(optstr)) == -1)
579     {
580       syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid option string"), cl->name, cl->hostname);
581       free(optstr); free(sender);
582       return -1;
583     }
584
585   free(optstr);
586
587   /* Check if identity is a valid name */
588
589   if(!check_id(new->name) || !check_id(sender))
590     {
591       syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
592       free(sender);
593       return -1;
594     }
595
596   /* Check if somebody tries to add ourself */
597
598   if(!strcmp(new->name, myself->name))
599     {
600       syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
601       sighup = 1;
602       free(sender);
603       return 0;
604     }
605
606   /* We got an ADD_HOST from ourself!? */
607
608   if(!strcmp(sender, myself->name))
609     {
610       syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) from ourself, restarting"), cl->name, cl->hostname);
611       sighup = 1;
612       free(sender);
613       return 0;
614     }
615
616   /* Lookup his uplink */
617
618   if(!(new->hisuplink = lookup_id(sender))
619     {
620       syslog(LOG_ERR, _("Got ADD_HOST from %s (%s) with origin %s which is not in our connection list"),
621              sender, cl->name, cl->hostname);
622       free(sender);
623       return -1;
624     }
625     
626   free(sender);
627
628   /* Fill in more of the new conn_list structure */
629
630   new->hostname = hostlookup(htonl(new->real_ip));
631
632   /* Check if the new host already exists in the connnection list */
633
634   if((old = lookup_id(new->name)))
635     {
636       if((new->real_ip == old->real_ip) && (new->port == old->port))
637         {
638           if(debug_lvl > DEBUG_CONNECTIONS)
639             syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
640                    old->name, old->hostname, new->name, new->hostname);
641           return 0;
642         }
643       else
644         {
645           if(debug_lvl > DEBUG_CONNECTIONS)
646             syslog(LOG_NOTICE, _("Removing old entry for %s (%s)"),
647                    old->name, old->hostname);
648           old->status.active = 0;
649           terminate_connection(old);
650         }
651     }
652
653   /* Fill in rest of conn_list structure */
654
655   new->myuplink = cl;
656   new->status.active = 1;
657
658   /* Hook it up into the conn_list */
659
660   conn_list_add(conn_list, new);
661
662   /* Tell the rest about the new host */
663
664   notify_others(new, cl, send_add_host);
665
666 cp
667   return 0;
668 }
669
670 int send_del_host(conn_list_t *cl, conn_list_t *other)
671 {
672   char *optstr;
673   int x;
674 cp
675   x = send_request(cl, "%d %s %s %lx:%d %s", DEL_HOST,
676                       myself->name, other->name, other->real_ip, other->port, optstr = opt2str(other->options));
677   free(optstr);
678 cp
679   return x;
680 }
681
682 int del_host_h(conn_list_t *cl)
683 {
684   char *name;
685   char *sender;
686   char *opstr;
687   ip_t address;
688   port_t port;
689   int options;
690   conn_list_t *old, *hisuplink;
691
692 cp
693   if(sscanf(cl->buffer, "%*d %as %as %lx:%d %as", &sender, &name, &address, &port, &optstr) != 5)
694     {
695       syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
696              cl->name, cl->hostname);
697       return -1;
698     }
699
700   /* Check if option string is valid */
701
702   if((options = str2opt(optstr)) == -1)
703     {
704       syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid option string"), cl->name, cl->hostname);
705       free(optstr); free(sender); free(name);
706       return -1;
707     }
708
709   free(optstr);
710       
711   /* Check if identity is a valid name */
712
713   if(!check_id(name) || !check_id(sender))
714     {
715       syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
716       free(name); free(sender);
717       return -1;
718     }
719
720   /* Check if somebody tries to delete ourself */
721
722   if(!strcmp(name, myself->name))
723     {
724       syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
725              cl->name, cl->hostname);
726       free(name); free(sender);
727       sighup = 1;
728       return 0;
729     }
730
731   /* We got an ADD_HOST from ourself!? */
732
733   if(!strcmp(sender, myself->name))
734     {
735       syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) from ourself, restarting"), cl->name, cl->hostname);
736       sighup = 1;
737       free(name); free(sender);
738       return 0;
739     }
740
741   /* Lookup his uplink */
742
743   if(!(hisuplink = lookup_id(sender))
744     {
745       syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) with origin %s which is not in our connection list"),
746              cl->name, cl->hostname, sender);
747       free(name); free(sender);
748       return -1;
749     }
750     
751   free(sender);
752
753   /* Check if the new host already exists in the connnection list */
754
755   if(!(old = lookup_id(name)))
756     {
757       syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
758              name, cl->name, cl->hostname);
759       free(name);
760       return -1;
761     }
762   
763   /* Check if the rest matches */
764   
765   if(address!=old->address || port!=old->port || options!=old->options || hisuplink!=old->hisuplink || cl!=old->myuplink)
766     {
767       syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
768       return 0;
769     }
770
771   /* Ok, since EVERYTHING seems to check out all right, delete it */
772
773   old->status.termreq = 1;
774   old->status.active = 0;
775
776   terminate_connection(old);
777 cp
778   return 0;
779 }
780
781 /* Status and error notification routines */
782
783 int send_status(conn_list_t *cl, int statusno, char *statusstring)
784 {
785 cp
786   if(!statusstring)
787     statusstring = status_text[statusno];
788 cp
789   return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
790 }
791
792 int status_h(conn_list_t *cl)
793 {
794   int statusno;
795   char *statusstring;
796 cp
797   if(sscanf(cl->buffer, "%*d %d %as", &statusno, &statusstring) != 2)
798     {
799        syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
800               cl->name, cl->hostname);
801        return -1;
802     }
803
804   if(debug_lvl > DEBUG_STATUS)
805     {
806       syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
807              cl->name, cl->hostname, status_text[statusno], statusstring);
808     }
809
810 cp
811   free(statusstring);
812   return 0;
813 }
814
815 int send_error(conn_list_t *cl, int errno, char *errstring)
816 {
817 cp
818   if(!errstring)
819     errstring = strerror(errno);
820   return send_request(cl, "%d %d %s", ERROR, errno, errstring);
821 }
822
823 int error_h(conn_list_t *cl)
824 {
825   int errno;
826   char *errorstring;
827 cp
828   if(sscanf(cl->buffer, "%*d %d %as", &errno, &errorstring) != 2)
829     {
830        syslog(LOG_ERR, _("Got bad error from %s (%s)"),
831               cl->name, cl->hostname);
832        return -1;
833     }
834
835   if(debug_lvl > DEBUG_error)
836     {
837       syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
838              cl->name, cl->hostname, strerror(errno), errorstring);
839     }
840
841   free(errorstring);
842   cl->status.termreq = 1;
843   terminate_connection(cl);
844 cp
845   return 0;
846 }
847
848 int send_termreq(conn_list_t *cl)
849 {
850 cp
851   return send_request(cl, "%d", TERMREQ);
852 }
853
854 int termreq_h(conn_list_t *cl)
855 {
856 cp
857   cl->status.termreq = 1;
858   terminate_connection(cl);
859 cp
860   return 0;
861 }
862
863 /* Keepalive routines - FIXME: needs a closer look */
864
865 int send_ping(conn_list_t *cl)
866 {
867   cl->status.pinged = 1;
868 cp
869   return send_request(cl, "%d", PING);
870 }
871
872 int ping_h(conn_list_t *cl)
873 {
874 cp
875   return send_pong(cl);
876 }
877
878 int send_pong(conn_list_t *cl)
879 {
880 cp
881   return send_request(cl, "%d", PONG);
882 }
883
884 int pong_h(conn_list_t *cl)
885 {
886 cp
887   cl->status.got_pong = 1;
888 cp
889   return 0;
890 }
891
892 /* Key exchange */
893
894 int send_key_changed(conn_list_t *from, conn_list_t *cl)
895 {
896   conn_list_t *p;
897 cp
898   for(p = conn_list; p != NULL; p = p->next)
899     {
900       if(p!=cl && p->status.meta && p->status.active)
901         send_request(p, "%d %s", KEY_CHANGED,
902                      from->name);
903     }
904 cp
905   return 0;
906 }
907
908 int key_changed_h(conn_list_t *cl)
909 {
910   char *from_id;
911   conn_list_t *from;
912 cp
913   if(sscanf(cl->buffer, "%*d %as", &from_id) != 1)
914     {
915       syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
916              cl->name, cl->hostname);
917       return -1;
918     }
919
920   if(!(from = lookup_id(from_id)))
921     {
922       syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
923              cl->name, cl->hostname, from_id);
924       free(from_id);
925       return -1;
926     }
927
928   free(from_id);
929
930   from->status.validkey = 0;
931   from->status.waitingforkey = 0;
932
933   send_key_changed(from, cl);
934 cp
935   return 0;
936 }
937
938 int send_req_key(conn_list_t *from, conn_list_t *to)
939 {
940 cp
941   return send_request(to->nexthop, "%d %s %s", REQ_KEY,
942                       from->name, to->name);
943 }
944
945 int req_key_h(conn_list_t *cl)
946 {
947   char *from_id, *to_id;
948   conn_list_t *from, *to;
949 cp
950   if(sscanf(cl->buffer, "%*d %as %as", &from_id, &to_id) != 2)
951     {
952        syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
953               cl->name, cl->hostname);
954        return -1;
955     }
956
957   if(!(from = lookup_id(from_id)))
958     {
959       syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
960              cl->name, cl->hostname, from_id);
961       free(from_id); free(to_id);
962       return -1;
963     }
964
965   /* Check if this key request is for us */
966
967   if(!strcmp(to_id, myself->name))
968     {
969       send_ans_key(myself, from, myself->datakey->key);
970     }
971   else
972     {
973       if(!(to = lookup_id(to_id)))
974         {
975           syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
976                  cl->name, cl->hostname, to_id);
977           free(from_id); free(to_id);
978           return -1;
979         }
980       send_req_key(from, to);
981     }
982
983   free(from_id); free(to_id);
984 cp
985   return 0;
986 }
987
988 int send_ans_key(conn_list_t *from, conn_list_t *to, char *datakey)
989 {
990 cp
991   return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
992                       from->name, to->name, datakey);
993 }
994
995 int ans_key_h(conn_list_t *cl)
996 {
997   char *from_id, *to_id, *datakey;
998   int keylength;
999   conn_list_t *from, *to;
1000 cp
1001   if(sscanf(cl->buffer, "%*d %as %as %as", &from_id, &to_id, &datakey) != 3)
1002     {
1003        syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
1004               cl->name, cl->hostname);
1005        return -1;
1006     }
1007
1008   if(!(from = lookup_id(from_id)))
1009     {
1010       syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
1011              cl->name, cl->hostname, from_id);
1012       free(from_id); free(to_id); free(datakey);
1013       return -1;
1014     }
1015
1016   /* Check if this key request is for us */
1017
1018   if(!strcmp(to_id, myself->name))
1019     {
1020       /* It is for us, convert it to binary and set the key with it. */
1021
1022       keylength = strlen(datakey);
1023
1024       if((keylength%2) || (keylength <= 0))
1025         {
1026           syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key"),
1027                  cl->name, cl->hostname, from->name);
1028           free(from_id); free(to_id); free(datakey);
1029           return -1;
1030         }
1031       keylength /= 2;
1032       hex2bin(datakey, datakey, keylength);
1033       BF_set_key(cl->datakey, keylength, datakey);
1034     }
1035   else
1036     {
1037       if(!(to = lookup_id(to_id)))
1038         {
1039           syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1040                  cl->name, cl->hostname, to_id);
1041           free(from_id); free(to_id); free(datakey);
1042           return -1;
1043         }
1044       send_ans_key(from, to, datakey);
1045     }
1046
1047   free(from_id); free(to_id); free(datakey);
1048 cp
1049   return 0;
1050 }
1051
1052 /* Old routines */
1053
1054 /*
1055   Notify all my direct connections of a new host
1056   that was added to the vpn, with the exception
1057   of the source of the announcement.
1058 */
1059
1060 int notify_others(conn_list_t *new, conn_list_t *source,
1061                   int (*function)(conn_list_t*, conn_list_t*))
1062 {
1063   conn_list_t *p;
1064 cp
1065   for(p = conn_list; p != NULL; p = p->next)
1066     if(p != new && p != source && p->status.meta && p->status.active)
1067       function(p, new);
1068 cp
1069   return 0;
1070 }
1071
1072 /*
1073   Notify one connection of everything
1074   I have connected
1075 */
1076
1077 int notify_one(conn_list_t *new)
1078 {
1079   conn_list_t *p;
1080 cp
1081   for(p = conn_list; p != NULL; p = p->next)
1082     if(p != new && p->status.active)
1083       send_add_host(new, p);
1084 cp
1085   return 0;
1086 }
1087
1088 /* "Complete overhaul". */
1089
1090 int (*request_handlers[])(conn_list_t*) = {
1091   id_h, challenge_h, chal_reply_h, ack_h,
1092   status_h, error_h, termreq_h,
1093   ping_h, pong_h,
1094   add_host_h, del_host_h,
1095   add_subnet_h, del_subnet_h,
1096   key_changed_h, req_key_h, ans_key_h,
1097 };
1098
1099 char (*request_name[]) = {
1100   "ID", "CHALLENGE", "CHAL_REPLY", "ACK",
1101   "STATUS", "ERROR", "TERMREQ",
1102   "PING", "PONG",
1103   "ADD_HOST", "DEL_HOST",
1104   "ADD_SUBNET", "DEL_SUBNET",
1105   "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1106 };