Skip to content

--connect-to incorrect destination port 0 #1148

Closed

Description

@jay

I did this

> curld -v --connect-to foo:123:bar:456 https://curl.haxx.se
* STATE: INIT => CONNECT handle 0x7b1ae0; line 1413 (connection #-5000)
* Rebuilt URL to: https://curl.haxx.se/
* Connecting to port: 0
* Added connection 0. The cache now contains 1 members
* STATE: CONNECT => WAITRESOLVE handle 0x7b1ae0; line 1450 (connection #0)
*   Trying 80.67.6.50...
* TCP_NODELAY set
* Immediate connect fail for 80.67.6.50: Address not available
* Closing connection 0
* The cache now contains 0 members
* Expire cleared
curl: (7) Couldn't connect to server

I expected the following

If the hostname and port combination of the requested URL is not in the connect-to entry list then it shouldn't change the hostname or the port.

analysis

connect-to lists have each entry in the format HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT.

parse_connect_to_slist is called by create_conn to parse the connect-to list and if a HOST:PORT match is found assign CONNECT-TO-HOST:CONNECT-TO-PORT to the connection. A function-local port variable is initialized to 0, and may or may not be changed by the parser to -1 on no match. Later when checking for a match it treats port 0 as a match. That does not make sense to me, who is using port 0? It looks like allowing that port might have been done purposely since no-match is signaled by -1.

In more detail parse_connect_to_slist calls parse_connect_to_string to parse HOST:PORT and if a match is found that function calls parse_connect_to_host_port to get the CONNECT-TO-HOST:CONNECT-TO-PORT. If the connect-to host and port are empty parse_connect_to_host_port will set the outvar port -1 and outvar host NULL as seen here to indicate no match.

The problem is if there is no match in the HOST:PORT then the outvar host and port (ie the result of parsing CONNECT-TO-HOST:CONNECT-TO-PORT) never receive the values. With host it starts as NULL so there's never a problem but with port it starts as 0 so that's a problem. A possible fix could be we set the host and port outvars first thing in parse_connect_to_string, much in the same way they're already set in parse_connect_to_host_port

diff --git a/lib/url.c b/lib/url.c
index 9ee1e6c..e0ea980 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -5677,6 +5677,9 @@ static CURLcode parse_connect_to_string(struct Curl_easy *data,
   int host_match = FALSE;
   int port_match = FALSE;
 
+  *host_result = NULL;
+  *port_result = -1;
+
   if(*ptr == ':') {
     /* an empty hostname always matches */
     host_match = TRUE;

Also maybe not initialize port to 0 if it's a valid value? (and again why is this)

curl/libcurl version

master curl-7_51_0-112-g19613fb 2016-11-28

curl 7.52.0-DEV (i386-pc-win32) libcurl/7.52.0-DEV OpenSSL/1.0.2j nghttp2/1.16.1
Protocols: dict file ftp ftps gopher http https imap imaps ldap pop3 pop3s rtsp
smb smbs smtp smtps telnet tftp
Features: AsynchDNS Debug Largefile NTLM SSL HTTP2 HTTPS-proxy

operating system

Windows 7 Enterprise x64

/cc @mkauf

Activity

  1. bagder commented on Nov 29, 2016

    @bagder
    Member

    Port 0 is actually a fully legal and working port in TCP and UDP and this is a fine chance for me to link to my own blog post on the subject. The problem with port 0 is primarily for APIs that use zero to mean something else than a port number. I don't think we need to add to those problems so we should instead use a value outside of the 16 bit range to mark it as a non-existing port. -1 seems reasonable to me!

  2. jay commented on Nov 29, 2016

    @jay
    MemberAuthor

    Port 0 is actually a fully legal and working port in TCP and UDP

    Well sometimes then. I get no outgoing packets in Windows when I try to connect to an ip with port 0. In Linux I get conn refused though. Interesting post.

  3. bagder commented on Nov 29, 2016

    @bagder
    Member

    I think you can proceed and merge your suggested change, including initializing port to -1 in parse_connect_to_slist.

  4. mkauf commented on Nov 29, 2016

    @mkauf
    Contributor

    Thank you for the bug report! I think I found an additional small bug in the "while" condition. The loop should stop if a "connect to port" has been found.

    Proposed bugfix:

    diff --git a/lib/url.c b/lib/url.c
    index 9ee1e6c..dd3f62d 100644
    --- a/lib/url.c
    +++ b/lib/url.c
    @@ -5677,6 +5677,9 @@
       int host_match = FALSE;
       int port_match = FALSE;
     
    +  *host_result = NULL;
    +  *port_result = -1;
    +
       if(*ptr == ':') {
         /* an empty hostname always matches */
         host_match = TRUE;
    @@ -5739,9 +5742,9 @@
     {
       CURLcode result = CURLE_OK;
       char *host = NULL;
    -  int port = 0;
    +  int port = -1;
     
    -  while(conn_to_host && !host) {
    +  while(conn_to_host && !host && port == -1) {
         result = parse_connect_to_string(data, conn, conn_to_host->data,
                                          &host, &port);
         if(result)
    @@ -5760,7 +5763,7 @@
         else {
           /* no "connect to host" */
           conn->bits.conn_to_host = FALSE;
    -      free(host);
    +      Curl_safefree(host);
         }
     
         if(port >= 0) {
    @@ -5771,6 +5774,7 @@
         else {
           /* no "connect to port" */
           conn->bits.conn_to_port = FALSE;
    +      port = -1;
         }
     
         conn_to_host = conn_to_host->next;
  5. bagder commented on Nov 29, 2016

    @bagder
    Member

    👍 looks good to me!

  6. jay commented on Nov 29, 2016

    @jay
    MemberAuthor

    👍 me too, go for it

  7. mkauf commented on Nov 30, 2016

    @mkauf
    Contributor

    Fixed, thanks!

  8. locked as resolved and limited conversation to collaborators on May 7, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions