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>
36 int send_ack(conn_list_t *cl)
38 unsigned char tmp = ACK;
41 syslog(LOG_DEBUG, "Send ACK to %s", cl->hostname);
43 syslog(LOG_NOTICE, "Connection with %s activated.", cl->hostname);
44 if((send(cl->meta_socket, &tmp, sizeof(tmp), 0)) < 0)
46 syslog(LOG_ERR, "send failed: %d:%d: %m", __FILE__, __LINE__);
53 int send_termreq(conn_list_t *cl)
58 tmp.vpn_ip = myself->vpn_ip;
61 syslog(LOG_DEBUG, "Send TERMREQ(" IP_ADDR_S ") to " IP_ADDR_S, IP_ADDR_V(tmp.vpn_ip),
62 IP_ADDR_V(cl->vpn_ip));
64 if((send(cl->meta_socket, &tmp, sizeof(tmp), 0)) < 0)
66 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
73 int send_timeout(conn_list_t *cl)
77 tmp.type = PINGTIMEOUT;
78 tmp.vpn_ip = myself->vpn_ip;
81 syslog(LOG_DEBUG, "Send TIMEOUT(" IP_ADDR_S ") to " IP_ADDR_S, IP_ADDR_V(tmp.vpn_ip),
82 IP_ADDR_V(cl->vpn_ip));
84 if((send(cl->meta_socket, &tmp, sizeof(tmp), 0)) < 0)
86 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
93 int send_del_host(conn_list_t *cl, conn_list_t *new_host)
98 tmp.vpn_ip = new_host->vpn_ip;
101 syslog(LOG_DEBUG, "Sending delete host %lx to " IP_ADDR_S,
102 tmp.vpn_ip, IP_ADDR_V(cl->vpn_ip));
104 if((send(cl->meta_socket, (unsigned char*)&tmp, sizeof(del_host_t), 0)) < 0)
106 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
113 int send_ping(conn_list_t *cl)
115 unsigned char tmp = PING;
118 syslog(LOG_DEBUG, "pinging " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
120 if((send(cl->meta_socket, &tmp, sizeof(tmp), 0)) < 0)
122 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
129 int send_pong(conn_list_t *cl)
131 unsigned char tmp = PONG;
133 if((send(cl->meta_socket, &tmp, sizeof(tmp), 0)) < 0)
135 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
142 int send_add_host(conn_list_t *cl, conn_list_t *new_host)
147 tmp.real_ip = new_host->real_ip;
148 tmp.vpn_ip = new_host->vpn_ip;
149 tmp.vpn_mask = new_host->vpn_mask;
150 tmp.portnr = new_host->port;
153 syslog(LOG_DEBUG, "Sending add host (%lx/%lx %lx:%hd) to " IP_ADDR_S,
154 tmp.vpn_ip, tmp.vpn_mask, tmp.real_ip, tmp.portnr,
155 IP_ADDR_V(cl->vpn_ip));
157 if((send(cl->meta_socket, (unsigned char*)&tmp, sizeof(add_host_t), 0)) < 0)
159 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
166 int send_key_changed(conn_list_t *cl, conn_list_t *src)
170 tmp.type = KEY_CHANGED;
171 tmp.from = src->vpn_ip;
174 syslog(LOG_DEBUG, "Sending KEY_CHANGED (%lx) to " IP_ADDR_S,
175 tmp.from, IP_ADDR_V(cl->vpn_ip));
177 if((send(cl->meta_socket, (unsigned char*)&tmp, sizeof(key_changed_t), 0)) < 0)
179 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
186 void send_key_changed2(void)
190 for(p = conn_list; p != NULL; p = p->next)
191 if(p->status.meta && p->protocol_version > PROT_3)
192 send_key_changed(p, myself);
195 int send_basic_info(conn_list_t *cl)
199 tmp.type = BASIC_INFO;
200 tmp.protocol = PROT_CURRENT;
202 tmp.portnr = myself->port;
203 tmp.vpn_ip = myself->vpn_ip;
204 tmp.vpn_mask = myself->vpn_mask;
207 syslog(LOG_DEBUG, "Send BASIC_INFO(%d,%hd," IP_ADDR_S "," IP_ADDR_S ") to " IP_ADDR_S,
208 tmp.protocol, tmp.portnr, IP_ADDR_V(tmp.vpn_ip), IP_ADDR_V(tmp.vpn_mask),
209 IP_ADDR_V(cl->real_ip));
211 if((send(cl->meta_socket, &tmp, sizeof(tmp), 0)) < 0)
213 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
220 int send_passphrase(conn_list_t *cl)
224 tmp.type = PASSPHRASE;
225 encrypt_passphrase(&tmp);
228 syslog(LOG_DEBUG, "Send PASSPHRASE(%hd,...) to " IP_ADDR_S, tmp.len,
229 IP_ADDR_V(cl->vpn_ip));
231 if((send(cl->meta_socket, &tmp, tmp.len+3, 0)) < 0)
233 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
240 int send_public_key(conn_list_t *cl)
244 tmp = (public_key_t*)xmalloc(strlen(my_public_key_base36)+sizeof(public_key_t));
245 tmp->type = PUBLIC_KEY;
246 tmp->len = strlen(my_public_key_base36);
247 strcpy(&tmp->key, my_public_key_base36);
250 syslog(LOG_DEBUG, "Send PUBLIC_KEY(%hd,%s) to " IP_ADDR_S, tmp->len, &tmp->key,
251 IP_ADDR_V(cl->vpn_ip));
253 if((send(cl->meta_socket, tmp, tmp->len+sizeof(public_key_t), 0)) < 0)
255 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
262 int send_calculate(conn_list_t *cl, char *k)
266 tmp = xmalloc(strlen(k)+sizeof(calculate_t));
267 tmp->type = CALCULATE;
268 tmp->len = strlen(k);
269 strcpy(&tmp->key, k);
271 if(send(cl->meta_socket, tmp, tmp->len+4, 0) < 0)
273 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
280 int send_key_request(ip_t to)
285 tmp = xmalloc(sizeof(key_req_t));
288 tmp->from = myself->vpn_ip;
291 fw = lookup_conn(to);
294 syslog(LOG_ERR, "Attempting to send key request to " IP_ADDR_S ", which does not exist?",
300 syslog(LOG_DEBUG, "Sending out request for public key to " IP_ADDR_S,
301 IP_ADDR_V(fw->nexthop->vpn_ip));
302 if(send(fw->nexthop->meta_socket, tmp, sizeof(key_req_t), 0) < 0)
304 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
307 fw->status.waitingforkey = 1;
312 int send_key_answer(conn_list_t *cl, ip_t to)
317 tmp = xmalloc(sizeof(key_req_t)+strlen(my_public_key_base36));
320 tmp->from = myself->vpn_ip;
321 tmp->expiry = my_key_expiry;
322 tmp->len = strlen(my_public_key_base36);
323 strcpy(&tmp->key, my_public_key_base36);
325 fw = lookup_conn(to);
329 syslog(LOG_ERR, "Attempting to send key answer to " IP_ADDR_S ", which does not exist?",
335 syslog(LOG_DEBUG, "Sending public key to " IP_ADDR_S,
336 IP_ADDR_V(fw->nexthop->vpn_ip));
337 if(send(fw->nexthop->meta_socket, tmp, sizeof(key_req_t)+tmp->len, 0) < 0)
339 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
347 notify all my direct connections of a new host
348 that was added to the vpn, with the exception
349 of the source of the announcement.
351 int notify_others(conn_list_t *new, conn_list_t *source,
352 int (*function)(conn_list_t*, conn_list_t*))
356 for(p = conn_list; p != NULL; p = p->next)
357 if(p != new && p != source && p->status.meta && p->protocol_version > PROT_3)
364 notify one connection of everything
367 int notify_one(conn_list_t *new)
371 for(p = conn_list; p != NULL; p = p->next)
372 if(p != new && p->protocol_version > PROT_3)
373 send_add_host(new, p);
379 The incoming request handlers
382 int basic_info_h(conn_list_t *cl, unsigned char *d, int len)
384 basic_info_t *tmp = (basic_info_t*)d;
386 cl->protocol_version = tmp->protocol;
387 cl->port = tmp->portnr;
388 cl->vpn_ip = tmp->vpn_ip;
389 cl->vpn_mask = tmp->vpn_mask;
391 if(cl->protocol_version < PROT_CURRENT)
393 syslog(LOG_ERR, "Peer uses protocol version %d which is too old.",
394 cl->protocol_version);
399 syslog(LOG_DEBUG, "got BASIC_INFO(%hd," IP_ADDR_S "," IP_ADDR_S ")", cl->port,
400 IP_ADDR_V(cl->vpn_ip), IP_ADDR_V(cl->vpn_mask));
402 syslog(LOG_DEBUG, "Peer uses protocol version %d",
403 cl->protocol_version);
405 if(cl->status.outgoing)
407 if(setup_vpn_connection(cl) < 0)
413 if(setup_vpn_connection(cl) < 0)
418 cl->status.active = 0;
423 int passphrase_h(conn_list_t *cl, unsigned char *d, int len)
425 passphrase_t *tmp = (passphrase_t*)d;
427 cl->pp = xmalloc(tmp->len+3);
428 memcpy(cl->pp, tmp, tmp->len+3);
431 syslog(LOG_DEBUG, "got PASSPHRASE(%hd,...)", cl->pp->len);
433 if(cl->status.outgoing)
441 int public_key_h(conn_list_t *cl, unsigned char *d, int len)
444 public_key_t *tmp = (public_key_t*)d;
447 syslog(LOG_DEBUG, "got PUBLIC_KEY(%hd,%s)", tmp->len, &tmp->key);
449 g_n = xmalloc(tmp->len+1);
450 strcpy(g_n, &tmp->key);
452 if(verify_passphrase(cl, g_n))
455 syslog(LOG_ERR, "Intruder: passphrase does not match.");
460 syslog(LOG_INFO, "Passphrase OK");
462 if(cl->status.outgoing)
467 cl->status.active = 1;
468 notify_others(cl, NULL, send_add_host);
474 int ack_h(conn_list_t *cl, unsigned char *d, int len)
477 syslog(LOG_DEBUG, "got ACK");
479 cl->status.active = 1;
480 syslog(LOG_NOTICE, "Connection with %s activated.", cl->hostname);
483 Now I'm going to cheat. The meta protocol is actually
484 a stream of requests, that may come in in the same TCP
485 packet. This is the only place that it will happen,
487 I may change it in the future, if it appears that this
490 if(len > 1) /* An ADD_HOST follows */
492 if(request_handlers[d[1]] == NULL)
493 syslog(LOG_ERR, "Unknown request %d.", d[1]);
494 if(request_handlers[d[1]](cl, d, len - 1) < 0)
501 int termreq_h(conn_list_t *cl, unsigned char *d, int len)
503 syslog(LOG_NOTICE, IP_ADDR_S " wants to quit", IP_ADDR_V(cl->vpn_ip));
504 cl->status.termreq = 1;
505 terminate_connection(cl);
507 notify_others(cl, NULL, send_del_host);
512 int timeout_h(conn_list_t *cl, unsigned char *d, int len)
514 syslog(LOG_NOTICE, IP_ADDR_S " says it's gotten a timeout from us", IP_ADDR_V(cl->vpn_ip));
515 cl->status.termreq = 1;
516 terminate_connection(cl);
521 int del_host_h(conn_list_t *cl, unsigned char *d, int len)
523 del_host_t *tmp = (del_host_t*)d;
527 syslog(LOG_DEBUG, "got DEL_HOST for " IP_ADDR_S,
528 IP_ADDR_V(tmp->vpn_ip));
530 if(!(fw = lookup_conn(tmp->vpn_ip)))
532 syslog(LOG_ERR, "Somebody wanted to delete " IP_ADDR_S " which does not exist?",
533 IP_ADDR_V(tmp->vpn_ip));
537 notify_others(cl, fw, send_del_host);
539 fw->status.termreq = 1;
540 terminate_connection(fw);
545 int ping_h(conn_list_t *cl, unsigned char *d, int len)
548 syslog(LOG_DEBUG, "responding to ping from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
549 cl->status.pinged = 0;
550 cl->status.got_pong = 1;
557 int pong_h(conn_list_t *cl, unsigned char *d, int len)
560 syslog(LOG_DEBUG, "ok, got pong from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
561 cl->status.got_pong = 1;
566 int add_host_h(conn_list_t *cl, unsigned char *d, int len)
568 add_host_t *tmp = (add_host_t*)d;
569 conn_list_t *ncn, *fw;
572 syslog(LOG_DEBUG, "Add host request from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
574 syslog(LOG_DEBUG, "got ADD_HOST(" IP_ADDR_S "," IP_ADDR_S ",%hd)",
575 IP_ADDR_V(tmp->vpn_ip), IP_ADDR_V(tmp->vpn_mask), tmp->portnr);
578 Suggestion of Hans Bayle
580 if((fw = lookup_conn(tmp->vpn_ip)))
582 notify_others(fw, cl, send_add_host);
586 ncn = new_conn_list();
587 ncn->real_ip = tmp->real_ip;
588 ncn->vpn_ip = tmp->vpn_ip;
589 ncn->vpn_mask = tmp->vpn_mask;
590 ncn->port = tmp->portnr;
591 ncn->hostname = hostlookup(tmp->real_ip);
593 ncn->next = conn_list;
595 ncn->status.active = 1;
596 notify_others(ncn, cl, send_add_host);
599 again, i'm cheating here. see the comment in ack_h.
601 if(len > sizeof(add_host_t)) /* Another ADD_HOST follows */
603 if(request_handlers[d[sizeof(add_host_t)]] == NULL)
604 syslog(LOG_ERR, "Unknown request %d.", d[sizeof(add_host_t)]);
605 if(request_handlers[d[sizeof(add_host_t)]](cl, d, len - sizeof(add_host_t)) < 0)
612 int req_key_h(conn_list_t *cl, unsigned char *d, int len)
614 key_req_t *tmp = (key_req_t*)d;
618 syslog(LOG_DEBUG, "got REQ_KEY from " IP_ADDR_S " for " IP_ADDR_S,
619 IP_ADDR_V(tmp->from), IP_ADDR_V(tmp->to));
621 if((tmp->to & myself->vpn_mask) == (myself->vpn_ip & myself->vpn_mask))
622 { /* hey! they want something from ME! :) */
623 send_key_answer(cl, tmp->from);
627 fw = lookup_conn(tmp->to);
631 syslog(LOG_ERR, "Attempting to forward key request to " IP_ADDR_S ", which does not exist?",
637 syslog(LOG_DEBUG, "Forwarding request for public key to " IP_ADDR_S,
638 IP_ADDR_V(fw->nexthop->vpn_ip));
639 if(send(fw->nexthop->meta_socket, tmp, sizeof(key_req_t), 0) < 0)
641 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
648 void set_keys(conn_list_t *cl, key_req_t *k)
654 cl->public_key = xmalloc(sizeof(enc_key_t));
655 cl->public_key->key = NULL;
657 if(cl->public_key->key)
658 free(cl->public_key->key);
659 cl->public_key->length = k->len;
660 cl->public_key->expiry = k->expiry;
661 cl->public_key->key = xmalloc(k->len + 1);
662 strcpy(cl->public_key->key, &(k->key));
664 ek = make_shared_key(&(k->key));
667 cl->key = xmalloc(sizeof(enc_key_t));
672 cl->key->length = strlen(ek);
673 cl->key->expiry = k->expiry;
674 cl->key->key = xmalloc(strlen(ek) + 1);
675 strcpy(cl->key->key, ek);
678 int ans_key_h(conn_list_t *cl, unsigned char *d, int len)
680 key_req_t *tmp = (key_req_t*)d;
681 conn_list_t *fw, *gk;
684 syslog(LOG_DEBUG, "got ANS_KEY from " IP_ADDR_S " for " IP_ADDR_S,
685 IP_ADDR_V(tmp->from), IP_ADDR_V(tmp->to));
687 if(tmp->to == myself->vpn_ip)
688 { /* hey! that key's for ME! :) */
690 syslog(LOG_DEBUG, "Yeah! key arrived. Now do something with it.");
691 gk = lookup_conn(tmp->from);
695 syslog(LOG_ERR, "Receiving key from " IP_ADDR_S ", which does not exist?",
696 IP_ADDR_V(tmp->from));
701 gk->status.validkey = 1;
702 gk->status.waitingforkey = 0;
707 fw = lookup_conn(tmp->to);
711 syslog(LOG_ERR, "Attempting to forward key to " IP_ADDR_S ", which does not exist?",
717 syslog(LOG_DEBUG, "Forwarding public key to " IP_ADDR_S,
718 IP_ADDR_V(fw->nexthop->vpn_ip));
719 if(send(fw->nexthop->meta_socket, tmp, sizeof(key_req_t)+tmp->len, 0) < 0)
721 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
728 int key_changed_h(conn_list_t *cl, unsigned char *d, int len)
730 key_changed_t *tmp = (key_changed_t*)d;
734 syslog(LOG_DEBUG, "got KEY_CHANGED from " IP_ADDR_S,
735 IP_ADDR_V(tmp->from));
737 ik = lookup_conn(tmp->from);
741 syslog(LOG_ERR, "Got changed key from " IP_ADDR_S ", which does not exist?",
742 IP_ADDR_V(tmp->from));
746 ik->status.validkey = 0;
747 ik->status.waitingforkey = 0;
750 syslog(LOG_DEBUG, "Forwarding key invalidation request");
752 notify_others(cl, ik, send_key_changed);
757 int (*request_handlers[256])(conn_list_t*, unsigned char*, int) = {
758 0, ack_h, 0, 0, 0, 0, 0, 0, 0, 0,
759 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
760 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
761 termreq_h, timeout_h, del_host_h, 0, 0, 0, 0, 0, 0, 0,
762 ping_h, pong_h, 0, 0, 0, 0, 0, 0, 0, 0,
763 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
764 add_host_h, basic_info_h, passphrase_h, public_key_h, 0, 0, 0, 0, 0, 0,
765 0, 0, 0, 0, 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, 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 req_key_h, ans_key_h, key_changed_h, 0, 0, 0, 0, 0, 0, 0,
773 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
774 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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