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