25ed4d019ad347eee1a2cf05890d6f6dc4a0c94e
[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.38 2000/10/11 22:01:00 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, 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   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[CHAL_LENGTH*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)))
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
485   subnet_add(owner, subnet);
486 cp
487   return 0;
488 }
489
490 int send_del_subnet(conn_list_t *cl, conn_list_t *other, subnet_t *subnet)
491 {
492 cp
493   return send_request(cl, "%d %s %s", DEL_SUBNET, other->name, net2str(subnet));
494 }
495
496 int del_subnet_h(conn_list_t *cl)
497 {
498   char *subnetstr;
499   char *name;
500   conn_list_t *owner;
501   subnet_t *subnet, *old;
502 cp
503   if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
504     {
505       syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
506       free(name); free(subnetstr);
507       return -1;
508     }
509
510   /* Check if owner name is a valid */
511
512   if(!check_id(name))
513     {
514       syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
515       free(name); free(subnetstr);
516       return -1;
517     }
518
519   /* Check if subnet string is valid */
520
521   if(!(subnet = str2net(subnetstr)))
522     {
523       syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
524       free(name); free(subnetstr);
525       return -1;
526     }
527
528   free(subnetstr);
529   
530   /* Check if somebody tries to add a subnet of ourself */
531
532   if(!strcmp(name, myself->name))
533     {
534       syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
535              cl->name, cl->hostname);
536       free(name);
537       sighup = 1;
538       return 0;
539     }
540
541   /* Check if the owner of the new subnet is in the connection list */
542
543   if(!(owner = lookup_id(name)))
544     {
545       syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
546              name, cl->name, cl->hostname);
547       free(name);
548       return -1;
549     }
550
551   /* If everything is correct, delete the subnet from the list of the owner */
552
553   subnet_del(subnet);
554 cp
555   return 0;
556 }
557
558 /* New and closed connections notification */
559
560 int send_add_host(conn_list_t *cl, conn_list_t *other)
561 {
562 cp
563   return send_request(cl, "%d %s %s %lx:%d %lx", ADD_HOST,
564                       myself->name, other->name, other->address, other->port, other->options);
565 }
566
567 int add_host_h(conn_list_t *cl)
568 {
569   char *sender;
570   conn_list_t *old, *new, *hisuplink;
571 cp
572   new = new_conn_list();
573
574   if(sscanf(cl->buffer, "%*d %as %as %lx:%d %lx", &sender, &new->name, &new->address, &new->port, &new->options) != 5)
575     {
576        syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
577        return -1;
578     }
579
580   /* Check if identity is a valid name */
581
582   if(!check_id(new->name) || !check_id(sender))
583     {
584       syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
585       free(sender);
586       return -1;
587     }
588
589   /* Check if somebody tries to add ourself */
590
591   if(!strcmp(new->name, myself->name))
592     {
593       syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
594       sighup = 1;
595       free(sender);
596       return 0;
597     }
598
599   /* We got an ADD_HOST from ourself!? */
600
601   if(!strcmp(sender, myself->name))
602     {
603       syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) from ourself, restarting"), cl->name, cl->hostname);
604       sighup = 1;
605       free(sender);
606       return 0;
607     }
608
609   /* Lookup his uplink */
610
611   if(!(new->hisuplink = lookup_id(sender)))
612     {
613       syslog(LOG_ERR, _("Got ADD_HOST from %s (%s) with origin %s which is not in our connection list"),
614              sender, cl->name, cl->hostname);
615       free(sender);
616       return -1;
617     }
618     
619   free(sender);
620
621   /* Fill in more of the new conn_list structure */
622
623   new->hostname = hostlookup(htonl(new->address));
624
625   /* Check if the new host already exists in the connnection list */
626
627   if((old = lookup_id(new->name)))
628     {
629       if((new->address == old->address) && (new->port == old->port))
630         {
631           if(debug_lvl > DEBUG_CONNECTIONS)
632             syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
633                    old->name, old->hostname, new->name, new->hostname);
634           return 0;
635         }
636       else
637         {
638           if(debug_lvl > DEBUG_CONNECTIONS)
639             syslog(LOG_NOTICE, _("Removing old entry for %s (%s)"),
640                    old->name, old->hostname);
641           old->status.active = 0;
642           terminate_connection(old);
643         }
644     }
645
646   /* Fill in rest of conn_list structure */
647
648   new->myuplink = cl;
649   new->status.active = 1;
650
651   /* Hook it up into the conn_list */
652
653   conn_list_add(conn_list, new);
654
655   /* Tell the rest about the new host */
656
657   notify_others(new, cl, send_add_host);
658
659 cp
660   return 0;
661 }
662
663 int send_del_host(conn_list_t *cl, conn_list_t *other)
664 {
665 cp
666   return send_request(cl, "%d %s %s %lx:%d %lx", DEL_HOST,
667                       myself->name, other->name, other->address, other->port, other->options);
668 }
669
670 int del_host_h(conn_list_t *cl)
671 {
672   char *name;
673   char *sender;
674   ip_t address;
675   port_t port;
676   int options;
677   conn_list_t *old, *hisuplink;
678
679 cp
680   if(sscanf(cl->buffer, "%*d %as %as %lx:%d %lx", &sender, &name, &address, &port, &options) != 5)
681     {
682       syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
683              cl->name, cl->hostname);
684       return -1;
685     }
686
687   /* Check if identity is a valid name */
688
689   if(!check_id(name) || !check_id(sender))
690     {
691       syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
692       free(name); free(sender);
693       return -1;
694     }
695
696   /* Check if somebody tries to delete ourself */
697
698   if(!strcmp(name, myself->name))
699     {
700       syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
701              cl->name, cl->hostname);
702       free(name); free(sender);
703       sighup = 1;
704       return 0;
705     }
706
707   /* We got an ADD_HOST from ourself!? */
708
709   if(!strcmp(sender, myself->name))
710     {
711       syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) from ourself, restarting"), cl->name, cl->hostname);
712       sighup = 1;
713       free(name); free(sender);
714       return 0;
715     }
716
717   /* Lookup his uplink */
718
719   if(!(hisuplink = lookup_id(sender)))
720     {
721       syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) with origin %s which is not in our connection list"),
722              cl->name, cl->hostname, sender);
723       free(name); free(sender);
724       return -1;
725     }
726     
727   free(sender);
728
729   /* Check if the new host already exists in the connnection list */
730
731   if(!(old = lookup_id(name)))
732     {
733       syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
734              name, cl->name, cl->hostname);
735       free(name);
736       return -1;
737     }
738   
739   /* Check if the rest matches */
740   
741   if(address!=old->address || port!=old->port || options!=old->options || hisuplink!=old->hisuplink || cl!=old->myuplink)
742     {
743       syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
744       return 0;
745     }
746
747   /* Ok, since EVERYTHING seems to check out all right, delete it */
748
749   old->status.termreq = 1;
750   old->status.active = 0;
751
752   terminate_connection(old);
753 cp
754   return 0;
755 }
756
757 /* Status and error notification routines */
758
759 int send_status(conn_list_t *cl, int statusno, char *statusstring)
760 {
761 cp
762   if(!statusstring)
763     statusstring = status_text[statusno];
764 cp
765   return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
766 }
767
768 int status_h(conn_list_t *cl)
769 {
770   int statusno;
771   char *statusstring;
772 cp
773   if(sscanf(cl->buffer, "%*d %d %as", &statusno, &statusstring) != 2)
774     {
775        syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
776               cl->name, cl->hostname);
777        return -1;
778     }
779
780   if(debug_lvl > DEBUG_STATUS)
781     {
782       syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
783              cl->name, cl->hostname, status_text[statusno], statusstring);
784     }
785
786 cp
787   free(statusstring);
788   return 0;
789 }
790
791 int send_error(conn_list_t *cl, int errno, char *errstring)
792 {
793 cp
794   if(!errstring)
795     errstring = strerror(errno);
796   return send_request(cl, "%d %d %s", ERROR, errno, errstring);
797 }
798
799 int error_h(conn_list_t *cl)
800 {
801   int errno;
802   char *errorstring;
803 cp
804   if(sscanf(cl->buffer, "%*d %d %as", &errno, &errorstring) != 2)
805     {
806        syslog(LOG_ERR, _("Got bad error from %s (%s)"),
807               cl->name, cl->hostname);
808        return -1;
809     }
810
811   if(debug_lvl > DEBUG_error)
812     {
813       syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
814              cl->name, cl->hostname, strerror(errno), errorstring);
815     }
816
817   free(errorstring);
818   cl->status.termreq = 1;
819   terminate_connection(cl);
820 cp
821   return 0;
822 }
823
824 int send_termreq(conn_list_t *cl)
825 {
826 cp
827   return send_request(cl, "%d", TERMREQ);
828 }
829
830 int termreq_h(conn_list_t *cl)
831 {
832 cp
833   cl->status.termreq = 1;
834   terminate_connection(cl);
835 cp
836   return 0;
837 }
838
839 /* Keepalive routines - FIXME: needs a closer look */
840
841 int send_ping(conn_list_t *cl)
842 {
843   cl->status.pinged = 1;
844 cp
845   return send_request(cl, "%d", PING);
846 }
847
848 int ping_h(conn_list_t *cl)
849 {
850 cp
851   return send_pong(cl);
852 }
853
854 int send_pong(conn_list_t *cl)
855 {
856 cp
857   return send_request(cl, "%d", PONG);
858 }
859
860 int pong_h(conn_list_t *cl)
861 {
862 cp
863   cl->status.got_pong = 1;
864 cp
865   return 0;
866 }
867
868 /* Key exchange */
869
870 int send_key_changed(conn_list_t *from, conn_list_t *cl)
871 {
872   conn_list_t *p;
873 cp
874   for(p = conn_list; p != NULL; p = p->next)
875     {
876       if(p!=cl && p->status.meta && p->status.active)
877         send_request(p, "%d %s", KEY_CHANGED,
878                      from->name);
879     }
880 cp
881   return 0;
882 }
883
884 int key_changed_h(conn_list_t *cl)
885 {
886   char *from_id;
887   conn_list_t *from;
888 cp
889   if(sscanf(cl->buffer, "%*d %as", &from_id) != 1)
890     {
891       syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
892              cl->name, cl->hostname);
893       return -1;
894     }
895
896   if(!(from = lookup_id(from_id)))
897     {
898       syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
899              cl->name, cl->hostname, from_id);
900       free(from_id);
901       return -1;
902     }
903
904   free(from_id);
905
906   from->status.validkey = 0;
907   from->status.waitingforkey = 0;
908
909   send_key_changed(from, cl);
910 cp
911   return 0;
912 }
913
914 int send_req_key(conn_list_t *from, conn_list_t *to)
915 {
916 cp
917   return send_request(to->nexthop, "%d %s %s", REQ_KEY,
918                       from->name, to->name);
919 }
920
921 int req_key_h(conn_list_t *cl)
922 {
923   char *from_id, *to_id;
924   conn_list_t *from, *to;
925 cp
926   if(sscanf(cl->buffer, "%*d %as %as", &from_id, &to_id) != 2)
927     {
928        syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
929               cl->name, cl->hostname);
930        return -1;
931     }
932
933   if(!(from = lookup_id(from_id)))
934     {
935       syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
936              cl->name, cl->hostname, from_id);
937       free(from_id); free(to_id);
938       return -1;
939     }
940
941   /* Check if this key request is for us */
942
943   if(!strcmp(to_id, myself->name))
944     {
945       send_ans_key(myself, from, myself->datakey->key);
946     }
947   else
948     {
949       if(!(to = lookup_id(to_id)))
950         {
951           syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
952                  cl->name, cl->hostname, to_id);
953           free(from_id); free(to_id);
954           return -1;
955         }
956       send_req_key(from, to);
957     }
958
959   free(from_id); free(to_id);
960 cp
961   return 0;
962 }
963
964 int send_ans_key(conn_list_t *from, conn_list_t *to, char *datakey)
965 {
966 cp
967   return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
968                       from->name, to->name, datakey);
969 }
970
971 int ans_key_h(conn_list_t *cl)
972 {
973   char *from_id, *to_id, *datakey;
974   int keylength;
975   conn_list_t *from, *to;
976 cp
977   if(sscanf(cl->buffer, "%*d %as %as %as", &from_id, &to_id, &datakey) != 3)
978     {
979        syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
980               cl->name, cl->hostname);
981        return -1;
982     }
983
984   if(!(from = lookup_id(from_id)))
985     {
986       syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
987              cl->name, cl->hostname, from_id);
988       free(from_id); free(to_id); free(datakey);
989       return -1;
990     }
991
992   /* Check if this key request is for us */
993
994   if(!strcmp(to_id, myself->name))
995     {
996       /* It is for us, convert it to binary and set the key with it. */
997
998       keylength = strlen(datakey);
999
1000       if((keylength%2) || (keylength <= 0))
1001         {
1002           syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key"),
1003                  cl->name, cl->hostname, from->name);
1004           free(from_id); free(to_id); free(datakey);
1005           return -1;
1006         }
1007       keylength /= 2;
1008       hex2bin(datakey, datakey, keylength);
1009       BF_set_key(cl->datakey, keylength, datakey);
1010     }
1011   else
1012     {
1013       if(!(to = lookup_id(to_id)))
1014         {
1015           syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1016                  cl->name, cl->hostname, to_id);
1017           free(from_id); free(to_id); free(datakey);
1018           return -1;
1019         }
1020       send_ans_key(from, to, datakey);
1021     }
1022
1023   free(from_id); free(to_id); free(datakey);
1024 cp
1025   return 0;
1026 }
1027
1028 /* Jumptable for the request handlers */
1029
1030 int (*request_handlers[])(conn_list_t*) = {
1031   id_h, challenge_h, chal_reply_h, ack_h,
1032   status_h, error_h, termreq_h,
1033   ping_h, pong_h,
1034   add_host_h, del_host_h,
1035   add_subnet_h, del_subnet_h,
1036   key_changed_h, req_key_h, ans_key_h,
1037 };
1038
1039 /* Request names */
1040
1041 char (*request_name[]) = {
1042   "ID", "CHALLENGE", "CHAL_REPLY", "ACK",
1043   "STATUS", "ERROR", "TERMREQ",
1044   "PING", "PONG",
1045   "ADD_HOST", "DEL_HOST",
1046   "ADD_SUBNET", "DEL_SUBNET",
1047   "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1048 };