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.4.1 2000/06/23 19:27:03 guus 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)
161 syslog(LOG_DEBUG, _("Sending add host to " IP_ADDR_S),
162 IP_ADDR_V(cl->vpn_ip));
164 real_ip = new_host->real_ip;
165 flags = new_host->flags;
167 /* If we need to propagate information about a new host that wants us to export
168 * it's indirectdata flag, we set the INDIRECTDATA flag and unset the EXPORT...
169 * flag, and set it's real_ip to our vpn_ip, so that net.c send_packet() will
173 if(flags & EXPORTINDIRECTDATA)
175 flags &= ~EXPORTINDIRECTDATA;
176 flags |= INDIRECTDATA;
177 real_ip = myself->vpn_ip;
180 buflen = snprintf(buffer, MAXBUFSIZE, "%d %lx %lx/%lx:%x %d\n", ADD_HOST, new_host->real_ip, new_host->vpn_ip, new_host->vpn_mask, new_host->port, flags);
182 if((write(cl->meta_socket, buffer, buflen)) < 0)
184 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
191 int send_key_changed(conn_list_t *cl, conn_list_t *src)
195 syslog(LOG_DEBUG, _("Sending KEY_CHANGED to " IP_ADDR_S),
196 IP_ADDR_V(cl->vpn_ip));
198 buflen = snprintf(buffer, MAXBUFSIZE, "%d %lx\n", KEY_CHANGED, src->vpn_ip);
200 if((write(cl->meta_socket, buffer, buflen)) < 0)
202 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
209 void send_key_changed_all(void)
213 for(p = conn_list; p != NULL; p = p->next)
214 if(p->status.meta && p->status.active)
215 send_key_changed(p, myself);
219 int send_basic_info(conn_list_t *cl)
223 syslog(LOG_DEBUG, _("Send BASIC_INFO to " IP_ADDR_S),
224 IP_ADDR_V(cl->real_ip));
226 buflen = snprintf(buffer, MAXBUFSIZE, "%d %d %lx/%lx:%x %d\n", BASIC_INFO, PROT_CURRENT, myself->vpn_ip, myself->vpn_mask, myself->port, myself->flags);
228 if((write(cl->meta_socket, buffer, buflen)) < 0)
230 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
237 int send_passphrase(conn_list_t *cl)
241 encrypt_passphrase(&tmp);
244 syslog(LOG_DEBUG, _("Send PASSPHRASE %s to " IP_ADDR_S),
245 tmp.phrase, IP_ADDR_V(cl->vpn_ip));
247 buflen = snprintf(buffer, MAXBUFSIZE, "%d %s\n", PASSPHRASE, tmp.phrase);
249 if((write(cl->meta_socket, buffer, buflen)) < 0)
251 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
258 int send_public_key(conn_list_t *cl)
262 syslog(LOG_DEBUG, _("Send PUBLIC_KEY %s to " IP_ADDR_S),
263 my_public_key_base36, IP_ADDR_V(cl->vpn_ip));
265 buflen = snprintf(buffer, MAXBUFSIZE, "%d %s\n", PUBLIC_KEY, my_public_key_base36);
267 if((write(cl->meta_socket, buffer, buflen)) < 0)
269 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
276 int send_calculate(conn_list_t *cl, char *k)
279 buflen = snprintf(buffer, MAXBUFSIZE, "%d %s\n", CALCULATE, k);
281 if((write(cl->meta_socket, buffer, buflen)) < 0)
283 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
290 int send_key_request(ip_t to)
294 fw = lookup_conn(to);
297 syslog(LOG_ERR, _("Attempting to send key request to " IP_ADDR_S ", which does not exist?"),
303 syslog(LOG_DEBUG, _("Sending out request for public key to " IP_ADDR_S),
304 IP_ADDR_V(fw->nexthop->vpn_ip));
306 buflen = snprintf(buffer, MAXBUFSIZE, "%d %lx %lx\n", REQ_KEY, to, myself->vpn_ip);
308 if((write(fw->nexthop->meta_socket, buffer, buflen)) < 0)
310 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
313 fw->status.waitingforkey = 1;
318 int send_key_answer(conn_list_t *cl, ip_t to)
323 fw = lookup_conn(to);
327 syslog(LOG_ERR, _("Attempting to send key answer to " IP_ADDR_S ", which does not exist?"),
333 syslog(LOG_DEBUG, _("Sending public key to " IP_ADDR_S),
334 IP_ADDR_V(fw->nexthop->vpn_ip));
336 buflen = snprintf(buffer, MAXBUFSIZE, "%d %lx %lx %d %s\n", ANS_KEY, to, myself->vpn_ip, my_key_expiry, my_public_key_base36);
338 if((write(fw->nexthop->meta_socket, buffer, buflen)) < 0)
340 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
348 notify all my direct connections of a new host
349 that was added to the vpn, with the exception
350 of the source of the announcement.
352 int notify_others(conn_list_t *new, conn_list_t *source,
353 int (*function)(conn_list_t*, conn_list_t*))
357 for(p = conn_list; p != NULL; p = p->next)
358 if(p != new && p != source && p->status.meta && p->status.active)
365 notify one connection of everything
368 int notify_one(conn_list_t *new)
372 for(p = conn_list; p != NULL; p = p->next)
373 if(p != new && p->status.active)
374 send_add_host(new, p);
380 The incoming request handlers
383 int basic_info_h(conn_list_t *cl)
386 if(sscanf(cl->buffer, "%*d %d %lx/%lx:%hx %d", &cl->protocol_version, &cl->vpn_ip, &cl->vpn_mask, &cl->port, &cl->flags) != 5)
388 syslog(LOG_ERR, _("got bad BASIC_INFO request: %s"), cl->buffer);
392 if(cl->protocol_version != PROT_CURRENT)
394 syslog(LOG_ERR, _("Peer uses incompatible protocol version %d."),
395 cl->protocol_version);
400 syslog(LOG_DEBUG, _("got BASIC_INFO(%hd," IP_ADDR_S "," IP_ADDR_S ")"), cl->port,
401 IP_ADDR_V(cl->vpn_ip), IP_ADDR_V(cl->vpn_mask));
403 syslog(LOG_DEBUG, _("Peer uses protocol version %d"),
404 cl->protocol_version);
406 if(cl->status.outgoing)
408 if(setup_vpn_connection(cl) < 0)
414 if(setup_vpn_connection(cl) < 0)
422 int passphrase_h(conn_list_t *cl)
425 cl->pp = xmalloc(sizeof(*(cl->pp)));
427 if(sscanf(cl->buffer, "%*d %as", &(cl->pp->phrase)) != 1)
429 syslog(LOG_ERR, _("got bad PASSPHRASE request: %s"), cl->buffer);
432 cl->pp->len = strlen(cl->pp->phrase);
435 syslog(LOG_DEBUG, _("got PASSPHRASE"));
437 if(cl->status.outgoing)
445 int public_key_h(conn_list_t *cl)
450 if(sscanf(cl->buffer, "%*d %as", &g_n) != 1)
452 syslog(LOG_ERR, _("got bad PUBLIC_KEY request: %s"), cl->buffer);
457 syslog(LOG_DEBUG, _("got PUBLIC_KEY %s"), g_n);
459 if(verify_passphrase(cl, g_n))
462 syslog(LOG_ERR, _("Intruder: passphrase does not match."));
467 syslog(LOG_INFO, _("Passphrase OK"));
469 if(cl->status.outgoing)
475 /* Okay, before we active the connection, we check if there is another entry
476 in the connection list with the same vpn_ip. If so, it presumably is an
477 old connection that has timed out but we don't know it yet. Because our
478 conn_list entry is not active, lookup_conn will skip ourself. */
480 while(old=lookup_conn(cl->vpn_ip))
481 terminate_connection(old);
483 cl->status.active = 1;
484 notify_others(cl, NULL, send_add_host);
491 int ack_h(conn_list_t *cl)
495 syslog(LOG_DEBUG, _("got ACK"));
497 cl->status.active = 1;
498 syslog(LOG_NOTICE, _("Connection with %s activated."), cl->hostname);
503 int termreq_h(conn_list_t *cl)
506 syslog(LOG_NOTICE, _(IP_ADDR_S " wants to quit"), IP_ADDR_V(cl->vpn_ip));
507 cl->status.termreq = 1;
508 terminate_connection(cl);
510 notify_others(cl, NULL, send_del_host);
515 int timeout_h(conn_list_t *cl)
518 if(!cl->status.active) return -1;
519 syslog(LOG_NOTICE, _(IP_ADDR_S " says it's gotten a timeout from us"), IP_ADDR_V(cl->vpn_ip));
520 cl->status.termreq = 1;
521 terminate_connection(cl);
526 int del_host_h(conn_list_t *cl)
531 if(!cl->status.active) return -1;
533 if(sscanf(cl->buffer, "%*d %lx", &vpn_ip) != 1)
535 syslog(LOG_ERR, _("got bad DEL_HOST request: %s"), cl->buffer);
540 syslog(LOG_DEBUG, _("got DEL_HOST for " IP_ADDR_S),
543 if(!(fw = lookup_conn(vpn_ip)))
545 syslog(LOG_ERR, _("Somebody wanted to delete " IP_ADDR_S " which does not exist?"),
550 notify_others(cl, fw, send_del_host);
552 fw->status.termreq = 1;
553 terminate_connection(fw);
558 int ping_h(conn_list_t *cl)
561 if(!cl->status.active) return -1;
563 syslog(LOG_DEBUG, _("responding to ping from " IP_ADDR_S), IP_ADDR_V(cl->vpn_ip));
564 cl->status.pinged = 0;
565 cl->status.got_pong = 1;
572 int pong_h(conn_list_t *cl)
575 if(!cl->status.active) return -1;
577 syslog(LOG_DEBUG, _("ok, got pong from " IP_ADDR_S), IP_ADDR_V(cl->vpn_ip));
578 cl->status.got_pong = 1;
583 int add_host_h(conn_list_t *cl)
590 conn_list_t *ncn, *fw;
592 if(!cl->status.active)
594 if(sscanf(cl->buffer, "%*d %lx %lx/%lx:%hx %d", &real_ip, &vpn_ip, &vpn_mask, &port, &flags) != 5)
596 syslog(LOG_ERR, _("got bad ADD_HOST request: %s"), cl->buffer);
601 syslog(LOG_DEBUG, _("Add host request from " IP_ADDR_S), IP_ADDR_V(cl->vpn_ip));
603 syslog(LOG_DEBUG, _("got ADD_HOST(" IP_ADDR_S "," IP_ADDR_S ",%hd)"),
604 IP_ADDR_V(vpn_ip), IP_ADDR_V(vpn_mask), port);
607 Suggestion of Hans Bayle
609 if((fw = lookup_conn(vpn_ip)))
611 if(fw->nexthop == cl)
612 notify_others(fw, cl, send_add_host);
615 syslog(LOG_DEBUG, _("Invalid add_host request from " IP_ADDR_S),
616 IP_ADDR_V(cl->vpn_ip));
620 ncn = new_conn_list();
621 ncn->real_ip = real_ip;
622 ncn->vpn_ip = vpn_ip;
623 ncn->vpn_mask = vpn_mask;
626 ncn->hostname = hostlookup(real_ip);
628 ncn->next = conn_list;
630 ncn->status.active = 1;
631 notify_others(ncn, cl, send_add_host);
636 int req_key_h(conn_list_t *cl)
642 if(!cl->status.active) return -1;
643 if(sscanf(cl->buffer, "%*d %lx %lx", &to, &from) != 2)
645 syslog(LOG_ERR, _("got bad request: %s"), cl->buffer);
650 syslog(LOG_DEBUG, _("got REQ_KEY from " IP_ADDR_S " for " IP_ADDR_S),
651 IP_ADDR_V(from), IP_ADDR_V(to));
653 if((to & myself->vpn_mask) == (myself->vpn_ip & myself->vpn_mask))
654 { /* hey! they want something from ME! :) */
655 send_key_answer(cl, from);
659 fw = lookup_conn(to);
663 syslog(LOG_ERR, _("Attempting to forward key request to " IP_ADDR_S ", which does not exist?"),
669 syslog(LOG_DEBUG, _("Forwarding request for public key to " IP_ADDR_S),
670 IP_ADDR_V(fw->nexthop->vpn_ip));
672 cl->buffer[cl->reqlen-1] = '\n';
674 if(write(fw->nexthop->meta_socket, cl->buffer, cl->reqlen) < 0)
676 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
683 void set_keys(conn_list_t *cl, int expiry, char *key)
689 cl->public_key = xmalloc(sizeof(*cl->key));
690 cl->public_key->key = NULL;
693 if(cl->public_key->key)
694 free(cl->public_key->key);
695 cl->public_key->length = strlen(key);
696 cl->public_key->expiry = expiry;
697 cl->public_key->key = xmalloc(cl->public_key->length + 1);
698 strcpy(cl->public_key->key, key);
700 ek = make_shared_key(key);
704 cl->key = xmalloc(sizeof(*cl->key));
711 cl->key->length = strlen(ek);
712 cl->key->expiry = expiry;
713 cl->key->key = xmalloc(cl->key->length + 1);
714 strcpy(cl->key->key, ek);
718 int ans_key_h(conn_list_t *cl)
724 conn_list_t *fw, *gk;
726 if(!cl->status.active) return -1;
727 if(sscanf(cl->buffer, "%*d %lx %lx %d %as", &to, &from, &expiry, &key) != 4)
729 syslog(LOG_ERR, _("got bad ANS_KEY request: %s"), cl->buffer);
734 syslog(LOG_DEBUG, _("got ANS_KEY from " IP_ADDR_S " for " IP_ADDR_S),
735 IP_ADDR_V(from), IP_ADDR_V(to));
737 if(to == myself->vpn_ip)
738 { /* hey! that key's for ME! :) */
740 syslog(LOG_DEBUG, _("Yeah! key arrived. Now do something with it."));
741 gk = lookup_conn(from);
745 syslog(LOG_ERR, _("Receiving key from " IP_ADDR_S ", which does not exist?"),
750 set_keys(gk, expiry, key);
751 gk->status.validkey = 1;
752 gk->status.waitingforkey = 0;
757 fw = lookup_conn(to);
761 syslog(LOG_ERR, _("Attempting to forward key to " IP_ADDR_S ", which does not exist?"),
767 syslog(LOG_DEBUG, _("Forwarding public key to " IP_ADDR_S),
768 IP_ADDR_V(fw->nexthop->vpn_ip));
770 cl->buffer[cl->reqlen-1] = '\n';
772 if((write(fw->nexthop->meta_socket, cl->buffer, cl->reqlen)) < 0)
774 syslog(LOG_ERR, _("send failed: %s:%d: %m"), __FILE__, __LINE__);
781 int key_changed_h(conn_list_t *cl)
786 if(!cl->status.active) return -1;
787 if(sscanf(cl->buffer, "%*d %lx", &from) != 1)
789 syslog(LOG_ERR, _("got bad ANS_KEY request: %s"), cl->buffer);
794 syslog(LOG_DEBUG, _("got KEY_CHANGED from " IP_ADDR_S),
797 ik = lookup_conn(from);
801 syslog(LOG_ERR, _("Got changed key from " IP_ADDR_S ", which does not exist?"),
806 ik->status.validkey = 0;
807 ik->status.waitingforkey = 0;
810 syslog(LOG_DEBUG, _("Forwarding key invalidation request"));
812 notify_others(cl, ik, send_key_changed);
817 int (*request_handlers[256])(conn_list_t*) = {
818 0, ack_h, 0, 0, 0, 0, 0, 0, 0, 0,
819 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
820 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
821 termreq_h, timeout_h, del_host_h, 0, 0, 0, 0, 0, 0, 0,
822 ping_h, pong_h, 0, 0, 0, 0, 0, 0, 0, 0,
823 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
824 add_host_h, basic_info_h, passphrase_h, public_key_h, 0, 0, 0, 0, 0, 0,
825 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
826 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
827 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
828 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
829 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
830 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
831 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
832 req_key_h, ans_key_h, key_changed_h, 0, 0, 0, 0, 0, 0, 0,
833 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
834 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
835 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
836 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
837 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0