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>
38 char buffer[MAXBUFSIZE];
41 int send_ack(conn_list_t *cl)
45 syslog(LOG_DEBUG, "Send ACK to %s", cl->hostname);
47 buflen = sprintf(buffer, "%d\n", ACK);
49 if((write(cl->meta_socket, buffer, buflen)) < 0)
51 syslog(LOG_ERR, "send failed: %d:%d: %m", __FILE__, __LINE__);
55 syslog(LOG_NOTICE, "Connection with %s activated.", cl->hostname);
60 int send_termreq(conn_list_t *cl)
64 syslog(LOG_DEBUG, "Send TERMREQ to " IP_ADDR_S,
65 IP_ADDR_V(cl->vpn_ip));
67 buflen = sprintf(buffer, "%d %lx\n", TERMREQ, myself->vpn_ip);
69 if((write(cl->meta_socket, buffer, buflen)) < 0)
71 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
78 int send_timeout(conn_list_t *cl)
82 syslog(LOG_DEBUG, "Send TIMEOUT to " IP_ADDR_S,
83 IP_ADDR_V(cl->vpn_ip));
85 buflen = sprintf(buffer, "%d %lx\n", PINGTIMEOUT, myself->vpn_ip);
87 if((write(cl->meta_socket, buffer, buflen)) < 0)
89 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
96 int send_del_host(conn_list_t *cl, conn_list_t *new_host)
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));
103 buflen = sprintf(buffer, "%d %lx\n", DEL_HOST, new_host->vpn_ip);
105 if((write(cl->meta_socket, buffer, buflen)) < 0)
107 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
114 int send_ping(conn_list_t *cl)
118 syslog(LOG_DEBUG, "pinging " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
120 buflen = sprintf(buffer, "%d\n", PING);
122 if((write(cl->meta_socket, buffer, buflen)) < 0)
124 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
131 int send_pong(conn_list_t *cl)
134 buflen = sprintf(buffer, "%d\n", PONG);
136 if((write(cl->meta_socket, buffer, buflen)) < 0)
138 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
145 int send_add_host(conn_list_t *cl, conn_list_t *new_host)
149 syslog(LOG_DEBUG, "Sending add host to " IP_ADDR_S,
150 IP_ADDR_V(cl->vpn_ip));
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);
154 if((write(cl->meta_socket, buffer, buflen)) < 0)
156 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
163 int send_key_changed(conn_list_t *cl, conn_list_t *src)
167 syslog(LOG_DEBUG, "Sending KEY_CHANGED to " IP_ADDR_S,
168 IP_ADDR_V(cl->vpn_ip));
170 buflen = sprintf(buffer, "%d %lx\n", KEY_CHANGED, src->vpn_ip);
172 if((write(cl->meta_socket, buffer, buflen)) < 0)
174 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
181 void send_key_changed2(void)
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);
191 int send_basic_info(conn_list_t *cl)
195 syslog(LOG_DEBUG, "Send BASIC_INFO to " IP_ADDR_S,
196 IP_ADDR_V(cl->real_ip));
198 buflen = sprintf(buffer, "%d %d %lx/%lx:%x\n", BASIC_INFO, PROT_CURRENT, myself->vpn_ip, myself->vpn_mask, myself->port);
200 if((write(cl->meta_socket, buffer, buflen)) < 0)
202 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
209 int send_passphrase(conn_list_t *cl)
213 encrypt_passphrase(&tmp);
216 syslog(LOG_DEBUG, "Send PASSPHRASE %s to " IP_ADDR_S,
217 tmp.phrase, IP_ADDR_V(cl->vpn_ip));
219 buflen = snprintf(buffer, MAXBUFSIZE, "%d %s\n", PASSPHRASE, tmp.phrase);
221 if((write(cl->meta_socket, buffer, buflen)) < 0)
223 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
230 int send_public_key(conn_list_t *cl)
234 syslog(LOG_DEBUG, "Send PUBLIC_KEY %s to " IP_ADDR_S,
235 my_public_key_base36, IP_ADDR_V(cl->vpn_ip));
237 buflen = sprintf(buffer, "%d %s\n", PUBLIC_KEY, my_public_key_base36);
239 if((write(cl->meta_socket, buffer, buflen)) < 0)
241 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
248 int send_calculate(conn_list_t *cl, char *k)
251 buflen = sprintf(buffer, "%d %s\n", CALCULATE, k);
253 if((write(cl->meta_socket, buffer, buflen)) < 0)
255 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
262 int send_key_request(ip_t to)
266 fw = lookup_conn(to);
269 syslog(LOG_ERR, "Attempting to send key request to " IP_ADDR_S ", which does not exist?",
275 syslog(LOG_DEBUG, "Sending out request for public key to " IP_ADDR_S,
276 IP_ADDR_V(fw->nexthop->vpn_ip));
278 buflen = sprintf(buffer, "%d %lx %lx\n", REQ_KEY, to, myself->vpn_ip);
280 if((write(fw->nexthop->meta_socket, buffer, buflen)) < 0)
282 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
285 fw->status.waitingforkey = 1;
290 int send_key_answer(conn_list_t *cl, ip_t to)
295 fw = lookup_conn(to);
299 syslog(LOG_ERR, "Attempting to send key answer to " IP_ADDR_S ", which does not exist?",
305 syslog(LOG_DEBUG, "Sending public key to " IP_ADDR_S,
306 IP_ADDR_V(fw->nexthop->vpn_ip));
308 buflen = sprintf(buffer, "%d %lx %lx %d %s\n", ANS_KEY, to, myself->vpn_ip, my_key_expiry, my_public_key_base36);
310 if((write(fw->nexthop->meta_socket, buffer, buflen)) < 0)
312 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
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.
324 int notify_others(conn_list_t *new, conn_list_t *source,
325 int (*function)(conn_list_t*, conn_list_t*))
329 for(p = conn_list; p != NULL; p = p->next)
330 if(p != new && p != source && p->status.meta)
337 notify one connection of everything
340 int notify_one(conn_list_t *new)
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);
352 The incoming request handlers
355 int basic_info_h(conn_list_t *cl)
358 if(sscanf(cl->buffer, "%*d %d %lx/%lx:%hx", &cl->protocol_version, &cl->vpn_ip, &cl->vpn_mask, &cl->port) != 4)
360 syslog(LOG_ERR, "got bad BASIC_INFO request: %s", cl->buffer);
364 if(cl->protocol_version != PROT_CURRENT)
366 syslog(LOG_ERR, "Peer uses incompatible protocol version %d.",
367 cl->protocol_version);
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));
375 syslog(LOG_DEBUG, "Peer uses protocol version %d",
376 cl->protocol_version);
378 if(cl->status.outgoing)
380 if(setup_vpn_connection(cl) < 0)
386 if(setup_vpn_connection(cl) < 0)
391 cl->status.active = 0;
396 int passphrase_h(conn_list_t *cl)
399 cl->pp=xmalloc(sizeof(*(cl->pp)));
400 if(sscanf(cl->buffer, "%*d %as", &(cl->pp->phrase)) != 1)
402 syslog(LOG_ERR, "got bad PASSPHRASE request: %s", cl->buffer);
405 cl->pp->len = strlen(cl->pp->phrase);
408 syslog(LOG_DEBUG, "got PASSPHRASE");
410 if(cl->status.outgoing)
418 int public_key_h(conn_list_t *cl)
422 if(sscanf(cl->buffer, "%*d %as", &g_n) != 1)
424 syslog(LOG_ERR, "got bad PUBLIC_KEY request: %s", cl->buffer);
429 syslog(LOG_DEBUG, "got PUBLIC_KEY %s", g_n);
431 if(verify_passphrase(cl, g_n))
434 syslog(LOG_ERR, "Intruder: passphrase does not match.");
439 syslog(LOG_INFO, "Passphrase OK");
441 if(cl->status.outgoing)
446 cl->status.active = 1;
447 notify_others(cl, NULL, send_add_host);
453 int ack_h(conn_list_t *cl)
457 syslog(LOG_DEBUG, "got ACK");
459 cl->status.active = 1;
460 syslog(LOG_NOTICE, "Connection with %s activated.", cl->hostname);
465 int termreq_h(conn_list_t *cl)
468 syslog(LOG_NOTICE, IP_ADDR_S " wants to quit", IP_ADDR_V(cl->vpn_ip));
469 cl->status.termreq = 1;
470 terminate_connection(cl);
472 notify_others(cl, NULL, send_del_host);
477 int timeout_h(conn_list_t *cl)
480 syslog(LOG_NOTICE, IP_ADDR_S " says it's gotten a timeout from us", IP_ADDR_V(cl->vpn_ip));
481 cl->status.termreq = 1;
482 terminate_connection(cl);
487 int del_host_h(conn_list_t *cl)
492 if(sscanf(cl->buffer, "%*d %lx", &vpn_ip) != 1)
494 syslog(LOG_ERR, "got bad DEL_HOST request: %s", cl->buffer);
499 syslog(LOG_DEBUG, "got DEL_HOST for " IP_ADDR_S,
502 if(!(fw = lookup_conn(vpn_ip)))
504 syslog(LOG_ERR, "Somebody wanted to delete " IP_ADDR_S " which does not exist?",
509 notify_others(cl, fw, send_del_host);
511 fw->status.termreq = 1;
512 terminate_connection(fw);
517 int ping_h(conn_list_t *cl)
521 syslog(LOG_DEBUG, "responding to ping from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
522 cl->status.pinged = 0;
523 cl->status.got_pong = 1;
530 int pong_h(conn_list_t *cl)
534 syslog(LOG_DEBUG, "ok, got pong from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
535 cl->status.got_pong = 1;
540 int add_host_h(conn_list_t *cl)
546 conn_list_t *ncn, *fw;
548 if(sscanf(cl->buffer, "%*d %lx %lx/%lx:%hx", &real_ip, &vpn_ip, &vpn_mask, &port) != 4)
550 syslog(LOG_ERR, "got bad ADD_HOST request: %s", cl->buffer);
555 syslog(LOG_DEBUG, "Add host request from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
557 syslog(LOG_DEBUG, "got ADD_HOST(" IP_ADDR_S "," IP_ADDR_S ",%hd)",
558 IP_ADDR_V(vpn_ip), IP_ADDR_V(vpn_mask), port);
561 Suggestion of Hans Bayle
563 if((fw = lookup_conn(vpn_ip)))
565 notify_others(fw, cl, send_add_host);
569 ncn = new_conn_list();
570 ncn->real_ip = real_ip;
571 ncn->vpn_ip = vpn_ip;
572 ncn->vpn_mask = vpn_mask;
574 ncn->hostname = hostlookup(real_ip);
576 ncn->next = conn_list;
578 ncn->status.active = 1;
579 notify_others(ncn, cl, send_add_host);
584 int req_key_h(conn_list_t *cl)
590 if(sscanf(cl->buffer, "%*d %lx %lx", &to, &from) != 2)
592 syslog(LOG_ERR, "got bad request: %s", cl->buffer);
597 syslog(LOG_DEBUG, "got REQ_KEY from " IP_ADDR_S " for " IP_ADDR_S,
598 IP_ADDR_V(from), IP_ADDR_V(to));
600 if((to & myself->vpn_mask) == (myself->vpn_ip & myself->vpn_mask))
601 { /* hey! they want something from ME! :) */
602 send_key_answer(cl, from);
606 fw = lookup_conn(to);
610 syslog(LOG_ERR, "Attempting to forward key request to " IP_ADDR_S ", which does not exist?",
616 syslog(LOG_DEBUG, "Forwarding request for public key to " IP_ADDR_S,
617 IP_ADDR_V(fw->nexthop->vpn_ip));
619 if(write(fw->nexthop->meta_socket, cl->buffer, strlen(cl->buffer)) < 0)
621 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
628 void set_keys(conn_list_t *cl, int expiry, char *key)
634 cl->public_key = xmalloc(sizeof(*cl->key));
635 cl->public_key->key = NULL;
638 if(cl->public_key->key)
639 free(cl->public_key->key);
640 cl->public_key->length = strlen(key);
641 cl->public_key->expiry = expiry;
642 cl->public_key->key = xmalloc(cl->public_key->length + 1);
643 strcpy(cl->public_key->key, key);
645 ek = make_shared_key(key);
649 cl->key = xmalloc(sizeof(*cl->key));
656 cl->key->length = strlen(ek);
657 cl->key->expiry = expiry;
658 cl->key->key = xmalloc(cl->key->length + 1);
659 strcpy(cl->key->key, ek);
663 int ans_key_h(conn_list_t *cl)
669 conn_list_t *fw, *gk;
671 if(sscanf(cl->buffer, "%*d %lx %lx %d %as", &to, &from, &expiry, &key) != 4)
673 syslog(LOG_ERR, "got bad ANS_KEY request: %s", cl->buffer);
678 syslog(LOG_DEBUG, "got ANS_KEY from " IP_ADDR_S " for " IP_ADDR_S,
679 IP_ADDR_V(from), IP_ADDR_V(to));
681 if(to == myself->vpn_ip)
682 { /* hey! that key's for ME! :) */
684 syslog(LOG_DEBUG, "Yeah! key arrived. Now do something with it.");
685 gk = lookup_conn(from);
689 syslog(LOG_ERR, "Receiving key from " IP_ADDR_S ", which does not exist?",
694 set_keys(gk, expiry, key);
695 gk->status.validkey = 1;
696 gk->status.waitingforkey = 0;
701 fw = lookup_conn(to);
705 syslog(LOG_ERR, "Attempting to forward key to " IP_ADDR_S ", which does not exist?",
711 syslog(LOG_DEBUG, "Forwarding public key to " IP_ADDR_S,
712 IP_ADDR_V(fw->nexthop->vpn_ip));
714 if((write(fw->nexthop->meta_socket, cl->buffer, strlen(cl->buffer))) < 0)
716 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
723 int key_changed_h(conn_list_t *cl)
728 if(sscanf(cl->buffer, "%*d %lx", &from) != 1)
730 syslog(LOG_ERR, "got bad ANS_KEY request: %s", cl->buffer);
735 syslog(LOG_DEBUG, "got KEY_CHANGED from " IP_ADDR_S,
738 ik = lookup_conn(from);
742 syslog(LOG_ERR, "Got changed key from " IP_ADDR_S ", which does not exist?",
747 ik->status.validkey = 0;
748 ik->status.waitingforkey = 0;
751 syslog(LOG_DEBUG, "Forwarding key invalidation request");
753 notify_others(cl, ik, send_key_changed);
758 int (*request_handlers[256])(conn_list_t*) = {
759 0, ack_h, 0, 0, 0, 0, 0, 0, 0, 0,
760 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
761 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
762 termreq_h, timeout_h, del_host_h, 0, 0, 0, 0, 0, 0, 0,
763 ping_h, pong_h, 0, 0, 0, 0, 0, 0, 0, 0,
764 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
765 add_host_h, basic_info_h, passphrase_h, public_key_h, 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,
770 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
771 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
772 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
773 req_key_h, ans_key_h, key_changed_h, 0, 0, 0, 0, 0, 0, 0,
774 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, 0, 0, 0, 0,
777 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
778 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0