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 + 1, 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.
600 Naughty zarq! Now you see what cheating will get you... [GS]
602 if(len > sizeof(add_host_t)) /* Another ADD_HOST follows */
604 if(request_handlers[d[sizeof(add_host_t)]] == NULL)
605 syslog(LOG_ERR, "Unknown request %d.", d[sizeof(add_host_t)]);
606 if(request_handlers[d[sizeof(add_host_t)]](cl, d + sizeof(add_host_t), len - sizeof(add_host_t)) < 0)
613 int req_key_h(conn_list_t *cl, unsigned char *d, int len)
615 key_req_t *tmp = (key_req_t*)d;
619 syslog(LOG_DEBUG, "got REQ_KEY from " IP_ADDR_S " for " IP_ADDR_S,
620 IP_ADDR_V(tmp->from), IP_ADDR_V(tmp->to));
622 if((tmp->to & myself->vpn_mask) == (myself->vpn_ip & myself->vpn_mask))
623 { /* hey! they want something from ME! :) */
624 send_key_answer(cl, tmp->from);
628 fw = lookup_conn(tmp->to);
632 syslog(LOG_ERR, "Attempting to forward key request to " IP_ADDR_S ", which does not exist?",
638 syslog(LOG_DEBUG, "Forwarding request for public key to " IP_ADDR_S,
639 IP_ADDR_V(fw->nexthop->vpn_ip));
640 if(send(fw->nexthop->meta_socket, tmp, sizeof(key_req_t), 0) < 0)
642 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
649 void set_keys(conn_list_t *cl, key_req_t *k)
655 cl->public_key = xmalloc(sizeof(enc_key_t));
656 cl->public_key->key = NULL;
658 if(cl->public_key->key)
659 free(cl->public_key->key);
660 cl->public_key->length = k->len;
661 cl->public_key->expiry = k->expiry;
662 cl->public_key->key = xmalloc(k->len + 1);
663 strcpy(cl->public_key->key, &(k->key));
665 ek = make_shared_key(&(k->key));
668 cl->key = xmalloc(sizeof(enc_key_t));
673 cl->key->length = strlen(ek);
674 cl->key->expiry = k->expiry;
675 cl->key->key = xmalloc(strlen(ek) + 1);
676 strcpy(cl->key->key, ek);
679 int ans_key_h(conn_list_t *cl, unsigned char *d, int len)
681 key_req_t *tmp = (key_req_t*)d;
682 conn_list_t *fw, *gk;
685 syslog(LOG_DEBUG, "got ANS_KEY from " IP_ADDR_S " for " IP_ADDR_S,
686 IP_ADDR_V(tmp->from), IP_ADDR_V(tmp->to));
688 if(tmp->to == myself->vpn_ip)
689 { /* hey! that key's for ME! :) */
691 syslog(LOG_DEBUG, "Yeah! key arrived. Now do something with it.");
692 gk = lookup_conn(tmp->from);
696 syslog(LOG_ERR, "Receiving key from " IP_ADDR_S ", which does not exist?",
697 IP_ADDR_V(tmp->from));
702 gk->status.validkey = 1;
703 gk->status.waitingforkey = 0;
708 fw = lookup_conn(tmp->to);
712 syslog(LOG_ERR, "Attempting to forward key to " IP_ADDR_S ", which does not exist?",
718 syslog(LOG_DEBUG, "Forwarding public key to " IP_ADDR_S,
719 IP_ADDR_V(fw->nexthop->vpn_ip));
720 if(send(fw->nexthop->meta_socket, tmp, sizeof(key_req_t)+tmp->len, 0) < 0)
722 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
729 int key_changed_h(conn_list_t *cl, unsigned char *d, int len)
731 key_changed_t *tmp = (key_changed_t*)d;
735 syslog(LOG_DEBUG, "got KEY_CHANGED from " IP_ADDR_S,
736 IP_ADDR_V(tmp->from));
738 ik = lookup_conn(tmp->from);
742 syslog(LOG_ERR, "Got changed key from " IP_ADDR_S ", which does not exist?",
743 IP_ADDR_V(tmp->from));
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*, unsigned char*, int) = {
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