X-Git-Url: https://tinc-vpn.org/git/browse?p=tinc;a=blobdiff_plain;f=src%2Fprotocol.c;h=625c7094115d1924ef845168b31e5f2fcbdb2aeb;hp=bdb78c2b41d1cfa864923714a45927d66a23cfc7;hb=156ec676525ed789364b7a77926dd0717d0cf5d7;hpb=34b7a876c3583f7a34585cff6a694bc9e35cdc87 diff --git a/src/protocol.c b/src/protocol.c index bdb78c2b..625c7094 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: protocol.c,v 1.28.4.82 2001/02/26 11:37:20 guus Exp $ + $Id: protocol.c,v 1.28.4.86 2001/03/13 21:33:31 guus Exp $ */ #include "config.h" @@ -119,7 +119,7 @@ int receive_request(connection_t *cl) cp if(sscanf(cl->buffer, "%d", &request) == 1) { - if((request < 0) || (request > 255) || (request_handlers[request] == NULL)) + if((request < 0) || (request >= LAST) || (request_handlers[request] == NULL)) { syslog(LOG_ERR, _("Unknown request from %s (%s)"), cl->name, cl->hostname); @@ -271,6 +271,89 @@ cp return send_metakey(cl); } +int ack_h(connection_t *cl) +{ + config_t const *cfg; + connection_t *old, *p; + subnet_t *subnet; + avl_node_t *node, *node2; +cp + /* Okay, before we active the connection, we check if there is another entry + in the connection list with the same name. If so, it presumably is an + old connection that has timed out but we don't know it yet. + */ + + while((old = lookup_id(cl->name))) + { + if(debug_lvl >= DEBUG_CONNECTIONS) + syslog(LOG_NOTICE, _("Removing old entry for %s at %s in favour of new connection from %s"), + cl->name, old->hostname, cl->hostname); + + terminate_connection(old); + } + + /* Activate this connection */ + + cl->allow_request = ALL; + cl->status.active = 1; + cl->nexthop = cl; + cl->cipher_pkttype = EVP_bf_cbc(); + cl->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len; + + if(debug_lvl >= DEBUG_CONNECTIONS) + syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname); + +cp + /* Check some options */ + + if((cfg = get_config_val(cl->config, config_indirectdata))) + { + if(cfg->data.val == stupid_true) + cl->options |= OPTION_INDIRECT; + } + + if((cfg = get_config_val(cl->config, config_tcponly))) + { + if(cfg->data.val == stupid_true) + cl->options |= OPTION_TCPONLY; + } + + /* Send him our subnets */ + + for(node = myself->subnet_tree->head; node; node = node->next) + { + subnet = (subnet_t *)node->data; + send_add_subnet(cl, subnet); + } + + /* And send him all the hosts and their subnets we know... */ + + for(node = connection_tree->head; node; node = node->next) + { + p = (connection_t *)node->data; + + if(p != cl && p->status.active) + { + /* Notify others of this connection */ + + if(p->status.meta) + send_add_host(p, cl); + + /* Notify new connection of everything we know */ + + send_add_host(cl, p); + + for(node2 = p->subnet_tree->head; node2; node2 = node2->next) + { + subnet = (subnet_t *)node2->data; + send_add_subnet(cl, subnet); + } + } + } +cp + return 0; +} + int send_challenge(connection_t *cl) { char *buffer; @@ -439,7 +522,17 @@ cp RAND_bytes(cl->cipher_outkey, len); - cl->cipher_outkey[0] &= 0x0F; /* Make sure that the random data is smaller than the modulus of the RSA key */ + /* The message we send must be smaller than the modulus of the RSA key. + By definition, for a key of k bits, the following formula holds: + + 2^(k-1) <= modulus < 2^(k) + + Where ^ means "to the power of", not "xor". + This means that to be sure, we must choose our message < 2^(k-1). + This can be done by setting the most significant bit to zero. + */ + + cl->cipher_outkey[0] &= 0x7F; if(debug_lvl >= DEBUG_SCARY_THINGS) { @@ -448,9 +541,14 @@ cp syslog(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"), buffer); } - /* Encrypt the random data */ + /* Encrypt the random data + + We do not use one of the PKCS padding schemes here. + This is allowed, because we encrypt a totally random string + with a length equal to that of the modulus of the RSA key. + */ - if(RSA_public_encrypt(len, cl->cipher_outkey, buffer, cl->rsa_key, RSA_NO_PADDING) != len) /* NO_PADDING because the message size equals the RSA key size and it is totally random */ + if(RSA_public_encrypt(len, cl->cipher_outkey, buffer, cl->rsa_key, RSA_NO_PADDING) != len) { syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), cl->name, cl->hostname); free(buffer); @@ -539,88 +637,6 @@ cp return send_challenge(cl); } -int ack_h(connection_t *cl) -{ - config_t const *cfg; - connection_t *old, *p; - subnet_t *subnet; - avl_node_t *node, *node2; -cp - /* Okay, before we active the connection, we check if there is another entry - in the connection list with the same name. If so, it presumably is an - old connection that has timed out but we don't know it yet. - */ - - while((old = lookup_id(cl->name))) - { - if(debug_lvl >= DEBUG_CONNECTIONS) - syslog(LOG_NOTICE, _("Removing old entry for %s at %s in favour of new connection from %s"), - cl->name, old->hostname, cl->hostname); - - terminate_connection(old); - } - - /* Activate this connection */ - - cl->allow_request = ALL; - cl->status.active = 1; - cl->nexthop = cl; - cl->cipher_pkttype = EVP_bf_cbc(); - cl->cipher_pktkeylength = cl->cipher_pkttype->key_len + cl->cipher_pkttype->iv_len; - - if(debug_lvl >= DEBUG_CONNECTIONS) - syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname); - -cp - /* Check some options */ - - if((cfg = get_config_val(cl->config, config_indirectdata))) - { - if(cfg->data.val == stupid_true) - cl->options |= OPTION_INDIRECT; - } - - if((cfg = get_config_val(cl->config, config_tcponly))) - { - if(cfg->data.val == stupid_true) - cl->options |= OPTION_TCPONLY; - } - - /* Send him our subnets */ - - for(node = myself->subnet_tree->head; node; node = node->next) - { - subnet = (subnet_t *)node->data; - send_add_subnet(cl, subnet); - } - /* And send him all the hosts and their subnets we know... */ - - for(node = connection_tree->head; node; node = node->next) - { - p = (connection_t *)node->data; - - if(p != cl && p->status.active) - { - /* Notify others of this connection */ - - if(p->status.meta) - send_add_host(p, cl); - - /* Notify new connection of everything we know */ - - send_add_host(cl, p); - - for(node2 = p->subnet_tree->head; node2; node2 = node2->next) - { - subnet = (subnet_t *)node2->data; - send_add_subnet(cl, subnet); - } - } - } -cp - return 0; -} - /* Address and subnet information exchange */ int send_add_subnet(connection_t *cl, subnet_t *subnet) @@ -629,7 +645,7 @@ int send_add_subnet(connection_t *cl, subnet_t *subnet) char *netstr; char *owner; cp - if(cl->options & OPTION_INDIRECT) + if((cl->options | myself->options | subnet->owner->options) & OPTION_INDIRECT) owner = myself->name; else owner = subnet->owner->name; @@ -795,9 +811,11 @@ cp int send_add_host(connection_t *cl, connection_t *other) { cp - if(!(cl->options & OPTION_INDIRECT)) + if(!((cl->options | myself->options | other->options) & OPTION_INDIRECT)) return send_request(cl, "%d %s %lx:%d %lx", ADD_HOST, other->name, other->address, other->port, other->options); + else + return 0; } int add_host_h(connection_t *cl) @@ -808,7 +826,7 @@ int add_host_h(connection_t *cl) cp new = new_connection(); - if(sscanf(cl->buffer, "%*d "MAX_STRING" %lx:%d %lx", name, &new->address, &new->port, &new->options) != 4) + if(sscanf(cl->buffer, "%*d "MAX_STRING" %lx:%hd %lx", name, &new->address, &new->port, &new->options) != 4) { syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname); return -1; @@ -887,9 +905,11 @@ cp int send_del_host(connection_t *cl, connection_t *other) { cp - if(!(cl->options & OPTION_INDIRECT)) + if(!((cl->options | myself->options) & OPTION_INDIRECT)) return send_request(cl, "%d %s %lx:%d %lx", DEL_HOST, other->name, other->address, other->port, other->options); + else + return 0; } int del_host_h(connection_t *cl) @@ -901,7 +921,7 @@ int del_host_h(connection_t *cl) connection_t *old, *p; avl_node_t *node; cp - if(sscanf(cl->buffer, "%*d "MAX_STRING" %lx:%d %lx", name, &address, &port, &options) != 4) + if(sscanf(cl->buffer, "%*d "MAX_STRING" %lx:%hd %lx", name, &address, &port, &options) != 4) { syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"), cl->name, cl->hostname); @@ -1107,7 +1127,8 @@ cp from->status.validkey = 0; from->status.waitingforkey = 0; - send_key_changed(from, cl); + if(!(from->options | cl->options | myself->options) & OPTION_INDIRECT) + send_key_changed(from, cl); cp return 0; } @@ -1245,7 +1266,7 @@ cp int send_tcppacket(connection_t *cl, vpn_packet_t *packet) { int x; - +cp x = send_request(cl->nexthop, "%d %hd", PACKET, packet->len); if(x) @@ -1259,8 +1280,8 @@ int tcppacket_h(connection_t *cl) vpn_packet_t packet; char *p; int todo, x; - - if(sscanf(cl->buffer, "%*d %hd", packet.len) != 1) +cp + if(sscanf(cl->buffer, "%*d %hd", &packet.len) != 1) { syslog(LOG_ERR, _("Got bad PACKET from %s (%s)"), cl->name, cl->hostname); return -1; @@ -1270,7 +1291,7 @@ int tcppacket_h(connection_t *cl) p = packet.data; todo = packet.len; - + while(todo) { x = read(cl->meta_socket, p, todo); @@ -1280,7 +1301,7 @@ int tcppacket_h(connection_t *cl) if(x==0) syslog(LOG_NOTICE, _("Connection closed by %s (%s)"), cl->name, cl->hostname); else - if(errno==EINTR) + if(errno==EINTR || errno==EAGAIN) /* FIXME: select() or poll() or reimplement this evil hack */ continue; else syslog(LOG_ERR, _("Error during reception of PACKET from %s (%s): %m"), cl->name, cl->hostname); @@ -1292,7 +1313,9 @@ int tcppacket_h(connection_t *cl) p += x; } - return receive_packet(cl, &packet); + receive_packet(cl, &packet); +cp + return 0; } /* Jumptable for the request handlers */