X-Git-Url: https://www.tinc-vpn.org/git/browse?p=tinc;a=blobdiff_plain;f=src%2Fnet_setup.c;h=5b985c342c727da95b5d55b9748c19aff804b1b3;hp=623ac3838119d3947fe1c584a5cc68720a35b837;hb=a85864809febde02687b52dc2931ac4505f57067;hpb=eb372a8c58479857f02422109d9da4f937954c61 diff --git a/src/net_setup.c b/src/net_setup.c index 623ac383..5b985c34 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -1,7 +1,7 @@ /* net_setup.c -- Setup. Copyright (C) 1998-2005 Ivo Timmermans, - 2000-2013 Guus Sliepen + 2000-2016 Guus Sliepen 2006 Scott Lamb 2010 Brandon Black @@ -39,6 +39,7 @@ #include "netutl.h" #include "process.h" #include "protocol.h" +#include "proxy.h" #include "route.h" #include "subnet.h" #include "utils.h" @@ -47,17 +48,22 @@ char *myport; devops_t devops; -char *proxyhost; -char *proxyport; -char *proxyuser; -char *proxypass; -proxytype_t proxytype; +#ifndef HAVE_RSA_SET0_KEY +int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) { + BN_free(r->n); r->n = n; + BN_free(r->e); r->e = e; + BN_free(r->d); r->d = d; + return 1; +} +#endif bool read_rsa_public_key(connection_t *c) { FILE *fp; char *pubname; char *hcfname; char *key; + BIGNUM *n = NULL; + BIGNUM *e = NULL; if(!c->rsa_key) { c->rsa_key = RSA_new(); @@ -67,12 +73,19 @@ bool read_rsa_public_key(connection_t *c) { /* First, check for simple PublicKey statement */ if(get_config_string(lookup_config(c->config_tree, "PublicKey"), &key)) { - if(BN_hex2bn(&c->rsa_key->n, key) != strlen(key)) { + if(BN_hex2bn(&n, key) != strlen(key)) { + free(key); logger(LOG_ERR, "Invalid PublicKey for %s!", c->name); return false; } - BN_hex2bn(&c->rsa_key->e, "FFFF"); free(key); + BN_hex2bn(&e, "FFFF"); + if(!n || !e || RSA_set0_key(c->rsa_key, n, e, NULL) != 1) { + BN_free(e); + BN_free(n); + logger(LOG_ERR, "RSA_set0_key() failed with PublicKey for %s!", c->name); + return false; + } return true; } @@ -163,25 +176,39 @@ bool read_rsa_public_key(connection_t *c) { static bool read_rsa_private_key(void) { FILE *fp; char *fname, *key, *pubkey; + BIGNUM *n = NULL; + BIGNUM *e = NULL; + BIGNUM *d = NULL; if(get_config_string(lookup_config(config_tree, "PrivateKey"), &key)) { - if(!get_config_string(lookup_config(config_tree, "PublicKey"), &pubkey)) { - logger(LOG_ERR, "PrivateKey used but no PublicKey found!"); - return false; - } myself->connection->rsa_key = RSA_new(); // RSA_blinding_on(myself->connection->rsa_key, NULL); - if(BN_hex2bn(&myself->connection->rsa_key->d, key) != strlen(key)) { + if(BN_hex2bn(&d, key) != strlen(key)) { logger(LOG_ERR, "Invalid PrivateKey for myself!"); + free(key); return false; } - if(BN_hex2bn(&myself->connection->rsa_key->n, pubkey) != strlen(pubkey)) { + free(key); + if(!get_config_string(lookup_config(config_tree, "PublicKey"), &pubkey)) { + BN_free(d); + logger(LOG_ERR, "PrivateKey used but no PublicKey found!"); + return false; + } + if(BN_hex2bn(&n, pubkey) != strlen(pubkey)) { + free(pubkey); + BN_free(d); logger(LOG_ERR, "Invalid PublicKey for myself!"); return false; } - BN_hex2bn(&myself->connection->rsa_key->e, "FFFF"); - free(key); free(pubkey); + BN_hex2bn(&e, "FFFF"); + if(!n || !e || !d || RSA_set0_key(myself->connection->rsa_key, n, e, d) != 1) { + BN_free(d); + BN_free(e); + BN_free(n); + logger(LOG_ERR, "RSA_set0_key() failed with PrivateKey for myself!"); + return false; + } return true; } @@ -200,15 +227,12 @@ static bool read_rsa_private_key(void) { #if !defined(HAVE_MINGW) && !defined(HAVE_CYGWIN) struct stat s; - if(fstat(fileno(fp), &s)) { - logger(LOG_ERR, "Could not stat RSA private key file `%s': %s'", - fname, strerror(errno)); - free(fname); - return false; + if(!fstat(fileno(fp), &s)) { + if(s.st_mode & ~0100700) + logger(LOG_WARNING, "Warning: insecure file permissions for RSA private key file `%s'!", fname); + } else { + logger(LOG_WARNING, "Could not stat RSA private key file `%s': %s'", fname, strerror(errno)); } - - if(s.st_mode & ~0100700) - logger(LOG_WARNING, "Warning: insecure file permissions for RSA private key file `%s'!", fname); #endif myself->connection->rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL); @@ -295,17 +319,20 @@ char *get_name(void) { if(*name == '$') { char *envname = getenv(name + 1); + char hostname[32] = ""; if(!envname) { if(strcmp(name + 1, "HOST")) { fprintf(stderr, "Invalid Name: environment variable %s does not exist\n", name + 1); + free(name); return false; } - char envname[32]; - if(gethostname(envname, 32)) { + if(gethostname(hostname, sizeof hostname) || !*hostname) { fprintf(stderr, "Could not get hostname: %s\n", strerror(errno)); + free(name); return false; } - envname[31] = 0; + hostname[31] = 0; + envname = hostname; } free(name); name = xstrdup(envname); @@ -339,6 +366,7 @@ static bool setup_myself(void) { bool choice; int i, err; int replaywin_int; + bool port_specified = false; myself = new_node(); myself->connection = new_connection(); @@ -354,6 +382,8 @@ static bool setup_myself(void) { return false; } + /* Read tinc.conf and our own host config file */ + myself->name = name; myself->connection->name = xstrdup(name); xasprintf(&fname, "%s/hosts/%s", confbase, name); @@ -366,6 +396,10 @@ static bool setup_myself(void) { if(!get_config_string(lookup_config(config_tree, "Port"), &myport)) myport = xstrdup("655"); + else + port_specified = true; + + /* Ensure myport is numeric */ if(!atoi(myport)) { struct addrinfo *ai = str2addrinfo("localhost", myport, SOCK_DGRAM); @@ -377,8 +411,7 @@ static bool setup_myself(void) { sockaddr2str(&sa, NULL, &myport); } - get_config_string(lookup_config(config_tree, "Proxy"), &proxy); - if(proxy) { + if(get_config_string(lookup_config(config_tree, "Proxy"), &proxy)) { if((space = strchr(proxy, ' '))) *space++ = 0; @@ -396,6 +429,7 @@ static bool setup_myself(void) { proxytype = PROXY_EXEC; } else { logger(LOG_ERR, "Unknown proxy type %s!", proxy); + free(proxy); return false; } @@ -407,6 +441,7 @@ static bool setup_myself(void) { case PROXY_EXEC: if(!space || !*space) { logger(LOG_ERR, "Argument expected for proxy type exec!"); + free(proxy); return false; } proxyhost = xstrdup(space); @@ -425,6 +460,7 @@ static bool setup_myself(void) { *space++ = 0, proxypass = space; if(!proxyhost || !*proxyhost || !proxyport || !*proxyport) { logger(LOG_ERR, "Host and port argument expected for proxy!"); + free(proxy); return false; } proxyhost = xstrdup(proxyhost); @@ -478,6 +514,7 @@ static bool setup_myself(void) { routing_mode = RMODE_HUB; else { logger(LOG_ERR, "Invalid routing mode!"); + free(mode); return false; } free(mode); @@ -492,6 +529,7 @@ static bool setup_myself(void) { forwarding_mode = FMODE_KERNEL; else { logger(LOG_ERR, "Invalid forwarding mode!"); + free(mode); return false; } free(mode); @@ -518,6 +556,7 @@ static bool setup_myself(void) { broadcast_mode = BMODE_DIRECT; else { logger(LOG_ERR, "Invalid broadcast mode!"); + free(mode); return false; } free(mode); @@ -525,7 +564,12 @@ static bool setup_myself(void) { #if !defined(SOL_IP) || !defined(IP_TOS) if(priorityinheritance) - logger(LOG_WARNING, "%s not supported on this platform", "PriorityInheritance"); + logger(LOG_WARNING, "%s not supported on this platform for IPv4 connection", "PriorityInheritance"); +#endif + +#if !defined(IPPROTO_IPV6) || !defined(IPV6_TCLASS) + if(priorityinheritance) + logger(LOG_WARNING, "%s not supported on this platform for IPv6 connection", "PriorityInheritance"); #endif if(!get_config_int(lookup_config(config_tree, "MACExpire"), &macexpire)) @@ -539,6 +583,18 @@ static bool setup_myself(void) { } else maxtimeout = 900; + if(get_config_int(lookup_config(config_tree, "MinTimeout"), &mintimeout)) { + if(mintimeout < 0) { + logger(LOG_ERR, "Bogus minimum timeout!"); + return false; + } + if(mintimeout > maxtimeout) { + logger(LOG_WARNING, "Minimum timeout (%d s) cannot be larger than maximum timeout (%d s). Correcting !", mintimeout, maxtimeout ); + mintimeout=maxtimeout; + } + } else + mintimeout = 0; + if(get_config_int(lookup_config(config_tree, "UDPRcvBuf"), &udp_rcvbuf)) { if(udp_rcvbuf <= 0) { logger(LOG_ERR, "UDPRcvBuf cannot be negative!"); @@ -570,6 +626,7 @@ static bool setup_myself(void) { addressfamily = AF_UNSPEC; else { logger(LOG_ERR, "Invalid address family!"); + free(afname); return false; } free(afname); @@ -579,8 +636,7 @@ static bool setup_myself(void) { /* Generate packet encryption key */ - if(get_config_string - (lookup_config(config_tree, "Cipher"), &cipher)) { + if(get_config_string(lookup_config(config_tree, "Cipher"), &cipher)) { if(!strcasecmp(cipher, "none")) { myself->incipher = NULL; } else { @@ -588,18 +644,31 @@ static bool setup_myself(void) { if(!myself->incipher) { logger(LOG_ERR, "Unrecognized cipher type!"); + free(cipher); return false; } } + free(cipher); } else - myself->incipher = EVP_bf_cbc(); + myself->incipher = EVP_aes_256_cbc(); if(myself->incipher) - myself->inkeylength = myself->incipher->key_len + myself->incipher->iv_len; + myself->inkeylength = EVP_CIPHER_key_length(myself->incipher) + EVP_CIPHER_iv_length(myself->incipher); else myself->inkeylength = 1; - myself->connection->outcipher = EVP_bf_ofb(); + /* We need to use OFB mode for the meta protocol. Use AES for this, + but try to match the key size with the one from the cipher selected + by Cipher. + */ + + int keylen = EVP_CIPHER_key_length(myself->incipher); + if(keylen <= 16) + myself->connection->outcipher = EVP_aes_128_ofb(); + else if(keylen <= 24) + myself->connection->outcipher = EVP_aes_192_ofb(); + else + myself->connection->outcipher = EVP_aes_256_ofb(); if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime)) keylifetime = 3600; @@ -616,17 +685,20 @@ static bool setup_myself(void) { if(!myself->indigest) { logger(LOG_ERR, "Unrecognized digest type!"); + free(digest); return false; } } + + free(digest); } else - myself->indigest = EVP_sha1(); + myself->indigest = EVP_sha256(); - myself->connection->outdigest = EVP_sha1(); + myself->connection->outdigest = EVP_sha256(); if(get_config_int(lookup_config(config_tree, "MACLength"), &myself->inmaclength)) { if(myself->indigest) { - if(myself->inmaclength > myself->indigest->md_size) { + if(myself->inmaclength > EVP_MD_size(myself->indigest)) { logger(LOG_ERR, "MAC length exceeds size of digest!"); return false; } else if(myself->inmaclength < 0) { @@ -682,6 +754,7 @@ static bool setup_myself(void) { else if(!strcasecmp(type, "vde")) devops = vde_devops; #endif + free(type); } if(!devops.setup()) @@ -693,6 +766,12 @@ static bool setup_myself(void) { xasprintf(&envp[2], "INTERFACE=%s", iface ? : ""); xasprintf(&envp[3], "NAME=%s", myself->name); +#ifdef HAVE_MINGW + Sleep(1000); +#endif +#ifdef HAVE_CYGWIN + sleep(1); +#endif execute_script("tinc-up", envp); for(i = 0; i < 4; i++) @@ -770,6 +849,10 @@ static bool setup_myself(void) { hint.ai_protocol = IPPROTO_TCP; hint.ai_flags = AI_PASSIVE; +#if HAVE_DECL_RES_INIT + // ensure glibc reloads /etc/resolv.conf. + res_init(); +#endif err = getaddrinfo(address && *address ? address : NULL, port, &hint, &ai); free(address); @@ -811,13 +894,27 @@ static bool setup_myself(void) { } while(cfg); } - if(listen_sockets) - logger(LOG_NOTICE, "Ready"); - else { + if(!listen_sockets) { logger(LOG_ERR, "Unable to create any listening socket!"); return false; } + /* If no Port option was specified, set myport to the port used by the first listening socket. */ + + if(!port_specified) { + sockaddr_t sa; + socklen_t salen = sizeof sa; + if(!getsockname(listen_socket[0].udp, &sa.sa, &salen)) { + free(myport); + sockaddr2str(&sa, NULL, &myport); + if(!myport) + myport = xstrdup("655"); + } + } + + /* Done. */ + + logger(LOG_NOTICE, "Ready"); return true; }