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);
327 syslog(LOG_DEBUG, "Sending public key to " IP_ADDR_S,
328 IP_ADDR_V(fw->nexthop->vpn_ip));
329 if(send(fw->nexthop->meta_socket, tmp, sizeof(key_req_t)+tmp->len, 0) < 0)
331 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
339 notify all my direct connections of a new host
340 that was added to the vpn, with the exception
341 of the source of the announcement.
343 int notify_others(conn_list_t *new, conn_list_t *source,
344 int (*function)(conn_list_t*, conn_list_t*))
348 for(p = conn_list; p != NULL; p = p->next)
349 if(p != new && p != source && p->status.meta && p->protocol_version > PROT_3)
356 notify one connection of everything
359 int notify_one(conn_list_t *new)
363 for(p = conn_list; p != NULL; p = p->next)
364 if(p != new && p->protocol_version > PROT_3)
365 send_add_host(new, p);
371 The incoming request handlers
374 int basic_info_h(conn_list_t *cl, unsigned char *d, int len)
376 basic_info_t *tmp = (basic_info_t*)d;
378 cl->protocol_version = tmp->protocol;
379 cl->port = tmp->portnr;
380 cl->vpn_ip = tmp->vpn_ip;
381 cl->vpn_mask = tmp->vpn_mask;
383 if(cl->protocol_version < PROT_CURRENT)
385 syslog(LOG_ERR, "Peer uses protocol version %d which is too old.",
386 cl->protocol_version);
391 syslog(LOG_DEBUG, "got BASIC_INFO(%hd," IP_ADDR_S "," IP_ADDR_S ")", cl->port,
392 IP_ADDR_V(cl->vpn_ip), IP_ADDR_V(cl->vpn_mask));
394 syslog(LOG_DEBUG, "Peer uses protocol version %d",
395 cl->protocol_version);
397 if(cl->status.outgoing)
399 if(setup_vpn_connection(cl) < 0)
405 if(setup_vpn_connection(cl) < 0)
410 cl->status.active = 0;
415 int passphrase_h(conn_list_t *cl, unsigned char *d, int len)
417 passphrase_t *tmp = (passphrase_t*)d;
419 cl->pp = xmalloc(tmp->len+3);
420 memcpy(cl->pp, tmp, tmp->len+3);
423 syslog(LOG_DEBUG, "got PASSPHRASE(%hd,...)", cl->pp->len);
425 if(cl->status.outgoing)
433 int public_key_h(conn_list_t *cl, unsigned char *d, int len)
436 public_key_t *tmp = (public_key_t*)d;
439 syslog(LOG_DEBUG, "got PUBLIC_KEY(%hd,%s)", tmp->len, &tmp->key);
441 g_n = xmalloc(tmp->len+1);
442 strcpy(g_n, &tmp->key);
444 if(verify_passphrase(cl, g_n))
447 syslog(LOG_ERR, "Intruder: passphrase does not match.");
452 syslog(LOG_INFO, "Passphrase OK");
454 if(cl->status.outgoing)
459 cl->status.active = 1;
460 notify_others(cl, NULL, send_add_host);
466 int ack_h(conn_list_t *cl, unsigned char *d, int len)
469 syslog(LOG_DEBUG, "got ACK");
471 cl->status.active = 1;
472 syslog(LOG_NOTICE, "Connection with %s activated.", cl->hostname);
475 Now I'm going to cheat. The meta protocol is actually
476 a stream of requests, that may come in in the same TCP
477 packet. This is the only place that it will happen,
479 I may change it in the future, if it appears that this
482 if(len > 1) /* An ADD_HOST follows */
484 if(request_handlers[d[1]] == NULL)
485 syslog(LOG_ERR, "Unknown request %d.", d[1]);
486 if(request_handlers[d[1]](cl, d, len - 1) < 0)
493 int termreq_h(conn_list_t *cl, unsigned char *d, int len)
495 syslog(LOG_NOTICE, IP_ADDR_S " wants to quit", IP_ADDR_V(cl->vpn_ip));
496 cl->status.termreq = 1;
497 terminate_connection(cl);
499 notify_others(cl, NULL, send_del_host);
504 int timeout_h(conn_list_t *cl, unsigned char *d, int len)
506 syslog(LOG_NOTICE, IP_ADDR_S " says it's gotten a timeout from us", IP_ADDR_V(cl->vpn_ip));
507 cl->status.termreq = 1;
508 terminate_connection(cl);
513 int del_host_h(conn_list_t *cl, unsigned char *d, int len)
515 del_host_t *tmp = (del_host_t*)d;
519 syslog(LOG_DEBUG, "got DEL_HOST for " IP_ADDR_S,
520 IP_ADDR_V(tmp->vpn_ip));
522 if(!(fw = lookup_conn(tmp->vpn_ip)))
524 syslog(LOG_ERR, "Somebody wanted to delete " IP_ADDR_S " which does not exist?",
525 IP_ADDR_V(tmp->vpn_ip));
529 notify_others(cl, fw, send_del_host);
531 fw->status.termreq = 1;
532 terminate_connection(fw);
537 int ping_h(conn_list_t *cl, unsigned char *d, int len)
540 syslog(LOG_DEBUG, "responding to ping from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
541 cl->status.pinged = 0;
542 cl->status.got_pong = 1;
549 int pong_h(conn_list_t *cl, unsigned char *d, int len)
552 syslog(LOG_DEBUG, "ok, got pong from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
553 cl->status.got_pong = 1;
558 int add_host_h(conn_list_t *cl, unsigned char *d, int len)
560 add_host_t *tmp = (add_host_t*)d;
561 conn_list_t *ncn, *fw;
564 syslog(LOG_DEBUG, "Add host request from " IP_ADDR_S, IP_ADDR_V(cl->vpn_ip));
566 syslog(LOG_DEBUG, "got ADD_HOST(" IP_ADDR_S "," IP_ADDR_S ",%hd)",
567 IP_ADDR_V(tmp->vpn_ip), IP_ADDR_V(tmp->vpn_mask), tmp->portnr);
570 Suggestion of Hans Bayle
572 if((fw = lookup_conn(tmp->vpn_ip)))
574 notify_others(fw, cl, send_add_host);
578 ncn = new_conn_list();
579 ncn->real_ip = tmp->real_ip;
580 ncn->vpn_ip = tmp->vpn_ip;
581 ncn->vpn_mask = tmp->vpn_mask;
582 ncn->port = tmp->portnr;
583 ncn->hostname = hostlookup(tmp->real_ip);
585 ncn->next = conn_list;
587 ncn->status.active = 1;
588 notify_others(ncn, cl, send_add_host);
591 again, i'm cheating here. see the comment in ack_h.
593 if(len > sizeof(add_host_t)) /* Another ADD_HOST follows */
595 if(request_handlers[d[sizeof(add_host_t)]] == NULL)
596 syslog(LOG_ERR, "Unknown request %d.", d[sizeof(add_host_t)]);
597 if(request_handlers[d[sizeof(add_host_t)]](cl, d, len - sizeof(add_host_t)) < 0)
604 int req_key_h(conn_list_t *cl, unsigned char *d, int len)
606 key_req_t *tmp = (key_req_t*)d;
610 syslog(LOG_DEBUG, "got REQ_KEY from " IP_ADDR_S " for " IP_ADDR_S,
611 IP_ADDR_V(tmp->from), IP_ADDR_V(tmp->to));
613 if((tmp->to & myself->vpn_mask) == (myself->vpn_ip & myself->vpn_mask))
614 { /* hey! they want something from ME! :) */
615 send_key_answer(cl, tmp->from);
619 fw = lookup_conn(tmp->to);
621 syslog(LOG_DEBUG, "Forwarding request for public key to " IP_ADDR_S,
622 IP_ADDR_V(fw->nexthop->vpn_ip));
623 if(send(fw->nexthop->meta_socket, tmp, sizeof(key_req_t), 0) < 0)
625 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
632 void set_keys(conn_list_t *cl, key_req_t *k)
638 cl->public_key = xmalloc(sizeof(enc_key_t));
639 cl->public_key->key = NULL;
641 if(cl->public_key->key)
642 free(cl->public_key->key);
643 cl->public_key->length = k->len;
644 cl->public_key->expiry = k->expiry;
645 cl->public_key->key = xmalloc(k->len + 1);
646 strcpy(cl->public_key->key, &(k->key));
648 ek = make_shared_key(&(k->key));
651 cl->key = xmalloc(sizeof(enc_key_t));
656 cl->key->length = strlen(ek);
657 cl->key->expiry = k->expiry;
658 cl->key->key = xmalloc(strlen(ek) + 1);
659 strcpy(cl->key->key, ek);
662 int ans_key_h(conn_list_t *cl, unsigned char *d, int len)
664 key_req_t *tmp = (key_req_t*)d;
665 conn_list_t *fw, *gk;
668 syslog(LOG_DEBUG, "got ANS_KEY from " IP_ADDR_S " for " IP_ADDR_S,
669 IP_ADDR_V(tmp->from), IP_ADDR_V(tmp->to));
671 if(tmp->to == myself->vpn_ip)
672 { /* hey! that key's for ME! :) */
674 syslog(LOG_DEBUG, "Yeah! key arrived. Now do something with it.");
675 gk = lookup_conn(tmp->from);
677 gk->status.validkey = 1;
678 gk->status.waitingforkey = 0;
683 fw = lookup_conn(tmp->to);
685 syslog(LOG_DEBUG, "Forwarding public key to " IP_ADDR_S,
686 IP_ADDR_V(fw->nexthop->vpn_ip));
687 if(send(fw->nexthop->meta_socket, tmp, sizeof(key_req_t)+tmp->len, 0) < 0)
689 syslog(LOG_ERR, "send failed: %s:%d: %m", __FILE__, __LINE__);
696 int key_changed_h(conn_list_t *cl, unsigned char *d, int len)
698 key_changed_t *tmp = (key_changed_t*)d;
702 syslog(LOG_DEBUG, "got KEY_CHANGED from " IP_ADDR_S,
703 IP_ADDR_V(tmp->from));
705 ik = lookup_conn(tmp->from);
706 ik->status.validkey = 0;
707 ik->status.waitingforkey = 0;
710 syslog(LOG_DEBUG, "Forwarding key invalidation request");
712 notify_others(cl, ik, send_key_changed);
717 int (*request_handlers[256])(conn_list_t*, unsigned char*, int) = {
718 0, ack_h, 0, 0, 0, 0, 0, 0, 0, 0,
719 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
720 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
721 termreq_h, timeout_h, del_host_h, 0, 0, 0, 0, 0, 0, 0,
722 ping_h, pong_h, 0, 0, 0, 0, 0, 0, 0, 0,
723 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
724 add_host_h, basic_info_h, passphrase_h, public_key_h, 0, 0, 0, 0, 0, 0,
725 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
726 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
727 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
728 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
729 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
730 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
731 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
732 req_key_h, ans_key_h, key_changed_h, 0, 0, 0, 0, 0, 0, 0,
733 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
734 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
735 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
736 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
737 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0