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);
196 int send_basic_info(conn_list_t *cl)
200 tmp.type = BASIC_INFO;
201 tmp.protocol = PROT_CURRENT;
203 tmp.portnr = myself->port;
204 tmp.vpn_ip = myself->vpn_ip;
205 tmp.vpn_mask = myself->vpn_mask;
208 syslog(LOG_DEBUG, "Send BASIC_INFO(%d,%hd," IP_ADDR_S "," IP_ADDR_S ") to " IP_ADDR_S,
209 tmp.protocol, tmp.portnr, IP_ADDR_V(tmp.vpn_ip), IP_ADDR_V(tmp.vpn_mask),
210 IP_ADDR_V(cl->real_ip));
212 if((send(cl->meta_socket, &tmp, sizeof(tmp), 0)) < 0)
214 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
221 int send_passphrase(conn_list_t *cl)
225 tmp.type = PASSPHRASE;
226 encrypt_passphrase(&tmp);
229 syslog(LOG_DEBUG, "Send PASSPHRASE(%hd,...) to " IP_ADDR_S, tmp.len,
230 IP_ADDR_V(cl->vpn_ip));
232 if((send(cl->meta_socket, &tmp, tmp.len+3, 0)) < 0)
234 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
241 int send_public_key(conn_list_t *cl)
245 tmp = (public_key_t*)xmalloc(strlen(my_public_key_base36)+sizeof(public_key_t));
246 tmp->type = PUBLIC_KEY;
247 tmp->len = strlen(my_public_key_base36);
248 strcpy(&tmp->key, my_public_key_base36);
251 syslog(LOG_DEBUG, "Send PUBLIC_KEY(%hd,%s) to " IP_ADDR_S, tmp->len, &tmp->key,
252 IP_ADDR_V(cl->vpn_ip));
254 if((send(cl->meta_socket, tmp, tmp->len+sizeof(public_key_t), 0)) < 0)
256 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
263 int send_calculate(conn_list_t *cl, char *k)
267 tmp = xmalloc(strlen(k)+sizeof(calculate_t));
268 tmp->type = CALCULATE;
269 tmp->len = strlen(k);
270 strcpy(&tmp->key, k);
272 if(send(cl->meta_socket, tmp, tmp->len+4, 0) < 0)
274 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
281 int send_key_request(ip_t to)
286 tmp = xmalloc(sizeof(key_req_t));
289 tmp->from = myself->vpn_ip;
292 fw = lookup_conn(to);
295 syslog(LOG_ERR, "Attempting to send key request to " IP_ADDR_S ", which does not exist?",
301 syslog(LOG_DEBUG, "Sending out request for public key to " IP_ADDR_S,
302 IP_ADDR_V(fw->nexthop->vpn_ip));
303 if(send(fw->nexthop->meta_socket, tmp, sizeof(key_req_t), 0) < 0)
305 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
308 fw->status.waitingforkey = 1;
313 int send_key_answer(conn_list_t *cl, ip_t to)
318 tmp = xmalloc(sizeof(key_req_t)+strlen(my_public_key_base36));
321 tmp->from = myself->vpn_ip;
322 tmp->expiry = my_key_expiry;
323 tmp->len = strlen(my_public_key_base36);
324 strcpy(&tmp->key, my_public_key_base36);
326 fw = lookup_conn(to);
330 syslog(LOG_ERR, "Attempting to send key answer to " IP_ADDR_S ", which does not exist?",
336 syslog(LOG_DEBUG, "Sending public key to " IP_ADDR_S,
337 IP_ADDR_V(fw->nexthop->vpn_ip));
338 if(send(fw->nexthop->meta_socket, tmp, sizeof(key_req_t)+tmp->len, 0) < 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->protocol_version > PROT_3)
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->protocol_version > PROT_3)
374 send_add_host(new, p);
380 The incoming request handlers
383 int basic_info_h(conn_list_t *cl, unsigned char *d, int len)
385 basic_info_t *tmp = (basic_info_t*)d;
387 cl->protocol_version = tmp->protocol;
388 cl->port = tmp->portnr;
389 cl->vpn_ip = tmp->vpn_ip;
390 cl->vpn_mask = tmp->vpn_mask;
392 if(cl->protocol_version < PROT_CURRENT)
394 syslog(LOG_ERR, "Peer uses protocol version %d which is too old.",
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)
419 cl->status.active = 0;
424 int passphrase_h(conn_list_t *cl, unsigned char *d, int len)
426 passphrase_t *tmp = (passphrase_t*)d;
428 cl->pp = xmalloc(tmp->len+3);
429 memcpy(cl->pp, tmp, tmp->len+3);
432 syslog(LOG_DEBUG, "got PASSPHRASE(%hd,...)", cl->pp->len);
434 if(cl->status.outgoing)
442 int public_key_h(conn_list_t *cl, unsigned char *d, int len)
445 public_key_t *tmp = (public_key_t*)d;
448 syslog(LOG_DEBUG, "got PUBLIC_KEY(%hd,%s)", tmp->len, &tmp->key);
450 g_n = xmalloc(tmp->len+1);
451 strcpy(g_n, &tmp->key);
453 if(verify_passphrase(cl, g_n))
456 syslog(LOG_ERR, "Intruder: passphrase does not match.");
461 syslog(LOG_INFO, "Passphrase OK");
463 if(cl->status.outgoing)
468 cl->status.active = 1;
469 notify_others(cl, NULL, send_add_host);
475 int ack_h(conn_list_t *cl, unsigned char *d, int len)
479 syslog(LOG_DEBUG, "got ACK");
481 cl->status.active = 1;
482 syslog(LOG_NOTICE, "Connection with %s activated.", cl->hostname);
486 Now I'm going to cheat. The meta protocol is actually
487 a stream of requests, that may come in in the same TCP
488 packet. This is the only place that it will happen,
490 I may change it in the future, if it appears that this
493 if(len > 1) /* An ADD_HOST follows */
495 if(request_handlers[d[1]] == NULL)
496 syslog(LOG_ERR, "Unknown request %d.", d[1]);
497 if(request_handlers[d[1]](cl, d + 1, len - 1) < 0)
504 int termreq_h(conn_list_t *cl, unsigned char *d, int len)
507 syslog(LOG_NOTICE, IP_ADDR_S " wants to quit", IP_ADDR_V(cl->vpn_ip));
508 cl->status.termreq = 1;
509 terminate_connection(cl);
511 notify_others(cl, NULL, send_del_host);
516 int timeout_h(conn_list_t *cl, unsigned char *d, int len)
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, unsigned char *d, int len)
528 del_host_t *tmp = (del_host_t*)d;
532 syslog(LOG_DEBUG, "got DEL_HOST for " IP_ADDR_S,
533 IP_ADDR_V(tmp->vpn_ip));
535 if(!(fw = lookup_conn(tmp->vpn_ip)))
537 syslog(LOG_ERR, "Somebody wanted to delete " IP_ADDR_S " which does not exist?",
538 IP_ADDR_V(tmp->vpn_ip));
542 notify_others(cl, fw, send_del_host);
544 fw->status.termreq = 1;
545 terminate_connection(fw);
550 int ping_h(conn_list_t *cl, unsigned char *d, int len)
554 syslog(LOG_DEBUG, "responding to ping from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
555 cl->status.pinged = 0;
556 cl->status.got_pong = 1;
563 int pong_h(conn_list_t *cl, unsigned char *d, int len)
567 syslog(LOG_DEBUG, "ok, got pong from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
568 cl->status.got_pong = 1;
573 int add_host_h(conn_list_t *cl, unsigned char *d, int len)
575 add_host_t *tmp = (add_host_t*)d;
576 conn_list_t *ncn, *fw;
579 syslog(LOG_DEBUG, "Add host request from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
581 syslog(LOG_DEBUG, "got ADD_HOST(" IP_ADDR_S "," IP_ADDR_S ",%hd)",
582 IP_ADDR_V(tmp->vpn_ip), IP_ADDR_V(tmp->vpn_mask), tmp->portnr);
585 Suggestion of Hans Bayle
587 if((fw = lookup_conn(tmp->vpn_ip)))
589 notify_others(fw, cl, send_add_host);
593 ncn = new_conn_list();
594 ncn->real_ip = tmp->real_ip;
595 ncn->vpn_ip = tmp->vpn_ip;
596 ncn->vpn_mask = tmp->vpn_mask;
597 ncn->port = tmp->portnr;
598 ncn->hostname = hostlookup(tmp->real_ip);
600 ncn->next = conn_list;
602 ncn->status.active = 1;
603 notify_others(ncn, cl, send_add_host);
606 again, i'm cheating here. see the comment in ack_h.
607 Naughty zarq! Now you see what cheating will get you... [GS]
609 if(len > sizeof(add_host_t)) /* Another ADD_HOST follows */
611 if(request_handlers[d[sizeof(add_host_t)]] == NULL)
612 syslog(LOG_ERR, "Unknown request %d.", d[sizeof(add_host_t)]);
613 if(request_handlers[d[sizeof(add_host_t)]](cl, d + sizeof(add_host_t), len - sizeof(add_host_t)) < 0)
620 int req_key_h(conn_list_t *cl, unsigned char *d, int len)
622 key_req_t *tmp = (key_req_t*)d;
626 syslog(LOG_DEBUG, "got REQ_KEY from " IP_ADDR_S " for " IP_ADDR_S,
627 IP_ADDR_V(tmp->from), IP_ADDR_V(tmp->to));
629 if((tmp->to & myself->vpn_mask) == (myself->vpn_ip & myself->vpn_mask))
630 { /* hey! they want something from ME! :) */
631 send_key_answer(cl, tmp->from);
635 fw = lookup_conn(tmp->to);
639 syslog(LOG_ERR, "Attempting to forward key request to " IP_ADDR_S ", which does not exist?",
645 syslog(LOG_DEBUG, "Forwarding request for public key to " IP_ADDR_S,
646 IP_ADDR_V(fw->nexthop->vpn_ip));
647 if(send(fw->nexthop->meta_socket, tmp, sizeof(key_req_t), 0) < 0)
649 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
656 void set_keys(conn_list_t *cl, key_req_t *k)
662 cl->public_key = xmalloc(sizeof(enc_key_t));
663 cl->public_key->key = NULL;
665 if(cl->public_key->key)
666 free(cl->public_key->key);
667 cl->public_key->length = k->len;
668 cl->public_key->expiry = k->expiry;
669 cl->public_key->key = xmalloc(k->len + 1);
670 strcpy(cl->public_key->key, &(k->key));
672 ek = make_shared_key(&(k->key));
675 cl->key = xmalloc(sizeof(enc_key_t));
680 cl->key->length = strlen(ek);
681 cl->key->expiry = k->expiry;
682 cl->key->key = xmalloc(strlen(ek) + 1);
683 strcpy(cl->key->key, ek);
687 int ans_key_h(conn_list_t *cl, unsigned char *d, int len)
689 key_req_t *tmp = (key_req_t*)d;
690 conn_list_t *fw, *gk;
693 syslog(LOG_DEBUG, "got ANS_KEY from " IP_ADDR_S " for " IP_ADDR_S,
694 IP_ADDR_V(tmp->from), IP_ADDR_V(tmp->to));
696 if(tmp->to == myself->vpn_ip)
697 { /* hey! that key's for ME! :) */
699 syslog(LOG_DEBUG, "Yeah! key arrived. Now do something with it.");
700 gk = lookup_conn(tmp->from);
704 syslog(LOG_ERR, "Receiving key from " IP_ADDR_S ", which does not exist?",
705 IP_ADDR_V(tmp->from));
710 gk->status.validkey = 1;
711 gk->status.waitingforkey = 0;
716 fw = lookup_conn(tmp->to);
720 syslog(LOG_ERR, "Attempting to forward key to " IP_ADDR_S ", which does not exist?",
726 syslog(LOG_DEBUG, "Forwarding public key to " IP_ADDR_S,
727 IP_ADDR_V(fw->nexthop->vpn_ip));
728 if(send(fw->nexthop->meta_socket, tmp, sizeof(key_req_t)+tmp->len, 0) < 0)
730 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
737 int key_changed_h(conn_list_t *cl, unsigned char *d, int len)
739 key_changed_t *tmp = (key_changed_t*)d;
743 syslog(LOG_DEBUG, "got KEY_CHANGED from " IP_ADDR_S,
744 IP_ADDR_V(tmp->from));
746 ik = lookup_conn(tmp->from);
750 syslog(LOG_ERR, "Got changed key from " IP_ADDR_S ", which does not exist?",
751 IP_ADDR_V(tmp->from));
755 ik->status.validkey = 0;
756 ik->status.waitingforkey = 0;
759 syslog(LOG_DEBUG, "Forwarding key invalidation request");
761 notify_others(cl, ik, send_key_changed);
766 int (*request_handlers[256])(conn_list_t*, unsigned char*, int) = {
767 0, ack_h, 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 termreq_h, timeout_h, del_host_h, 0, 0, 0, 0, 0, 0, 0,
771 ping_h, pong_h, 0, 0, 0, 0, 0, 0, 0, 0,
772 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
773 add_host_h, basic_info_h, passphrase_h, public_key_h, 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,
776 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
777 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
778 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
779 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
780 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
781 req_key_h, ans_key_h, key_changed_h, 0, 0, 0, 0, 0, 0, 0,
782 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
783 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
784 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
785 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
786 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0