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