mountd - Turn on SO_REUSEADDR (2)
authorMatthew Dillon <dillon@apollo.backplane.com>
Sat, 20 Jun 2020 18:24:22 +0000 (11:24 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sat, 20 Jun 2020 19:07:19 +0000 (12:07 -0700)
* After several years it turns out that just turning SO_REUSEADDR
  on can cause a duplicate port to be assigned when an anonymous
  port is requested.  This is really a bug in the kernel which also
  needs to be fixed, but for now only set this option when a specific
  port is selected.

* Enhance bind error reporting.

sbin/mountd/mountd.c

index 9b6293d..db4e835 100644 (file)
@@ -459,7 +459,7 @@ main(int argc, char **argv)
 /*
  * This routine creates and binds sockets on the appropriate
  * addresses. It gets called one time for each transport and
 /*
  * This routine creates and binds sockets on the appropriate
  * addresses. It gets called one time for each transport and
- * registrates the service with rpcbind on that trasport.
+ * registrates the service with rpcbind on that transport.
  */
 void
 create_service(struct netconfig *nconf)
  */
 void
 create_service(struct netconfig *nconf)
@@ -577,6 +577,7 @@ create_service(struct netconfig *nconf)
                                res->ai_flags = hints.ai_flags;
                                res->ai_family = hints.ai_family;
                                res->ai_protocol = hints.ai_protocol;
                                res->ai_flags = hints.ai_flags;
                                res->ai_family = hints.ai_family;
                                res->ai_protocol = hints.ai_protocol;
+
                                switch (res->ai_family) {
                                case AF_INET:
                                        sin = malloc(sizeof(struct sockaddr_in));
                                switch (res->ai_family) {
                                case AF_INET:
                                        sin = malloc(sizeof(struct sockaddr_in));
@@ -623,7 +624,10 @@ create_service(struct netconfig *nconf)
                        }
                }
 
                        }
                }
 
-               {
+               /*
+                * Set SO_REUSEADDR only if binding to a specific port
+                */
+               if (svcport_str) {
                        int on = 1;
 
                        setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
                        int on = 1;
 
                        setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
@@ -632,7 +636,28 @@ create_service(struct netconfig *nconf)
 
                r = bindresvport_sa(fd, res->ai_addr);
                if (r != 0) {
 
                r = bindresvport_sa(fd, res->ai_addr);
                if (r != 0) {
-                       syslog(LOG_ERR, "bindresvport_sa: %m");
+                       struct sockaddr_in *sin = (void *)res->ai_addr;
+                       struct sockaddr_in6 *sin6 = (void *)res->ai_addr;
+                       const char *protostr;
+                       int portno;
+
+                       switch(sin->sin_family) {
+                       case AF_INET:
+                               protostr = "inet";
+                               portno = ntohs(sin->sin_port);
+                               break;
+                       case AF_INET6:
+                               protostr = "inet6";
+                               portno = ntohs(sin6->sin6_port);
+                               break;
+                       default:
+                               protostr = "unknown";
+                               portno = -1;
+                               break;
+                       }
+
+                       syslog(LOG_ERR, "bindresvport_sa: %m proto %s port %d",
+                               protostr, portno);
                        exit(1);
                }
 
                        exit(1);
                }