- Fixed all debug levels.
[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.44 2000/10/21 11:52:07 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   upstreamindex = 0;
473
474 cp
475   if(cl->status.outgoing)
476     return 0;
477   else
478     return send_ack(cl);
479 }
480
481 /* Address and subnet information exchange */
482
483 int send_add_subnet(conn_list_t *cl, conn_list_t *other, subnet_t *subnet)
484 {
485   int x;
486   char *netstr;
487 cp
488   x = send_request(cl, "%d %s %s", ADD_SUBNET,
489                       other->name, netstr = net2str(subnet));
490   free(netstr);
491 cp
492   return x;
493 }
494
495 int add_subnet_h(conn_list_t *cl)
496 {
497   char *subnetstr;
498   char *name;
499   conn_list_t *owner;
500   subnet_t *subnet, *old;
501 cp
502   if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
503     {
504       syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
505       free(name); free(subnetstr);
506       return -1;
507     }
508
509   /* Check if owner name is a valid */
510
511   if(check_id(name))
512     {
513       syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
514       free(name); free(subnetstr);
515       return -1;
516     }
517
518   /* Check if subnet string is valid */
519
520   if(!(subnet = str2net(subnetstr)))
521     {
522       syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
523       free(name); free(subnetstr);
524       return -1;
525     }
526
527   free(subnetstr);
528   
529   /* Check if somebody tries to add a subnet of ourself */
530
531   if(!strcmp(name, myself->name))
532     {
533       syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
534              cl->name, cl->hostname);
535       free(name);
536       sighup = 1;
537       return 0;
538     }
539
540   /* Check if the owner of the new subnet is in the connection list */
541
542   if(!(owner = lookup_id(name)))
543     {
544       syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
545              name, cl->name, cl->hostname);
546       free(name);
547       return -1;
548     }
549
550   /* If everything is correct, add the subnet to the list of the owner */
551
552   subnet_add(owner, subnet);
553 cp
554   return 0;
555 }
556
557 int send_del_subnet(conn_list_t *cl, conn_list_t *other, subnet_t *subnet)
558 {
559 cp
560   return send_request(cl, "%d %s %s", DEL_SUBNET, other->name, net2str(subnet));
561 }
562
563 int del_subnet_h(conn_list_t *cl)
564 {
565   char *subnetstr;
566   char *name;
567   conn_list_t *owner;
568   subnet_t *subnet, *old;
569 cp
570   if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
571     {
572       syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
573       free(name); free(subnetstr);
574       return -1;
575     }
576
577   /* Check if owner name is a valid */
578
579   if(check_id(name))
580     {
581       syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
582       free(name); free(subnetstr);
583       return -1;
584     }
585
586   /* Check if subnet string is valid */
587
588   if(!(subnet = str2net(subnetstr)))
589     {
590       syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
591       free(name); free(subnetstr);
592       return -1;
593     }
594
595   free(subnetstr);
596   
597   /* Check if somebody tries to add a subnet of ourself */
598
599   if(!strcmp(name, myself->name))
600     {
601       syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
602              cl->name, cl->hostname);
603       free(name);
604       sighup = 1;
605       return 0;
606     }
607
608   /* Check if the owner of the new subnet is in the connection list */
609
610   if(!(owner = lookup_id(name)))
611     {
612       syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
613              name, cl->name, cl->hostname);
614       free(name);
615       return -1;
616     }
617
618   /* If everything is correct, delete the subnet from the list of the owner */
619
620   subnet_del(subnet);
621 cp
622   return 0;
623 }
624
625 /* New and closed connections notification */
626
627 int send_add_host(conn_list_t *cl, conn_list_t *other)
628 {
629 cp
630   return send_request(cl, "%d %s %s %lx:%d %lx", ADD_HOST,
631                       myself->name, other->name, other->address, other->port, other->options);
632 }
633
634 int add_host_h(conn_list_t *cl)
635 {
636   char *sender;
637   conn_list_t *old, *new, *hisuplink;
638 cp
639   new = new_conn_list();
640
641   if(sscanf(cl->buffer, "%*d %as %as %lx:%d %lx", &sender, &new->name, &new->address, &new->port, &new->options) != 5)
642     {
643        syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
644        return -1;
645     }
646
647   /* Check if identity is a valid name */
648
649   if(check_id(new->name) || check_id(sender))
650     {
651       syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
652       free(sender);
653       return -1;
654     }
655
656   /* Check if somebody tries to add ourself */
657
658   if(!strcmp(new->name, myself->name))
659     {
660       syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
661       sighup = 1;
662       free(sender);
663       return 0;
664     }
665
666   /* We got an ADD_HOST from ourself!? */
667
668   if(!strcmp(sender, myself->name))
669     {
670       syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) from ourself, restarting"), cl->name, cl->hostname);
671       sighup = 1;
672       free(sender);
673       return 0;
674     }
675
676   /* Lookup his uplink */
677
678   if(!(new->hisuplink = lookup_id(sender)))
679     {
680       syslog(LOG_ERR, _("Got ADD_HOST from %s (%s) with origin %s which is not in our connection list"),
681              sender, cl->name, cl->hostname);
682       free(sender);
683       return -1;
684     }
685     
686   free(sender);
687
688   /* Fill in more of the new conn_list structure */
689
690   new->hostname = hostlookup(htonl(new->address));
691
692   /* Check if the new host already exists in the connnection list */
693
694   if((old = lookup_id(new->name)))
695     {
696       if((new->address == old->address) && (new->port == old->port))
697         {
698           if(debug_lvl >= DEBUG_CONNECTIONS)
699             syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
700                    old->name, old->hostname, new->name, new->hostname);
701           return 0;
702         }
703       else
704         {
705           if(debug_lvl >= DEBUG_CONNECTIONS)
706             syslog(LOG_NOTICE, _("Removing old entry for %s (%s)"),
707                    old->name, old->hostname);
708           old->status.active = 0;
709           terminate_connection(old);
710         }
711     }
712
713   /* Fill in rest of conn_list structure */
714
715   new->myuplink = cl;
716   new->status.active = 1;
717
718   /* Hook it up into the conn_list */
719
720   conn_list_add(conn_list, new);
721
722   /* Tell the rest about the new host */
723 /* FIXME: reprogram this.
724   notify_others(new, cl, send_add_host);
725 */
726 cp
727   return 0;
728 }
729
730 int send_del_host(conn_list_t *cl, conn_list_t *other)
731 {
732 cp
733   return send_request(cl, "%d %s %s %lx:%d %lx", DEL_HOST,
734                       myself->name, other->name, other->address, other->port, other->options);
735 }
736
737 int del_host_h(conn_list_t *cl)
738 {
739   char *name;
740   char *sender;
741   ip_t address;
742   port_t port;
743   int options;
744   conn_list_t *old, *hisuplink;
745
746 cp
747   if(sscanf(cl->buffer, "%*d %as %as %lx:%d %lx", &sender, &name, &address, &port, &options) != 5)
748     {
749       syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
750              cl->name, cl->hostname);
751       return -1;
752     }
753
754   /* Check if identity is a valid name */
755
756   if(check_id(name) || check_id(sender))
757     {
758       syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
759       free(name); free(sender);
760       return -1;
761     }
762
763   /* Check if somebody tries to delete ourself */
764
765   if(!strcmp(name, myself->name))
766     {
767       syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
768              cl->name, cl->hostname);
769       free(name); free(sender);
770       sighup = 1;
771       return 0;
772     }
773
774   /* We got an ADD_HOST from ourself!? */
775
776   if(!strcmp(sender, myself->name))
777     {
778       syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) from ourself, restarting"), cl->name, cl->hostname);
779       sighup = 1;
780       free(name); free(sender);
781       return 0;
782     }
783
784   /* Lookup his uplink */
785
786   if(!(hisuplink = lookup_id(sender)))
787     {
788       syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) with origin %s which is not in our connection list"),
789              cl->name, cl->hostname, sender);
790       free(name); free(sender);
791       return -1;
792     }
793     
794   free(sender);
795
796   /* Check if the new host already exists in the connnection list */
797
798   if(!(old = lookup_id(name)))
799     {
800       syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
801              name, cl->name, cl->hostname);
802       free(name);
803       return -1;
804     }
805   
806   /* Check if the rest matches */
807   
808   if(address!=old->address || port!=old->port || options!=old->options || hisuplink!=old->hisuplink || cl!=old->myuplink)
809     {
810       syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
811       return 0;
812     }
813
814   /* Ok, since EVERYTHING seems to check out all right, delete it */
815
816   old->status.termreq = 1;
817   old->status.active = 0;
818
819   terminate_connection(old);
820 cp
821   return 0;
822 }
823
824 /* Status and error notification routines */
825
826 int send_status(conn_list_t *cl, int statusno, char *statusstring)
827 {
828 cp
829   if(!statusstring)
830     statusstring = status_text[statusno];
831 cp
832   return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
833 }
834
835 int status_h(conn_list_t *cl)
836 {
837   int statusno;
838   char *statusstring;
839 cp
840   if(sscanf(cl->buffer, "%*d %d %as", &statusno, &statusstring) != 2)
841     {
842        syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
843               cl->name, cl->hostname);
844        return -1;
845     }
846
847   if(debug_lvl >= DEBUG_STATUS)
848     {
849       syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
850              cl->name, cl->hostname, status_text[statusno], statusstring);
851     }
852
853 cp
854   free(statusstring);
855   return 0;
856 }
857
858 int send_error(conn_list_t *cl, int errno, char *errstring)
859 {
860 cp
861   if(!errstring)
862     errstring = strerror(errno);
863   return send_request(cl, "%d %d %s", ERROR, errno, errstring);
864 }
865
866 int error_h(conn_list_t *cl)
867 {
868   int errno;
869   char *errorstring;
870 cp
871   if(sscanf(cl->buffer, "%*d %d %as", &errno, &errorstring) != 2)
872     {
873        syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
874               cl->name, cl->hostname);
875        return -1;
876     }
877
878   if(debug_lvl >= DEBUG_ERROR)
879     {
880       syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
881              cl->name, cl->hostname, strerror(errno), errorstring);
882     }
883
884   free(errorstring);
885   cl->status.termreq = 1;
886   terminate_connection(cl);
887 cp
888   return 0;
889 }
890
891 int send_termreq(conn_list_t *cl)
892 {
893 cp
894   return send_request(cl, "%d", TERMREQ);
895 }
896
897 int termreq_h(conn_list_t *cl)
898 {
899 cp
900   cl->status.termreq = 1;
901   terminate_connection(cl);
902 cp
903   return 0;
904 }
905
906 /* Keepalive routines - FIXME: needs a closer look */
907
908 int send_ping(conn_list_t *cl)
909 {
910   cl->status.pinged = 1;
911 cp
912   return send_request(cl, "%d", PING);
913 }
914
915 int ping_h(conn_list_t *cl)
916 {
917 cp
918   return send_pong(cl);
919 }
920
921 int send_pong(conn_list_t *cl)
922 {
923 cp
924   return send_request(cl, "%d", PONG);
925 }
926
927 int pong_h(conn_list_t *cl)
928 {
929 cp
930   cl->status.got_pong = 1;
931 cp
932   return 0;
933 }
934
935 /* Key exchange */
936
937 int send_key_changed(conn_list_t *from, conn_list_t *cl)
938 {
939   conn_list_t *p;
940 cp
941   for(p = conn_list; p != NULL; p = p->next)
942     {
943       if(p!=cl && p->status.meta && p->status.active)
944         send_request(p, "%d %s", KEY_CHANGED,
945                      from->name);
946     }
947 cp
948   return 0;
949 }
950
951 int key_changed_h(conn_list_t *cl)
952 {
953   char *from_id;
954   conn_list_t *from;
955 cp
956   if(sscanf(cl->buffer, "%*d %as", &from_id) != 1)
957     {
958       syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
959              cl->name, cl->hostname);
960       return -1;
961     }
962
963   if(!(from = lookup_id(from_id)))
964     {
965       syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
966              cl->name, cl->hostname, from_id);
967       free(from_id);
968       return -1;
969     }
970
971   free(from_id);
972
973   from->status.validkey = 0;
974   from->status.waitingforkey = 0;
975
976   send_key_changed(from, cl);
977 cp
978   return 0;
979 }
980
981 int send_req_key(conn_list_t *from, conn_list_t *to)
982 {
983 cp
984   return send_request(to->nexthop, "%d %s %s", REQ_KEY,
985                       from->name, to->name);
986 }
987
988 int req_key_h(conn_list_t *cl)
989 {
990   char *from_id, *to_id;
991   conn_list_t *from, *to;
992 cp
993   if(sscanf(cl->buffer, "%*d %as %as", &from_id, &to_id) != 2)
994     {
995        syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
996               cl->name, cl->hostname);
997        return -1;
998     }
999
1000   if(!(from = lookup_id(from_id)))
1001     {
1002       syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
1003              cl->name, cl->hostname, from_id);
1004       free(from_id); free(to_id);
1005       return -1;
1006     }
1007
1008   /* Check if this key request is for us */
1009
1010   if(!strcmp(to_id, myself->name))
1011     {
1012       send_ans_key(myself, from, myself->cipher_pktkey);
1013     }
1014   else
1015     {
1016       if(!(to = lookup_id(to_id)))
1017         {
1018           syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
1019                  cl->name, cl->hostname, to_id);
1020           free(from_id); free(to_id);
1021           return -1;
1022         }
1023       send_req_key(from, to);
1024     }
1025
1026   free(from_id); free(to_id);
1027 cp
1028   return 0;
1029 }
1030
1031 int send_ans_key(conn_list_t *from, conn_list_t *to, char *pktkey)
1032 {
1033 cp
1034   return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
1035                       from->name, to->name, pktkey);
1036 }
1037
1038 int ans_key_h(conn_list_t *cl)
1039 {
1040   char *from_id, *to_id, *pktkey;
1041   int keylength;
1042   conn_list_t *from, *to;
1043 cp
1044   if(sscanf(cl->buffer, "%*d %as %as %as", &from_id, &to_id, &pktkey) != 3)
1045     {
1046        syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
1047               cl->name, cl->hostname);
1048        return -1;
1049     }
1050
1051   if(!(from = lookup_id(from_id)))
1052     {
1053       syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
1054              cl->name, cl->hostname, from_id);
1055       free(from_id); free(to_id); free(pktkey);
1056       return -1;
1057     }
1058
1059   /* Check if this key request is for us */
1060
1061   if(!strcmp(to_id, myself->name))
1062     {
1063       /* It is for us, convert it to binary and set the key with it. */
1064
1065       keylength = strlen(pktkey);
1066
1067       if((keylength%2) || (keylength <= 0))
1068         {
1069           syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key"),
1070                  cl->name, cl->hostname, from->name);
1071           free(from_id); free(to_id); free(pktkey);
1072           return -1;
1073         }
1074       keylength /= 2;
1075       hex2bin(pktkey, pktkey, keylength);
1076       BF_set_key(cl->cipher_pktkey, keylength, pktkey);
1077     }
1078   else
1079     {
1080       if(!(to = lookup_id(to_id)))
1081         {
1082           syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1083                  cl->name, cl->hostname, to_id);
1084           free(from_id); free(to_id); free(pktkey);
1085           return -1;
1086         }
1087       send_ans_key(from, to, pktkey);
1088     }
1089
1090   free(from_id); free(to_id); free(pktkey);
1091 cp
1092   return 0;
1093 }
1094
1095 /* Jumptable for the request handlers */
1096
1097 int (*request_handlers[])(conn_list_t*) = {
1098   id_h, challenge_h, chal_reply_h, ack_h,
1099   status_h, error_h, termreq_h,
1100   ping_h, pong_h,
1101   add_host_h, del_host_h,
1102   add_subnet_h, del_subnet_h,
1103   key_changed_h, req_key_h, ans_key_h,
1104 };
1105
1106 /* Request names */
1107
1108 char (*request_name[]) = {
1109   "ID", "CHALLENGE", "CHAL_REPLY", "ACK",
1110   "STATUS", "ERROR", "TERMREQ",
1111   "PING", "PONG",
1112   "ADD_HOST", "DEL_HOST",
1113   "ADD_SUBNET", "DEL_SUBNET",
1114   "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1115 };
1116
1117 /* Status strings */
1118
1119 char (*status_text[]) = {
1120   "Warning",
1121 };
1122
1123 /* Error strings */
1124
1125 char (*error_text[]) = {
1126   "Error",
1127 };