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