X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=src%2Fnet_setup.c;h=9cbdeb2691409f1c23c7221f0e9bf4af3d5b9b83;hb=4c57e6902219ecca1872e18e34365d8e54a0f407;hp=1b091db04034bd1a343390f508752d89de571b6a;hpb=a97a07d79c847d0b30c61a2589e7bde62f25d603;p=meshlink diff --git a/src/net_setup.c b/src/net_setup.c index 1b091db0..9cbdeb26 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -301,25 +301,121 @@ static bool load_node(meshlink_handle_t *mesh, const char *name, void *priv) { return true; } -/* - Add listening sockets. -*/ -static bool add_listen_address(meshlink_handle_t *mesh, char *address, bool bindto) { - char *port = mesh->myport; +int setup_tcp_listen_socket(meshlink_handle_t *mesh, const struct addrinfo *aip) { + int nfd = socket(aip->ai_family, SOCK_STREAM, IPPROTO_TCP); + + if(nfd == -1) { + return -1; + } - if(address) { - char *space = strchr(address, ' '); +#ifdef FD_CLOEXEC + fcntl(nfd, F_SETFD, FD_CLOEXEC); +#endif - if(space) { - *space++ = 0; - port = space; - } + int option = 1; + setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option)); - if(!strcmp(address, "*")) { - *address = 0; - } +#if defined(IPV6_V6ONLY) + + if(aip->ai_family == AF_INET6) { + setsockopt(nfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&option, sizeof(option)); } +#else +#warning IPV6_V6ONLY not defined +#endif + + if(bind(nfd, aip->ai_addr, aip->ai_addrlen)) { + closesocket(nfd); + return -1; + } + + if(listen(nfd, 3)) { + logger(mesh, MESHLINK_ERROR, "System call `%s' failed: %s", "listen", sockstrerror(sockerrno)); + closesocket(nfd); + return -1; + } + + return nfd; +} + +int setup_udp_listen_socket(meshlink_handle_t *mesh, const struct addrinfo *aip) { + int nfd = socket(aip->ai_family, SOCK_DGRAM, IPPROTO_UDP); + + if(nfd == -1) { + return -1; + } + +#ifdef FD_CLOEXEC + fcntl(nfd, F_SETFD, FD_CLOEXEC); +#endif + +#ifdef O_NONBLOCK + int flags = fcntl(nfd, F_GETFL); + + if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) { + closesocket(nfd); + logger(mesh, MESHLINK_ERROR, "System call `%s' failed: %s", "fcntl", strerror(errno)); + return -1; + } + +#elif defined(WIN32) + unsigned long arg = 1; + + if(ioctlsocket(nfd, FIONBIO, &arg) != 0) { + closesocket(nfd); + logger(mesh, MESHLINK_ERROR, "Call to `%s' failed: %s", "ioctlsocket", sockstrerror(sockerrno)); + return -1; + } + +#endif + + int option = 1; + setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option)); + setsockopt(nfd, SOL_SOCKET, SO_BROADCAST, (void *)&option, sizeof(option)); + +#if defined(IPV6_V6ONLY) + + if(aip->ai_family == AF_INET6) { + setsockopt(nfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&option, sizeof(option)); + } + +#endif + +#if defined(IP_DONTFRAG) && !defined(IP_DONTFRAGMENT) +#define IP_DONTFRAGMENT IP_DONTFRAG +#endif + +#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO) + option = IP_PMTUDISC_DO; + setsockopt(nfd, IPPROTO_IP, IP_MTU_DISCOVER, (void *)&option, sizeof(option)); +#elif defined(IP_DONTFRAGMENT) + option = 1; + setsockopt(nfd, IPPROTO_IP, IP_DONTFRAGMENT, (void *)&option, sizeof(option)); +#endif + + if(aip->ai_family == AF_INET6) { +#if defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO) + option = IPV6_PMTUDISC_DO; + setsockopt(nfd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, (void *)&option, sizeof(option)); +#elif defined(IPV6_DONTFRAG) + option = 1; + setsockopt(nfd, IPPROTO_IPV6, IPV6_DONTFRAG, (void *)&option, sizeof(option)); +#endif + } + + if(bind(nfd, aip->ai_addr, aip->ai_addrlen)) { + closesocket(nfd); + return -1; + } + + return nfd; +} + +/* + Add listening sockets. +*/ +static bool add_listen_sockets(meshlink_handle_t *mesh) { struct addrinfo *ai; struct addrinfo hint = { @@ -329,9 +425,7 @@ static bool add_listen_address(meshlink_handle_t *mesh, char *address, bool bind .ai_flags = AI_PASSIVE, }; - int err = getaddrinfo(address && *address ? address : NULL, port, &hint, &ai); - - free(address); + int err = getaddrinfo(NULL, mesh->myport, &hint, &ai); if(err || !ai) { logger(mesh, MESHLINK_ERROR, "System call `%s' failed: %s", "getaddrinfo", err == EAI_SYSTEM ? strerror(err) : gai_strerror(err)); @@ -344,11 +438,12 @@ static bool add_listen_address(meshlink_handle_t *mesh, char *address, bool bind // Ignore duplicate addresses bool found = false; - for(int i = 0; i < mesh->listen_sockets; i++) + for(int i = 0; i < mesh->listen_sockets; i++) { if(!memcmp(&mesh->listen_socket[i].sa, aip->ai_addr, aip->ai_addrlen)) { found = true; break; } + } if(found) { continue; @@ -359,29 +454,39 @@ static bool add_listen_address(meshlink_handle_t *mesh, char *address, bool bind return false; } - int tcp_fd = setup_listen_socket((sockaddr_t *) aip->ai_addr); + /* Try to bind to TCP */ - if(tcp_fd < 0) { - continue; + int tcp_fd = setup_tcp_listen_socket(mesh, aip); + + if(tcp_fd == -1) { + if(errno == EADDRINUSE) { + /* If this port is in use for any address family, avoid it. */ + success = false; + break; + } else { + continue; + } } - int udp_fd = setup_vpn_in_socket(mesh, (sockaddr_t *) aip->ai_addr); + /* If TCP worked, then we require that UDP works as well. */ - if(udp_fd < 0) { - close(tcp_fd); - continue; + int udp_fd = setup_udp_listen_socket(mesh, aip); + + if(udp_fd == -1) { + closesocket(tcp_fd); + success = false; + break; } io_add(&mesh->loop, &mesh->listen_socket[mesh->listen_sockets].tcp, handle_new_meta_connection, &mesh->listen_socket[mesh->listen_sockets], tcp_fd, IO_READ); io_add(&mesh->loop, &mesh->listen_socket[mesh->listen_sockets].udp, handle_incoming_vpn_data, &mesh->listen_socket[mesh->listen_sockets], udp_fd, IO_READ); - if(mesh->log_level >= MESHLINK_INFO) { + if(mesh->log_level <= MESHLINK_INFO) { char *hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr); logger(mesh, MESHLINK_INFO, "Listening on %s", hostname); free(hostname); } - mesh->listen_socket[mesh->listen_sockets].bindto = bindto; memcpy(&mesh->listen_socket[mesh->listen_sockets].sa, aip->ai_addr, aip->ai_addrlen); memcpy(&mesh->listen_socket[mesh->listen_sockets].broadcast_sa, aip->ai_addr, aip->ai_addrlen); @@ -398,6 +503,18 @@ static bool add_listen_address(meshlink_handle_t *mesh, char *address, bool bind } freeaddrinfo(ai); + + if(!success) { + for(int i = 0; i < mesh->listen_sockets; i++) { + io_del(&mesh->loop, &mesh->listen_socket[i].tcp); + io_del(&mesh->loop, &mesh->listen_socket[i].udp); + close(mesh->listen_socket[i].tcp.fd); + close(mesh->listen_socket[i].udp.fd); + } + + mesh->listen_sockets = 0; + } + return success; } @@ -423,17 +540,17 @@ bool setup_myself(meshlink_handle_t *mesh) { mesh->listen_sockets = 0; - if(!add_listen_address(mesh, NULL, NULL)) { + if(!add_listen_sockets(mesh)) { if(strcmp(mesh->myport, "0")) { - logger(mesh, MESHLINK_INFO, "Could not bind to port %s, asking OS to choose one for us", mesh->myport); - free(mesh->myport); - mesh->myport = strdup("0"); + logger(mesh, MESHLINK_WARNING, "Could not bind to port %s, trying to find an alternative port", mesh->myport); - if(!mesh->myport) { - return false; + if(!check_port(mesh)) { + logger(mesh, MESHLINK_WARNING, "Could not bind to any port, trying to bind to port 0"); + free(mesh->myport); + mesh->myport = xstrdup("0"); } - if(!add_listen_address(mesh, NULL, NULL)) { + if(!add_listen_sockets(mesh)) { return false; } } else { @@ -448,7 +565,6 @@ bool setup_myself(meshlink_handle_t *mesh) { /* Done. */ - mesh->last_config_check = mesh->loop.now.tv_sec; mesh->last_unreachable = mesh->loop.now.tv_sec; return true;