2 protocol.c -- handle the meta-protocol
3 Copyright (C) 1999 Ivo Timmermans <zarq@iname.com>
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.
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.
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.
25 #include <sys/socket.h>
37 int send_ack(conn_list_t *cl)
39 unsigned char tmp = ACK;
42 syslog(LOG_DEBUG, "Send ACK to %s", cl->hostname);
44 syslog(LOG_NOTICE, "Connection with %s activated.", cl->hostname);
45 if((write(cl->meta_socket, &tmp, sizeof(tmp))) < 0)
47 syslog(LOG_ERR, "send failed: %d:%d: %m", __FILE__, __LINE__);
54 int send_termreq(conn_list_t *cl)
59 tmp.vpn_ip = myself->vpn_ip;
62 syslog(LOG_DEBUG, "Send TERMREQ(" IP_ADDR_S ") to " IP_ADDR_S, IP_ADDR_V(tmp.vpn_ip),
63 IP_ADDR_V(cl->vpn_ip));
65 if((write(cl->meta_socket, &tmp, sizeof(tmp))) < 0)
67 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
74 int send_timeout(conn_list_t *cl)
78 tmp.type = PINGTIMEOUT;
79 tmp.vpn_ip = myself->vpn_ip;
82 syslog(LOG_DEBUG, "Send TIMEOUT(" IP_ADDR_S ") to " IP_ADDR_S, IP_ADDR_V(tmp.vpn_ip),
83 IP_ADDR_V(cl->vpn_ip));
85 if((write(cl->meta_socket, &tmp, sizeof(tmp))) < 0)
87 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
94 int send_del_host(conn_list_t *cl, conn_list_t *new_host)
99 tmp.vpn_ip = new_host->vpn_ip;
102 syslog(LOG_DEBUG, "Sending delete host %lx to " IP_ADDR_S,
103 tmp.vpn_ip, IP_ADDR_V(cl->vpn_ip));
105 if((write(cl->meta_socket, &tmp, sizeof(tmp))) < 0)
107 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
114 int send_ping(conn_list_t *cl)
116 unsigned char tmp = PING;
119 syslog(LOG_DEBUG, "pinging " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
121 if((write(cl->meta_socket, &tmp, sizeof(tmp))) < 0)
123 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
130 int send_pong(conn_list_t *cl)
132 unsigned char tmp = PONG;
134 if((write(cl->meta_socket, &tmp, sizeof(tmp))) < 0)
136 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
143 int send_add_host(conn_list_t *cl, conn_list_t *new_host)
148 tmp.real_ip = new_host->real_ip;
149 tmp.vpn_ip = new_host->vpn_ip;
150 tmp.vpn_mask = new_host->vpn_mask;
151 tmp.portnr = new_host->port;
154 syslog(LOG_DEBUG, "Sending add host (%lx/%lx %lx:%hd) to " IP_ADDR_S,
155 tmp.vpn_ip, tmp.vpn_mask, tmp.real_ip, tmp.portnr,
156 IP_ADDR_V(cl->vpn_ip));
158 if((write(cl->meta_socket, &tmp, sizeof(tmp))) < 0)
160 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
167 int send_key_changed(conn_list_t *cl, conn_list_t *src)
171 tmp.type = KEY_CHANGED;
172 tmp.from = src->vpn_ip;
175 syslog(LOG_DEBUG, "Sending KEY_CHANGED (%lx) to " IP_ADDR_S,
176 tmp.from, IP_ADDR_V(cl->vpn_ip));
178 if((write(cl->meta_socket, &tmp, sizeof(tmp))) < 0)
180 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
187 void send_key_changed2(void)
191 for(p = conn_list; p != NULL; p = p->next)
192 if(p->status.meta && p->protocol_version > PROT_3)
193 send_key_changed(p, myself);
197 int send_basic_info(conn_list_t *cl)
201 tmp.type = BASIC_INFO;
202 tmp.protocol = PROT_CURRENT;
204 tmp.portnr = myself->port;
205 tmp.vpn_ip = myself->vpn_ip;
206 tmp.vpn_mask = myself->vpn_mask;
209 syslog(LOG_DEBUG, "Send BASIC_INFO(%d,%hd," IP_ADDR_S "," IP_ADDR_S ") to " IP_ADDR_S,
210 tmp.protocol, tmp.portnr, IP_ADDR_V(tmp.vpn_ip), IP_ADDR_V(tmp.vpn_mask),
211 IP_ADDR_V(cl->real_ip));
213 if((write(cl->meta_socket, &tmp, sizeof(tmp))) < 0)
215 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
222 int send_passphrase(conn_list_t *cl)
226 tmp.type = PASSPHRASE;
227 encrypt_passphrase(&tmp);
230 syslog(LOG_DEBUG, "Send PASSPHRASE(%hd,...) to " IP_ADDR_S, tmp.len,
231 IP_ADDR_V(cl->vpn_ip));
233 if((write(cl->meta_socket, &tmp, tmp.len+3)) < 0)
235 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
242 int send_public_key(conn_list_t *cl)
246 tmp = (public_key_t*)xmalloc(strlen(my_public_key_base36)+sizeof(*tmp));
247 tmp->type = PUBLIC_KEY;
248 tmp->len = strlen(my_public_key_base36);
249 strcpy(&tmp->key, my_public_key_base36);
252 syslog(LOG_DEBUG, "Send PUBLIC_KEY(%hd,%s) to " IP_ADDR_S, tmp->len, &tmp->key,
253 IP_ADDR_V(cl->vpn_ip));
255 if((write(cl->meta_socket, tmp, tmp->len+sizeof(*tmp))) < 0)
257 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
264 int send_calculate(conn_list_t *cl, char *k)
268 tmp = xmalloc(strlen(k)+sizeof(*tmp));
269 tmp->type = CALCULATE;
270 tmp->len = strlen(k);
271 strcpy(&tmp->key, k);
273 if((write(cl->meta_socket, tmp, tmp->len+sizeof(*tmp))) < 0)
275 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
282 int send_key_request(ip_t to)
287 tmp = xmalloc(sizeof(*tmp));
290 tmp->from = myself->vpn_ip;
293 fw = lookup_conn(to);
296 syslog(LOG_ERR, "Attempting to send key request to " IP_ADDR_S ", which does not exist?",
302 syslog(LOG_DEBUG, "Sending out request for public key to " IP_ADDR_S,
303 IP_ADDR_V(fw->nexthop->vpn_ip));
304 if(write(fw->nexthop->meta_socket, tmp, sizeof(*tmp)) < 0)
306 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
309 fw->status.waitingforkey = 1;
314 int send_key_answer(conn_list_t *cl, ip_t to)
319 tmp = xmalloc(sizeof(*tmp)+strlen(my_public_key_base36));
322 tmp->from = myself->vpn_ip;
323 tmp->expiry = my_key_expiry;
324 tmp->len = strlen(my_public_key_base36);
325 strcpy(&tmp->key, my_public_key_base36);
327 fw = lookup_conn(to);
331 syslog(LOG_ERR, "Attempting to send key answer to " IP_ADDR_S ", which does not exist?",
337 syslog(LOG_DEBUG, "Sending public key to " IP_ADDR_S,
338 IP_ADDR_V(fw->nexthop->vpn_ip));
339 if(write(fw->nexthop->meta_socket, tmp, sizeof(*tmp)+tmp->len) < 0)
341 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
349 notify all my direct connections of a new host
350 that was added to the vpn, with the exception
351 of the source of the announcement.
353 int notify_others(conn_list_t *new, conn_list_t *source,
354 int (*function)(conn_list_t*, conn_list_t*))
358 for(p = conn_list; p != NULL; p = p->next)
359 if(p != new && p != source && p->status.meta && p->protocol_version > PROT_3)
366 notify one connection of everything
369 int notify_one(conn_list_t *new)
373 for(p = conn_list; p != NULL; p = p->next)
374 if(p != new && p->protocol_version > PROT_3)
375 send_add_host(new, p);
381 The incoming request handlers
384 int basic_info_h(conn_list_t *cl, unsigned char *d, int len)
386 basic_info_t *tmp = (basic_info_t*)d;
388 cl->protocol_version = tmp->protocol;
389 cl->port = tmp->portnr;
390 cl->vpn_ip = tmp->vpn_ip;
391 cl->vpn_mask = tmp->vpn_mask;
393 if(cl->protocol_version < PROT_CURRENT)
395 syslog(LOG_ERR, "Peer uses protocol version %d which is too old.",
396 cl->protocol_version);
401 syslog(LOG_DEBUG, "got BASIC_INFO(%hd," IP_ADDR_S "," IP_ADDR_S ")", cl->port,
402 IP_ADDR_V(cl->vpn_ip), IP_ADDR_V(cl->vpn_mask));
404 syslog(LOG_DEBUG, "Peer uses protocol version %d",
405 cl->protocol_version);
407 if(cl->status.outgoing)
409 if(setup_vpn_connection(cl) < 0)
415 if(setup_vpn_connection(cl) < 0)
420 cl->status.active = 0;
425 int passphrase_h(conn_list_t *cl, unsigned char *d, int len)
427 passphrase_t *tmp = (passphrase_t*)d;
429 cl->pp = xmalloc(tmp->len+3);
430 memcpy(cl->pp, tmp, tmp->len+3);
433 syslog(LOG_DEBUG, "got PASSPHRASE(%hd,...)", cl->pp->len);
435 if(cl->status.outgoing)
443 int public_key_h(conn_list_t *cl, unsigned char *d, int len)
446 public_key_t *tmp = (public_key_t*)d;
449 syslog(LOG_DEBUG, "got PUBLIC_KEY(%hd,%s)", tmp->len, &tmp->key);
451 g_n = xmalloc(tmp->len+1);
452 strcpy(g_n, &tmp->key);
454 if(verify_passphrase(cl, g_n))
457 syslog(LOG_ERR, "Intruder: passphrase does not match.");
462 syslog(LOG_INFO, "Passphrase OK");
464 if(cl->status.outgoing)
469 cl->status.active = 1;
470 notify_others(cl, NULL, send_add_host);
476 int ack_h(conn_list_t *cl, unsigned char *d, int len)
480 syslog(LOG_DEBUG, "got ACK");
482 cl->status.active = 1;
483 syslog(LOG_NOTICE, "Connection with %s activated.", cl->hostname);
487 Now I'm going to cheat. The meta protocol is actually
488 a stream of requests, that may come in in the same TCP
489 packet. This is the only place that it will happen,
491 I may change it in the future, if it appears that this
494 if(len > 1) /* An ADD_HOST follows */
496 if(request_handlers[d[1]] == NULL)
497 syslog(LOG_ERR, "Unknown request %d.", d[1]);
498 if(request_handlers[d[1]](cl, d + 1, len - 1) < 0)
505 int termreq_h(conn_list_t *cl, unsigned char *d, int len)
508 syslog(LOG_NOTICE, IP_ADDR_S " wants to quit", IP_ADDR_V(cl->vpn_ip));
509 cl->status.termreq = 1;
510 terminate_connection(cl);
512 notify_others(cl, NULL, send_del_host);
517 int timeout_h(conn_list_t *cl, unsigned char *d, int len)
520 syslog(LOG_NOTICE, IP_ADDR_S " says it's gotten a timeout from us", IP_ADDR_V(cl->vpn_ip));
521 cl->status.termreq = 1;
522 terminate_connection(cl);
527 int del_host_h(conn_list_t *cl, unsigned char *d, int len)
529 del_host_t *tmp = (del_host_t*)d;
533 syslog(LOG_DEBUG, "got DEL_HOST for " IP_ADDR_S,
534 IP_ADDR_V(tmp->vpn_ip));
536 if(!(fw = lookup_conn(tmp->vpn_ip)))
538 syslog(LOG_ERR, "Somebody wanted to delete " IP_ADDR_S " which does not exist?",
539 IP_ADDR_V(tmp->vpn_ip));
543 notify_others(cl, fw, send_del_host);
545 fw->status.termreq = 1;
546 terminate_connection(fw);
551 int ping_h(conn_list_t *cl, unsigned char *d, int len)
555 syslog(LOG_DEBUG, "responding to ping from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
556 cl->status.pinged = 0;
557 cl->status.got_pong = 1;
564 int pong_h(conn_list_t *cl, unsigned char *d, int len)
568 syslog(LOG_DEBUG, "ok, got pong from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
569 cl->status.got_pong = 1;
574 int add_host_h(conn_list_t *cl, unsigned char *d, int len)
576 add_host_t *tmp = (add_host_t*)d;
577 conn_list_t *ncn, *fw;
580 syslog(LOG_DEBUG, "Add host request from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
582 syslog(LOG_DEBUG, "got ADD_HOST(" IP_ADDR_S "," IP_ADDR_S ",%hd)",
583 IP_ADDR_V(tmp->vpn_ip), IP_ADDR_V(tmp->vpn_mask), tmp->portnr);
586 Suggestion of Hans Bayle
588 if((fw = lookup_conn(tmp->vpn_ip)))
590 notify_others(fw, cl, send_add_host);
594 ncn = new_conn_list();
595 ncn->real_ip = tmp->real_ip;
596 ncn->vpn_ip = tmp->vpn_ip;
597 ncn->vpn_mask = tmp->vpn_mask;
598 ncn->port = tmp->portnr;
599 ncn->hostname = hostlookup(tmp->real_ip);
601 ncn->next = conn_list;
603 ncn->status.active = 1;
604 notify_others(ncn, cl, send_add_host);
607 again, i'm cheating here. see the comment in ack_h.
608 Naughty zarq! Now you see what cheating will get you... [GS]
610 if(len > sizeof(*tmp)) /* Another ADD_HOST follows */
612 if(request_handlers[d[sizeof(*tmp)]] == NULL)
613 syslog(LOG_ERR, "Unknown request %d.", d[sizeof(*tmp)]);
614 if(request_handlers[d[sizeof(*tmp)]](cl, d + sizeof(*tmp), len - sizeof(*tmp)) < 0)
621 int req_key_h(conn_list_t *cl, unsigned char *d, int len)
623 key_req_t *tmp = (key_req_t*)d;
627 syslog(LOG_DEBUG, "got REQ_KEY from " IP_ADDR_S " for " IP_ADDR_S,
628 IP_ADDR_V(tmp->from), IP_ADDR_V(tmp->to));
630 if((tmp->to & myself->vpn_mask) == (myself->vpn_ip & myself->vpn_mask))
631 { /* hey! they want something from ME! :) */
632 send_key_answer(cl, tmp->from);
636 fw = lookup_conn(tmp->to);
640 syslog(LOG_ERR, "Attempting to forward key request to " IP_ADDR_S ", which does not exist?",
646 syslog(LOG_DEBUG, "Forwarding request for public key to " IP_ADDR_S,
647 IP_ADDR_V(fw->nexthop->vpn_ip));
648 if(write(fw->nexthop->meta_socket, tmp, sizeof(*tmp)) < 0)
650 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
657 void set_keys(conn_list_t *cl, key_req_t *k)
663 cl->public_key = xmalloc(sizeof(*cl->key));
664 cl->public_key->key = NULL;
666 if(cl->public_key->key)
667 free(cl->public_key->key);
668 cl->public_key->length = k->len;
669 cl->public_key->expiry = k->expiry;
670 cl->public_key->key = xmalloc(k->len + 1);
671 strcpy(cl->public_key->key, &(k->key));
673 ek = make_shared_key(&(k->key));
676 cl->key = xmalloc(sizeof(*cl->key));
681 cl->key->length = strlen(ek);
682 cl->key->expiry = k->expiry;
683 cl->key->key = xmalloc(strlen(ek) + 1);
684 strcpy(cl->key->key, ek);
688 int ans_key_h(conn_list_t *cl, unsigned char *d, int len)
690 key_req_t *tmp = (key_req_t*)d;
691 conn_list_t *fw, *gk;
694 syslog(LOG_DEBUG, "got ANS_KEY from " IP_ADDR_S " for " IP_ADDR_S,
695 IP_ADDR_V(tmp->from), IP_ADDR_V(tmp->to));
697 if(tmp->to == myself->vpn_ip)
698 { /* hey! that key's for ME! :) */
700 syslog(LOG_DEBUG, "Yeah! key arrived. Now do something with it.");
701 gk = lookup_conn(tmp->from);
705 syslog(LOG_ERR, "Receiving key from " IP_ADDR_S ", which does not exist?",
706 IP_ADDR_V(tmp->from));
711 gk->status.validkey = 1;
712 gk->status.waitingforkey = 0;
717 fw = lookup_conn(tmp->to);
721 syslog(LOG_ERR, "Attempting to forward key to " IP_ADDR_S ", which does not exist?",
727 syslog(LOG_DEBUG, "Forwarding public key to " IP_ADDR_S,
728 IP_ADDR_V(fw->nexthop->vpn_ip));
729 if(write(fw->nexthop->meta_socket, tmp, sizeof(*tmp)+tmp->len) < 0)
731 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
738 int key_changed_h(conn_list_t *cl, unsigned char *d, int len)
740 key_changed_t *tmp = (key_changed_t*)d;
744 syslog(LOG_DEBUG, "got KEY_CHANGED from " IP_ADDR_S,
745 IP_ADDR_V(tmp->from));
747 ik = lookup_conn(tmp->from);
751 syslog(LOG_ERR, "Got changed key from " IP_ADDR_S ", which does not exist?",
752 IP_ADDR_V(tmp->from));
756 ik->status.validkey = 0;
757 ik->status.waitingforkey = 0;
760 syslog(LOG_DEBUG, "Forwarding key invalidation request");
762 notify_others(cl, ik, send_key_changed);
767 int (*request_handlers[256])(conn_list_t*, unsigned char*, int) = {
768 0, ack_h, 0, 0, 0, 0, 0, 0, 0, 0,
769 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
770 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
771 termreq_h, timeout_h, del_host_h, 0, 0, 0, 0, 0, 0, 0,
772 ping_h, pong_h, 0, 0, 0, 0, 0, 0, 0, 0,
773 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
774 add_host_h, basic_info_h, passphrase_h, public_key_h, 0, 0, 0, 0, 0, 0,
775 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
776 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
777 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
778 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
779 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
780 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
781 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
782 req_key_h, ans_key_h, key_changed_h, 0, 0, 0, 0, 0, 0, 0,
783 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
784 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
785 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
786 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
787 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0