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>
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.
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.
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.
20 $Id: protocol.c,v 1.28 2000/05/30 21:36:16 zarq Exp $
25 #include <sys/types.h>
30 #include <sys/socket.h>
45 char buffer[MAXBUFSIZE+1];
48 /* Outgoing request routines */
50 int send_ack(conn_list_t *cl)
54 syslog(LOG_DEBUG, _("Send ACK to %s"), cl->hostname);
56 buflen = snprintf(buffer, MAXBUFSIZE, "%d\n", ACK);
58 if((write(cl->meta_socket, buffer, buflen)) < 0)
60 syslog(LOG_ERR, _("send failed: %d:%d: %m"), __FILE__, __LINE__);
64 syslog(LOG_NOTICE, _("Connection with %s activated."), cl->hostname);
69 int send_termreq(conn_list_t *cl)
73 syslog(LOG_DEBUG, _("Send TERMREQ to " IP_ADDR_S),
74 IP_ADDR_V(cl->vpn_ip));
76 buflen = snprintf(buffer, MAXBUFSIZE, "%d %lx\n", TERMREQ, myself->vpn_ip);
78 if(write(cl->meta_socket, buffer, buflen) < 0)
81 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
88 int send_timeout(conn_list_t *cl)
92 syslog(LOG_DEBUG, _("Send TIMEOUT to " IP_ADDR_S),
93 IP_ADDR_V(cl->vpn_ip));
95 buflen = snprintf(buffer, MAXBUFSIZE, "%d %lx\n", PINGTIMEOUT, myself->vpn_ip);
97 if((write(cl->meta_socket, buffer, buflen)) < 0)
99 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
106 int send_del_host(conn_list_t *cl, conn_list_t *new_host)
110 syslog(LOG_DEBUG, _("Sending delete host " IP_ADDR_S " to " IP_ADDR_S),
111 IP_ADDR_V(new_host->vpn_ip), IP_ADDR_V(cl->vpn_ip));
113 buflen = snprintf(buffer, MAXBUFSIZE, "%d %lx\n", DEL_HOST, new_host->vpn_ip);
115 if((write(cl->meta_socket, buffer, buflen)) < 0)
117 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
124 int send_ping(conn_list_t *cl)
128 syslog(LOG_DEBUG, _("pinging " IP_ADDR_S), IP_ADDR_V(cl->vpn_ip));
130 buflen = snprintf(buffer, MAXBUFSIZE, "%d\n", PING);
132 if((write(cl->meta_socket, buffer, buflen)) < 0)
134 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
141 int send_pong(conn_list_t *cl)
144 buflen = snprintf(buffer, MAXBUFSIZE, "%d\n", PONG);
146 if((write(cl->meta_socket, buffer, buflen)) < 0)
148 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
155 int send_add_host(conn_list_t *cl, conn_list_t *new_host)
159 syslog(LOG_DEBUG, _("Sending add host to " IP_ADDR_S),
160 IP_ADDR_V(cl->vpn_ip));
162 buflen = snprintf(buffer, MAXBUFSIZE, "%d %lx %lx/%lx:%x\n", ADD_HOST, new_host->real_ip, new_host->vpn_ip, new_host->vpn_mask, new_host->port);
164 if((write(cl->meta_socket, buffer, buflen)) < 0)
166 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
173 int send_key_changed(conn_list_t *cl, conn_list_t *src)
177 syslog(LOG_DEBUG, _("Sending KEY_CHANGED to " IP_ADDR_S),
178 IP_ADDR_V(cl->vpn_ip));
180 buflen = snprintf(buffer, MAXBUFSIZE, "%d %lx\n", KEY_CHANGED, src->vpn_ip);
182 if((write(cl->meta_socket, buffer, buflen)) < 0)
184 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
191 void send_key_changed_all(void)
195 for(p = conn_list; p != NULL; p = p->next)
196 if(p->status.meta && p->status.active)
197 send_key_changed(p, myself);
201 int send_basic_info(conn_list_t *cl)
205 syslog(LOG_DEBUG, _("Send BASIC_INFO to " IP_ADDR_S),
206 IP_ADDR_V(cl->real_ip));
208 buflen = snprintf(buffer, MAXBUFSIZE, "%d %d %lx/%lx:%x\n", BASIC_INFO, PROT_CURRENT, myself->vpn_ip, myself->vpn_mask, myself->port);
210 if((write(cl->meta_socket, buffer, buflen)) < 0)
212 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
219 int send_passphrase(conn_list_t *cl)
223 encrypt_passphrase(&tmp);
226 syslog(LOG_DEBUG, _("Send PASSPHRASE %s to " IP_ADDR_S),
227 tmp.phrase, IP_ADDR_V(cl->vpn_ip));
229 buflen = snprintf(buffer, MAXBUFSIZE, "%d %s\n", PASSPHRASE, tmp.phrase);
231 if((write(cl->meta_socket, buffer, buflen)) < 0)
233 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
240 int send_public_key(conn_list_t *cl)
244 syslog(LOG_DEBUG, _("Send PUBLIC_KEY %s to " IP_ADDR_S),
245 my_public_key_base36, IP_ADDR_V(cl->vpn_ip));
247 buflen = snprintf(buffer, MAXBUFSIZE, "%d %s\n", PUBLIC_KEY, my_public_key_base36);
249 if((write(cl->meta_socket, buffer, buflen)) < 0)
251 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
258 int send_calculate(conn_list_t *cl, char *k)
261 buflen = snprintf(buffer, MAXBUFSIZE, "%d %s\n", CALCULATE, k);
263 if((write(cl->meta_socket, buffer, buflen)) < 0)
265 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
272 int send_key_request(ip_t to)
276 fw = lookup_conn(to);
279 syslog(LOG_ERR, _("Attempting to send key request to " IP_ADDR_S ", which does not exist?"),
285 syslog(LOG_DEBUG, _("Sending out request for public key to " IP_ADDR_S),
286 IP_ADDR_V(fw->nexthop->vpn_ip));
288 buflen = snprintf(buffer, MAXBUFSIZE, "%d %lx %lx\n", REQ_KEY, to, myself->vpn_ip);
290 if((write(fw->nexthop->meta_socket, buffer, buflen)) < 0)
292 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
295 fw->status.waitingforkey = 1;
300 int send_key_answer(conn_list_t *cl, ip_t to)
305 fw = lookup_conn(to);
309 syslog(LOG_ERR, _("Attempting to send key answer to " IP_ADDR_S ", which does not exist?"),
315 syslog(LOG_DEBUG, _("Sending public key to " IP_ADDR_S),
316 IP_ADDR_V(fw->nexthop->vpn_ip));
318 buflen = snprintf(buffer, MAXBUFSIZE, "%d %lx %lx %d %s\n", ANS_KEY, to, myself->vpn_ip, my_key_expiry, my_public_key_base36);
320 if((write(fw->nexthop->meta_socket, buffer, buflen)) < 0)
322 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
330 notify all my direct connections of a new host
331 that was added to the vpn, with the exception
332 of the source of the announcement.
334 int notify_others(conn_list_t *new, conn_list_t *source,
335 int (*function)(conn_list_t*, conn_list_t*))
339 for(p = conn_list; p != NULL; p = p->next)
340 if(p != new && p != source && p->status.meta && p->status.active)
347 notify one connection of everything
350 int notify_one(conn_list_t *new)
354 for(p = conn_list; p != NULL; p = p->next)
355 if(p != new && p->status.active)
356 send_add_host(new, p);
362 The incoming request handlers
365 int basic_info_h(conn_list_t *cl)
368 if(sscanf(cl->buffer, "%*d %d %lx/%lx:%hx", &cl->protocol_version, &cl->vpn_ip, &cl->vpn_mask, &cl->port) != 4)
370 syslog(LOG_ERR, _("got bad BASIC_INFO request: %s"), cl->buffer);
374 if(cl->protocol_version != PROT_CURRENT)
376 syslog(LOG_ERR, _("Peer uses incompatible protocol version %d."),
377 cl->protocol_version);
382 syslog(LOG_DEBUG, _("got BASIC_INFO(%hd," IP_ADDR_S "," IP_ADDR_S ")"), cl->port,
383 IP_ADDR_V(cl->vpn_ip), IP_ADDR_V(cl->vpn_mask));
385 syslog(LOG_DEBUG, _("Peer uses protocol version %d"),
386 cl->protocol_version);
388 if(cl->status.outgoing)
390 if(setup_vpn_connection(cl) < 0)
396 if(setup_vpn_connection(cl) < 0)
404 int passphrase_h(conn_list_t *cl)
407 cl->pp = xmalloc(sizeof(*(cl->pp)));
409 if(sscanf(cl->buffer, "%*d %as", &(cl->pp->phrase)) != 1)
411 syslog(LOG_ERR, _("got bad PASSPHRASE request: %s"), cl->buffer);
414 cl->pp->len = strlen(cl->pp->phrase);
417 syslog(LOG_DEBUG, _("got PASSPHRASE"));
419 if(cl->status.outgoing)
427 int public_key_h(conn_list_t *cl)
432 if(sscanf(cl->buffer, "%*d %as", &g_n) != 1)
434 syslog(LOG_ERR, _("got bad PUBLIC_KEY request: %s"), cl->buffer);
439 syslog(LOG_DEBUG, _("got PUBLIC_KEY %s"), g_n);
441 if(verify_passphrase(cl, g_n))
444 syslog(LOG_ERR, _("Intruder: passphrase does not match."));
449 syslog(LOG_INFO, _("Passphrase OK"));
451 if(cl->status.outgoing)
457 /* Okay, before we active the connection, we check if there is another entry
458 in the connection list with the same vpn_ip. If so, it presumably is an
459 old connection that has timed out but we don't know it yet. Because our
460 conn_list entry is not active, lookup_conn will skip ourself. */
462 while(old=lookup_conn(cl->vpn_ip))
463 terminate_connection(old);
465 cl->status.active = 1;
466 notify_others(cl, NULL, send_add_host);
473 int ack_h(conn_list_t *cl)
477 syslog(LOG_DEBUG, _("got ACK"));
479 cl->status.active = 1;
480 syslog(LOG_NOTICE, _("Connection with %s activated."), cl->hostname);
485 int termreq_h(conn_list_t *cl)
488 syslog(LOG_NOTICE, _(IP_ADDR_S " wants to quit"), IP_ADDR_V(cl->vpn_ip));
489 cl->status.termreq = 1;
490 terminate_connection(cl);
492 notify_others(cl, NULL, send_del_host);
497 int timeout_h(conn_list_t *cl)
500 if(!cl->status.active) return -1;
501 syslog(LOG_NOTICE, _(IP_ADDR_S " says it's gotten a timeout from us"), IP_ADDR_V(cl->vpn_ip));
502 cl->status.termreq = 1;
503 terminate_connection(cl);
508 int del_host_h(conn_list_t *cl)
513 if(!cl->status.active) return -1;
515 if(sscanf(cl->buffer, "%*d %lx", &vpn_ip) != 1)
517 syslog(LOG_ERR, _("got bad DEL_HOST request: %s"), cl->buffer);
522 syslog(LOG_DEBUG, _("got DEL_HOST for " IP_ADDR_S),
525 if(!(fw = lookup_conn(vpn_ip)))
527 syslog(LOG_ERR, _("Somebody wanted to delete " IP_ADDR_S " which does not exist?"),
532 notify_others(cl, fw, send_del_host);
534 fw->status.termreq = 1;
535 terminate_connection(fw);
540 int ping_h(conn_list_t *cl)
543 if(!cl->status.active) return -1;
545 syslog(LOG_DEBUG, _("responding to ping from " IP_ADDR_S), IP_ADDR_V(cl->vpn_ip));
546 cl->status.pinged = 0;
547 cl->status.got_pong = 1;
554 int pong_h(conn_list_t *cl)
557 if(!cl->status.active) return -1;
559 syslog(LOG_DEBUG, _("ok, got pong from " IP_ADDR_S), IP_ADDR_V(cl->vpn_ip));
560 cl->status.got_pong = 1;
565 int add_host_h(conn_list_t *cl)
571 conn_list_t *ncn, *fw;
573 if(!cl->status.active)
575 if(sscanf(cl->buffer, "%*d %lx %lx/%lx:%hx", &real_ip, &vpn_ip, &vpn_mask, &port) != 4)
577 syslog(LOG_ERR, _("got bad ADD_HOST request: %s"), cl->buffer);
582 syslog(LOG_DEBUG, _("Add host request from " IP_ADDR_S), IP_ADDR_V(cl->vpn_ip));
584 syslog(LOG_DEBUG, _("got ADD_HOST(" IP_ADDR_S "," IP_ADDR_S ",%hd)"),
585 IP_ADDR_V(vpn_ip), IP_ADDR_V(vpn_mask), port);
588 Suggestion of Hans Bayle
590 if((fw = lookup_conn(vpn_ip)))
592 if(fw->nexthop == cl)
593 notify_others(fw, cl, send_add_host);
596 syslog(LOG_DEBUG, _("Invalid add_host request from " IP_ADDR_S),
597 IP_ADDR_V(cl->vpn_ip));
601 ncn = new_conn_list();
602 ncn->real_ip = real_ip;
603 ncn->vpn_ip = vpn_ip;
604 ncn->vpn_mask = vpn_mask;
606 ncn->hostname = hostlookup(real_ip);
608 ncn->next = conn_list;
610 ncn->status.active = 1;
611 notify_others(ncn, cl, send_add_host);
616 int req_key_h(conn_list_t *cl)
622 if(!cl->status.active) return -1;
623 if(sscanf(cl->buffer, "%*d %lx %lx", &to, &from) != 2)
625 syslog(LOG_ERR, _("got bad request: %s"), cl->buffer);
630 syslog(LOG_DEBUG, _("got REQ_KEY from " IP_ADDR_S " for " IP_ADDR_S),
631 IP_ADDR_V(from), IP_ADDR_V(to));
633 if((to & myself->vpn_mask) == (myself->vpn_ip & myself->vpn_mask))
634 { /* hey! they want something from ME! :) */
635 send_key_answer(cl, from);
639 fw = lookup_conn(to);
643 syslog(LOG_ERR, _("Attempting to forward key request to " IP_ADDR_S ", which does not exist?"),
649 syslog(LOG_DEBUG, _("Forwarding request for public key to " IP_ADDR_S),
650 IP_ADDR_V(fw->nexthop->vpn_ip));
652 cl->buffer[cl->reqlen-1] = '\n';
654 if(write(fw->nexthop->meta_socket, cl->buffer, cl->reqlen) < 0)
656 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
663 void set_keys(conn_list_t *cl, int expiry, char *key)
669 cl->public_key = xmalloc(sizeof(*cl->key));
670 cl->public_key->key = NULL;
673 if(cl->public_key->key)
674 free(cl->public_key->key);
675 cl->public_key->length = strlen(key);
676 cl->public_key->expiry = expiry;
677 cl->public_key->key = xmalloc(cl->public_key->length + 1);
678 strcpy(cl->public_key->key, key);
680 ek = make_shared_key(key);
684 cl->key = xmalloc(sizeof(*cl->key));
691 cl->key->length = strlen(ek);
692 cl->key->expiry = expiry;
693 cl->key->key = xmalloc(cl->key->length + 1);
694 strcpy(cl->key->key, ek);
698 int ans_key_h(conn_list_t *cl)
704 conn_list_t *fw, *gk;
706 if(!cl->status.active) return -1;
707 if(sscanf(cl->buffer, "%*d %lx %lx %d %as", &to, &from, &expiry, &key) != 4)
709 syslog(LOG_ERR, _("got bad ANS_KEY request: %s"), cl->buffer);
714 syslog(LOG_DEBUG, _("got ANS_KEY from " IP_ADDR_S " for " IP_ADDR_S),
715 IP_ADDR_V(from), IP_ADDR_V(to));
717 if(to == myself->vpn_ip)
718 { /* hey! that key's for ME! :) */
720 syslog(LOG_DEBUG, _("Yeah! key arrived. Now do something with it."));
721 gk = lookup_conn(from);
725 syslog(LOG_ERR, _("Receiving key from " IP_ADDR_S ", which does not exist?"),
730 set_keys(gk, expiry, key);
731 gk->status.validkey = 1;
732 gk->status.waitingforkey = 0;
737 fw = lookup_conn(to);
741 syslog(LOG_ERR, _("Attempting to forward key to " IP_ADDR_S ", which does not exist?"),
747 syslog(LOG_DEBUG, _("Forwarding public key to " IP_ADDR_S),
748 IP_ADDR_V(fw->nexthop->vpn_ip));
750 cl->buffer[cl->reqlen-1] = '\n';
752 if((write(fw->nexthop->meta_socket, cl->buffer, cl->reqlen)) < 0)
754 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
761 int key_changed_h(conn_list_t *cl)
766 if(!cl->status.active) return -1;
767 if(sscanf(cl->buffer, "%*d %lx", &from) != 1)
769 syslog(LOG_ERR, _("got bad ANS_KEY request: %s"), cl->buffer);
774 syslog(LOG_DEBUG, _("got KEY_CHANGED from " IP_ADDR_S),
777 ik = lookup_conn(from);
781 syslog(LOG_ERR, _("Got changed key from " IP_ADDR_S ", which does not exist?"),
786 ik->status.validkey = 0;
787 ik->status.waitingforkey = 0;
790 syslog(LOG_DEBUG, _("Forwarding key invalidation request"));
792 notify_others(cl, ik, send_key_changed);
797 int (*request_handlers[256])(conn_list_t*) = {
798 0, ack_h, 0, 0, 0, 0, 0, 0, 0, 0,
799 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
800 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
801 termreq_h, timeout_h, del_host_h, 0, 0, 0, 0, 0, 0, 0,
802 ping_h, pong_h, 0, 0, 0, 0, 0, 0, 0, 0,
803 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
804 add_host_h, basic_info_h, passphrase_h, public_key_h, 0, 0, 0, 0, 0, 0,
805 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
806 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
807 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
808 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
809 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
810 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
811 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
812 req_key_h, ans_key_h, key_changed_h, 0, 0, 0, 0, 0, 0, 0,
813 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
814 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
815 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
816 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
817 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0