2 protocol.c -- handle the meta-protocol
3 Copyright (C) 1999,2000 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.
22 #include <sys/types.h>
27 #include <sys/socket.h>
40 char buffer[MAXBUFSIZE+1];
43 /* Outgoing request routines */
45 int send_ack(conn_list_t *cl)
49 syslog(LOG_DEBUG, "Send ACK to %s", cl->hostname);
51 buflen = snprintf(buffer, MAXBUFSIZE, "%d\n", ACK);
53 if((write(cl->meta_socket, buffer, buflen)) < 0)
55 syslog(LOG_ERR, "send failed: %d:%d: %m", __FILE__, __LINE__);
59 syslog(LOG_NOTICE, "Connection with %s activated.", cl->hostname);
64 int send_termreq(conn_list_t *cl)
68 syslog(LOG_DEBUG, "Send TERMREQ to " IP_ADDR_S,
69 IP_ADDR_V(cl->vpn_ip));
71 buflen = snprintf(buffer, MAXBUFSIZE, "%d %lx\n", TERMREQ, myself->vpn_ip);
73 if(write(cl->meta_socket, buffer, buflen) < 0)
76 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
83 int send_timeout(conn_list_t *cl)
87 syslog(LOG_DEBUG, "Send TIMEOUT to " IP_ADDR_S,
88 IP_ADDR_V(cl->vpn_ip));
90 buflen = snprintf(buffer, MAXBUFSIZE, "%d %lx\n", PINGTIMEOUT, myself->vpn_ip);
92 if((write(cl->meta_socket, buffer, buflen)) < 0)
94 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
101 int send_del_host(conn_list_t *cl, conn_list_t *new_host)
105 syslog(LOG_DEBUG, "Sending delete host " IP_ADDR_S " to " IP_ADDR_S,
106 IP_ADDR_V(new_host->vpn_ip), IP_ADDR_V(cl->vpn_ip));
108 buflen = snprintf(buffer, MAXBUFSIZE, "%d %lx\n", DEL_HOST, new_host->vpn_ip);
110 if((write(cl->meta_socket, buffer, buflen)) < 0)
112 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
119 int send_ping(conn_list_t *cl)
123 syslog(LOG_DEBUG, "pinging " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
125 buflen = snprintf(buffer, MAXBUFSIZE, "%d\n", PING);
127 if((write(cl->meta_socket, buffer, buflen)) < 0)
129 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
136 int send_pong(conn_list_t *cl)
139 buflen = snprintf(buffer, MAXBUFSIZE, "%d\n", PONG);
141 if((write(cl->meta_socket, buffer, buflen)) < 0)
143 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
150 int send_add_host(conn_list_t *cl, conn_list_t *new_host)
154 syslog(LOG_DEBUG, "Sending add host to " IP_ADDR_S,
155 IP_ADDR_V(cl->vpn_ip));
157 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);
159 if((write(cl->meta_socket, buffer, buflen)) < 0)
161 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
168 int send_key_changed(conn_list_t *cl, conn_list_t *src)
172 syslog(LOG_DEBUG, "Sending KEY_CHANGED to " IP_ADDR_S,
173 IP_ADDR_V(cl->vpn_ip));
175 buflen = snprintf(buffer, MAXBUFSIZE, "%d %lx\n", KEY_CHANGED, src->vpn_ip);
177 if((write(cl->meta_socket, buffer, buflen)) < 0)
179 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
186 void send_key_changed_all(void)
190 for(p = conn_list; p != NULL; p = p->next)
191 if(p->status.meta && p->status.active)
192 send_key_changed(p, myself);
196 int send_basic_info(conn_list_t *cl)
200 syslog(LOG_DEBUG, "Send BASIC_INFO to " IP_ADDR_S,
201 IP_ADDR_V(cl->real_ip));
203 buflen = snprintf(buffer, MAXBUFSIZE, "%d %d %lx/%lx:%x\n", BASIC_INFO, PROT_CURRENT, myself->vpn_ip, myself->vpn_mask, myself->port);
205 if((write(cl->meta_socket, buffer, buflen)) < 0)
207 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
214 int send_passphrase(conn_list_t *cl)
218 encrypt_passphrase(&tmp);
221 syslog(LOG_DEBUG, "Send PASSPHRASE %s to " IP_ADDR_S,
222 tmp.phrase, IP_ADDR_V(cl->vpn_ip));
224 buflen = snprintf(buffer, MAXBUFSIZE, "%d %s\n", PASSPHRASE, tmp.phrase);
226 if((write(cl->meta_socket, buffer, buflen)) < 0)
228 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
235 int send_public_key(conn_list_t *cl)
239 syslog(LOG_DEBUG, "Send PUBLIC_KEY %s to " IP_ADDR_S,
240 my_public_key_base36, IP_ADDR_V(cl->vpn_ip));
242 buflen = snprintf(buffer, MAXBUFSIZE, "%d %s\n", PUBLIC_KEY, my_public_key_base36);
244 if((write(cl->meta_socket, buffer, buflen)) < 0)
246 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
253 int send_calculate(conn_list_t *cl, char *k)
256 buflen = snprintf(buffer, MAXBUFSIZE, "%d %s\n", CALCULATE, k);
258 if((write(cl->meta_socket, buffer, buflen)) < 0)
260 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
267 int send_key_request(ip_t to)
271 fw = lookup_conn(to);
274 syslog(LOG_ERR, "Attempting to send key request to " IP_ADDR_S ", which does not exist?",
280 syslog(LOG_DEBUG, "Sending out request for public key to " IP_ADDR_S,
281 IP_ADDR_V(fw->nexthop->vpn_ip));
283 buflen = snprintf(buffer, MAXBUFSIZE, "%d %lx %lx\n", REQ_KEY, to, myself->vpn_ip);
285 if((write(fw->nexthop->meta_socket, buffer, buflen)) < 0)
287 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
290 fw->status.waitingforkey = 1;
295 int send_key_answer(conn_list_t *cl, ip_t to)
300 fw = lookup_conn(to);
304 syslog(LOG_ERR, "Attempting to send key answer to " IP_ADDR_S ", which does not exist?",
310 syslog(LOG_DEBUG, "Sending public key to " IP_ADDR_S,
311 IP_ADDR_V(fw->nexthop->vpn_ip));
313 buflen = snprintf(buffer, MAXBUFSIZE, "%d %lx %lx %d %s\n", ANS_KEY, to, myself->vpn_ip, my_key_expiry, my_public_key_base36);
315 if((write(fw->nexthop->meta_socket, buffer, buflen)) < 0)
317 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
325 notify all my direct connections of a new host
326 that was added to the vpn, with the exception
327 of the source of the announcement.
329 int notify_others(conn_list_t *new, conn_list_t *source,
330 int (*function)(conn_list_t*, conn_list_t*))
334 for(p = conn_list; p != NULL; p = p->next)
335 if(p != new && p != source && p->status.meta && p->status.active)
342 notify one connection of everything
345 int notify_one(conn_list_t *new)
349 for(p = conn_list; p != NULL; p = p->next)
350 if(p != new && p->status.active)
351 send_add_host(new, p);
357 The incoming request handlers
360 int basic_info_h(conn_list_t *cl)
363 if(sscanf(cl->buffer, "%*d %d %lx/%lx:%hx", &cl->protocol_version, &cl->vpn_ip, &cl->vpn_mask, &cl->port) != 4)
365 syslog(LOG_ERR, "got bad BASIC_INFO request: %s", cl->buffer);
369 if(cl->protocol_version != PROT_CURRENT)
371 syslog(LOG_ERR, "Peer uses incompatible protocol version %d.",
372 cl->protocol_version);
377 syslog(LOG_DEBUG, "got BASIC_INFO(%hd," IP_ADDR_S "," IP_ADDR_S ")", cl->port,
378 IP_ADDR_V(cl->vpn_ip), IP_ADDR_V(cl->vpn_mask));
380 syslog(LOG_DEBUG, "Peer uses protocol version %d",
381 cl->protocol_version);
383 if(cl->status.outgoing)
385 if(setup_vpn_connection(cl) < 0)
391 if(setup_vpn_connection(cl) < 0)
399 int passphrase_h(conn_list_t *cl)
402 cl->pp = xmalloc(sizeof(*(cl->pp)));
404 if(sscanf(cl->buffer, "%*d %as", &(cl->pp->phrase)) != 1)
406 syslog(LOG_ERR, "got bad PASSPHRASE request: %s", cl->buffer);
409 cl->pp->len = strlen(cl->pp->phrase);
412 syslog(LOG_DEBUG, "got PASSPHRASE");
414 if(cl->status.outgoing)
422 int public_key_h(conn_list_t *cl)
427 if(sscanf(cl->buffer, "%*d %as", &g_n) != 1)
429 syslog(LOG_ERR, "got bad PUBLIC_KEY request: %s", cl->buffer);
434 syslog(LOG_DEBUG, "got PUBLIC_KEY %s", g_n);
436 if(verify_passphrase(cl, g_n))
439 syslog(LOG_ERR, "Intruder: passphrase does not match.");
444 syslog(LOG_INFO, "Passphrase OK");
446 if(cl->status.outgoing)
451 /* Okay, before we active the connection, we check if there is another entry
452 in the connection list with the same vpn_ip. If so, it presumably is an
453 old connection that has timed out but we don't know it yet. Because our
454 conn_list entry is not active, lookup_conn will skip ourself. */
456 while(old=lookup_conn(cl->vpn_ip))
457 terminate_connection(old);
459 cl->status.active = 1;
460 notify_others(cl, NULL, send_add_host);
466 int ack_h(conn_list_t *cl)
470 syslog(LOG_DEBUG, "got ACK");
472 cl->status.active = 1;
473 syslog(LOG_NOTICE, "Connection with %s activated.", cl->hostname);
478 int termreq_h(conn_list_t *cl)
481 syslog(LOG_NOTICE, IP_ADDR_S " wants to quit", IP_ADDR_V(cl->vpn_ip));
482 cl->status.termreq = 1;
483 terminate_connection(cl);
485 notify_others(cl, NULL, send_del_host);
490 int timeout_h(conn_list_t *cl)
493 if(!cl->status.active) return -1;
494 syslog(LOG_NOTICE, IP_ADDR_S " says it's gotten a timeout from us", IP_ADDR_V(cl->vpn_ip));
495 cl->status.termreq = 1;
496 terminate_connection(cl);
501 int del_host_h(conn_list_t *cl)
506 if(!cl->status.active) return -1;
508 if(sscanf(cl->buffer, "%*d %lx", &vpn_ip) != 1)
510 syslog(LOG_ERR, "got bad DEL_HOST request: %s", cl->buffer);
515 syslog(LOG_DEBUG, "got DEL_HOST for " IP_ADDR_S,
518 if(!(fw = lookup_conn(vpn_ip)))
520 syslog(LOG_ERR, "Somebody wanted to delete " IP_ADDR_S " which does not exist?",
525 notify_others(cl, fw, send_del_host);
527 fw->status.termreq = 1;
528 terminate_connection(fw);
533 int ping_h(conn_list_t *cl)
536 if(!cl->status.active) return -1;
538 syslog(LOG_DEBUG, "responding to ping from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
539 cl->status.pinged = 0;
540 cl->status.got_pong = 1;
547 int pong_h(conn_list_t *cl)
550 if(!cl->status.active) return -1;
552 syslog(LOG_DEBUG, "ok, got pong from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
553 cl->status.got_pong = 1;
558 int add_host_h(conn_list_t *cl)
564 conn_list_t *ncn, *fw;
566 if(!cl->status.active) return -1;
567 if(sscanf(cl->buffer, "%*d %lx %lx/%lx:%hx", &real_ip, &vpn_ip, &vpn_mask, &port) != 4)
569 syslog(LOG_ERR, "got bad ADD_HOST request: %s", cl->buffer);
574 syslog(LOG_DEBUG, "Add host request from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
576 syslog(LOG_DEBUG, "got ADD_HOST(" IP_ADDR_S "," IP_ADDR_S ",%hd)",
577 IP_ADDR_V(vpn_ip), IP_ADDR_V(vpn_mask), port);
580 Suggestion of Hans Bayle
582 if((fw = lookup_conn(vpn_ip)))
584 notify_others(fw, cl, send_add_host);
588 ncn = new_conn_list();
589 ncn->real_ip = real_ip;
590 ncn->vpn_ip = vpn_ip;
591 ncn->vpn_mask = vpn_mask;
593 ncn->hostname = hostlookup(real_ip);
595 ncn->next = conn_list;
597 ncn->status.active = 1;
598 notify_others(ncn, cl, send_add_host);
603 int req_key_h(conn_list_t *cl)
609 if(!cl->status.active) return -1;
610 if(sscanf(cl->buffer, "%*d %lx %lx", &to, &from) != 2)
612 syslog(LOG_ERR, "got bad request: %s", cl->buffer);
617 syslog(LOG_DEBUG, "got REQ_KEY from " IP_ADDR_S " for " IP_ADDR_S,
618 IP_ADDR_V(from), IP_ADDR_V(to));
620 if((to & myself->vpn_mask) == (myself->vpn_ip & myself->vpn_mask))
621 { /* hey! they want something from ME! :) */
622 send_key_answer(cl, from);
626 fw = lookup_conn(to);
630 syslog(LOG_ERR, "Attempting to forward key request to " IP_ADDR_S ", which does not exist?",
636 syslog(LOG_DEBUG, "Forwarding request for public key to " IP_ADDR_S,
637 IP_ADDR_V(fw->nexthop->vpn_ip));
639 cl->buffer[cl->reqlen-1] = '\n';
641 if(write(fw->nexthop->meta_socket, cl->buffer, cl->reqlen) < 0)
643 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
650 void set_keys(conn_list_t *cl, int expiry, char *key)
656 cl->public_key = xmalloc(sizeof(*cl->key));
657 cl->public_key->key = NULL;
660 if(cl->public_key->key)
661 free(cl->public_key->key);
662 cl->public_key->length = strlen(key);
663 cl->public_key->expiry = expiry;
664 cl->public_key->key = xmalloc(cl->public_key->length + 1);
665 strcpy(cl->public_key->key, key);
667 ek = make_shared_key(key);
671 cl->key = xmalloc(sizeof(*cl->key));
678 cl->key->length = strlen(ek);
679 cl->key->expiry = expiry;
680 cl->key->key = xmalloc(cl->key->length + 1);
681 strcpy(cl->key->key, ek);
685 int ans_key_h(conn_list_t *cl)
691 conn_list_t *fw, *gk;
693 if(!cl->status.active) return -1;
694 if(sscanf(cl->buffer, "%*d %lx %lx %d %as", &to, &from, &expiry, &key) != 4)
696 syslog(LOG_ERR, "got bad ANS_KEY request: %s", cl->buffer);
701 syslog(LOG_DEBUG, "got ANS_KEY from " IP_ADDR_S " for " IP_ADDR_S,
702 IP_ADDR_V(from), IP_ADDR_V(to));
704 if(to == myself->vpn_ip)
705 { /* hey! that key's for ME! :) */
707 syslog(LOG_DEBUG, "Yeah! key arrived. Now do something with it.");
708 gk = lookup_conn(from);
712 syslog(LOG_ERR, "Receiving key from " IP_ADDR_S ", which does not exist?",
717 set_keys(gk, expiry, key);
718 gk->status.validkey = 1;
719 gk->status.waitingforkey = 0;
724 fw = lookup_conn(to);
728 syslog(LOG_ERR, "Attempting to forward key to " IP_ADDR_S ", which does not exist?",
734 syslog(LOG_DEBUG, "Forwarding public key to " IP_ADDR_S,
735 IP_ADDR_V(fw->nexthop->vpn_ip));
737 cl->buffer[cl->reqlen-1] = '\n';
739 if((write(fw->nexthop->meta_socket, cl->buffer, cl->reqlen)) < 0)
741 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
748 int key_changed_h(conn_list_t *cl)
753 if(!cl->status.active) return -1;
754 if(sscanf(cl->buffer, "%*d %lx", &from) != 1)
756 syslog(LOG_ERR, "got bad ANS_KEY request: %s", cl->buffer);
761 syslog(LOG_DEBUG, "got KEY_CHANGED from " IP_ADDR_S,
764 ik = lookup_conn(from);
768 syslog(LOG_ERR, "Got changed key from " IP_ADDR_S ", which does not exist?",
773 ik->status.validkey = 0;
774 ik->status.waitingforkey = 0;
777 syslog(LOG_DEBUG, "Forwarding key invalidation request");
779 notify_others(cl, ik, send_key_changed);
784 int (*request_handlers[256])(conn_list_t*) = {
785 0, ack_h, 0, 0, 0, 0, 0, 0, 0, 0,
786 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
787 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
788 termreq_h, timeout_h, del_host_h, 0, 0, 0, 0, 0, 0, 0,
789 ping_h, pong_h, 0, 0, 0, 0, 0, 0, 0, 0,
790 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
791 add_host_h, basic_info_h, passphrase_h, public_key_h, 0, 0, 0, 0, 0, 0,
792 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
793 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
794 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
795 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
796 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
797 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
798 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
799 req_key_h, ans_key_h, key_changed_h, 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, 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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0