]> git.meshlink.io Git - meshlink/commitdiff
Fix the order of socket operations when setting up listening sockets.
authorGuus Sliepen <guus@meshlink.io>
Sun, 15 Mar 2020 15:08:44 +0000 (16:08 +0100)
committerGuus Sliepen <guus@meshlink.io>
Sun, 15 Mar 2020 15:08:44 +0000 (16:08 +0100)
Commit db8e6e4 caused calls to setsockopt() for setting up socket parameters
to be called after the call to bind().

src/net.h
src/net_setup.c
src/net_socket.c

index 63fb922f401f5e9936770c9bb1962ca977a08000..cdb0cca561197a1d2002277a47e93340f155ab19 100644 (file)
--- a/src/net.h
+++ b/src/net.h
@@ -84,8 +84,6 @@ extern void handle_incoming_vpn_data(struct event_loop_t *loop, void *, int);
 extern void finish_connecting(struct meshlink_handle *mesh, struct connection_t *);
 extern void do_outgoing_connection(struct meshlink_handle *mesh, struct outgoing_t *);
 extern void handle_new_meta_connection(struct event_loop_t *loop, void *, int);
-extern bool setup_listen_socket(struct meshlink_handle *mesh, int fd, int sa_family) __attribute__((__warn_unused_result__));
-extern bool setup_vpn_in_socket(struct meshlink_handle *mesh, int fd, int sa_family) __attribute__((__warn_unused_result__));
 extern bool send_sptps_data(void *handle, uint8_t type, const void *data, size_t len);
 extern bool receive_sptps_record(void *handle, uint8_t type, const void *data, uint16_t len) __attribute__((__warn_unused_result__));
 extern void send_packet(struct meshlink_handle *mesh, struct node_t *, struct vpn_packet_t *);
index 4cff1a5ee83d679ff952fe181cf0c84fbe738d07..d0e450039913c995298f304f3b4003730ad606f8 100644 (file)
@@ -301,6 +301,117 @@ static bool load_node(meshlink_handle_t *mesh, const char *name, void *priv) {
        return true;
 }
 
+static 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;
+       }
+
+#ifdef FD_CLOEXEC
+       fcntl(nfd, F_SETFD, FD_CLOEXEC);
+#endif
+
+       int option = 1;
+       setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option));
+
+#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;
+}
+
+static int setup_udp_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.
 */
@@ -345,15 +456,9 @@ static bool add_listen_sockets(meshlink_handle_t *mesh) {
 
                /* Try to bind to TCP */
 
-               int tcp_fd = socket(aip->ai_family, SOCK_STREAM, IPPROTO_TCP);
+               int tcp_fd = setup_tcp_listen_socket(mesh, aip);
 
                if(tcp_fd == -1) {
-                       continue;
-               }
-
-               if(bind(tcp_fd, aip->ai_addr, aip->ai_addrlen)) {
-                       closesocket(tcp_fd);
-
                        if(errno == EADDRINUSE) {
                                /* If this port is in use for any address family, avoid it. */
                                success = false;
@@ -363,15 +468,9 @@ static bool add_listen_sockets(meshlink_handle_t *mesh) {
                        }
                }
 
-               if(!setup_listen_socket(mesh, tcp_fd, aip->ai_family)) {
-                       closesocket(tcp_fd);
-                       success = false;
-                       break;
-               }
-
                /* If TCP worked, then we require that UDP works as well. */
 
-               int udp_fd = socket(aip->ai_family, SOCK_DGRAM, IPPROTO_UDP);
+               int udp_fd = setup_udp_socket(mesh, aip);
 
                if(udp_fd == -1) {
                        closesocket(tcp_fd);
@@ -379,13 +478,6 @@ static bool add_listen_sockets(meshlink_handle_t *mesh) {
                        break;
                }
 
-               if(bind(udp_fd, aip->ai_addr, aip->ai_addrlen) || !setup_vpn_in_socket(mesh, udp_fd, aip->ai_family)) {
-                       closesocket(tcp_fd);
-                       closesocket(udp_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);
 
index 931f21d111ee9625047d6e35737656611d41df32..fcadd90c25e95531cc8f05833971f18f1267699f 100644 (file)
@@ -72,95 +72,6 @@ static void configure_tcp(connection_t *c) {
 #endif
 }
 
-bool setup_listen_socket(meshlink_handle_t *mesh, int nfd, int sa_family) {
-#ifdef FD_CLOEXEC
-       fcntl(nfd, F_SETFD, FD_CLOEXEC);
-#endif
-
-       int option = 1;
-       setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option));
-
-#if defined(IPV6_V6ONLY)
-
-       if(sa_family == AF_INET6) {
-               setsockopt(nfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&option, sizeof(option));
-       }
-
-#else
-#warning IPV6_V6ONLY not defined
-#endif
-
-       if(listen(nfd, 3)) {
-               logger(mesh, MESHLINK_ERROR, "System call `%s' failed: %s", "listen", sockstrerror(sockerrno));
-               return false;
-       }
-
-       return true;
-}
-
-bool setup_vpn_in_socket(meshlink_handle_t *mesh, int nfd, int sa_family) {
-#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 false;
-               }
-       }
-#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 false;
-               }
-       }
-#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(sa_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 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
-
-       return true;
-} /* int setup_vpn_in_socket */
-
 static void retry_outgoing_handler(event_loop_t *loop, void *data) {
        assert(data);