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>
37 int send_ack(conn_list_t *cl)
39 unsigned char tmp = ACK;
42 syslog(LOG_DEBUG, "Send ACK to %s", cl->hostname);
44 syslog(LOG_NOTICE, "Connection with %s activated.", cl->hostname);
45 if((write(cl->meta_socket, &tmp, sizeof(tmp))) < 0)
47 syslog(LOG_ERR, "send failed: %d:%d: %m", __FILE__, __LINE__);
54 int send_termreq(conn_list_t *cl)
58 memset(&tmp, 0, sizeof(tmp));
60 tmp.vpn_ip = myself->vpn_ip;
63 syslog(LOG_DEBUG, "Send TERMREQ(" IP_ADDR_S ") to " IP_ADDR_S, IP_ADDR_V(tmp.vpn_ip),
64 IP_ADDR_V(cl->vpn_ip));
66 if((write(cl->meta_socket, &tmp, sizeof(tmp))) < 0)
68 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
75 int send_timeout(conn_list_t *cl)
79 memset(&tmp, 0, sizeof(tmp));
80 tmp.type = PINGTIMEOUT;
81 tmp.vpn_ip = myself->vpn_ip;
84 syslog(LOG_DEBUG, "Send TIMEOUT(" IP_ADDR_S ") to " IP_ADDR_S, IP_ADDR_V(tmp.vpn_ip),
85 IP_ADDR_V(cl->vpn_ip));
87 if((write(cl->meta_socket, &tmp, sizeof(tmp))) < 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 memset(&tmp, 0, sizeof(tmp));
102 tmp.vpn_ip = new_host->vpn_ip;
105 syslog(LOG_DEBUG, "Sending delete host %lx to " IP_ADDR_S,
106 tmp.vpn_ip, IP_ADDR_V(cl->vpn_ip));
108 if((write(cl->meta_socket, &tmp, sizeof(tmp))) < 0)
110 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
117 int send_ping(conn_list_t *cl)
119 unsigned char tmp = PING;
122 syslog(LOG_DEBUG, "pinging " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
124 if((write(cl->meta_socket, &tmp, sizeof(tmp))) < 0)
126 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
133 int send_pong(conn_list_t *cl)
135 unsigned char tmp = PONG;
137 if((write(cl->meta_socket, &tmp, sizeof(tmp))) < 0)
139 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
146 int send_add_host(conn_list_t *cl, conn_list_t *new_host)
150 memset(&tmp, 0, sizeof(tmp));
152 tmp.real_ip = new_host->real_ip;
153 tmp.vpn_ip = new_host->vpn_ip;
154 tmp.vpn_mask = new_host->vpn_mask;
155 tmp.portnr = new_host->port;
158 syslog(LOG_DEBUG, "Sending add host (%lx/%lx %lx:%hd) to " IP_ADDR_S,
159 tmp.vpn_ip, tmp.vpn_mask, tmp.real_ip, tmp.portnr,
160 IP_ADDR_V(cl->vpn_ip));
162 if((write(cl->meta_socket, &tmp, sizeof(tmp))) < 0)
164 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
171 int send_key_changed(conn_list_t *cl, conn_list_t *src)
175 memset(&tmp, 0, sizeof(tmp));
176 tmp.type = KEY_CHANGED;
177 tmp.from = src->vpn_ip;
180 syslog(LOG_DEBUG, "Sending KEY_CHANGED (%lx) to " IP_ADDR_S,
181 tmp.from, IP_ADDR_V(cl->vpn_ip));
183 if((write(cl->meta_socket, &tmp, sizeof(tmp))) < 0)
185 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
192 void send_key_changed2(void)
196 for(p = conn_list; p != NULL; p = p->next)
197 if(p->status.meta && p->protocol_version > PROT_3)
198 send_key_changed(p, myself);
202 int send_basic_info(conn_list_t *cl)
206 memset(&tmp, 0, sizeof(tmp));
207 tmp.type = BASIC_INFO;
208 tmp.protocol = PROT_CURRENT;
210 tmp.portnr = myself->port;
211 tmp.vpn_ip = myself->vpn_ip;
212 tmp.vpn_mask = myself->vpn_mask;
215 syslog(LOG_DEBUG, "Send BASIC_INFO(%d,%hd," IP_ADDR_S "," IP_ADDR_S ") to " IP_ADDR_S,
216 tmp.protocol, tmp.portnr, IP_ADDR_V(tmp.vpn_ip), IP_ADDR_V(tmp.vpn_mask),
217 IP_ADDR_V(cl->real_ip));
219 if((write(cl->meta_socket, &tmp, sizeof(tmp))) < 0)
221 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
228 int send_passphrase(conn_list_t *cl)
232 memset(&tmp, 0, sizeof(tmp));
233 tmp.type = PASSPHRASE;
234 encrypt_passphrase(&tmp);
237 syslog(LOG_DEBUG, "Send PASSPHRASE(%hd,...) to " IP_ADDR_S, tmp.len,
238 IP_ADDR_V(cl->vpn_ip));
240 if((write(cl->meta_socket, &tmp, tmp.len+3)) < 0)
242 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
249 int send_public_key(conn_list_t *cl)
253 tmp = (public_key_t*)xmalloc(strlen(my_public_key_base36)+sizeof(*tmp));
254 memset(tmp, 0, sizeof(*tmp));
255 tmp->type = PUBLIC_KEY;
256 tmp->len = strlen(my_public_key_base36);
257 strcpy(&tmp->key, my_public_key_base36);
260 syslog(LOG_DEBUG, "Send PUBLIC_KEY(%hd,%s) to " IP_ADDR_S, tmp->len, &tmp->key,
261 IP_ADDR_V(cl->vpn_ip));
263 if((write(cl->meta_socket, tmp, tmp->len+sizeof(*tmp))) < 0)
265 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
272 int send_calculate(conn_list_t *cl, char *k)
276 tmp = xmalloc(strlen(k)+sizeof(*tmp));
277 memset(tmp, 0, sizeof(*tmp));
278 tmp->type = CALCULATE;
279 tmp->len = strlen(k);
280 strcpy(&tmp->key, k);
282 if((write(cl->meta_socket, tmp, tmp->len+sizeof(*tmp))) < 0)
284 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
291 int send_key_request(ip_t to)
296 tmp = xmalloc(sizeof(*tmp));
297 memset(tmp, 0, sizeof(*tmp));
300 tmp->from = myself->vpn_ip;
303 fw = lookup_conn(to);
306 syslog(LOG_ERR, "Attempting to send key request to " IP_ADDR_S ", which does not exist?",
312 syslog(LOG_DEBUG, "Sending out request for public key to " IP_ADDR_S,
313 IP_ADDR_V(fw->nexthop->vpn_ip));
314 if(write(fw->nexthop->meta_socket, tmp, sizeof(*tmp)) < 0)
316 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
319 fw->status.waitingforkey = 1;
324 int send_key_answer(conn_list_t *cl, ip_t to)
329 tmp = xmalloc(sizeof(*tmp)+strlen(my_public_key_base36));
330 memset(tmp, 0, sizeof(*tmp));
333 tmp->from = myself->vpn_ip;
334 tmp->expiry = my_key_expiry;
335 tmp->len = strlen(my_public_key_base36);
336 strcpy(&tmp->key, my_public_key_base36);
338 fw = lookup_conn(to);
342 syslog(LOG_ERR, "Attempting to send key answer to " IP_ADDR_S ", which does not exist?",
348 syslog(LOG_DEBUG, "Sending public key to " IP_ADDR_S,
349 IP_ADDR_V(fw->nexthop->vpn_ip));
350 if(write(fw->nexthop->meta_socket, tmp, sizeof(*tmp)+tmp->len) < 0)
352 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
360 notify all my direct connections of a new host
361 that was added to the vpn, with the exception
362 of the source of the announcement.
364 int notify_others(conn_list_t *new, conn_list_t *source,
365 int (*function)(conn_list_t*, conn_list_t*))
369 for(p = conn_list; p != NULL; p = p->next)
370 if(p != new && p != source && p->status.meta && p->protocol_version > PROT_3)
377 notify one connection of everything
380 int notify_one(conn_list_t *new)
384 for(p = conn_list; p != NULL; p = p->next)
385 if(p != new && p->protocol_version > PROT_3)
386 send_add_host(new, p);
392 The incoming request handlers
395 int basic_info_h(conn_list_t *cl, unsigned char *d, int len)
397 basic_info_t *tmp = (basic_info_t*)d;
399 cl->protocol_version = tmp->protocol;
400 cl->port = tmp->portnr;
401 cl->vpn_ip = tmp->vpn_ip;
402 cl->vpn_mask = tmp->vpn_mask;
404 if(cl->protocol_version < PROT_CURRENT)
406 syslog(LOG_ERR, "Peer uses protocol version %d which is too old.",
407 cl->protocol_version);
412 syslog(LOG_DEBUG, "got BASIC_INFO(%hd," IP_ADDR_S "," IP_ADDR_S ")", cl->port,
413 IP_ADDR_V(cl->vpn_ip), IP_ADDR_V(cl->vpn_mask));
415 syslog(LOG_DEBUG, "Peer uses protocol version %d",
416 cl->protocol_version);
418 if(cl->status.outgoing)
420 if(setup_vpn_connection(cl) < 0)
426 if(setup_vpn_connection(cl) < 0)
431 cl->status.active = 0;
436 int passphrase_h(conn_list_t *cl, unsigned char *d, int len)
438 passphrase_t *tmp = (passphrase_t*)d;
440 cl->pp = xmalloc(tmp->len+3);
441 memcpy(cl->pp, tmp, tmp->len+3);
444 syslog(LOG_DEBUG, "got PASSPHRASE(%hd,...)", cl->pp->len);
446 if(cl->status.outgoing)
454 int public_key_h(conn_list_t *cl, unsigned char *d, int len)
457 public_key_t *tmp = (public_key_t*)d;
460 syslog(LOG_DEBUG, "got PUBLIC_KEY(%hd,%s)", tmp->len, &tmp->key);
462 g_n = xmalloc(tmp->len+1);
463 strcpy(g_n, &tmp->key);
465 if(verify_passphrase(cl, g_n))
468 syslog(LOG_ERR, "Intruder: passphrase does not match.");
473 syslog(LOG_INFO, "Passphrase OK");
475 if(cl->status.outgoing)
480 cl->status.active = 1;
481 notify_others(cl, NULL, send_add_host);
487 int ack_h(conn_list_t *cl, unsigned char *d, int len)
491 syslog(LOG_DEBUG, "got ACK");
493 cl->status.active = 1;
494 syslog(LOG_NOTICE, "Connection with %s activated.", cl->hostname);
498 Now I'm going to cheat. The meta protocol is actually
499 a stream of requests, that may come in in the same TCP
500 packet. This is the only place that it will happen,
502 I may change it in the future, if it appears that this
505 if(len > 1) /* An ADD_HOST follows */
507 if(request_handlers[d[1]] == NULL)
508 syslog(LOG_ERR, "Unknown request %d.", d[1]);
509 if(request_handlers[d[1]](cl, d + 1, len - 1) < 0)
516 int termreq_h(conn_list_t *cl, unsigned char *d, int len)
519 syslog(LOG_NOTICE, IP_ADDR_S " wants to quit", IP_ADDR_V(cl->vpn_ip));
520 cl->status.termreq = 1;
521 terminate_connection(cl);
523 notify_others(cl, NULL, send_del_host);
528 int timeout_h(conn_list_t *cl, unsigned char *d, int len)
531 syslog(LOG_NOTICE, IP_ADDR_S " says it's gotten a timeout from us", IP_ADDR_V(cl->vpn_ip));
532 cl->status.termreq = 1;
533 terminate_connection(cl);
538 int del_host_h(conn_list_t *cl, unsigned char *d, int len)
540 del_host_t *tmp = (del_host_t*)d;
544 syslog(LOG_DEBUG, "got DEL_HOST for " IP_ADDR_S,
545 IP_ADDR_V(tmp->vpn_ip));
547 if(!(fw = lookup_conn(tmp->vpn_ip)))
549 syslog(LOG_ERR, "Somebody wanted to delete " IP_ADDR_S " which does not exist?",
550 IP_ADDR_V(tmp->vpn_ip));
554 notify_others(cl, fw, send_del_host);
556 fw->status.termreq = 1;
557 terminate_connection(fw);
562 int ping_h(conn_list_t *cl, unsigned char *d, int len)
566 syslog(LOG_DEBUG, "responding to ping from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
567 cl->status.pinged = 0;
568 cl->status.got_pong = 1;
575 int pong_h(conn_list_t *cl, unsigned char *d, int len)
579 syslog(LOG_DEBUG, "ok, got pong from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
580 cl->status.got_pong = 1;
585 int add_host_h(conn_list_t *cl, unsigned char *d, int len)
587 add_host_t *tmp = (add_host_t*)d;
588 conn_list_t *ncn, *fw;
591 syslog(LOG_DEBUG, "Add host request from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
593 syslog(LOG_DEBUG, "got ADD_HOST(" IP_ADDR_S "," IP_ADDR_S ",%hd)",
594 IP_ADDR_V(tmp->vpn_ip), IP_ADDR_V(tmp->vpn_mask), tmp->portnr);
597 Suggestion of Hans Bayle
599 if((fw = lookup_conn(tmp->vpn_ip)))
601 notify_others(fw, cl, send_add_host);
605 ncn = new_conn_list();
606 ncn->real_ip = tmp->real_ip;
607 ncn->vpn_ip = tmp->vpn_ip;
608 ncn->vpn_mask = tmp->vpn_mask;
609 ncn->port = tmp->portnr;
610 ncn->hostname = hostlookup(tmp->real_ip);
612 ncn->next = conn_list;
614 ncn->status.active = 1;
615 notify_others(ncn, cl, send_add_host);
618 again, i'm cheating here. see the comment in ack_h.
619 Naughty zarq! Now you see what cheating will get you... [GS]
621 if(len > sizeof(*tmp)) /* Another ADD_HOST follows */
623 if(request_handlers[d[sizeof(*tmp)]] == NULL)
624 syslog(LOG_ERR, "Unknown request %d.", d[sizeof(*tmp)]);
625 if(request_handlers[d[sizeof(*tmp)]](cl, d + sizeof(*tmp), len - sizeof(*tmp)) < 0)
632 int req_key_h(conn_list_t *cl, unsigned char *d, int len)
634 key_req_t *tmp = (key_req_t*)d;
638 syslog(LOG_DEBUG, "got REQ_KEY from " IP_ADDR_S " for " IP_ADDR_S,
639 IP_ADDR_V(tmp->from), IP_ADDR_V(tmp->to));
641 if((tmp->to & myself->vpn_mask) == (myself->vpn_ip & myself->vpn_mask))
642 { /* hey! they want something from ME! :) */
643 send_key_answer(cl, tmp->from);
647 fw = lookup_conn(tmp->to);
651 syslog(LOG_ERR, "Attempting to forward key request to " IP_ADDR_S ", which does not exist?",
657 syslog(LOG_DEBUG, "Forwarding request for public key to " IP_ADDR_S,
658 IP_ADDR_V(fw->nexthop->vpn_ip));
659 if(write(fw->nexthop->meta_socket, tmp, sizeof(*tmp)) < 0)
661 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
668 void set_keys(conn_list_t *cl, key_req_t *k)
674 cl->public_key = xmalloc(sizeof(*cl->key));
675 cl->public_key->key = NULL;
677 if(cl->public_key->key)
678 free(cl->public_key->key);
679 cl->public_key->length = k->len;
680 cl->public_key->expiry = k->expiry;
681 cl->public_key->key = xmalloc(k->len + 1);
682 strcpy(cl->public_key->key, &(k->key));
684 ek = make_shared_key(&(k->key));
687 cl->key = xmalloc(sizeof(*cl->key));
692 cl->key->length = strlen(ek);
693 cl->key->expiry = k->expiry;
694 cl->key->key = xmalloc(strlen(ek) + 1);
695 strcpy(cl->key->key, ek);
699 int ans_key_h(conn_list_t *cl, unsigned char *d, int len)
701 key_req_t *tmp = (key_req_t*)d;
702 conn_list_t *fw, *gk;
705 syslog(LOG_DEBUG, "got ANS_KEY from " IP_ADDR_S " for " IP_ADDR_S,
706 IP_ADDR_V(tmp->from), IP_ADDR_V(tmp->to));
708 if(tmp->to == myself->vpn_ip)
709 { /* hey! that key's for ME! :) */
711 syslog(LOG_DEBUG, "Yeah! key arrived. Now do something with it.");
712 gk = lookup_conn(tmp->from);
716 syslog(LOG_ERR, "Receiving key from " IP_ADDR_S ", which does not exist?",
717 IP_ADDR_V(tmp->from));
722 gk->status.validkey = 1;
723 gk->status.waitingforkey = 0;
728 fw = lookup_conn(tmp->to);
732 syslog(LOG_ERR, "Attempting to forward key to " IP_ADDR_S ", which does not exist?",
738 syslog(LOG_DEBUG, "Forwarding public key to " IP_ADDR_S,
739 IP_ADDR_V(fw->nexthop->vpn_ip));
740 if(write(fw->nexthop->meta_socket, tmp, sizeof(*tmp)+tmp->len) < 0)
742 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
749 int key_changed_h(conn_list_t *cl, unsigned char *d, int len)
751 key_changed_t *tmp = (key_changed_t*)d;
755 syslog(LOG_DEBUG, "got KEY_CHANGED from " IP_ADDR_S,
756 IP_ADDR_V(tmp->from));
758 ik = lookup_conn(tmp->from);
762 syslog(LOG_ERR, "Got changed key from " IP_ADDR_S ", which does not exist?",
763 IP_ADDR_V(tmp->from));
767 ik->status.validkey = 0;
768 ik->status.waitingforkey = 0;
771 syslog(LOG_DEBUG, "Forwarding key invalidation request");
773 notify_others(cl, ik, send_key_changed);
778 int (*request_handlers[256])(conn_list_t*, unsigned char*, int) = {
779 0, ack_h, 0, 0, 0, 0, 0, 0, 0, 0,
780 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
781 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
782 termreq_h, timeout_h, del_host_h, 0, 0, 0, 0, 0, 0, 0,
783 ping_h, pong_h, 0, 0, 0, 0, 0, 0, 0, 0,
784 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
785 add_host_h, basic_info_h, passphrase_h, public_key_h, 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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
789 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
790 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
791 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
792 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
793 req_key_h, ans_key_h, key_changed_h, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
796 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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