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