- Lots of small fixes
[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.46 2000/10/28 21:05:18 guus Exp $
21 */
22
23 #include "config.h"
24
25 #include <sys/types.h>
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include <syslog.h>
30 #include <sys/socket.h>
31 #include <unistd.h>
32 #include <stdio.h>
33
34 #include <utils.h>
35 #include <xalloc.h>
36
37 #include <netinet/in.h>
38
39 #include <openssl/sha.h>
40
41 #include "conf.h"
42 #include "encr.h"
43 #include "net.h"
44 #include "netutl.h"
45 #include "protocol.h"
46 #include "meta.h"
47
48 #include "system.h"
49
50 int check_id(char *id)
51 {
52   int i;
53
54   for (i = 0; i < strlen(id); i++)
55     if(!isalnum(id[i]) && id[i] != '_')
56       return -1;
57           
58   return 0;
59 }
60
61 /* Generic request routines - takes care of logging and error detection as well */
62
63 int send_request(conn_list_t *cl, const char *format, ...)
64 {
65   va_list args;
66   char buffer[MAXBUFSIZE];
67   int len, request;
68
69 cp
70   /* Use vsnprintf instead of vasprintf: faster, no memory fragmentation, cleanup is automatic,
71      and there is a limit on the input buffer anyway */
72
73   va_start(args, format);
74   len = vsnprintf(buffer, MAXBUFSIZE, format, args);
75   request = va_arg(args, int);
76   va_end(args);
77
78   if(len < 0 || len > MAXBUFSIZE-1)
79     {
80       syslog(LOG_ERR, _("Output buffer overflow while sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
81       return -1;
82     }
83
84   len++;
85
86   if(debug_lvl >= DEBUG_PROTOCOL)
87     syslog(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
88
89 cp
90   return send_meta(cl, buffer, len);
91 }
92
93 int receive_request(conn_list_t *cl)
94 {
95   int request;
96 cp  
97   if(sscanf(cl->buffer, "%d", &request) == 1)
98     {
99       if((request < 0) || (request > 255) || (request_handlers[request] == NULL))
100         {
101           syslog(LOG_ERR, _("Unknown request from %s (%s)"),
102                  cl->name, cl->hostname);
103           return -1;
104         }
105       else
106         {
107           if(debug_lvl >= DEBUG_PROTOCOL)
108             syslog(LOG_DEBUG, _("Got %s from %s (%s)"),
109                    request_name[request], cl->name, cl->hostname);
110         }
111       if(request_handlers[request](cl))
112         /* Something went wrong. Probably scriptkiddies. Terminate. */
113         {
114           syslog(LOG_ERR, _("Error while processing %s from %s (%s)"),
115                  request_name[request], cl->name, cl->hostname);
116           return -1;
117         }
118     }
119   else
120     {
121       syslog(LOG_ERR, _("Bogus data received from %s (%s)"),
122              cl->name, cl->hostname);
123       return -1;
124     }
125 }
126
127 /* Connection protocol:
128
129    Client               Server
130    send_id(u)
131                         send_challenge(R)
132    send_chal_reply(H)
133                         send_id(u)
134    send_challenge(R)
135                         send_chal_reply(H)
136    ---------------------------------------
137    Any negotations about the meta protocol
138    encryption go here(u).
139    ---------------------------------------
140    send_ack(u)
141                         send_ack(u)
142    ---------------------------------------
143    Other requests(E)...
144
145    (u) Unencrypted,
146    (R) RSA,
147    (H) SHA1,
148    (E) Encrypted with symmetric cipher.
149
150    Part of the challenge is directly used to set the symmetric cipher key and the initial vector.
151    Since a man-in-the-middle cannot decrypt the RSA challenges, this means that he cannot get or
152    forge the key for the symmetric cipher.
153 */
154
155 int send_id(conn_list_t *cl)
156 {
157 cp
158   cl->allow_request = CHALLENGE;
159 cp
160   return send_request(cl, "%d %s %d %lx %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   config_t *cfg;
167 cp
168   if(sscanf(cl->buffer, "%*d %as %d %lx %hd", &cl->name, &cl->protocol_version, &cl->options, &cl->port) != 4)
169     {
170        syslog(LOG_ERR, _("Got bad ID from %s"), cl->hostname);
171        return -1;
172     }
173
174   /* Check if version matches */
175
176   if(cl->protocol_version != myself->protocol_version)
177     {
178       syslog(LOG_ERR, _("Peer %s (%s) uses incompatible version %d"),
179              cl->name, cl->hostname, cl->protocol_version);
180       return -1;
181     }
182
183   /* Check if identity is a valid name */
184
185   if(check_id(cl->name))
186     {
187       syslog(LOG_ERR, _("Peer %s uses invalid identity name"), cl->hostname);
188       return -1;
189     }
190
191   /* Load information about peer */
192 cp
193   if(read_host_config(cl))
194     {
195       syslog(LOG_ERR, _("Peer %s had unknown identity (%s)"), cl->hostname, cl->name);
196       return -1;
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 cp
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   if(!(cfg = get_config_val(cl->config, publickey)))
218     {
219       syslog(LOG_ERR, _("No public key known for %s (%s)"), cl->name, cl->hostname);
220       return -1;
221     }
222   else
223     {
224 cp
225       cl->rsa_key = RSA_new();
226       BN_hex2bn(&cl->rsa_key->n, cfg->data.ptr);
227       BN_hex2bn(&cl->rsa_key->e, "FFFF");
228     }
229
230 cp
231   return send_challenge(cl);
232 }
233
234 int send_challenge(conn_list_t *cl)
235 {
236   char *buffer;
237   int len, x;
238 cp
239   len = RSA_size(cl->rsa_key);
240
241   /* Allocate buffers for the challenge */
242
243   buffer = xmalloc(len*2+1);
244
245   if(cl->hischallenge)
246     free(cl->hischallenge);
247     
248   cl->hischallenge = xmalloc(len);
249 cp
250   /* Seed the PRNG with urandom (can't afford to block) */
251
252   RAND_load_file("/dev/urandom", 1024);
253
254   /* Copy random data to the buffer */
255
256   RAND_bytes(cl->hischallenge, len);
257
258   cl->hischallenge[0] &= 0x7F;  /* Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
259
260   if(debug_lvl >= DEBUG_SCARY_THINGS)
261     {
262       bin2hex(cl->hischallenge, buffer, len);
263       buffer[len*2] = '\0';
264       syslog(LOG_DEBUG, _("Generated random challenge (unencrypted): %s"), buffer);
265     }
266
267   /* Encrypt the random data */
268   
269   if(RSA_public_encrypt(len, cl->hischallenge, buffer, cl->rsa_key, RSA_NO_PADDING) != len)     /* NO_PADDING because the message size equals the RSA key size and it is totally random */
270     {
271       syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
272       free(buffer);
273       return -1;
274     }
275 cp
276   /* Convert the encrypted random data to a hexadecimal formatted string */
277
278   bin2hex(buffer, buffer, len);
279   buffer[len*2] = '\0';
280
281   /* Send the challenge */
282
283   cl->allow_request = CHAL_REPLY;
284   x = send_request(cl, "%d %s", CHALLENGE, buffer);
285   free(buffer);
286 cp
287   return x;
288 }
289
290 int challenge_h(conn_list_t *cl)
291 {
292   char *buffer;
293   int len;
294 cp
295   if(sscanf(cl->buffer, "%*d %as", &buffer) != 1)
296     {
297        syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
298        return -1;
299     }
300
301   len = RSA_size(myself->rsa_key);
302
303   /* Check if the length of the challenge is all right */
304
305   if(strlen(buffer) != len*2)
306     {
307       syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
308       free(buffer);
309       return -1;
310     }
311
312   /* Allocate buffers for the challenge */
313
314   if(!cl->mychallenge)
315     cl->mychallenge = xmalloc(len);
316
317   /* Convert the challenge from hexadecimal back to binary */
318
319   hex2bin(buffer,buffer,len);
320
321   /* Decrypt the challenge */
322   
323   if(RSA_private_decrypt(len, buffer, cl->mychallenge, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
324     {
325       syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
326       free(buffer);
327       return -1;
328     }
329
330   if(debug_lvl >= DEBUG_SCARY_THINGS)
331     {
332       bin2hex(cl->mychallenge, buffer, len);
333       buffer[len*2] = '\0';
334       syslog(LOG_DEBUG, _("Received random challenge (unencrypted): %s"), buffer);
335     }
336
337   free(buffer);
338     
339   /* Rest is done by send_chal_reply() */
340 cp
341   return send_chal_reply(cl);
342 }
343
344 int send_chal_reply(conn_list_t *cl)
345 {
346   char hash[SHA_DIGEST_LENGTH*2+1];
347 cp
348   if(!cl->mychallenge)
349     {
350       syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
351       return -1;
352     }
353      
354   /* Calculate the hash from the challenge we received */
355
356   SHA1(cl->mychallenge, RSA_size(myself->rsa_key), hash);
357
358   /* Convert the hash to a hexadecimal formatted string */
359
360   bin2hex(hash,hash,SHA_DIGEST_LENGTH);
361   hash[SHA_DIGEST_LENGTH*2] = '\0';
362
363   /* Send the reply */
364
365   if(cl->status.outgoing)
366     cl->allow_request = ID;
367   else
368     cl->allow_request = ACK;
369
370 cp
371   return send_request(cl, "%d %s", CHAL_REPLY, hash);
372 }
373
374 int chal_reply_h(conn_list_t *cl)
375 {
376   char *hishash;
377   char myhash[SHA_DIGEST_LENGTH];
378 cp
379   if(sscanf(cl->buffer, "%*d %as", &hishash) != 1)
380     {
381        syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
382        free(hishash);
383        return -1;
384     }
385
386   /* Check if the length of the hash is all right */
387
388   if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
389     {
390       syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
391       free(hishash);
392       return -1;
393     }
394
395   /* Convert the hash to binary format */
396
397   hex2bin(hishash, hishash, SHA_DIGEST_LENGTH);
398
399   /* Calculate the hash from the challenge we sent */
400
401   SHA1(cl->hischallenge, RSA_size(cl->rsa_key), myhash);
402
403   /* Verify the incoming hash with the calculated hash */
404
405   if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
406     {
407       syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
408       if(debug_lvl >= DEBUG_SCARY_THINGS)
409         {
410           bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
411           hishash[SHA_DIGEST_LENGTH*2] = '\0';
412           syslog(LOG_DEBUG, _("Expected challenge reply: %s"), hishash);
413         }
414       free(hishash);
415       return -1;
416     }
417
418
419   free(hishash);
420
421   /* Identity has now been positively verified.
422      If we are accepting this new connection, then send our identity,
423      if we are making this connecting, acknowledge.
424    */
425 cp
426   if(cl->status.outgoing)
427       return send_ack(cl);
428   else
429       return send_id(cl);
430 }
431
432 int send_ack(conn_list_t *cl)
433 {
434 cp
435   cl->allow_request = ACK;
436 cp
437   return send_request(cl, "%d", ACK);
438 }
439
440 int ack_h(conn_list_t *cl)
441 {
442   conn_list_t *old, *p;
443   subnet_t *s;
444 cp
445   /* Okay, before we active the connection, we check if there is another entry
446      in the connection list with the same name. If so, it presumably is an
447      old connection that has timed out but we don't know it yet.
448    */
449
450   while((old = lookup_id(cl->name)))
451     {
452       if(debug_lvl >= DEBUG_CONNECTIONS)
453         syslog(LOG_NOTICE, _("Removing old entry for %s at %s in favour of new connection from %s"),
454         cl->name, old->hostname, cl->hostname);
455       old->status.active = 0;
456       terminate_connection(old);
457     }
458
459   /* Notify others of this connection */
460   
461   for(p = conn_list; p; p = p->next)
462     if(p->status.active)
463       send_add_host(p, cl);
464
465   /* Activate this connection */
466
467   cl->allow_request = ALL;
468   cl->status.active = 1;
469   cl->nexthop = cl;
470
471   if(debug_lvl >= DEBUG_CONNECTIONS)
472     syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname);
473
474 cp
475   if(!cl->status.outgoing)
476     send_ack(cl);
477
478   /* Send him our subnets */
479   
480   for(s = myself->subnets; s; s = s->next)
481     send_add_subnet(cl, s);
482 cp
483   return 0;
484 }
485
486 /* Address and subnet information exchange */
487
488 int send_add_subnet(conn_list_t *cl, subnet_t *subnet)
489 {
490   int x;
491   char *netstr;
492 cp
493   x = send_request(cl, "%d %s %s", ADD_SUBNET,
494                       subnet->owner->name, netstr = net2str(subnet));
495   free(netstr);
496 cp
497   return x;
498 }
499
500 int add_subnet_h(conn_list_t *cl)
501 {
502   char *subnetstr;
503   char *name;
504   conn_list_t *owner;
505   subnet_t *subnet, *old;
506 cp
507   if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 2)
508     {
509       syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
510       free(name); free(subnetstr);
511       return -1;
512     }
513
514   /* Check if owner name is a valid */
515
516   if(check_id(name))
517     {
518       syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
519       free(name); free(subnetstr);
520       return -1;
521     }
522
523   /* Check if subnet string is valid */
524
525   if(!(subnet = str2net(subnetstr)))
526     {
527       syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
528       free(name); free(subnetstr);
529       return -1;
530     }
531
532   free(subnetstr);
533   
534   /* Check if somebody tries to add a subnet of ourself */
535
536   if(!strcmp(name, myself->name))
537     {
538       syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
539              cl->name, cl->hostname);
540       free(name);
541       sighup = 1;
542       return 0;
543     }
544
545   /* Check if the owner of the new subnet is in the connection list */
546
547   if(!(owner = lookup_id(name)))
548     {
549       syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
550              name, cl->name, cl->hostname);
551       free(name);
552       return -1;
553     }
554
555   /* If everything is correct, add the subnet to the list of the owner */
556
557   subnet_add(owner, subnet);
558 cp
559   return 0;
560 }
561
562 int send_del_subnet(conn_list_t *cl, subnet_t *subnet)
563 {
564   int x;
565   char *netstr;
566 cp
567   netstr = net2str(subnet);
568   x = send_request(cl, "%d %s %s", DEL_SUBNET, subnet->owner->name, netstr);
569   free(netstr);
570 cp
571   return x;
572 }
573
574 int del_subnet_h(conn_list_t *cl)
575 {
576   char *subnetstr;
577   char *name;
578   conn_list_t *owner;
579   subnet_t *subnet, *old;
580 cp
581   if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
582     {
583       syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
584       free(name); free(subnetstr);
585       return -1;
586     }
587
588   /* Check if owner name is a valid */
589
590   if(check_id(name))
591     {
592       syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
593       free(name); free(subnetstr);
594       return -1;
595     }
596
597   /* Check if subnet string is valid */
598
599   if(!(subnet = str2net(subnetstr)))
600     {
601       syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
602       free(name); free(subnetstr);
603       return -1;
604     }
605
606   free(subnetstr);
607   
608   /* Check if somebody tries to add a subnet of ourself */
609
610   if(!strcmp(name, myself->name))
611     {
612       syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
613              cl->name, cl->hostname);
614       free(name);
615       sighup = 1;
616       return 0;
617     }
618
619   /* Check if the owner of the new subnet is in the connection list */
620
621   if(!(owner = lookup_id(name)))
622     {
623       syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
624              name, cl->name, cl->hostname);
625       free(name);
626       return -1;
627     }
628
629   /* If everything is correct, delete the subnet from the list of the owner */
630
631   subnet_del(subnet);
632 cp
633   return 0;
634 }
635
636 /* New and closed connections notification */
637
638 int send_add_host(conn_list_t *cl, conn_list_t *other)
639 {
640 cp
641   return send_request(cl, "%d %s %s %lx:%d %lx", ADD_HOST,
642                       myself->name, other->name, other->address, other->port, other->options);
643 }
644
645 int add_host_h(conn_list_t *cl)
646 {
647   char *sender;
648   conn_list_t *old, *new, *hisuplink;
649 cp
650   new = new_conn_list();
651
652   if(sscanf(cl->buffer, "%*d %as %as %lx:%d %lx", &sender, &new->name, &new->address, &new->port, &new->options) != 5)
653     {
654        syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
655        return -1;
656     }
657
658   /* Check if identity is a valid name */
659
660   if(check_id(new->name) || check_id(sender))
661     {
662       syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
663       free(sender);
664       return -1;
665     }
666
667   /* Check if somebody tries to add ourself */
668
669   if(!strcmp(new->name, myself->name))
670     {
671       syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
672       sighup = 1;
673       free(sender);
674       return 0;
675     }
676
677   /* We got an ADD_HOST from ourself!? */
678
679   if(!strcmp(sender, myself->name))
680     {
681       syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) from ourself, restarting"), cl->name, cl->hostname);
682       sighup = 1;
683       free(sender);
684       return 0;
685     }
686
687   /* Lookup his uplink */
688
689   if(!(new->hisuplink = lookup_id(sender)))
690     {
691       syslog(LOG_ERR, _("Got ADD_HOST from %s (%s) with origin %s which is not in our connection list"),
692              sender, cl->name, cl->hostname);
693       free(sender);
694       return -1;
695     }
696     
697   free(sender);
698
699   /* Fill in more of the new conn_list structure */
700
701   new->hostname = hostlookup(htonl(new->address));
702
703   /* Check if the new host already exists in the connnection list */
704
705   if((old = lookup_id(new->name)))
706     {
707       if((new->address == old->address) && (new->port == old->port))
708         {
709           if(debug_lvl >= DEBUG_CONNECTIONS)
710             syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
711                    old->name, old->hostname, new->name, new->hostname);
712           return 0;
713         }
714       else
715         {
716           if(debug_lvl >= DEBUG_CONNECTIONS)
717             syslog(LOG_NOTICE, _("Removing old entry for %s (%s)"),
718                    old->name, old->hostname);
719           old->status.active = 0;
720           terminate_connection(old);
721         }
722     }
723
724   /* Fill in rest of conn_list structure */
725
726   new->nexthop = cl;
727   new->status.active = 1;
728
729   /* Hook it up into the conn_list */
730
731   conn_list_add(conn_list, new);
732
733   /* Tell the rest about the new host */
734 /* FIXME: reprogram this.
735   notify_others(new, cl, send_add_host);
736 */
737 cp
738   return 0;
739 }
740
741 int send_del_host(conn_list_t *cl, conn_list_t *other)
742 {
743 cp
744   return send_request(cl, "%d %s %s %lx:%d %lx", DEL_HOST,
745                       myself->name, other->name, other->address, other->port, other->options);
746 }
747
748 int del_host_h(conn_list_t *cl)
749 {
750   char *name;
751   char *sender;
752   ip_t address;
753   port_t port;
754   int options;
755   conn_list_t *old, *hisuplink;
756
757 cp
758   if(sscanf(cl->buffer, "%*d %as %as %lx:%d %lx", &sender, &name, &address, &port, &options) != 5)
759     {
760       syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
761              cl->name, cl->hostname);
762       return -1;
763     }
764
765   /* Check if identity is a valid name */
766
767   if(check_id(name) || check_id(sender))
768     {
769       syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
770       free(name); free(sender);
771       return -1;
772     }
773
774   /* Check if somebody tries to delete ourself */
775
776   if(!strcmp(name, myself->name))
777     {
778       syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
779              cl->name, cl->hostname);
780       free(name); free(sender);
781       sighup = 1;
782       return 0;
783     }
784
785   /* We got an ADD_HOST from ourself!? */
786
787   if(!strcmp(sender, myself->name))
788     {
789       syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) from ourself, restarting"), cl->name, cl->hostname);
790       sighup = 1;
791       free(name); free(sender);
792       return 0;
793     }
794
795   /* Lookup his uplink */
796
797   if(!(hisuplink = lookup_id(sender)))
798     {
799       syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) with origin %s which is not in our connection list"),
800              cl->name, cl->hostname, sender);
801       free(name); free(sender);
802       return -1;
803     }
804     
805   free(sender);
806
807   /* Check if the new host already exists in the connnection list */
808
809   if(!(old = lookup_id(name)))
810     {
811       syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
812              name, cl->name, cl->hostname);
813       free(name);
814       return -1;
815     }
816   
817   /* Check if the rest matches */
818   
819   if(address!=old->address || port!=old->port || options!=old->options || hisuplink!=old->hisuplink || cl!=old->myuplink)
820     {
821       syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
822       return 0;
823     }
824
825   /* Ok, since EVERYTHING seems to check out all right, delete it */
826
827   old->status.termreq = 1;
828   old->status.active = 0;
829
830   terminate_connection(old);
831 cp
832   return 0;
833 }
834
835 /* Status and error notification routines */
836
837 int send_status(conn_list_t *cl, int statusno, char *statusstring)
838 {
839 cp
840   if(!statusstring)
841     statusstring = status_text[statusno];
842 cp
843   return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
844 }
845
846 int status_h(conn_list_t *cl)
847 {
848   int statusno;
849   char *statusstring;
850 cp
851   if(sscanf(cl->buffer, "%*d %d %as", &statusno, &statusstring) != 2)
852     {
853        syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
854               cl->name, cl->hostname);
855        return -1;
856     }
857
858   if(debug_lvl >= DEBUG_STATUS)
859     {
860       syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
861              cl->name, cl->hostname, status_text[statusno], statusstring);
862     }
863
864 cp
865   free(statusstring);
866   return 0;
867 }
868
869 int send_error(conn_list_t *cl, int errno, char *errstring)
870 {
871 cp
872   if(!errstring)
873     errstring = strerror(errno);
874   return send_request(cl, "%d %d %s", ERROR, errno, errstring);
875 }
876
877 int error_h(conn_list_t *cl)
878 {
879   int errno;
880   char *errorstring;
881 cp
882   if(sscanf(cl->buffer, "%*d %d %as", &errno, &errorstring) != 2)
883     {
884        syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
885               cl->name, cl->hostname);
886        return -1;
887     }
888
889   if(debug_lvl >= DEBUG_ERROR)
890     {
891       syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
892              cl->name, cl->hostname, strerror(errno), errorstring);
893     }
894
895   free(errorstring);
896   cl->status.termreq = 1;
897   terminate_connection(cl);
898 cp
899   return 0;
900 }
901
902 int send_termreq(conn_list_t *cl)
903 {
904 cp
905   return send_request(cl, "%d", TERMREQ);
906 }
907
908 int termreq_h(conn_list_t *cl)
909 {
910 cp
911   cl->status.termreq = 1;
912   terminate_connection(cl);
913 cp
914   return 0;
915 }
916
917 /* Keepalive routines - FIXME: needs a closer look */
918
919 int send_ping(conn_list_t *cl)
920 {
921   cl->status.pinged = 1;
922 cp
923   return send_request(cl, "%d", PING);
924 }
925
926 int ping_h(conn_list_t *cl)
927 {
928 cp
929   return send_pong(cl);
930 }
931
932 int send_pong(conn_list_t *cl)
933 {
934 cp
935   return send_request(cl, "%d", PONG);
936 }
937
938 int pong_h(conn_list_t *cl)
939 {
940 cp
941   cl->status.got_pong = 1;
942 cp
943   return 0;
944 }
945
946 /* Key exchange */
947
948 int send_key_changed(conn_list_t *from, conn_list_t *cl)
949 {
950   conn_list_t *p;
951 cp
952   for(p = conn_list; p != NULL; p = p->next)
953     {
954       if(p!=cl && p->status.meta && p->status.active)
955         send_request(p, "%d %s", KEY_CHANGED,
956                      from->name);
957     }
958 cp
959   return 0;
960 }
961
962 int key_changed_h(conn_list_t *cl)
963 {
964   char *from_id;
965   conn_list_t *from;
966 cp
967   if(sscanf(cl->buffer, "%*d %as", &from_id) != 1)
968     {
969       syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
970              cl->name, cl->hostname);
971       return -1;
972     }
973
974   if(!(from = lookup_id(from_id)))
975     {
976       syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
977              cl->name, cl->hostname, from_id);
978       free(from_id);
979       return -1;
980     }
981
982   free(from_id);
983
984   from->status.validkey = 0;
985   from->status.waitingforkey = 0;
986
987   send_key_changed(from, cl);
988 cp
989   return 0;
990 }
991
992 int send_req_key(conn_list_t *from, conn_list_t *to)
993 {
994 cp
995   return send_request(to->nexthop, "%d %s %s", REQ_KEY,
996                       from->name, to->name);
997 }
998
999 int req_key_h(conn_list_t *cl)
1000 {
1001   char *from_id, *to_id;
1002   conn_list_t *from, *to;
1003 cp
1004   if(sscanf(cl->buffer, "%*d %as %as", &from_id, &to_id) != 2)
1005     {
1006        syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
1007               cl->name, cl->hostname);
1008        return -1;
1009     }
1010
1011   if(!(from = lookup_id(from_id)))
1012     {
1013       syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
1014              cl->name, cl->hostname, from_id);
1015       free(from_id); free(to_id);
1016       return -1;
1017     }
1018
1019   /* Check if this key request is for us */
1020
1021   if(!strcmp(to_id, myself->name))
1022     {
1023       send_ans_key(myself, from, myself->cipher_pktkey);
1024     }
1025   else
1026     {
1027       if(!(to = lookup_id(to_id)))
1028         {
1029           syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
1030                  cl->name, cl->hostname, to_id);
1031           free(from_id); free(to_id);
1032           return -1;
1033         }
1034       send_req_key(from, to);
1035     }
1036
1037   free(from_id); free(to_id);
1038 cp
1039   return 0;
1040 }
1041
1042 int send_ans_key(conn_list_t *from, conn_list_t *to, char *pktkey)
1043 {
1044 cp
1045   return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
1046                       from->name, to->name, pktkey);
1047 }
1048
1049 int ans_key_h(conn_list_t *cl)
1050 {
1051   char *from_id, *to_id, *pktkey;
1052   int keylength;
1053   conn_list_t *from, *to;
1054 cp
1055   if(sscanf(cl->buffer, "%*d %as %as %as", &from_id, &to_id, &pktkey) != 3)
1056     {
1057        syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
1058               cl->name, cl->hostname);
1059        return -1;
1060     }
1061
1062   if(!(from = lookup_id(from_id)))
1063     {
1064       syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
1065              cl->name, cl->hostname, from_id);
1066       free(from_id); free(to_id); free(pktkey);
1067       return -1;
1068     }
1069
1070   /* Check if this key request is for us */
1071
1072   if(!strcmp(to_id, myself->name))
1073     {
1074       /* It is for us, convert it to binary and set the key with it. */
1075
1076       keylength = strlen(pktkey);
1077
1078 /* Don't do this... yet
1079       if((keylength%2) || (keylength <= 0))
1080         {
1081           syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key"),
1082                  cl->name, cl->hostname, from->name);
1083           free(from_id); free(to_id); free(pktkey);
1084           return -1;
1085         }
1086       keylength /= 2;
1087       hex2bin(pktkey, pktkey, keylength);
1088       BF_set_key(cl->cipher_pktkey, keylength, pktkey);
1089 */
1090
1091       cl->status.validkey = 1;
1092       cl->status.waitingforkey = 0;
1093     }
1094   else
1095     {
1096       if(!(to = lookup_id(to_id)))
1097         {
1098           syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1099                  cl->name, cl->hostname, to_id);
1100           free(from_id); free(to_id); free(pktkey);
1101           return -1;
1102         }
1103       send_ans_key(from, to, pktkey);
1104     }
1105
1106   free(from_id); free(to_id); free(pktkey);
1107 cp
1108   return 0;
1109 }
1110
1111 /* Jumptable for the request handlers */
1112
1113 int (*request_handlers[])(conn_list_t*) = {
1114   id_h, challenge_h, chal_reply_h, ack_h,
1115   status_h, error_h, termreq_h,
1116   ping_h, pong_h,
1117   add_host_h, del_host_h,
1118   add_subnet_h, del_subnet_h,
1119   key_changed_h, req_key_h, ans_key_h,
1120 };
1121
1122 /* Request names */
1123
1124 char (*request_name[]) = {
1125   "ID", "CHALLENGE", "CHAL_REPLY", "ACK",
1126   "STATUS", "ERROR", "TERMREQ",
1127   "PING", "PONG",
1128   "ADD_HOST", "DEL_HOST",
1129   "ADD_SUBNET", "DEL_SUBNET",
1130   "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1131 };
1132
1133 /* Status strings */
1134
1135 char (*status_text[]) = {
1136   "Warning",
1137 };
1138
1139 /* Error strings */
1140
1141 char (*error_text[]) = {
1142   "Error",
1143 };