cb5c92fc75a0da49ab790fece8955d6ba3426673
[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.41 2000/10/16 16:33:30 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     if(!isalnum(id[i]) && id[i] != '_')
56       return -1;
57           
58   return 0;
59 }
60
61 /* Generic request routines - takes care of logging and error detection as well */
62
63 int send_request(conn_list_t *cl, const char *format, ...)
64 {
65   va_list args;
66   char buffer[MAXBUFSIZE];
67   int len, request;
68
69 cp
70   /* Use vsnprintf instead of vasprintf: faster, no memory fragmentation, cleanup is automatic,
71      and there is a limit on the input buffer anyway */
72
73   va_start(args, format);
74   len = vsnprintf(buffer, MAXBUFSIZE, format, args);
75   request = va_arg(args, int);
76   va_end(args);
77
78   if(len < 0 || len > MAXBUFSIZE-1)
79     {
80       syslog(LOG_ERR, _("Output buffer overflow while sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
81       return -1;
82     }
83
84   len++;
85
86   if(debug_lvl >= DEBUG_PROTOCOL)
87     syslog(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
88
89 cp
90   return send_meta(cl, buffer, len);
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   cl->allow_request = CHALLENGE;
159 cp
160   return send_request(cl, "%d %s %d %lx", ID, myself->name, myself->protocol_version, myself->options);
161 }
162
163 int id_h(conn_list_t *cl)
164 {
165   conn_list_t *old;
166 cp
167   if(sscanf(cl->buffer, "%*d %as %d %lx", &cl->name, &cl->protocol_version, &cl->options) != 3)
168     {
169        syslog(LOG_ERR, _("Got bad ID from %s"), cl->hostname);
170        return -1;
171     }
172
173   /* Check if version matches */
174
175   if(cl->protocol_version != myself->protocol_version)
176     {
177       syslog(LOG_ERR, _("Peer %s (%s) uses incompatible version %d"),
178              cl->name, cl->hostname, cl->protocol_version);
179       return -1;
180     }
181
182   /* Check if identity is a valid name */
183
184   if(check_id(cl->name))
185     {
186       syslog(LOG_ERR, _("Peer %s uses invalid identity name"), cl->hostname);
187       return -1;
188     }
189
190   /* Load information about peer */
191
192   if(read_host_config(cl))
193     {
194       syslog(LOG_ERR, _("Peer %s had unknown identity (%s)"), cl->hostname, cl->name);
195       return -1;
196     }
197
198
199   /* First check if the host we connected to is already in our
200      connection list. If so, we are probably making a loop, which
201      is not desirable.
202    */
203
204   if(cl->status.outgoing)
205     {
206       if((old = lookup_id(cl->name)))
207        if(old != cl)
208         {
209           if(debug_lvl > DEBUG_CONNECTIONS)
210             syslog(LOG_NOTICE, _("Uplink %s (%s) is already in our connection list"), cl->name, cl->hostname);
211           cl->status.outgoing = 0;
212           old->status.outgoing = 1;
213           terminate_connection(cl);
214           return 0;
215         }
216     }
217 cp
218   return send_challenge(cl);
219 }
220
221 int send_challenge(conn_list_t *cl)
222 {
223   char buffer[CHAL_LENGTH*2+1];
224 cp
225   /* Allocate buffers for the challenge */
226
227   if(!cl->hischallenge)
228     cl->hischallenge = xmalloc(CHAL_LENGTH);
229 cp
230   /* Copy random data to the buffer */
231
232   RAND_bytes(cl->hischallenge, CHAL_LENGTH);
233 cp
234   /* Convert the random data to a hexadecimal formatted string */
235
236   bin2hex(cl->hischallenge, buffer, CHAL_LENGTH);
237   buffer[CHAL_LENGTH*2] = '\0';
238
239   /* Send the challenge */
240
241   cl->allow_request = CHAL_REPLY;
242 cp
243   return send_request(cl, "%d %s", CHALLENGE, buffer);
244 }
245
246 int challenge_h(conn_list_t *cl)
247 {
248   char *buffer;
249 cp
250   if(sscanf(cl->buffer, "%*d %as", &buffer) != 1)
251     {
252        syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
253        return -1;
254     }
255
256   /* Check if the length of the challenge is all right */
257
258   if(strlen(buffer) != CHAL_LENGTH*2)
259     {
260       syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
261       free(buffer);
262       return -1;
263     }
264
265   /* Allocate buffers for the challenge */
266
267   if(!cl->mychallenge)
268     cl->mychallenge = xmalloc(CHAL_LENGTH);
269
270   /* Convert the challenge from hexadecimal back to binary */
271
272   hex2bin(buffer,cl->mychallenge,CHAL_LENGTH);
273   free(buffer);
274     
275   /* Rest is done by send_chal_reply() */
276 cp
277   return send_chal_reply(cl);
278 }
279
280 int send_chal_reply(conn_list_t *cl)
281 {
282   char hash[SHA_DIGEST_LENGTH*2+1];
283 cp
284   if(!cl->mychallenge)
285     {
286       syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
287       return -1;
288     }
289      
290   /* Calculate the hash from the challenge we received */
291
292   SHA1(cl->mychallenge, CHAL_LENGTH, hash);
293
294   /* Convert the hash to a hexadecimal formatted string */
295
296   bin2hex(hash,hash,SHA_DIGEST_LENGTH);
297   hash[SHA_DIGEST_LENGTH*2] = '\0';
298
299   /* Send the reply */
300
301   if(cl->status.outgoing)
302     cl->allow_request = ID;
303   else
304     cl->allow_request = ACK;
305
306 cp
307   return send_request(cl, "%d %s", CHAL_REPLY, hash);
308 }
309
310 int chal_reply_h(conn_list_t *cl)
311 {
312   char *hishash;
313   char myhash[SHA_DIGEST_LENGTH];
314 cp
315   if(sscanf(cl->buffer, "%*d %as", &hishash) != 1)
316     {
317        syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
318        free(hishash);
319        return -1;
320     }
321
322   /* Check if the length of the hash is all right */
323
324   if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
325     {
326       syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
327       free(hishash);
328       return -1;
329     }
330
331   /* Convert the hash to binary format */
332
333   hex2bin(hishash, hishash, SHA_DIGEST_LENGTH);
334
335   /* Calculate the hash from the challenge we sent */
336
337   SHA1(cl->hischallenge, CHAL_LENGTH, myhash);
338
339   /* Verify the incoming hash with the calculated hash */
340
341   if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
342     {
343       syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
344       free(hishash);
345       return -1;
346     }
347
348   free(hishash);
349
350   /* Identity has now been positively verified.
351      If we are accepting this new connection, then send our identity,
352      if we are making this connecting, acknowledge.
353    */
354 cp
355   if(cl->status.outgoing)
356       return send_ack(cl);
357   else
358       return send_id(cl);
359 }
360
361 int send_ack(conn_list_t *cl)
362 {
363 cp
364   cl->allow_request = ACK;
365 cp
366   return send_request(cl, "%d", ACK);
367 }
368
369 int ack_h(conn_list_t *cl)
370 {
371   conn_list_t *old;
372 cp
373   /* Okay, before we active the connection, we check if there is another entry
374      in the connection list with the same name. If so, it presumably is an
375      old connection that has timed out but we don't know it yet.
376    */
377
378   while((old = lookup_id(cl->name)))
379     {
380       if(debug_lvl > DEBUG_CONNECTIONS)
381         syslog(LOG_NOTICE, _("Removing old entry for %s at %s in favour of new connection from %s"),
382         cl->name, old->hostname, cl->hostname);
383       old->status.active = 0;
384       terminate_connection(old);
385     }
386
387   /* Activate this connection */
388
389   cl->allow_request = ALL;
390   cl->status.active = 1;
391
392   if(debug_lvl > DEBUG_CONNECTIONS)
393     syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname);
394
395   /* Exchange information about other tinc daemons */
396
397 /* FIXME: reprogram this.
398   notify_others(cl, NULL, send_add_host);
399   notify_one(cl);
400 */
401   upstreamindex = 0;
402
403 cp
404   if(cl->status.outgoing)
405     return 0;
406   else
407     return send_ack(cl);
408 }
409
410 /* Address and subnet information exchange */
411
412 int send_add_subnet(conn_list_t *cl, conn_list_t *other, subnet_t *subnet)
413 {
414   int x;
415   char *netstr;
416 cp
417   x = send_request(cl, "%d %s %s", ADD_SUBNET,
418                       other->name, netstr = net2str(subnet));
419   free(netstr);
420 cp
421   return x;
422 }
423
424 int add_subnet_h(conn_list_t *cl)
425 {
426   char *subnetstr;
427   char *name;
428   conn_list_t *owner;
429   subnet_t *subnet, *old;
430 cp
431   if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
432     {
433       syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
434       free(name); free(subnetstr);
435       return -1;
436     }
437
438   /* Check if owner name is a valid */
439
440   if(check_id(name))
441     {
442       syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
443       free(name); free(subnetstr);
444       return -1;
445     }
446
447   /* Check if subnet string is valid */
448
449   if(!(subnet = str2net(subnetstr)))
450     {
451       syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
452       free(name); free(subnetstr);
453       return -1;
454     }
455
456   free(subnetstr);
457   
458   /* Check if somebody tries to add a subnet of ourself */
459
460   if(!strcmp(name, myself->name))
461     {
462       syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
463              cl->name, cl->hostname);
464       free(name);
465       sighup = 1;
466       return 0;
467     }
468
469   /* Check if the owner of the new subnet is in the connection list */
470
471   if(!(owner = lookup_id(name)))
472     {
473       syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
474              name, cl->name, cl->hostname);
475       free(name);
476       return -1;
477     }
478
479   /* If everything is correct, add the subnet to the list of the owner */
480
481   subnet_add(owner, subnet);
482 cp
483   return 0;
484 }
485
486 int send_del_subnet(conn_list_t *cl, conn_list_t *other, subnet_t *subnet)
487 {
488 cp
489   return send_request(cl, "%d %s %s", DEL_SUBNET, other->name, net2str(subnet));
490 }
491
492 int del_subnet_h(conn_list_t *cl)
493 {
494   char *subnetstr;
495   char *name;
496   conn_list_t *owner;
497   subnet_t *subnet, *old;
498 cp
499   if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
500     {
501       syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
502       free(name); free(subnetstr);
503       return -1;
504     }
505
506   /* Check if owner name is a valid */
507
508   if(check_id(name))
509     {
510       syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
511       free(name); free(subnetstr);
512       return -1;
513     }
514
515   /* Check if subnet string is valid */
516
517   if(!(subnet = str2net(subnetstr)))
518     {
519       syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
520       free(name); free(subnetstr);
521       return -1;
522     }
523
524   free(subnetstr);
525   
526   /* Check if somebody tries to add a subnet of ourself */
527
528   if(!strcmp(name, myself->name))
529     {
530       syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
531              cl->name, cl->hostname);
532       free(name);
533       sighup = 1;
534       return 0;
535     }
536
537   /* Check if the owner of the new subnet is in the connection list */
538
539   if(!(owner = lookup_id(name)))
540     {
541       syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
542              name, cl->name, cl->hostname);
543       free(name);
544       return -1;
545     }
546
547   /* If everything is correct, delete the subnet from the list of the owner */
548
549   subnet_del(subnet);
550 cp
551   return 0;
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->address, 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->address));
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->address == old->address) && (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 /* FIXME: reprogram this.
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->address, 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->cipher_pktkey);
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 *pktkey)
961 {
962 cp
963   return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
964                       from->name, to->name, pktkey);
965 }
966
967 int ans_key_h(conn_list_t *cl)
968 {
969   char *from_id, *to_id, *pktkey;
970   int keylength;
971   conn_list_t *from, *to;
972 cp
973   if(sscanf(cl->buffer, "%*d %as %as %as", &from_id, &to_id, &pktkey) != 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(pktkey);
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(pktkey);
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(pktkey);
1001           return -1;
1002         }
1003       keylength /= 2;
1004       hex2bin(pktkey, pktkey, keylength);
1005       BF_set_key(cl->cipher_pktkey, keylength, pktkey);
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(pktkey);
1014           return -1;
1015         }
1016       send_ans_key(from, to, pktkey);
1017     }
1018
1019   free(from_id); free(to_id); free(pktkey);
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 };
1045
1046 /* Status strings */
1047
1048 char (*status_text[]) = {
1049   "Warning",
1050 };
1051
1052 /* Error strings */
1053
1054 char (*error_text[]) = {
1055   "Error",
1056 };