X-Git-Url: https://www.tinc-vpn.org/git/browse?a=blobdiff_plain;f=src%2Fnet_setup.c;h=3ac5a6796fd5c453f2527078395fee0db9fa3160;hb=4436af55e55e79b496264fe114039fbc1198d71f;hp=d2adc13f32a1b220527bdce4a1a4c495c848d2c3;hpb=bcac314fe2d758e85335d499dbb4300bfa8a599e;p=tinc diff --git a/src/net_setup.c b/src/net_setup.c index d2adc13f..3ac5a679 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -28,6 +28,7 @@ #include "connection.h" #include "compression.h" #include "control.h" +#include "crypto.h" #include "device.h" #include "digest.h" #include "ecdsa.h" @@ -44,12 +45,13 @@ #include "utils.h" #include "xalloc.h" #include "keys.h" +#include "sandbox.h" #ifdef HAVE_MINIUPNPC #include "upnp.h" #endif -char *myport; +ports_t myport; static io_t device_io; devops_t devops; bool device_standby = false; @@ -142,7 +144,7 @@ static timeout_t keyexpire_timeout; static void keyexpire_handler(void *data) { regenerate_key(); timeout_set(data, &(struct timeval) { - keylifetime, rand() % 100000 + keylifetime, jitter() }); } #endif @@ -229,11 +231,25 @@ char *get_name(void) { return returned_name; } -bool setup_myself_reloadable(void) { - free(scriptinterpreter); - scriptinterpreter = NULL; +static void read_interpreter(void) { + char *interpreter = NULL; + get_config_string(lookup_config(&config_tree, "ScriptsInterpreter"), &interpreter); + + if(!interpreter || (sandbox_can(START_PROCESSES, AFTER_SANDBOX) && sandbox_can(USE_NEW_PATHS, AFTER_SANDBOX))) { + free(scriptinterpreter); + scriptinterpreter = interpreter; + return; + } + + if(!string_eq(interpreter, scriptinterpreter)) { + logger(DEBUG_ALWAYS, LOG_NOTICE, "Not changing ScriptsInterpreter because of sandbox."); + } - get_config_string(lookup_config(&config_tree, "ScriptsInterpreter"), &scriptinterpreter); + free(interpreter); +} + +bool setup_myself_reloadable(void) { + read_interpreter(); free(scriptextension); @@ -263,10 +279,15 @@ bool setup_myself_reloadable(void) { } else if(!strcasecmp(proxy, "http")) { proxytype = PROXY_HTTP; } else if(!strcasecmp(proxy, "exec")) { - proxytype = PROXY_EXEC; + if(sandbox_can(START_PROCESSES, AFTER_SANDBOX)) { + proxytype = PROXY_EXEC; + } else { + logger(DEBUG_ALWAYS, LOG_ERR, "Cannot use exec proxies with current sandbox level."); + return false; + } } else { logger(DEBUG_ALWAYS, LOG_ERR, "Unknown proxy type %s!", proxy); - free(proxy); + free_string(proxy); return false; } @@ -276,10 +297,10 @@ bool setup_myself_reloadable(void) { free(proxyport); proxyport = NULL; - free(proxyuser); + free_string(proxyuser); proxyuser = NULL; - free(proxypass); + free_string(proxypass); proxypass = NULL; switch(proxytype) { @@ -290,10 +311,14 @@ bool setup_myself_reloadable(void) { case PROXY_EXEC: if(!space || !*space) { logger(DEBUG_ALWAYS, LOG_ERR, "Argument expected for proxy type exec!"); - free(proxy); + free_string(proxy); return false; } + if(!sandbox_can(USE_NEW_PATHS, AFTER_SANDBOX)) { + logger(DEBUG_ALWAYS, LOG_NOTICE, "Changed exec proxy may fail to work because of sandbox."); + } + proxyhost = xstrdup(space); break; @@ -311,7 +336,7 @@ bool setup_myself_reloadable(void) { logger(DEBUG_ALWAYS, LOG_ERR, "Host and port argument expected for proxy!"); proxyport = NULL; proxyhost = NULL; - free(proxy); + free_string(proxy); return false; } @@ -337,7 +362,7 @@ bool setup_myself_reloadable(void) { break; } - free(proxy); + free_string(proxy); } bool choice; @@ -534,11 +559,70 @@ bool setup_myself_reloadable(void) { return true; } +// Get the port that `from_fd` is listening on, and assign it to +// `sa` if `sa` has a dynamically allocated (zero) port. +static bool assign_static_port(sockaddr_t *sa, int from_fd) { + // We cannot get a port from a bad FD. Bail out. + if(from_fd <= 0) { + return false; + } + + int port = get_bound_port(from_fd); + + if(!port) { + return false; + } + + // If the port is non-zero, don't reassign it as it's already static. + switch(sa->sa.sa_family) { + case AF_INET: + if(!sa->in.sin_port) { + sa->in.sin_port = htons(port); + } + + return true; + + case AF_INET6: + if(!sa->in6.sin6_port) { + sa->in6.sin6_port = htons(port); + } + + return true; + + default: + logger(DEBUG_ALWAYS, LOG_ERR, "Unknown address family 0x%x", sa->sa.sa_family); + return false; + } +} + +typedef int (*bind_fn_t)(const sockaddr_t *); + +static int bind_reusing_port(const sockaddr_t *sa, int from_fd, bind_fn_t setup) { + sockaddr_t reuse_sa; + memcpy(&reuse_sa, sa, SALEN(sa->sa)); + + int fd = -1; + + // Check if the address we've been passed here is using port 0. + // If it is, try to get an actual port from an already bound socket, and reuse it here. + if(assign_static_port(&reuse_sa, from_fd)) { + fd = setup(&reuse_sa); + } + + // If we're binding to a hardcoded non-zero port, or no socket is listening yet, + // or binding failed, try the original address. + if(fd < 0) { + fd = setup(sa); + } + + return fd; +} + /* Add listening sockets. */ static bool add_listen_address(char *address, bool bindto) { - char *port = myport; + char *port = myport.tcp; if(address) { char *space = strchr(address, ' '); @@ -596,30 +680,45 @@ static bool add_listen_address(char *address, bool bindto) { return false; } - int tcp_fd = setup_listen_socket((sockaddr_t *) aip->ai_addr); + const sockaddr_t *sa = (sockaddr_t *) aip->ai_addr; + int from_fd = listen_socket[0].tcp.fd; + + // If we're binding to a dynamically allocated (zero) port, try to get the actual + // port of the first TCP socket, and use it for this one. If that succeeds, our + // tincd instance will use the same port for all addresses it listens on. + int tcp_fd = bind_reusing_port(sa, from_fd, setup_listen_socket); if(tcp_fd < 0) { continue; } - int udp_fd = setup_vpn_in_socket((sockaddr_t *) aip->ai_addr); + // If we just successfully bound the first socket, use it for the UDP procedure below. + // Otherwise, keep using the socket we've obtained from listen_socket[0]. + if(!from_fd) { + from_fd = tcp_fd; + } + + int udp_fd = bind_reusing_port(sa, from_fd, setup_vpn_in_socket); if(udp_fd < 0) { - close(tcp_fd); + closesocket(tcp_fd); continue; } - io_add(&listen_socket[listen_sockets].tcp, handle_new_meta_connection, &listen_socket[listen_sockets], tcp_fd, IO_READ); - io_add(&listen_socket[listen_sockets].udp, handle_incoming_vpn_data, &listen_socket[listen_sockets], udp_fd, IO_READ); + listen_socket_t *sock = &listen_socket[listen_sockets]; + io_add(&sock->tcp, handle_new_meta_connection, sock, tcp_fd, IO_READ); + io_add(&sock->udp, handle_incoming_vpn_data, sock, udp_fd, IO_READ); if(debug_level >= DEBUG_CONNECTIONS) { - char *hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr); - logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Listening on %s", hostname); + int tcp_port = get_bound_port(tcp_fd); + char *hostname = NULL; + sockaddr2str(sa, &hostname, NULL); + logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Listening on %s port %d", hostname, tcp_port); free(hostname); } - listen_socket[listen_sockets].bindto = bindto; - memcpy(&listen_socket[listen_sockets].sa, aip->ai_addr, aip->ai_addrlen); + sock->bindto = bindto; + memcpy(&sock->sa, aip->ai_addr, aip->ai_addrlen); listen_sockets++; } @@ -655,7 +754,7 @@ void device_disable(void) { Configure node_t myself and set up the local sockets (listen only) */ static bool setup_myself(void) { - char *name, *hostname, *type; + char *name, *type; char *address = NULL; bool port_specified = false; @@ -671,12 +770,14 @@ static bool setup_myself(void) { myself->connection->name = xstrdup(name); read_host_config(&config_tree, name, true); - if(!get_config_string(lookup_config(&config_tree, "Port"), &myport)) { - myport = xstrdup("655"); + if(!get_config_string(lookup_config(&config_tree, "Port"), &myport.tcp)) { + myport.tcp = xstrdup("655"); } else { port_specified = true; } + myport.udp = xstrdup(myport.tcp); + myself->connection->options = 0; myself->connection->protocol_major = PROT_MAJOR; myself->connection->protocol_minor = PROT_MINOR; @@ -711,9 +812,11 @@ static bool setup_myself(void) { } } - myself->connection->rsa = read_rsa_private_key(&config_tree, NULL); + rsa_t *rsa = read_rsa_private_key(&config_tree, NULL); - if(!myself->connection->rsa) { + if(rsa) { + myself->connection->legacy = new_legacy_ctx(rsa); + } else { if(experimental) { logger(DEBUG_ALWAYS, LOG_WARNING, "Support for legacy protocol disabled."); } else { @@ -725,19 +828,18 @@ static bool setup_myself(void) { #endif /* Ensure myport is numeric */ + if(!is_decimal(myport.tcp)) { + uint16_t port = service_to_port(myport.tcp); - if(!atoi(myport)) { - struct addrinfo *ai = str2addrinfo("localhost", myport, SOCK_DGRAM); - sockaddr_t sa; - - if(!ai || !ai->ai_addr) { + if(!port) { return false; } - free(myport); - memcpy(&sa, ai->ai_addr, ai->ai_addrlen); - freeaddrinfo(ai); - sockaddr2str(&sa, NULL, &myport); + free(myport.tcp); + myport.tcp = int_to_str(port); + + free(myport.udp); + myport.udp = xstrdup(myport.tcp); } /* Read in all the subnets specified in the host configuration file */ @@ -825,7 +927,8 @@ static bool setup_myself(void) { if(!cipher_open_by_name(myself->incipher, cipher)) { logger(DEBUG_ALWAYS, LOG_ERR, "Unrecognized cipher type!"); - cipher_free(&myself->incipher); + cipher_free(myself->incipher); + myself->incipher = NULL; free(cipher); return false; } @@ -834,7 +937,7 @@ static bool setup_myself(void) { free(cipher); timeout_add(&keyexpire_timeout, keyexpire_handler, &keyexpire_timeout, &(struct timeval) { - keylifetime, rand() % 100000 + keylifetime, jitter() }); /* Check if we want to use message authentication codes... */ @@ -860,7 +963,8 @@ static bool setup_myself(void) { if(!digest_open_by_name(myself->indigest, digest, maclength)) { logger(DEBUG_ALWAYS, LOG_ERR, "Unrecognized digest type!"); - digest_free(&myself->indigest); + digest_free(myself->indigest); + myself->indigest = NULL; free(digest); return false; } @@ -870,7 +974,11 @@ static bool setup_myself(void) { #endif /* Compression */ - if(get_config_int(lookup_config(&config_tree, "Compression"), &myself->incompression)) { + int incompression = 0; + + if(get_config_int(lookup_config(&config_tree, "Compression"), &incompression)) { + myself->incompression = incompression; + switch(myself->incompression) { case COMPRESS_LZ4: #ifdef HAVE_LZ4 @@ -920,8 +1028,6 @@ static bool setup_myself(void) { myself->incompression = COMPRESS_NONE; } - myself->connection->outcompression = COMPRESS_NONE; - /* Done */ myself->nexthop = myself; @@ -940,7 +1046,7 @@ static bool setup_myself(void) { devops = os_devops; if(get_config_string(lookup_config(&config_tree, "DeviceType"), &type)) { - if(!strcasecmp(type, "dummy")) { + if(!strcasecmp(type, DEVICE_DUMMY)) { devops = dummy_devops; } else if(!strcasecmp(type, "raw_socket")) { devops = raw_socket_devops; @@ -996,15 +1102,16 @@ static bool setup_myself(void) { } for(int i = 0; i < listen_sockets; i++) { + const int tcp_fd = i + 3; salen = sizeof(sa); - if(getsockname(i + 3, &sa.sa, &salen) < 0) { - logger(DEBUG_ALWAYS, LOG_ERR, "Could not get address of listen fd %d: %s", i + 3, sockstrerror(sockerrno)); + if(getsockname(tcp_fd, &sa.sa, &salen) < 0) { + logger(DEBUG_ALWAYS, LOG_ERR, "Could not get address of listen fd %d: %s", tcp_fd, sockstrerror(sockerrno)); return false; } #ifdef FD_CLOEXEC - fcntl(i + 3, F_SETFD, FD_CLOEXEC); + fcntl(tcp_fd, F_SETFD, FD_CLOEXEC); #endif int udp_fd = setup_vpn_in_socket(&sa); @@ -1013,11 +1120,11 @@ static bool setup_myself(void) { return false; } - io_add(&listen_socket[i].tcp, (io_cb_t)handle_new_meta_connection, &listen_socket[i], i + 3, IO_READ); + io_add(&listen_socket[i].tcp, (io_cb_t)handle_new_meta_connection, &listen_socket[i], tcp_fd, IO_READ); io_add(&listen_socket[i].udp, (io_cb_t)handle_incoming_vpn_data, &listen_socket[i], udp_fd, IO_READ); if(debug_level >= DEBUG_CONNECTIONS) { - hostname = sockaddr2hostname(&sa); + char *hostname = sockaddr2hostname(&sa); logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Listening on %s", hostname); free(hostname); } @@ -1059,21 +1166,19 @@ static bool setup_myself(void) { /* If no Port option was specified, set myport to the port used by the first listening socket. */ - if(!port_specified || atoi(myport) == 0) { - sockaddr_t sa; - socklen_t salen = sizeof(sa); + if(!port_specified || atoi(myport.tcp) == 0) { + listen_socket_t *sock = &listen_socket[0]; - if(!getsockname(listen_socket[0].udp.fd, &sa.sa, &salen)) { - free(myport); - sockaddr2str(&sa, NULL, &myport); + uint16_t tcp = get_bound_port(sock->tcp.fd); + free(myport.tcp); + myport.tcp = int_to_str(tcp); - if(!myport) { - myport = xstrdup("655"); - } - } + uint16_t udp = get_bound_port(sock->udp.fd); + free(myport.udp); + myport.udp = int_to_str(udp); } - xasprintf(&myself->hostname, "MYSELF port %s", myport); + xasprintf(&myself->hostname, "MYSELF port %s", myport.tcp); myself->connection->hostname = xstrdup(myself->hostname); char *upnp = NULL; @@ -1179,8 +1284,8 @@ void close_network_connections(void) { for(int i = 0; i < listen_sockets; i++) { io_del(&listen_socket[i].tcp); io_del(&listen_socket[i].udp); - close(listen_socket[i].tcp.fd); - close(listen_socket[i].udp.fd); + closesocket(listen_socket[i].tcp.fd); + closesocket(listen_socket[i].udp.fd); } exit_requests(); @@ -1193,7 +1298,8 @@ void close_network_connections(void) { device_disable(); } - free(myport); + free(myport.tcp); + free(myport.udp); if(device_fd >= 0) { io_del(&device_io);