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