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.26 2000/05/29 21:01:25 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)
456 /* Okay, before we active the connection, we check if there is another entry
457 in the connection list with the same vpn_ip. If so, it presumably is an
458 old connection that has timed out but we don't know it yet. Because our
459 conn_list entry is not active, lookup_conn will skip ourself. */
461 while(old=lookup_conn(cl->vpn_ip))
462 terminate_connection(old);
464 cl->status.active = 1;
465 notify_others(cl, NULL, send_add_host);
471 int ack_h(conn_list_t *cl)
475 syslog(LOG_DEBUG, _("got ACK"));
477 cl->status.active = 1;
478 syslog(LOG_NOTICE, _("Connection with %s activated."), cl->hostname);
483 int termreq_h(conn_list_t *cl)
486 syslog(LOG_NOTICE, _(IP_ADDR_S " wants to quit"), IP_ADDR_V(cl->vpn_ip));
487 cl->status.termreq = 1;
488 terminate_connection(cl);
490 notify_others(cl, NULL, send_del_host);
495 int timeout_h(conn_list_t *cl)
498 if(!cl->status.active) return -1;
499 syslog(LOG_NOTICE, _(IP_ADDR_S " says it's gotten a timeout from us"), IP_ADDR_V(cl->vpn_ip));
500 cl->status.termreq = 1;
501 terminate_connection(cl);
506 int del_host_h(conn_list_t *cl)
511 if(!cl->status.active) return -1;
513 if(sscanf(cl->buffer, "%*d %lx", &vpn_ip) != 1)
515 syslog(LOG_ERR, _("got bad DEL_HOST request: %s"), cl->buffer);
520 syslog(LOG_DEBUG, _("got DEL_HOST for " IP_ADDR_S),
523 if(!(fw = lookup_conn(vpn_ip)))
525 syslog(LOG_ERR, _("Somebody wanted to delete " IP_ADDR_S " which does not exist?"),
530 notify_others(cl, fw, send_del_host);
532 fw->status.termreq = 1;
533 terminate_connection(fw);
538 int ping_h(conn_list_t *cl)
541 if(!cl->status.active) return -1;
543 syslog(LOG_DEBUG, _("responding to ping from " IP_ADDR_S), IP_ADDR_V(cl->vpn_ip));
544 cl->status.pinged = 0;
545 cl->status.got_pong = 1;
552 int pong_h(conn_list_t *cl)
555 if(!cl->status.active) return -1;
557 syslog(LOG_DEBUG, _("ok, got pong from " IP_ADDR_S), IP_ADDR_V(cl->vpn_ip));
558 cl->status.got_pong = 1;
563 int add_host_h(conn_list_t *cl)
569 conn_list_t *ncn, *fw;
571 if(!cl->status.active) return -1;
572 if(sscanf(cl->buffer, "%*d %lx %lx/%lx:%hx", &real_ip, &vpn_ip, &vpn_mask, &port) != 4)
574 syslog(LOG_ERR, _("got bad ADD_HOST request: %s"), cl->buffer);
579 syslog(LOG_DEBUG, _("Add host request from " IP_ADDR_S), IP_ADDR_V(cl->vpn_ip));
581 syslog(LOG_DEBUG, _("got ADD_HOST(" IP_ADDR_S "," IP_ADDR_S ",%hd)"),
582 IP_ADDR_V(vpn_ip), IP_ADDR_V(vpn_mask), port);
585 Suggestion of Hans Bayle
587 if((fw = lookup_conn(vpn_ip)))
589 notify_others(fw, cl, send_add_host);
593 ncn = new_conn_list();
594 ncn->real_ip = real_ip;
595 ncn->vpn_ip = vpn_ip;
596 ncn->vpn_mask = vpn_mask;
598 ncn->hostname = hostlookup(real_ip);
600 ncn->next = conn_list;
602 ncn->status.active = 1;
603 notify_others(ncn, cl, send_add_host);
608 int req_key_h(conn_list_t *cl)
614 if(!cl->status.active) return -1;
615 if(sscanf(cl->buffer, "%*d %lx %lx", &to, &from) != 2)
617 syslog(LOG_ERR, _("got bad request: %s"), cl->buffer);
622 syslog(LOG_DEBUG, _("got REQ_KEY from " IP_ADDR_S " for " IP_ADDR_S),
623 IP_ADDR_V(from), IP_ADDR_V(to));
625 if((to & myself->vpn_mask) == (myself->vpn_ip & myself->vpn_mask))
626 { /* hey! they want something from ME! :) */
627 send_key_answer(cl, from);
631 fw = lookup_conn(to);
635 syslog(LOG_ERR, _("Attempting to forward key request to " IP_ADDR_S ", which does not exist?"),
641 syslog(LOG_DEBUG, _("Forwarding request for public key to " IP_ADDR_S),
642 IP_ADDR_V(fw->nexthop->vpn_ip));
644 cl->buffer[cl->reqlen-1] = '\n';
646 if(write(fw->nexthop->meta_socket, cl->buffer, cl->reqlen) < 0)
648 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
655 void set_keys(conn_list_t *cl, int expiry, char *key)
661 cl->public_key = xmalloc(sizeof(*cl->key));
662 cl->public_key->key = NULL;
665 if(cl->public_key->key)
666 free(cl->public_key->key);
667 cl->public_key->length = strlen(key);
668 cl->public_key->expiry = expiry;
669 cl->public_key->key = xmalloc(cl->public_key->length + 1);
670 strcpy(cl->public_key->key, key);
672 ek = make_shared_key(key);
676 cl->key = xmalloc(sizeof(*cl->key));
683 cl->key->length = strlen(ek);
684 cl->key->expiry = expiry;
685 cl->key->key = xmalloc(cl->key->length + 1);
686 strcpy(cl->key->key, ek);
690 int ans_key_h(conn_list_t *cl)
696 conn_list_t *fw, *gk;
698 if(!cl->status.active) return -1;
699 if(sscanf(cl->buffer, "%*d %lx %lx %d %as", &to, &from, &expiry, &key) != 4)
701 syslog(LOG_ERR, _("got bad ANS_KEY request: %s"), cl->buffer);
706 syslog(LOG_DEBUG, _("got ANS_KEY from " IP_ADDR_S " for " IP_ADDR_S),
707 IP_ADDR_V(from), IP_ADDR_V(to));
709 if(to == myself->vpn_ip)
710 { /* hey! that key's for ME! :) */
712 syslog(LOG_DEBUG, _("Yeah! key arrived. Now do something with it."));
713 gk = lookup_conn(from);
717 syslog(LOG_ERR, _("Receiving key from " IP_ADDR_S ", which does not exist?"),
722 set_keys(gk, expiry, key);
723 gk->status.validkey = 1;
724 gk->status.waitingforkey = 0;
729 fw = lookup_conn(to);
733 syslog(LOG_ERR, _("Attempting to forward key to " IP_ADDR_S ", which does not exist?"),
739 syslog(LOG_DEBUG, _("Forwarding public key to " IP_ADDR_S),
740 IP_ADDR_V(fw->nexthop->vpn_ip));
742 cl->buffer[cl->reqlen-1] = '\n';
744 if((write(fw->nexthop->meta_socket, cl->buffer, cl->reqlen)) < 0)
746 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
753 int key_changed_h(conn_list_t *cl)
758 if(!cl->status.active) return -1;
759 if(sscanf(cl->buffer, "%*d %lx", &from) != 1)
761 syslog(LOG_ERR, _("got bad ANS_KEY request: %s"), cl->buffer);
766 syslog(LOG_DEBUG, _("got KEY_CHANGED from " IP_ADDR_S),
769 ik = lookup_conn(from);
773 syslog(LOG_ERR, _("Got changed key from " IP_ADDR_S ", which does not exist?"),
778 ik->status.validkey = 0;
779 ik->status.waitingforkey = 0;
782 syslog(LOG_DEBUG, _("Forwarding key invalidation request"));
784 notify_others(cl, ik, send_key_changed);
789 int (*request_handlers[256])(conn_list_t*) = {
790 0, ack_h, 0, 0, 0, 0, 0, 0, 0, 0,
791 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
792 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
793 termreq_h, timeout_h, del_host_h, 0, 0, 0, 0, 0, 0, 0,
794 ping_h, pong_h, 0, 0, 0, 0, 0, 0, 0, 0,
795 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
796 add_host_h, basic_info_h, passphrase_h, public_key_h, 0, 0, 0, 0, 0, 0,
797 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
798 0, 0, 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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
802 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
803 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
804 req_key_h, ans_key_h, key_changed_h, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
807 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
808 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
809 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0