]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
connect: defer port selection until connect() time
authorCristian Rodríguez <crodriguez@owncloud.com>
Wed, 9 Dec 2020 19:30:29 +0000 (16:30 -0300)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 10 Dec 2020 07:55:42 +0000 (08:55 +0100)
If supported, defer port selection until connect() time
if --interface is given and source port is 0.

Reproducer:

* start fast webserver on port 80
* starve system of ephemeral ports
$  sysctl net.ipv4.ip_local_port_range="60990 60999"

* start a curl/libcurl "crawler"
$curl --keepalive --parallel --parallel-immediate --head --interface
127.0.0.2 "http://127.0.0.[1-254]/file[001-002].txt"

current result:
(possible some successful data)
curl: (45) bind failed with errno 98: Address already in use

result after patch:
(complete success or few connections failing, higlhy depending on load)

Fail only when all the possible 4-tuple combinations are exhausted,
which is impossible to do when port is selected at bind() time becuse
the kernel does not know if socket will be listen()'ed on or connect'ed
yet.

Closes #6295

lib/connect.c

index 6e4608d98c30c5437e44af7aeac4374c84924d07..251145ce18c3502866a2d50696258ba4f0902038 100644 (file)
@@ -256,6 +256,9 @@ static CURLcode bindlocal(struct connectdata *conn,
   int portnum = data->set.localportrange;
   const char *dev = data->set.str[STRING_DEVICE];
   int error;
+#ifdef IP_BIND_ADDRESS_NO_PORT
+  int on = 1;
+#endif
 
   /*************************************************************
    * Select device to bind socket to
@@ -441,7 +444,9 @@ static CURLcode bindlocal(struct connectdata *conn,
       sizeof_sa = sizeof(struct sockaddr_in);
     }
   }
-
+#ifdef IP_BIND_ADDRESS_NO_PORT
+  setsockopt(sockfd, SOL_IP, IP_BIND_ADDRESS_NO_PORT, &on, sizeof(on));
+#endif
   for(;;) {
     if(bind(sockfd, sock, sizeof_sa) >= 0) {
       /* we succeeded to bind */