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