Add all the new files to the sources list for the utility library
[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.29 2000/10/18 20:12:09 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 #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 %hd", ID, myself->name, myself->protocol_version, myself->options, myself->port);
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 %hd", &cl->name, &cl->protocol_version, &cl->options, &cl->port) != 4)
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         {
208           if(debug_lvl > DEBUG_CONNECTIONS)
209             syslog(LOG_NOTICE, _("Uplink %s (%s) is already in our connection list"), cl->name, cl->hostname);
210           cl->status.outgoing = 0;
211           old->status.outgoing = 1;
212           terminate_connection(cl);
213           return 0;
214         }
215     }
216 cp
217   return send_challenge(cl);
218 }
219
220 int send_challenge(conn_list_t *cl)
221 {
222   char buffer[CHAL_LENGTH*2+1];
223 cp
224   /* Allocate buffers for the challenge */
225
226   if(!cl->hischallenge)
227     cl->hischallenge = xmalloc(CHAL_LENGTH);
228 cp
229   /* Copy random data to the buffer */
230
231   RAND_bytes(cl->hischallenge, CHAL_LENGTH);
232 cp
233   /* Convert the random data to a hexadecimal formatted string */
234
235   bin2hex(cl->hischallenge, buffer, CHAL_LENGTH);
236   buffer[CHAL_LENGTH*2] = '\0';
237
238   /* Send the challenge */
239
240   cl->allow_request = CHAL_REPLY;
241 cp
242   return send_request(cl, "%d %s", CHALLENGE, buffer);
243 }
244
245 int challenge_h(conn_list_t *cl)
246 {
247   char *buffer;
248 cp
249   if(sscanf(cl->buffer, "%*d %as", &buffer) != 1)
250     {
251        syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
252        return -1;
253     }
254
255   /* Check if the length of the challenge is all right */
256
257   if(strlen(buffer) != CHAL_LENGTH*2)
258     {
259       syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
260       free(buffer);
261       return -1;
262     }
263
264   /* Allocate buffers for the challenge */
265
266   if(!cl->mychallenge)
267     cl->mychallenge = xmalloc(CHAL_LENGTH);
268
269   /* Convert the challenge from hexadecimal back to binary */
270
271   hex2bin(buffer,cl->mychallenge,CHAL_LENGTH);
272   free(buffer);
273     
274   /* Rest is done by send_chal_reply() */
275 cp
276   return send_chal_reply(cl);
277 }
278
279 int send_chal_reply(conn_list_t *cl)
280 {
281   char hash[SHA_DIGEST_LENGTH*2+1];
282 cp
283   if(!cl->mychallenge)
284     {
285       syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
286       return -1;
287     }
288      
289   /* Calculate the hash from the challenge we received */
290
291   SHA1(cl->mychallenge, CHAL_LENGTH, hash);
292
293   /* Convert the hash to a hexadecimal formatted string */
294
295   bin2hex(hash,hash,SHA_DIGEST_LENGTH);
296   hash[SHA_DIGEST_LENGTH*2] = '\0';
297
298   /* Send the reply */
299
300   if(cl->status.outgoing)
301     cl->allow_request = ID;
302   else
303     cl->allow_request = ACK;
304
305 cp
306   return send_request(cl, "%d %s", CHAL_REPLY, hash);
307 }
308
309 int chal_reply_h(conn_list_t *cl)
310 {
311   char *hishash;
312   char myhash[SHA_DIGEST_LENGTH];
313 cp
314   if(sscanf(cl->buffer, "%*d %as", &hishash) != 1)
315     {
316        syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
317        free(hishash);
318        return -1;
319     }
320
321   /* Check if the length of the hash is all right */
322
323   if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
324     {
325       syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
326       free(hishash);
327       return -1;
328     }
329
330   /* Convert the hash to binary format */
331
332   hex2bin(hishash, hishash, SHA_DIGEST_LENGTH);
333
334   /* Calculate the hash from the challenge we sent */
335
336   SHA1(cl->hischallenge, CHAL_LENGTH, myhash);
337
338   /* Verify the incoming hash with the calculated hash */
339
340   if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
341     {
342       syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
343       free(hishash);
344       return -1;
345     }
346
347   free(hishash);
348
349   /* Identity has now been positively verified.
350      If we are accepting this new connection, then send our identity,
351      if we are making this connecting, acknowledge.
352    */
353 cp
354   if(cl->status.outgoing)
355       return send_ack(cl);
356   else
357       return send_id(cl);
358 }
359
360 int send_ack(conn_list_t *cl)
361 {
362 cp
363   cl->allow_request = ACK;
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 /* FIXME: reprogram this.
397   notify_others(cl, NULL, send_add_host);
398   notify_one(cl);
399 */
400   upstreamindex = 0;
401
402 cp
403   if(cl->status.outgoing)
404     return 0;
405   else
406     return send_ack(cl);
407 }
408
409 /* Address and subnet information exchange */
410
411 int send_add_subnet(conn_list_t *cl, conn_list_t *other, subnet_t *subnet)
412 {
413   int x;
414   char *netstr;
415 cp
416   x = send_request(cl, "%d %s %s", ADD_SUBNET,
417                       other->name, netstr = net2str(subnet));
418   free(netstr);
419 cp
420   return x;
421 }
422
423 int add_subnet_h(conn_list_t *cl)
424 {
425   char *subnetstr;
426   char *name;
427   conn_list_t *owner;
428   subnet_t *subnet, *old;
429 cp
430   if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
431     {
432       syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
433       free(name); free(subnetstr);
434       return -1;
435     }
436
437   /* Check if owner name is a valid */
438
439   if(check_id(name))
440     {
441       syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
442       free(name); free(subnetstr);
443       return -1;
444     }
445
446   /* Check if subnet string is valid */
447
448   if(!(subnet = str2net(subnetstr)))
449     {
450       syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
451       free(name); free(subnetstr);
452       return -1;
453     }
454
455   free(subnetstr);
456   
457   /* Check if somebody tries to add a subnet of ourself */
458
459   if(!strcmp(name, myself->name))
460     {
461       syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
462              cl->name, cl->hostname);
463       free(name);
464       sighup = 1;
465       return 0;
466     }
467
468   /* Check if the owner of the new subnet is in the connection list */
469
470   if(!(owner = lookup_id(name)))
471     {
472       syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
473              name, cl->name, cl->hostname);
474       free(name);
475       return -1;
476     }
477
478   /* If everything is correct, add the subnet to the list of the owner */
479
480   subnet_add(owner, subnet);
481 cp
482   return 0;
483 }
484
485 int send_del_subnet(conn_list_t *cl, conn_list_t *other, subnet_t *subnet)
486 {
487 cp
488   return send_request(cl, "%d %s %s", DEL_SUBNET, other->name, net2str(subnet));
489 }
490
491 int del_subnet_h(conn_list_t *cl)
492 {
493   char *subnetstr;
494   char *name;
495   conn_list_t *owner;
496   subnet_t *subnet, *old;
497 cp
498   if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
499     {
500       syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
501       free(name); free(subnetstr);
502       return -1;
503     }
504
505   /* Check if owner name is a valid */
506
507   if(check_id(name))
508     {
509       syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
510       free(name); free(subnetstr);
511       return -1;
512     }
513
514   /* Check if subnet string is valid */
515
516   if(!(subnet = str2net(subnetstr)))
517     {
518       syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
519       free(name); free(subnetstr);
520       return -1;
521     }
522
523   free(subnetstr);
524   
525   /* Check if somebody tries to add a subnet of ourself */
526
527   if(!strcmp(name, myself->name))
528     {
529       syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
530              cl->name, cl->hostname);
531       free(name);
532       sighup = 1;
533       return 0;
534     }
535
536   /* Check if the owner of the new subnet is in the connection list */
537
538   if(!(owner = lookup_id(name)))
539     {
540       syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
541              name, cl->name, cl->hostname);
542       free(name);
543       return -1;
544     }
545
546   /* If everything is correct, delete the subnet from the list of the owner */
547
548   subnet_del(subnet);
549 cp
550   return 0;
551 }
552
553 /* New and closed connections notification */
554
555 int send_add_host(conn_list_t *cl, conn_list_t *other)
556 {
557 cp
558   return send_request(cl, "%d %s %s %lx:%d %lx", ADD_HOST,
559                       myself->name, other->name, other->address, other->port, other->options);
560 }
561
562 int add_host_h(conn_list_t *cl)
563 {
564   char *sender;
565   conn_list_t *old, *new, *hisuplink;
566 cp
567   new = new_conn_list();
568
569   if(sscanf(cl->buffer, "%*d %as %as %lx:%d %lx", &sender, &new->name, &new->address, &new->port, &new->options) != 5)
570     {
571        syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
572        return -1;
573     }
574
575   /* Check if identity is a valid name */
576
577   if(check_id(new->name) || check_id(sender))
578     {
579       syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
580       free(sender);
581       return -1;
582     }
583
584   /* Check if somebody tries to add ourself */
585
586   if(!strcmp(new->name, myself->name))
587     {
588       syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
589       sighup = 1;
590       free(sender);
591       return 0;
592     }
593
594   /* We got an ADD_HOST from ourself!? */
595
596   if(!strcmp(sender, myself->name))
597     {
598       syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) from ourself, restarting"), cl->name, cl->hostname);
599       sighup = 1;
600       free(sender);
601       return 0;
602     }
603
604   /* Lookup his uplink */
605
606   if(!(new->hisuplink = lookup_id(sender)))
607     {
608       syslog(LOG_ERR, _("Got ADD_HOST from %s (%s) with origin %s which is not in our connection list"),
609              sender, cl->name, cl->hostname);
610       free(sender);
611       return -1;
612     }
613     
614   free(sender);
615
616   /* Fill in more of the new conn_list structure */
617
618   new->hostname = hostlookup(htonl(new->address));
619
620   /* Check if the new host already exists in the connnection list */
621
622   if((old = lookup_id(new->name)))
623     {
624       if((new->address == old->address) && (new->port == old->port))
625         {
626           if(debug_lvl > DEBUG_CONNECTIONS)
627             syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
628                    old->name, old->hostname, new->name, new->hostname);
629           return 0;
630         }
631       else
632         {
633           if(debug_lvl > DEBUG_CONNECTIONS)
634             syslog(LOG_NOTICE, _("Removing old entry for %s (%s)"),
635                    old->name, old->hostname);
636           old->status.active = 0;
637           terminate_connection(old);
638         }
639     }
640
641   /* Fill in rest of conn_list structure */
642
643   new->myuplink = cl;
644   new->status.active = 1;
645
646   /* Hook it up into the conn_list */
647
648   conn_list_add(conn_list, new);
649
650   /* Tell the rest about the new host */
651 /* FIXME: reprogram this.
652   notify_others(new, cl, send_add_host);
653 */
654 cp
655   return 0;
656 }
657
658 int send_del_host(conn_list_t *cl, conn_list_t *other)
659 {
660 cp
661   return send_request(cl, "%d %s %s %lx:%d %lx", DEL_HOST,
662                       myself->name, other->name, other->address, other->port, other->options);
663 }
664
665 int del_host_h(conn_list_t *cl)
666 {
667   char *name;
668   char *sender;
669   ip_t address;
670   port_t port;
671   int options;
672   conn_list_t *old, *hisuplink;
673
674 cp
675   if(sscanf(cl->buffer, "%*d %as %as %lx:%d %lx", &sender, &name, &address, &port, &options) != 5)
676     {
677       syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
678              cl->name, cl->hostname);
679       return -1;
680     }
681
682   /* Check if identity is a valid name */
683
684   if(check_id(name) || check_id(sender))
685     {
686       syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
687       free(name); free(sender);
688       return -1;
689     }
690
691   /* Check if somebody tries to delete ourself */
692
693   if(!strcmp(name, myself->name))
694     {
695       syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
696              cl->name, cl->hostname);
697       free(name); free(sender);
698       sighup = 1;
699       return 0;
700     }
701
702   /* We got an ADD_HOST from ourself!? */
703
704   if(!strcmp(sender, myself->name))
705     {
706       syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) from ourself, restarting"), cl->name, cl->hostname);
707       sighup = 1;
708       free(name); free(sender);
709       return 0;
710     }
711
712   /* Lookup his uplink */
713
714   if(!(hisuplink = lookup_id(sender)))
715     {
716       syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) with origin %s which is not in our connection list"),
717              cl->name, cl->hostname, sender);
718       free(name); free(sender);
719       return -1;
720     }
721     
722   free(sender);
723
724   /* Check if the new host already exists in the connnection list */
725
726   if(!(old = lookup_id(name)))
727     {
728       syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
729              name, cl->name, cl->hostname);
730       free(name);
731       return -1;
732     }
733   
734   /* Check if the rest matches */
735   
736   if(address!=old->address || port!=old->port || options!=old->options || hisuplink!=old->hisuplink || cl!=old->myuplink)
737     {
738       syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
739       return 0;
740     }
741
742   /* Ok, since EVERYTHING seems to check out all right, delete it */
743
744   old->status.termreq = 1;
745   old->status.active = 0;
746
747   terminate_connection(old);
748 cp
749   return 0;
750 }
751
752 /* Status and error notification routines */
753
754 int send_status(conn_list_t *cl, int statusno, char *statusstring)
755 {
756 cp
757   if(!statusstring)
758     statusstring = status_text[statusno];
759 cp
760   return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
761 }
762
763 int status_h(conn_list_t *cl)
764 {
765   int statusno;
766   char *statusstring;
767 cp
768   if(sscanf(cl->buffer, "%*d %d %as", &statusno, &statusstring) != 2)
769     {
770        syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
771               cl->name, cl->hostname);
772        return -1;
773     }
774
775   if(debug_lvl > DEBUG_STATUS)
776     {
777       syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
778              cl->name, cl->hostname, status_text[statusno], statusstring);
779     }
780
781 cp
782   free(statusstring);
783   return 0;
784 }
785
786 int send_error(conn_list_t *cl, int errno, char *errstring)
787 {
788 cp
789   if(!errstring)
790     errstring = strerror(errno);
791   return send_request(cl, "%d %d %s", ERROR, errno, errstring);
792 }
793
794 int error_h(conn_list_t *cl)
795 {
796   int errno;
797   char *errorstring;
798 cp
799   if(sscanf(cl->buffer, "%*d %d %as", &errno, &errorstring) != 2)
800     {
801        syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
802               cl->name, cl->hostname);
803        return -1;
804     }
805
806   if(debug_lvl > DEBUG_ERROR)
807     {
808       syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
809              cl->name, cl->hostname, strerror(errno), errorstring);
810     }
811
812   free(errorstring);
813   cl->status.termreq = 1;
814   terminate_connection(cl);
815 cp
816   return 0;
817 }
818
819 int send_termreq(conn_list_t *cl)
820 {
821 cp
822   return send_request(cl, "%d", TERMREQ);
823 }
824
825 int termreq_h(conn_list_t *cl)
826 {
827 cp
828   cl->status.termreq = 1;
829   terminate_connection(cl);
830 cp
831   return 0;
832 }
833
834 /* Keepalive routines - FIXME: needs a closer look */
835
836 int send_ping(conn_list_t *cl)
837 {
838   cl->status.pinged = 1;
839 cp
840   return send_request(cl, "%d", PING);
841 }
842
843 int ping_h(conn_list_t *cl)
844 {
845 cp
846   return send_pong(cl);
847 }
848
849 int send_pong(conn_list_t *cl)
850 {
851 cp
852   return send_request(cl, "%d", PONG);
853 }
854
855 int pong_h(conn_list_t *cl)
856 {
857 cp
858   cl->status.got_pong = 1;
859 cp
860   return 0;
861 }
862
863 /* Key exchange */
864
865 int send_key_changed(conn_list_t *from, conn_list_t *cl)
866 {
867   conn_list_t *p;
868 cp
869   for(p = conn_list; p != NULL; p = p->next)
870     {
871       if(p!=cl && p->status.meta && p->status.active)
872         send_request(p, "%d %s", KEY_CHANGED,
873                      from->name);
874     }
875 cp
876   return 0;
877 }
878
879 int key_changed_h(conn_list_t *cl)
880 {
881   char *from_id;
882   conn_list_t *from;
883 cp
884   if(sscanf(cl->buffer, "%*d %as", &from_id) != 1)
885     {
886       syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
887              cl->name, cl->hostname);
888       return -1;
889     }
890
891   if(!(from = lookup_id(from_id)))
892     {
893       syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
894              cl->name, cl->hostname, from_id);
895       free(from_id);
896       return -1;
897     }
898
899   free(from_id);
900
901   from->status.validkey = 0;
902   from->status.waitingforkey = 0;
903
904   send_key_changed(from, cl);
905 cp
906   return 0;
907 }
908
909 int send_req_key(conn_list_t *from, conn_list_t *to)
910 {
911 cp
912   return send_request(to->nexthop, "%d %s %s", REQ_KEY,
913                       from->name, to->name);
914 }
915
916 int req_key_h(conn_list_t *cl)
917 {
918   char *from_id, *to_id;
919   conn_list_t *from, *to;
920 cp
921   if(sscanf(cl->buffer, "%*d %as %as", &from_id, &to_id) != 2)
922     {
923        syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
924               cl->name, cl->hostname);
925        return -1;
926     }
927
928   if(!(from = lookup_id(from_id)))
929     {
930       syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
931              cl->name, cl->hostname, from_id);
932       free(from_id); free(to_id);
933       return -1;
934     }
935
936   /* Check if this key request is for us */
937
938   if(!strcmp(to_id, myself->name))
939     {
940       send_ans_key(myself, from, myself->cipher_pktkey);
941     }
942   else
943     {
944       if(!(to = lookup_id(to_id)))
945         {
946           syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
947                  cl->name, cl->hostname, to_id);
948           free(from_id); free(to_id);
949           return -1;
950         }
951       send_req_key(from, to);
952     }
953
954   free(from_id); free(to_id);
955 cp
956   return 0;
957 }
958
959 int send_ans_key(conn_list_t *from, conn_list_t *to, char *pktkey)
960 {
961 cp
962   return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
963                       from->name, to->name, pktkey);
964 }
965
966 int ans_key_h(conn_list_t *cl)
967 {
968   char *from_id, *to_id, *pktkey;
969   int keylength;
970   conn_list_t *from, *to;
971 cp
972   if(sscanf(cl->buffer, "%*d %as %as %as", &from_id, &to_id, &pktkey) != 3)
973     {
974        syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
975               cl->name, cl->hostname);
976        return -1;
977     }
978
979   if(!(from = lookup_id(from_id)))
980     {
981       syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
982              cl->name, cl->hostname, from_id);
983       free(from_id); free(to_id); free(pktkey);
984       return -1;
985     }
986
987   /* Check if this key request is for us */
988
989   if(!strcmp(to_id, myself->name))
990     {
991       /* It is for us, convert it to binary and set the key with it. */
992
993       keylength = strlen(pktkey);
994
995       if((keylength%2) || (keylength <= 0))
996         {
997           syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key"),
998                  cl->name, cl->hostname, from->name);
999           free(from_id); free(to_id); free(pktkey);
1000           return -1;
1001         }
1002       keylength /= 2;
1003       hex2bin(pktkey, pktkey, keylength);
1004       BF_set_key(cl->cipher_pktkey, keylength, pktkey);
1005     }
1006   else
1007     {
1008       if(!(to = lookup_id(to_id)))
1009         {
1010           syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1011                  cl->name, cl->hostname, to_id);
1012           free(from_id); free(to_id); free(pktkey);
1013           return -1;
1014         }
1015       send_ans_key(from, to, pktkey);
1016     }
1017
1018   free(from_id); free(to_id); free(pktkey);
1019 cp
1020   return 0;
1021 }
1022
1023 /* Jumptable for the request handlers */
1024
1025 int (*request_handlers[])(conn_list_t*) = {
1026   id_h, challenge_h, chal_reply_h, ack_h,
1027   status_h, error_h, termreq_h,
1028   ping_h, pong_h,
1029   add_host_h, del_host_h,
1030   add_subnet_h, del_subnet_h,
1031   key_changed_h, req_key_h, ans_key_h,
1032 };
1033
1034 /* Request names */
1035
1036 char (*request_name[]) = {
1037   "ID", "CHALLENGE", "CHAL_REPLY", "ACK",
1038   "STATUS", "ERROR", "TERMREQ",
1039   "PING", "PONG",
1040   "ADD_HOST", "DEL_HOST",
1041   "ADD_SUBNET", "DEL_SUBNET",
1042   "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1043 };
1044
1045 /* Status strings */
1046
1047 char (*status_text[]) = {
1048   "Warning",
1049 };
1050
1051 /* Error strings */
1052
1053 char (*error_text[]) = {
1054   "Error",
1055 };