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