21dba5bb2c5374d2d17ae255c34283fb6ba56af2
[tinc] / src / protocol.c
1 /*
2     protocol.c -- handle the meta-protocol
3     Copyright (C) 1999 Ivo Timmermans <zarq@iname.com>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include "config.h"
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <syslog.h>
25 #include <sys/socket.h>
26 #include <unistd.h>
27 #include <stdio.h>
28
29 #include <utils.h>
30 #include <xalloc.h>
31
32 #include "conf.h"
33 #include "encr.h"
34 #include "net.h"
35 #include "netutl.h"
36 #include "protocol.h"
37
38 char buffer[MAXBUFSIZE];
39 int buflen;
40
41 int send_ack(conn_list_t *cl)
42 {
43 cp
44   if(debug_lvl > 2)
45     syslog(LOG_DEBUG, "Send ACK to %s", cl->hostname);
46
47   buflen = sprintf(buffer, "%d\n", ACK);
48
49   if((write(cl->meta_socket, buffer, buflen)) < 0)
50     {
51       syslog(LOG_ERR, "send failed: %d:%d: %m", __FILE__, __LINE__);
52       return -1;
53     }
54
55   syslog(LOG_NOTICE, "Connection with %s activated.", cl->hostname);
56 cp
57   return 0;
58 }
59
60 int send_termreq(conn_list_t *cl)
61 {
62 cp
63   if(debug_lvl > 2)
64     syslog(LOG_DEBUG, "Send TERMREQ to " IP_ADDR_S,
65            IP_ADDR_V(cl->vpn_ip));
66
67   buflen = sprintf(buffer, "%d %lx\n", TERMREQ, myself->vpn_ip);
68
69   if((write(cl->meta_socket, buffer, buflen)) < 0)
70     {
71       syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
72       return -1;
73     }
74 cp
75   return 0;
76 }
77
78 int send_timeout(conn_list_t *cl)
79 {
80 cp
81   if(debug_lvl > 2)
82     syslog(LOG_DEBUG, "Send TIMEOUT to " IP_ADDR_S,
83            IP_ADDR_V(cl->vpn_ip));
84
85   buflen = sprintf(buffer, "%d %lx\n", PINGTIMEOUT, myself->vpn_ip);
86
87   if((write(cl->meta_socket, buffer, buflen)) < 0)
88     {
89       syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
90       return -1;
91     }
92 cp
93   return 0;
94 }
95
96 int send_del_host(conn_list_t *cl, conn_list_t *new_host)
97 {
98 cp
99   if(debug_lvl > 2)
100     syslog(LOG_DEBUG, "Sending delete host " IP_ADDR_S " to " IP_ADDR_S,
101            IP_ADDR_V(new_host->vpn_ip), IP_ADDR_V(cl->vpn_ip));
102
103   buflen = sprintf(buffer, "%d %lx\n", DEL_HOST, new_host->vpn_ip);
104
105   if((write(cl->meta_socket, buffer, buflen)) < 0)
106     {
107       syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
108       return -1;
109     }
110 cp
111   return 0;
112 }
113
114 int send_ping(conn_list_t *cl)
115 {
116 cp
117   if(debug_lvl > 3)
118     syslog(LOG_DEBUG, "pinging " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
119
120   buflen = sprintf(buffer, "%d\n", PING);
121
122   if((write(cl->meta_socket, buffer, buflen)) < 0)
123     {
124       syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
125       return -1;
126     }
127 cp
128   return 0;
129 }
130
131 int send_pong(conn_list_t *cl)
132 {
133 cp
134   buflen = sprintf(buffer, "%d\n", PONG);
135
136   if((write(cl->meta_socket, buffer, buflen)) < 0)
137     {
138       syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
139       return -1;
140     }
141 cp
142   return 0;
143 }
144
145 int send_add_host(conn_list_t *cl, conn_list_t *new_host)
146 {
147 cp
148   if(debug_lvl > 2)
149     syslog(LOG_DEBUG, "Sending add host to " IP_ADDR_S,
150            IP_ADDR_V(cl->vpn_ip));
151
152   buflen = sprintf(buffer, "%d %lx %lx/%lx:%x\n", ADD_HOST, new_host->real_ip, new_host->vpn_ip, new_host->vpn_mask, new_host->port);
153
154   if((write(cl->meta_socket, buffer, buflen)) < 0)
155     {
156       syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
157       return -1;
158     }
159 cp
160   return 0;
161 }
162
163 int send_key_changed(conn_list_t *cl, conn_list_t *src)
164 {
165 cp
166   if(debug_lvl > 2)
167     syslog(LOG_DEBUG, "Sending KEY_CHANGED to " IP_ADDR_S,
168            IP_ADDR_V(cl->vpn_ip));
169
170   buflen = sprintf(buffer, "%d %lx\n", KEY_CHANGED, src->vpn_ip);
171
172   if((write(cl->meta_socket, buffer, buflen)) < 0)
173     {
174       syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
175       return -1;
176     }
177 cp
178   return 0;
179 }
180
181 void send_key_changed2(void)
182 {
183   conn_list_t *p;
184 cp
185   for(p = conn_list; p != NULL; p = p->next)
186     if(p->status.meta && p->protocol_version > PROT_3)
187       send_key_changed(p, myself);
188 cp
189 }
190
191 int send_basic_info(conn_list_t *cl)
192 {
193 cp
194   if(debug_lvl > 2)
195     syslog(LOG_DEBUG, "Send BASIC_INFO to " IP_ADDR_S,
196            IP_ADDR_V(cl->real_ip));
197
198   buflen = sprintf(buffer, "%d %d %lx/%lx:%x\n", BASIC_INFO, PROT_CURRENT, myself->vpn_ip, myself->vpn_mask, myself->port);
199
200   if((write(cl->meta_socket, buffer, buflen)) < 0)
201     {
202       syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
203       return -1;
204     }
205 cp
206   return 0;
207 }
208
209 int send_passphrase(conn_list_t *cl)
210 {
211   passphrase_t tmp;
212 cp
213   encrypt_passphrase(&tmp);
214
215   if(debug_lvl > 2)
216     syslog(LOG_DEBUG, "Send PASSPHRASE to " IP_ADDR_S,
217            IP_ADDR_V(cl->vpn_ip));
218
219   buflen = sprintf(buffer, "%d %s\n", PASSPHRASE, tmp.phrase);
220
221   if((write(cl->meta_socket, buffer, buflen)) < 0)
222     {
223       syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
224       return -1;
225     }
226 cp
227   return 0;
228 }
229
230 int send_public_key(conn_list_t *cl)
231 {
232 cp
233   if(debug_lvl > 2)
234     syslog(LOG_DEBUG, "Send PUBLIC_KEY to " IP_ADDR_S,
235            IP_ADDR_V(cl->vpn_ip));
236
237   buflen = sprintf(buffer, "%d %s\n", PUBLIC_KEY, my_public_key_base36);
238
239   if((write(cl->meta_socket, buffer, buflen)) < 0)
240     {
241       syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
242       return -1;
243     }
244 cp
245   return 0;
246 }
247
248 int send_calculate(conn_list_t *cl, char *k)
249 {
250 cp
251   buflen = sprintf(buffer, "%d %s\n", CALCULATE, k);
252
253   if((write(cl->meta_socket, buffer, buflen)) < 0)
254     {
255       syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
256       return -1;
257     }
258 cp
259   return 0;
260 }
261
262 int send_key_request(ip_t to)
263 {
264   conn_list_t *fw;
265 cp
266   fw = lookup_conn(to);
267   if(!fw)
268     {
269       syslog(LOG_ERR, "Attempting to send key request to " IP_ADDR_S ", which does not exist?",
270              IP_ADDR_V(to));
271       return -1;
272     }
273
274   if(debug_lvl > 2)
275     syslog(LOG_DEBUG, "Sending out request for public key to " IP_ADDR_S,
276            IP_ADDR_V(fw->nexthop->vpn_ip));
277
278   buflen = sprintf(buffer, "%d %lx %lx\n", REQ_KEY, to, myself->vpn_ip);
279
280   if((write(fw->nexthop->meta_socket, buffer, buflen)) < 0)
281     {
282       syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
283       return -1;
284     }
285   fw->status.waitingforkey = 1;
286 cp
287   return 0;
288 }
289
290 int send_key_answer(conn_list_t *cl, ip_t to)
291 {
292   conn_list_t *fw;
293 cp
294
295   fw = lookup_conn(to);
296   
297   if(!fw)
298     {
299       syslog(LOG_ERR, "Attempting to send key answer to " IP_ADDR_S ", which does not exist?",
300              IP_ADDR_V(to));
301       return -1;
302     }
303
304  if(debug_lvl > 2)
305     syslog(LOG_DEBUG, "Sending public key to " IP_ADDR_S,
306            IP_ADDR_V(fw->nexthop->vpn_ip));
307
308   buflen = sprintf(buffer, "%d %lx %lx %d %s\n", ANS_KEY, to, myself->vpn_ip, my_key_expiry, my_public_key_base36);
309
310   if((write(fw->nexthop->meta_socket, buffer, buflen)) < 0)
311     {
312       syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
313       return -1;
314     }
315 cp
316   return 0;
317 }
318
319 /*
320   notify all my direct connections of a new host
321   that was added to the vpn, with the exception
322   of the source of the announcement.
323 */
324 int notify_others(conn_list_t *new, conn_list_t *source,
325                   int (*function)(conn_list_t*, conn_list_t*))
326 {
327   conn_list_t *p;
328 cp
329   for(p = conn_list; p != NULL; p = p->next)
330     if(p != new && p != source && p->status.meta)
331       function(p, new);
332 cp
333   return 0;
334 }
335
336 /*
337   notify one connection of everything
338   i have connected
339 */
340 int notify_one(conn_list_t *new)
341 {
342   conn_list_t *p;
343 cp
344   for(p = conn_list; p != NULL; p = p->next)
345     if(p != new && p->protocol_version > PROT_3)
346       send_add_host(new, p);
347 cp
348   return 0;
349 }
350
351 /*
352   The incoming request handlers
353 */
354
355 int basic_info_h(conn_list_t *cl)
356 {
357 cp
358   if(sscanf(cl->buffer, "%*d %d %lx/%lx:%hx", &cl->protocol_version, &cl->vpn_ip, &cl->vpn_mask, &cl->port) != 4)
359     {
360        syslog(LOG_ERR, "got bad BASIC_INFO request: %s", cl->buffer);
361        return -1;
362     }  
363
364   if(cl->protocol_version != PROT_CURRENT)
365     {
366       syslog(LOG_ERR, "Peer uses incompatible protocol version %d.",
367              cl->protocol_version);
368       return -1;
369     }
370
371   if(debug_lvl > 2)
372     syslog(LOG_DEBUG, "got BASIC_INFO(%hd," IP_ADDR_S "," IP_ADDR_S ")", cl->port,
373            IP_ADDR_V(cl->vpn_ip), IP_ADDR_V(cl->vpn_mask));
374   if(debug_lvl > 1)
375     syslog(LOG_DEBUG, "Peer uses protocol version %d",
376            cl->protocol_version);
377
378   if(cl->status.outgoing)
379     {
380       if(setup_vpn_connection(cl) < 0)
381         return -1;
382       send_basic_info(cl);
383     }
384   else
385     {
386       if(setup_vpn_connection(cl) < 0)
387         return -1;
388       send_passphrase(cl);
389     }
390
391   cl->status.active = 0;
392 cp
393   return 0;
394 }
395
396 int passphrase_h(conn_list_t *cl)
397 {
398 cp
399   if(sscanf(cl->buffer, "%*d %s", cl->pp) != 1)
400     {
401        syslog(LOG_ERR, "got bad PASSPHRASE request: %s", cl->buffer);
402        return -1;
403     }  
404     
405   if(debug_lvl > 2)
406     syslog(LOG_DEBUG, "got PASSPHRASE");
407
408   if(cl->status.outgoing)
409     send_passphrase(cl);
410   else
411     send_public_key(cl);
412 cp
413   return 0;
414 }
415
416 int public_key_h(conn_list_t *cl)
417 {
418   char *g_n;
419 cp
420   if(sscanf(cl->buffer, "%*d %as", &g_n) != 1)
421     {
422        syslog(LOG_ERR, "got bad PUBLIC_KEY request: %s", cl->buffer);
423        return -1;
424     }  
425
426   if(debug_lvl > 2)
427     syslog(LOG_DEBUG, "got PUBLIC_KEY");
428
429   if(verify_passphrase(cl, g_n))
430     {
431       /* intruder! */
432       syslog(LOG_ERR, "Intruder: passphrase does not match.");
433       return -1;
434     }
435
436   if(debug_lvl > 2)
437     syslog(LOG_INFO, "Passphrase OK");
438
439   if(cl->status.outgoing)
440     send_public_key(cl);
441   else
442     send_ack(cl);
443
444   cl->status.active = 1;
445   notify_others(cl, NULL, send_add_host);
446   notify_one(cl);
447 cp
448   return 0;
449 }
450
451 int ack_h(conn_list_t *cl)
452 {
453 cp
454   if(debug_lvl > 2)
455     syslog(LOG_DEBUG, "got ACK");
456   
457   cl->status.active = 1;
458   syslog(LOG_NOTICE, "Connection with %s activated.", cl->hostname);
459 cp
460   return 0;
461 }
462
463 int termreq_h(conn_list_t *cl)
464 {
465 cp
466   syslog(LOG_NOTICE, IP_ADDR_S " wants to quit", IP_ADDR_V(cl->vpn_ip));
467   cl->status.termreq = 1;
468   terminate_connection(cl);
469
470   notify_others(cl, NULL, send_del_host);
471 cp
472   return 0;
473 }
474
475 int timeout_h(conn_list_t *cl)
476 {
477 cp
478   syslog(LOG_NOTICE, IP_ADDR_S " says it's gotten a timeout from us", IP_ADDR_V(cl->vpn_ip));
479   cl->status.termreq = 1;
480   terminate_connection(cl);
481 cp
482   return 0;
483 }
484
485 int del_host_h(conn_list_t *cl)
486 {
487   ip_t vpn_ip;
488   conn_list_t *fw;
489 cp
490   if(sscanf(cl->buffer, "%*d %lx", &vpn_ip) != 1)
491     {
492        syslog(LOG_ERR, "got bad DEL_HOST request: %s", cl->buffer);
493        return -1;
494     }  
495
496   if(debug_lvl > 2)
497     syslog(LOG_DEBUG, "got DEL_HOST for " IP_ADDR_S,
498            IP_ADDR_V(vpn_ip));
499
500   if(!(fw = lookup_conn(vpn_ip)))
501     {
502       syslog(LOG_ERR, "Somebody wanted to delete " IP_ADDR_S " which does not exist?",
503              IP_ADDR_V(vpn_ip));
504       return 0;
505     }
506
507   notify_others(cl, fw, send_del_host);
508
509   fw->status.termreq = 1;
510   terminate_connection(fw);
511 cp
512   return 0;
513 }
514
515 int ping_h(conn_list_t *cl)
516 {
517 cp
518   if(debug_lvl > 3)
519     syslog(LOG_DEBUG, "responding to ping from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
520   cl->status.pinged = 0;
521   cl->status.got_pong = 1;
522
523   send_pong(cl);
524 cp
525   return 0;
526 }
527
528 int pong_h(conn_list_t *cl)
529 {
530 cp
531   if(debug_lvl > 3)
532     syslog(LOG_DEBUG, "ok, got pong from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
533   cl->status.got_pong = 1;
534 cp
535   return 0;
536 }
537
538 int add_host_h(conn_list_t *cl)
539 {
540   ip_t real_ip;
541   ip_t vpn_ip;
542   ip_t vpn_mask;
543   unsigned short port;
544   conn_list_t *ncn, *fw;
545 cp
546   if(sscanf(cl->buffer, "%*d %lx %lx/%lx:%hx", &real_ip, &vpn_ip, &vpn_mask, &port) != 4)
547     {
548        syslog(LOG_ERR, "got bad ADD_HOST request: %s", cl->buffer);
549        return -1;
550     }  
551
552   if(debug_lvl > 2)
553     syslog(LOG_DEBUG, "Add host request from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
554   if(debug_lvl > 3)
555     syslog(LOG_DEBUG, "got ADD_HOST(" IP_ADDR_S "," IP_ADDR_S ",%hd)",
556            IP_ADDR_V(vpn_ip), IP_ADDR_V(vpn_mask), port);
557
558   /*
559     Suggestion of Hans Bayle
560   */
561   if((fw = lookup_conn(vpn_ip)))
562     {
563       notify_others(fw, cl, send_add_host);
564       return 0;
565     }
566
567   ncn = new_conn_list();
568   ncn->real_ip = real_ip;
569   ncn->vpn_ip = vpn_ip;
570   ncn->vpn_mask = vpn_mask;
571   ncn->port = port;
572   ncn->hostname = hostlookup(real_ip);
573   ncn->nexthop = cl;
574   ncn->next = conn_list;
575   conn_list = ncn;
576   ncn->status.active = 1;
577   notify_others(ncn, cl, send_add_host);
578 cp
579   return 0;
580 }
581
582 int req_key_h(conn_list_t *cl)
583 {
584   ip_t to;
585   ip_t from;
586   conn_list_t *fw;
587 cp
588   if(sscanf(cl->buffer, "%*d %lx %lx", &to, &from) != 2)
589     {
590        syslog(LOG_ERR, "got bad request: %s", cl->buffer);
591        return -1;
592     }  
593
594   if(debug_lvl > 2)
595     syslog(LOG_DEBUG, "got REQ_KEY from " IP_ADDR_S " for " IP_ADDR_S,
596            IP_ADDR_V(from), IP_ADDR_V(to));
597
598   if((to & myself->vpn_mask) == (myself->vpn_ip & myself->vpn_mask))
599     {  /* hey! they want something from ME! :) */
600       send_key_answer(cl, from);
601       return 0;
602     }
603
604   fw = lookup_conn(to);
605   
606   if(!fw)
607     {
608       syslog(LOG_ERR, "Attempting to forward key request to " IP_ADDR_S ", which does not exist?",
609              IP_ADDR_V(to));
610       return -1;
611     }
612
613   if(debug_lvl > 3)
614     syslog(LOG_DEBUG, "Forwarding request for public key to " IP_ADDR_S,
615            IP_ADDR_V(fw->nexthop->vpn_ip));
616   
617   if(write(fw->nexthop->meta_socket, cl->buffer, strlen(cl->buffer)) < 0)
618     {
619       syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
620       return -1;
621     }
622 cp
623   return 0;
624 }
625
626 void set_keys(conn_list_t *cl, int expiry, char *key)
627 {
628   char *ek;
629 cp
630   if(!cl->public_key)
631     {
632       cl->public_key = xmalloc(sizeof(*cl->key));
633       cl->public_key->key = NULL;
634     }
635     
636   if(cl->public_key->key)
637     free(cl->public_key->key);
638   cl->public_key->length = strlen(key);
639   cl->public_key->expiry = expiry;
640   cl->public_key->key = xmalloc(cl->public_key->length + 1);
641   strcpy(cl->public_key->key, key);
642
643   ek = make_shared_key(key);
644   
645   if(!cl->key)
646     {
647       cl->key = xmalloc(sizeof(*cl->key));
648       cl->key->key = NULL;
649     }
650
651   if(cl->key->key)
652     free(cl->key->key);
653
654   cl->key->length = strlen(ek);
655   cl->key->expiry = expiry;
656   cl->key->key = xmalloc(cl->key->length + 1);
657   strcpy(cl->key->key, ek);
658 cp
659 }
660
661 int ans_key_h(conn_list_t *cl)
662 {
663   ip_t to;
664   ip_t from;
665   int expiry;
666   char *key;
667   conn_list_t *fw, *gk;
668 cp
669   if(sscanf(cl->buffer, "%*d %lx %lx %d %as", &to, &from, &expiry, &key) != 4)
670     {
671        syslog(LOG_ERR, "got bad ANS_KEY request: %s", cl->buffer);
672        return -1;
673     }  
674
675   if(debug_lvl > 3)
676     syslog(LOG_DEBUG, "got ANS_KEY from " IP_ADDR_S " for " IP_ADDR_S,
677            IP_ADDR_V(from), IP_ADDR_V(to));
678
679   if(to == myself->vpn_ip)
680     {  /* hey! that key's for ME! :) */
681       if(debug_lvl > 2)
682         syslog(LOG_DEBUG, "Yeah! key arrived. Now do something with it.");
683       gk = lookup_conn(from);
684
685       if(!gk)
686         {
687           syslog(LOG_ERR, "Receiving key from " IP_ADDR_S ", which does not exist?",
688                  IP_ADDR_V(from));
689           return -1;
690         }
691
692       set_keys(gk, expiry, key);
693       gk->status.validkey = 1;
694       gk->status.waitingforkey = 0;
695       flush_queues(gk);
696       return 0;
697     }
698
699   fw = lookup_conn(to);
700   
701   if(!fw)
702     {
703       syslog(LOG_ERR, "Attempting to forward key to " IP_ADDR_S ", which does not exist?",
704              IP_ADDR_V(to));
705       return -1;
706     }
707
708   if(debug_lvl > 2)
709     syslog(LOG_DEBUG, "Forwarding public key to " IP_ADDR_S,
710            IP_ADDR_V(fw->nexthop->vpn_ip));
711
712   if((write(fw->nexthop->meta_socket, cl->buffer, strlen(cl->buffer))) < 0)
713     {
714       syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
715       return -1;
716     }
717 cp
718   return 0;
719 }
720
721 int key_changed_h(conn_list_t *cl)
722 {
723   ip_t from;
724   conn_list_t *ik;
725 cp
726   if(sscanf(cl->buffer, "%*d %lx", &from) != 1)
727     {
728        syslog(LOG_ERR, "got bad ANS_KEY request: %s", cl->buffer);
729        return -1;
730     }  
731
732   if(debug_lvl > 2)
733     syslog(LOG_DEBUG, "got KEY_CHANGED from " IP_ADDR_S,
734            IP_ADDR_V(from));
735
736   ik = lookup_conn(from);
737
738   if(!ik)
739     {
740       syslog(LOG_ERR, "Got changed key from " IP_ADDR_S ", which does not exist?",
741              IP_ADDR_V(from));
742       return -1;
743     }
744
745   ik->status.validkey = 0;
746   ik->status.waitingforkey = 0;
747
748   if(debug_lvl > 3)
749     syslog(LOG_DEBUG, "Forwarding key invalidation request");
750
751   notify_others(cl, ik, send_key_changed);
752 cp
753   return 0;
754 }
755
756 int (*request_handlers[256])(conn_list_t*) = {
757   0, ack_h, 0, 0, 0, 0, 0, 0, 0, 0,
758   0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
759   0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
760   termreq_h, timeout_h, del_host_h, 0, 0, 0, 0, 0, 0, 0,
761   ping_h, pong_h, 0, 0, 0, 0, 0, 0, 0, 0,
762   0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
763   add_host_h, basic_info_h, passphrase_h, public_key_h, 0, 0, 0, 0, 0, 0,
764   0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
765   0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
766   0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
767   0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
768   0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
769   0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
770   0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
771   req_key_h, ans_key_h, key_changed_h, 0, 0, 0, 0, 0, 0, 0,
772   0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
773   0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
774   0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
775   0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
776   0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0
777 };