2 protocol.c -- handle the meta-protocol
3 Copyright (C) 1999,2000 Ivo Timmermans <itimmermans@bigfoot.com>,
4 2000 Guus Sliepen <guus@sliepen.warande.net>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 $Id: protocol.c,v 1.28.4.41 2000/10/16 16:33:30 guus Exp $
25 #include <sys/types.h>
30 #include <sys/socket.h>
37 #include <netinet/in.h>
39 #include <openssl/sha.h>
50 int check_id(char *id)
54 for (i = 0; i < strlen(id); i++)
55 if(!isalnum(id[i]) && id[i] != '_')
61 /* Generic request routines - takes care of logging and error detection as well */
63 int send_request(conn_list_t *cl, const char *format, ...)
66 char buffer[MAXBUFSIZE];
70 /* Use vsnprintf instead of vasprintf: faster, no memory fragmentation, cleanup is automatic,
71 and there is a limit on the input buffer anyway */
73 va_start(args, format);
74 len = vsnprintf(buffer, MAXBUFSIZE, format, args);
75 request = va_arg(args, int);
78 if(len < 0 || len > MAXBUFSIZE-1)
80 syslog(LOG_ERR, _("Output buffer overflow while sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
86 if(debug_lvl >= DEBUG_PROTOCOL)
87 syslog(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
90 return send_meta(cl, buffer, len);
93 int receive_request(conn_list_t *cl)
97 if(sscanf(cl->buffer, "%d", &request) == 1)
99 if((request < 0) || (request > 255) || (request_handlers[request] == NULL))
101 syslog(LOG_ERR, _("Unknown request from %s (%s)"),
102 cl->name, cl->hostname);
107 if(debug_lvl > DEBUG_PROTOCOL)
108 syslog(LOG_DEBUG, _("Got %s from %s (%s)"),
109 request_name[request], cl->name, cl->hostname);
111 if(request_handlers[request](cl))
112 /* Something went wrong. Probably scriptkiddies. Terminate. */
114 syslog(LOG_ERR, _("Error while processing %s from %s (%s)"),
115 request_name[request], cl->name, cl->hostname);
121 syslog(LOG_ERR, _("Bogus data received from %s (%s)"),
122 cl->name, cl->hostname);
127 /* Connection protocol:
136 ---------------------------------------
137 Any negotations about the meta protocol
138 encryption go here(u).
139 ---------------------------------------
142 ---------------------------------------
148 (E) Encrypted with symmetric cipher.
150 Part of the challenge is directly used to set the symmetric cipher key and the initial vector.
151 Since a man-in-the-middle cannot decrypt the RSA challenges, this means that he cannot get or
152 forge the key for the symmetric cipher.
155 int send_id(conn_list_t *cl)
158 cl->allow_request = CHALLENGE;
160 return send_request(cl, "%d %s %d %lx", ID, myself->name, myself->protocol_version, myself->options);
163 int id_h(conn_list_t *cl)
167 if(sscanf(cl->buffer, "%*d %as %d %lx", &cl->name, &cl->protocol_version, &cl->options) != 3)
169 syslog(LOG_ERR, _("Got bad ID from %s"), cl->hostname);
173 /* Check if version matches */
175 if(cl->protocol_version != myself->protocol_version)
177 syslog(LOG_ERR, _("Peer %s (%s) uses incompatible version %d"),
178 cl->name, cl->hostname, cl->protocol_version);
182 /* Check if identity is a valid name */
184 if(check_id(cl->name))
186 syslog(LOG_ERR, _("Peer %s uses invalid identity name"), cl->hostname);
190 /* Load information about peer */
192 if(read_host_config(cl))
194 syslog(LOG_ERR, _("Peer %s had unknown identity (%s)"), cl->hostname, cl->name);
199 /* First check if the host we connected to is already in our
200 connection list. If so, we are probably making a loop, which
204 if(cl->status.outgoing)
206 if((old = lookup_id(cl->name)))
209 if(debug_lvl > DEBUG_CONNECTIONS)
210 syslog(LOG_NOTICE, _("Uplink %s (%s) is already in our connection list"), cl->name, cl->hostname);
211 cl->status.outgoing = 0;
212 old->status.outgoing = 1;
213 terminate_connection(cl);
218 return send_challenge(cl);
221 int send_challenge(conn_list_t *cl)
223 char buffer[CHAL_LENGTH*2+1];
225 /* Allocate buffers for the challenge */
227 if(!cl->hischallenge)
228 cl->hischallenge = xmalloc(CHAL_LENGTH);
230 /* Copy random data to the buffer */
232 RAND_bytes(cl->hischallenge, CHAL_LENGTH);
234 /* Convert the random data to a hexadecimal formatted string */
236 bin2hex(cl->hischallenge, buffer, CHAL_LENGTH);
237 buffer[CHAL_LENGTH*2] = '\0';
239 /* Send the challenge */
241 cl->allow_request = CHAL_REPLY;
243 return send_request(cl, "%d %s", CHALLENGE, buffer);
246 int challenge_h(conn_list_t *cl)
250 if(sscanf(cl->buffer, "%*d %as", &buffer) != 1)
252 syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
256 /* Check if the length of the challenge is all right */
258 if(strlen(buffer) != CHAL_LENGTH*2)
260 syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
265 /* Allocate buffers for the challenge */
268 cl->mychallenge = xmalloc(CHAL_LENGTH);
270 /* Convert the challenge from hexadecimal back to binary */
272 hex2bin(buffer,cl->mychallenge,CHAL_LENGTH);
275 /* Rest is done by send_chal_reply() */
277 return send_chal_reply(cl);
280 int send_chal_reply(conn_list_t *cl)
282 char hash[SHA_DIGEST_LENGTH*2+1];
286 syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
290 /* Calculate the hash from the challenge we received */
292 SHA1(cl->mychallenge, CHAL_LENGTH, hash);
294 /* Convert the hash to a hexadecimal formatted string */
296 bin2hex(hash,hash,SHA_DIGEST_LENGTH);
297 hash[SHA_DIGEST_LENGTH*2] = '\0';
301 if(cl->status.outgoing)
302 cl->allow_request = ID;
304 cl->allow_request = ACK;
307 return send_request(cl, "%d %s", CHAL_REPLY, hash);
310 int chal_reply_h(conn_list_t *cl)
313 char myhash[SHA_DIGEST_LENGTH];
315 if(sscanf(cl->buffer, "%*d %as", &hishash) != 1)
317 syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
322 /* Check if the length of the hash is all right */
324 if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
326 syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
331 /* Convert the hash to binary format */
333 hex2bin(hishash, hishash, SHA_DIGEST_LENGTH);
335 /* Calculate the hash from the challenge we sent */
337 SHA1(cl->hischallenge, CHAL_LENGTH, myhash);
339 /* Verify the incoming hash with the calculated hash */
341 if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
343 syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
350 /* Identity has now been positively verified.
351 If we are accepting this new connection, then send our identity,
352 if we are making this connecting, acknowledge.
355 if(cl->status.outgoing)
361 int send_ack(conn_list_t *cl)
364 cl->allow_request = ACK;
366 return send_request(cl, "%d", ACK);
369 int ack_h(conn_list_t *cl)
373 /* Okay, before we active the connection, we check if there is another entry
374 in the connection list with the same name. If so, it presumably is an
375 old connection that has timed out but we don't know it yet.
378 while((old = lookup_id(cl->name)))
380 if(debug_lvl > DEBUG_CONNECTIONS)
381 syslog(LOG_NOTICE, _("Removing old entry for %s at %s in favour of new connection from %s"),
382 cl->name, old->hostname, cl->hostname);
383 old->status.active = 0;
384 terminate_connection(old);
387 /* Activate this connection */
389 cl->allow_request = ALL;
390 cl->status.active = 1;
392 if(debug_lvl > DEBUG_CONNECTIONS)
393 syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname);
395 /* Exchange information about other tinc daemons */
397 /* FIXME: reprogram this.
398 notify_others(cl, NULL, send_add_host);
404 if(cl->status.outgoing)
410 /* Address and subnet information exchange */
412 int send_add_subnet(conn_list_t *cl, conn_list_t *other, subnet_t *subnet)
417 x = send_request(cl, "%d %s %s", ADD_SUBNET,
418 other->name, netstr = net2str(subnet));
424 int add_subnet_h(conn_list_t *cl)
429 subnet_t *subnet, *old;
431 if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
433 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
434 free(name); free(subnetstr);
438 /* Check if owner name is a valid */
442 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
443 free(name); free(subnetstr);
447 /* Check if subnet string is valid */
449 if(!(subnet = str2net(subnetstr)))
451 syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
452 free(name); free(subnetstr);
458 /* Check if somebody tries to add a subnet of ourself */
460 if(!strcmp(name, myself->name))
462 syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
463 cl->name, cl->hostname);
469 /* Check if the owner of the new subnet is in the connection list */
471 if(!(owner = lookup_id(name)))
473 syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
474 name, cl->name, cl->hostname);
479 /* If everything is correct, add the subnet to the list of the owner */
481 subnet_add(owner, subnet);
486 int send_del_subnet(conn_list_t *cl, conn_list_t *other, subnet_t *subnet)
489 return send_request(cl, "%d %s %s", DEL_SUBNET, other->name, net2str(subnet));
492 int del_subnet_h(conn_list_t *cl)
497 subnet_t *subnet, *old;
499 if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
501 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
502 free(name); free(subnetstr);
506 /* Check if owner name is a valid */
510 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
511 free(name); free(subnetstr);
515 /* Check if subnet string is valid */
517 if(!(subnet = str2net(subnetstr)))
519 syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
520 free(name); free(subnetstr);
526 /* Check if somebody tries to add a subnet of ourself */
528 if(!strcmp(name, myself->name))
530 syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
531 cl->name, cl->hostname);
537 /* Check if the owner of the new subnet is in the connection list */
539 if(!(owner = lookup_id(name)))
541 syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
542 name, cl->name, cl->hostname);
547 /* If everything is correct, delete the subnet from the list of the owner */
554 /* New and closed connections notification */
556 int send_add_host(conn_list_t *cl, conn_list_t *other)
559 return send_request(cl, "%d %s %s %lx:%d %lx", ADD_HOST,
560 myself->name, other->name, other->address, other->port, other->options);
563 int add_host_h(conn_list_t *cl)
566 conn_list_t *old, *new, *hisuplink;
568 new = new_conn_list();
570 if(sscanf(cl->buffer, "%*d %as %as %lx:%d %lx", &sender, &new->name, &new->address, &new->port, &new->options) != 5)
572 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
576 /* Check if identity is a valid name */
578 if(check_id(new->name) || check_id(sender))
580 syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
585 /* Check if somebody tries to add ourself */
587 if(!strcmp(new->name, myself->name))
589 syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
595 /* We got an ADD_HOST from ourself!? */
597 if(!strcmp(sender, myself->name))
599 syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) from ourself, restarting"), cl->name, cl->hostname);
605 /* Lookup his uplink */
607 if(!(new->hisuplink = lookup_id(sender)))
609 syslog(LOG_ERR, _("Got ADD_HOST from %s (%s) with origin %s which is not in our connection list"),
610 sender, cl->name, cl->hostname);
617 /* Fill in more of the new conn_list structure */
619 new->hostname = hostlookup(htonl(new->address));
621 /* Check if the new host already exists in the connnection list */
623 if((old = lookup_id(new->name)))
625 if((new->address == old->address) && (new->port == old->port))
627 if(debug_lvl > DEBUG_CONNECTIONS)
628 syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
629 old->name, old->hostname, new->name, new->hostname);
634 if(debug_lvl > DEBUG_CONNECTIONS)
635 syslog(LOG_NOTICE, _("Removing old entry for %s (%s)"),
636 old->name, old->hostname);
637 old->status.active = 0;
638 terminate_connection(old);
642 /* Fill in rest of conn_list structure */
645 new->status.active = 1;
647 /* Hook it up into the conn_list */
649 conn_list_add(conn_list, new);
651 /* Tell the rest about the new host */
652 /* FIXME: reprogram this.
653 notify_others(new, cl, send_add_host);
659 int send_del_host(conn_list_t *cl, conn_list_t *other)
662 return send_request(cl, "%d %s %s %lx:%d %lx", DEL_HOST,
663 myself->name, other->name, other->address, other->port, other->options);
666 int del_host_h(conn_list_t *cl)
673 conn_list_t *old, *hisuplink;
676 if(sscanf(cl->buffer, "%*d %as %as %lx:%d %lx", &sender, &name, &address, &port, &options) != 5)
678 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
679 cl->name, cl->hostname);
683 /* Check if identity is a valid name */
685 if(check_id(name) || check_id(sender))
687 syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
688 free(name); free(sender);
692 /* Check if somebody tries to delete ourself */
694 if(!strcmp(name, myself->name))
696 syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
697 cl->name, cl->hostname);
698 free(name); free(sender);
703 /* We got an ADD_HOST from ourself!? */
705 if(!strcmp(sender, myself->name))
707 syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) from ourself, restarting"), cl->name, cl->hostname);
709 free(name); free(sender);
713 /* Lookup his uplink */
715 if(!(hisuplink = lookup_id(sender)))
717 syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) with origin %s which is not in our connection list"),
718 cl->name, cl->hostname, sender);
719 free(name); free(sender);
725 /* Check if the new host already exists in the connnection list */
727 if(!(old = lookup_id(name)))
729 syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
730 name, cl->name, cl->hostname);
735 /* Check if the rest matches */
737 if(address!=old->address || port!=old->port || options!=old->options || hisuplink!=old->hisuplink || cl!=old->myuplink)
739 syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
743 /* Ok, since EVERYTHING seems to check out all right, delete it */
745 old->status.termreq = 1;
746 old->status.active = 0;
748 terminate_connection(old);
753 /* Status and error notification routines */
755 int send_status(conn_list_t *cl, int statusno, char *statusstring)
759 statusstring = status_text[statusno];
761 return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
764 int status_h(conn_list_t *cl)
769 if(sscanf(cl->buffer, "%*d %d %as", &statusno, &statusstring) != 2)
771 syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
772 cl->name, cl->hostname);
776 if(debug_lvl > DEBUG_STATUS)
778 syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
779 cl->name, cl->hostname, status_text[statusno], statusstring);
787 int send_error(conn_list_t *cl, int errno, char *errstring)
791 errstring = strerror(errno);
792 return send_request(cl, "%d %d %s", ERROR, errno, errstring);
795 int error_h(conn_list_t *cl)
800 if(sscanf(cl->buffer, "%*d %d %as", &errno, &errorstring) != 2)
802 syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
803 cl->name, cl->hostname);
807 if(debug_lvl > DEBUG_ERROR)
809 syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
810 cl->name, cl->hostname, strerror(errno), errorstring);
814 cl->status.termreq = 1;
815 terminate_connection(cl);
820 int send_termreq(conn_list_t *cl)
823 return send_request(cl, "%d", TERMREQ);
826 int termreq_h(conn_list_t *cl)
829 cl->status.termreq = 1;
830 terminate_connection(cl);
835 /* Keepalive routines - FIXME: needs a closer look */
837 int send_ping(conn_list_t *cl)
839 cl->status.pinged = 1;
841 return send_request(cl, "%d", PING);
844 int ping_h(conn_list_t *cl)
847 return send_pong(cl);
850 int send_pong(conn_list_t *cl)
853 return send_request(cl, "%d", PONG);
856 int pong_h(conn_list_t *cl)
859 cl->status.got_pong = 1;
866 int send_key_changed(conn_list_t *from, conn_list_t *cl)
870 for(p = conn_list; p != NULL; p = p->next)
872 if(p!=cl && p->status.meta && p->status.active)
873 send_request(p, "%d %s", KEY_CHANGED,
880 int key_changed_h(conn_list_t *cl)
885 if(sscanf(cl->buffer, "%*d %as", &from_id) != 1)
887 syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
888 cl->name, cl->hostname);
892 if(!(from = lookup_id(from_id)))
894 syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
895 cl->name, cl->hostname, from_id);
902 from->status.validkey = 0;
903 from->status.waitingforkey = 0;
905 send_key_changed(from, cl);
910 int send_req_key(conn_list_t *from, conn_list_t *to)
913 return send_request(to->nexthop, "%d %s %s", REQ_KEY,
914 from->name, to->name);
917 int req_key_h(conn_list_t *cl)
919 char *from_id, *to_id;
920 conn_list_t *from, *to;
922 if(sscanf(cl->buffer, "%*d %as %as", &from_id, &to_id) != 2)
924 syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
925 cl->name, cl->hostname);
929 if(!(from = lookup_id(from_id)))
931 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
932 cl->name, cl->hostname, from_id);
933 free(from_id); free(to_id);
937 /* Check if this key request is for us */
939 if(!strcmp(to_id, myself->name))
941 send_ans_key(myself, from, myself->cipher_pktkey);
945 if(!(to = lookup_id(to_id)))
947 syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
948 cl->name, cl->hostname, to_id);
949 free(from_id); free(to_id);
952 send_req_key(from, to);
955 free(from_id); free(to_id);
960 int send_ans_key(conn_list_t *from, conn_list_t *to, char *pktkey)
963 return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
964 from->name, to->name, pktkey);
967 int ans_key_h(conn_list_t *cl)
969 char *from_id, *to_id, *pktkey;
971 conn_list_t *from, *to;
973 if(sscanf(cl->buffer, "%*d %as %as %as", &from_id, &to_id, &pktkey) != 3)
975 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
976 cl->name, cl->hostname);
980 if(!(from = lookup_id(from_id)))
982 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
983 cl->name, cl->hostname, from_id);
984 free(from_id); free(to_id); free(pktkey);
988 /* Check if this key request is for us */
990 if(!strcmp(to_id, myself->name))
992 /* It is for us, convert it to binary and set the key with it. */
994 keylength = strlen(pktkey);
996 if((keylength%2) || (keylength <= 0))
998 syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key"),
999 cl->name, cl->hostname, from->name);
1000 free(from_id); free(to_id); free(pktkey);
1004 hex2bin(pktkey, pktkey, keylength);
1005 BF_set_key(cl->cipher_pktkey, keylength, pktkey);
1009 if(!(to = lookup_id(to_id)))
1011 syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1012 cl->name, cl->hostname, to_id);
1013 free(from_id); free(to_id); free(pktkey);
1016 send_ans_key(from, to, pktkey);
1019 free(from_id); free(to_id); free(pktkey);
1024 /* Jumptable for the request handlers */
1026 int (*request_handlers[])(conn_list_t*) = {
1027 id_h, challenge_h, chal_reply_h, ack_h,
1028 status_h, error_h, termreq_h,
1030 add_host_h, del_host_h,
1031 add_subnet_h, del_subnet_h,
1032 key_changed_h, req_key_h, ans_key_h,
1037 char (*request_name[]) = {
1038 "ID", "CHALLENGE", "CHAL_REPLY", "ACK",
1039 "STATUS", "ERROR", "TERMREQ",
1041 "ADD_HOST", "DEL_HOST",
1042 "ADD_SUBNET", "DEL_SUBNET",
1043 "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1046 /* Status strings */
1048 char (*status_text[]) = {
1054 char (*error_text[]) = {