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