X-Git-Url: https://tinc-vpn.org/git/browse?p=tinc;a=blobdiff_plain;f=src%2Fnet.c;h=5c59c6fa5e11abf11063f8be58d077b3c9d73d50;hp=18e5951bf2be5a98651b37a743d0827aaa69f7f8;hb=4fa12eb85d72f039df5004abc201f01f5573c2e4;hpb=447a43d63960802a7a29201c512246be11eb9c94 diff --git a/src/net.c b/src/net.c index 18e5951b..5c59c6fa 100644 --- a/src/net.c +++ b/src/net.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: net.c,v 1.35.4.92 2001/01/07 20:19:29 guus Exp $ + $Id: net.c,v 1.35.4.100 2001/02/27 16:37:25 guus Exp $ */ #include "config.h" @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include #include @@ -112,7 +114,7 @@ int xsend(connection_t *cl, vpn_packet_t *inpkt) cp outpkt.len = inpkt->len; - /* Encrypt the packet. FIXME: we should use CBC, not CFB. */ + /* Encrypt the packet. */ EVP_EncryptInit(&ctx, cl->cipher_pkttype, cl->cipher_pktkey, cl->cipher_pktkey + cl->cipher_pkttype->key_len); EVP_EncryptUpdate(&ctx, outpkt.data, &outlen, inpkt->data, inpkt->len); @@ -202,6 +204,7 @@ int send_packet(ip_t to, vpn_packet_t *packet) { connection_t *cl; subnet_t *subnet; + vpn_packet_t *copy; cp if((subnet = lookup_subnet_ipv4(&to)) == NULL) { @@ -242,7 +245,13 @@ cp syslog(LOG_INFO, _("No valid key known yet for %s (%s), queueing packet"), cl->name, cl->hostname); - list_insert_tail(cl->queue, packet); + /* Since packet is on the stack of handle_tap_input(), + we have to make a copy of it first. */ + + copy = xmalloc(sizeof(vpn_packet_t)); + memcpy(copy, packet, sizeof(vpn_packet_t)); + + list_insert_tail(cl->queue, copy); if(!cl->status.waitingforkey) send_req_key(myself, cl); /* Keys should be sent to the host running the tincd */ @@ -260,7 +269,7 @@ cp void flush_queue(connection_t *cl) { list_node_t *node, *next; - +cp if(debug_lvl >= DEBUG_TRAFFIC) syslog(LOG_INFO, _("Flushing queue for %s (%s)"), cl->name, cl->hostname); @@ -270,6 +279,7 @@ void flush_queue(connection_t *cl) xsend(cl, (vpn_packet_t *)node->data); list_delete_node(cl->queue, node); } +cp } /* @@ -357,7 +367,7 @@ int setup_listen_meta_socket(int port) { int nfd, flags; struct sockaddr_in a; - const int one = 1; + int option; config_t const *cfg; cp if((nfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) @@ -366,22 +376,6 @@ cp return -1; } - if(setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) - { - close(nfd); - syslog(LOG_ERR, _("System call `%s' failed: %m"), - "setsockopt"); - return -1; - } - - if(setsockopt(nfd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one))) - { - close(nfd); - syslog(LOG_ERR, _("System call `%s' failed: %m"), - "setsockopt"); - return -1; - } - flags = fcntl(nfd, F_GETFL); if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) { @@ -391,9 +385,19 @@ cp return -1; } + /* Optimize TCP settings */ + + option = 1; + setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option)); + setsockopt(nfd, SOL_SOCKET, SO_KEEPALIVE, &option, sizeof(option)); + setsockopt(nfd, SOL_TCP, TCP_NODELAY, &option, sizeof(option)); + + option = IPTOS_LOWDELAY; + setsockopt(nfd, SOL_IP, IP_TOS, &option, sizeof(option)); + if((cfg = get_config_val(config, config_interface))) { - if(setsockopt(nfd, SOL_SOCKET, SO_KEEPALIVE, cfg->data.ptr, strlen(cfg->data.ptr))) + if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, cfg->data.ptr, strlen(cfg->data.ptr))) { close(nfd); syslog(LOG_ERR, _("Unable to bind listen socket to interface %s: %m"), cfg->data.ptr); @@ -445,13 +449,7 @@ cp return -1; } - if(setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) - { - close(nfd); - syslog(LOG_ERR, _("System call `%s' failed: %m"), - "setsockopt"); - return -1; - } + setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); flags = fcntl(nfd, F_GETFL); if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) @@ -485,6 +483,7 @@ int setup_outgoing_meta_socket(connection_t *cl) int flags; struct sockaddr_in a; config_t const *cfg; + int option; cp if(debug_lvl >= DEBUG_CONNECTIONS) syslog(LOG_INFO, _("Trying to connect to %s"), cl->hostname); @@ -514,6 +513,17 @@ cp syslog(LOG_ERR, _("System call `%s' failed: %m"), "bind"); return -1; } + + /* Optimize TCP settings */ + + option = 1; + setsockopt(cl->meta_socket, SOL_SOCKET, SO_KEEPALIVE, &option, sizeof(option)); + setsockopt(cl->meta_socket, SOL_TCP, TCP_NODELAY, &option, sizeof(option)); + + option = IPTOS_LOWDELAY; + setsockopt(cl->meta_socket, SOL_IP, IP_TOS, &option, sizeof(option)); + + /* Connect */ a.sin_family = AF_INET; a.sin_port = htons(cl->port); @@ -610,17 +620,24 @@ int read_rsa_public_key(connection_t *cl) { config_t const *cfg; FILE *fp; + char *fname; void *result; cp if(!cl->rsa_key) cl->rsa_key = RSA_new(); + /* First, check for simple PublicKey statement */ + if((cfg = get_config_val(cl->config, config_publickey))) { BN_hex2bn(&cl->rsa_key->n, cfg->data.ptr); BN_hex2bn(&cl->rsa_key->e, "FFFF"); + return 0; } - else if((cfg = get_config_val(cl->config, config_publickeyfile))) + + /* Else, check for PublicKeyFile statement and read it */ + + if((cfg = get_config_val(cl->config, config_publickeyfile))) { if(is_safe_path(cfg->data.ptr)) { @@ -638,17 +655,31 @@ cp cfg->data.ptr); return -1; } + return 0; } else return -1; } - else + + /* Else, check if a harnessed public key is in the config file */ + + asprintf(&fname, "%s/hosts/%s", confbase, cl->name); + if((fp = fopen(fname, "r"))) { - syslog(LOG_ERR, _("No public key for %s specified!"), cl->name); - return -1; + result = PEM_read_RSAPublicKey(fp, &cl->rsa_key, NULL, NULL); + fclose(fp); + free(fname); + if(result) + return 0; } + + free(fname); + + /* Nothing worked. */ + + syslog(LOG_ERR, _("No public key for %s specified!"), cl->name); cp - return 0; + return -1; } int read_rsa_private_key(void) @@ -787,7 +818,7 @@ cp cp /* Generate packet encryption key */ - myself->cipher_pkttype = EVP_bf_cfb(); + myself->cipher_pkttype = EVP_bf_cbc(); myself->cipher_pktkeylength = myself->cipher_pkttype->key_len + myself->cipher_pkttype->iv_len; @@ -940,82 +971,6 @@ cp return; } -/* - create a data (udp) socket - OBSOLETED: use only one listening socket for compatibility with non-Linux operating systems -*/ -int setup_vpn_connection(connection_t *cl) -{ - int nfd, flags; - struct sockaddr_in a; - const int one = 1; -cp - if(debug_lvl >= DEBUG_TRAFFIC) - syslog(LOG_DEBUG, _("Opening UDP socket to %s"), cl->hostname); - - nfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if(nfd == -1) - { - syslog(LOG_ERR, _("Creating UDP socket failed: %m")); - return -1; - } - - if(setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) - { - close(nfd); - syslog(LOG_ERR, _("System call `%s' failed: %m"), - "setsockopt"); - return -1; - } - - flags = fcntl(nfd, F_GETFL); - if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) - { - close(nfd); - syslog(LOG_ERR, _("System call `%s' failed: %m"), - "fcntl"); - return -1; - } - - memset(&a, 0, sizeof(a)); - a.sin_family = AF_INET; - a.sin_port = htons(myself->port); - a.sin_addr.s_addr = htonl(INADDR_ANY); - - if(bind(nfd, (struct sockaddr *)&a, sizeof(struct sockaddr))) - { - close(nfd); - syslog(LOG_ERR, _("Can't bind to port %hd/udp: %m"), myself->port); - return -1; - } - - a.sin_family = AF_INET; - a.sin_port = htons(cl->port); - a.sin_addr.s_addr = htonl(cl->address); - - if(connect(nfd, (struct sockaddr *)&a, sizeof(a)) == -1) - { - close(nfd); - syslog(LOG_ERR, _("Connecting to %s port %d failed: %m"), - cl->hostname, cl->port); - return -1; - } - - flags = fcntl(nfd, F_GETFL); - if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) - { - close(nfd); - syslog(LOG_ERR, _("This is a bug: %s:%d: %d:%m %s (%s)"), __FILE__, __LINE__, nfd, - cl->name, cl->hostname); - return -1; - } - - cl->socket = nfd; - cl->status.dataopen = 1; -cp - return 0; -} - /* handle an incoming tcp connect call and open a connection to it. @@ -1032,6 +987,7 @@ cp { syslog(LOG_ERR, _("System call `%s' failed: %m"), "getpeername"); + close(sfd); return NULL; } @@ -1141,37 +1097,40 @@ cp if(cl->status.remove) return; - cl->status.remove = 1; - if(debug_lvl >= DEBUG_CONNECTIONS) syslog(LOG_NOTICE, _("Closing connection with %s (%s)"), cl->name, cl->hostname); + cl->status.remove = 1; + if(cl->socket) close(cl->socket); if(cl->status.meta) close(cl->meta_socket); - /* Find all connections that were lost because they were behind cl - (the connection that was dropped). */ - if(cl->status.meta) - for(node = connection_tree->head; node; node = node->next) - { - p = (connection_t *)node->data; - if(p->nexthop == cl && p != cl) - terminate_connection(p); - } + { + + /* Find all connections that were lost because they were behind cl + (the connection that was dropped). */ - /* Inform others of termination if it was still active */ + for(node = connection_tree->head; node; node = node->next) + { + p = (connection_t *)node->data; + if(p->nexthop == cl && p != cl) + terminate_connection(p); + } - if(cl->status.active) - for(node = connection_tree->head; node; node = node->next) - { - p = (connection_t *)node->data; - if(p->status.meta && p->status.active && p!=cl) - send_del_host(p, cl); /* Sounds like recursion, but p does not have a meta connection :) */ - } + /* Inform others of termination if it was still active */ + + if(cl->status.active) + for(node = connection_tree->head; node; node = node->next) + { + p = (connection_t *)node->data; + if(p->status.meta && p->status.active && p != cl) + send_del_host(p, cl); /* Sounds like recursion, but p does not have a meta connection :) */ + } + } /* Remove the associated subnets */ @@ -1184,8 +1143,9 @@ cp /* Check if this was our outgoing connection */ - if(cl->status.outgoing && cl->status.active) + if(cl->status.outgoing) { + cl->status.outgoing = 0; signal(SIGALRM, sigalrm_handler); seconds_till_retry = 5; alarm(seconds_till_retry); @@ -1264,6 +1224,8 @@ cp } connection_add(ncn); + + send_id(ncn); cp return 0; }