diff options
| author | Michael Kaufmann <mail@michael-kaufmann.ch> | 2016-01-25 14:37:24 +0100 | 
|---|---|---|
| committer | Daniel Stenberg <daniel@haxx.se> | 2016-04-17 23:50:59 +0200 | 
| commit | cd8d23624594e21c37a0453459229a90a38ad471 (patch) | |
| tree | 57afa8a5d73bffd4f3b08ef691d68ff2d03d4c7f /lib | |
| parent | f86f50f05a466f8960d94179ca46e9561458c567 (diff) | |
news: CURLOPT_CONNECT_TO and --connect-to
Makes curl connect to the given host+port instead of the host+port found
in the URL.
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/conncache.c | 13 | ||||
| -rw-r--r-- | lib/connect.c | 12 | ||||
| -rw-r--r-- | lib/http.c | 2 | ||||
| -rw-r--r-- | lib/http_proxy.c | 25 | ||||
| -rw-r--r-- | lib/multi.c | 8 | ||||
| -rw-r--r-- | lib/url.c | 331 | ||||
| -rw-r--r-- | lib/urldata.h | 21 | ||||
| -rw-r--r-- | lib/vtls/vtls.c | 29 | 
8 files changed, 407 insertions, 34 deletions
| diff --git a/lib/conncache.c b/lib/conncache.c index 6e03caf3c..89086590a 100644 --- a/lib/conncache.c +++ b/lib/conncache.c @@ -132,9 +132,16 @@ void Curl_conncache_destroy(struct conncache *connc)  /* returns an allocated key to find a bundle for this connection */  static char *hashkey(struct connectdata *conn)  { -  return aprintf("%s:%d", -                 conn->bits.proxy?conn->proxy.name:conn->host.name, -                 conn->localport); +  const char *hostname; + +  if(conn->bits.proxy) +    hostname = conn->proxy.name; +  else if(conn->bits.conn_to_host) +    hostname = conn->conn_to_host.name; +  else +    hostname = conn->host.name; + +  return aprintf("%s:%d", hostname, conn->localport);  }  /* Look up the bundle with all the connections to the same host this diff --git a/lib/connect.c b/lib/connect.c index 567186a69..3f3d3f65f 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -841,6 +841,8 @@ CURLcode Curl_is_connected(struct connectdata *conn,    if(result) {      /* no more addresses to try */ +    const char* hostname; +      /* if the first address family runs out of addresses to try before         the happy eyeball timeout, go ahead and try the next family now */      if(conn->tempaddr[1] == NULL) { @@ -849,9 +851,15 @@ CURLcode Curl_is_connected(struct connectdata *conn,          return result;      } +    if(conn->bits.proxy) +      hostname = conn->proxy.name; +    else if(conn->bits.conn_to_host) +      hostname = conn->conn_to_host.name; +    else +      hostname = conn->host.name; +      failf(data, "Failed to connect to %s port %ld: %s", -          conn->bits.proxy?conn->proxy.name:conn->host.name, -          conn->port, Curl_strerror(conn, error)); +        hostname, conn->port, Curl_strerror(conn, error));    }    return result; diff --git a/lib/http.c b/lib/http.c index 91ab8326d..1b1cd2235 100644 --- a/lib/http.c +++ b/lib/http.c @@ -1832,6 +1832,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)      data->state.first_host = strdup(conn->host.name);      if(!data->state.first_host)        return CURLE_OUT_OF_MEMORY; + +    data->state.first_remote_port = conn->remote_port;    }    http->writebytecount = http->readbytecount = 0; diff --git a/lib/http_proxy.c b/lib/http_proxy.c index e082ba291..676f0cb5d 100644 --- a/lib/http_proxy.c +++ b/lib/http_proxy.c @@ -49,6 +49,8 @@ CURLcode Curl_proxy_connect(struct connectdata *conn)      /* for [protocol] tunneled through HTTP proxy */      struct HTTP http_proxy;      void *prot_save; +    const char *hostname; +    int remote_port;      CURLcode result;      /* BLOCKING */ @@ -67,8 +69,16 @@ CURLcode Curl_proxy_connect(struct connectdata *conn)      memset(&http_proxy, 0, sizeof(http_proxy));      conn->data->req.protop = &http_proxy;      connkeep(conn, "HTTP proxy CONNECT"); -    result = Curl_proxyCONNECT(conn, FIRSTSOCKET, -                               conn->host.name, conn->remote_port, FALSE); +    if(conn->bits.conn_to_host) +      hostname = conn->conn_to_host.name; +    else +      hostname = conn->host.name; +    if(conn->bits.conn_to_port) +      remote_port = conn->conn_to_port; +    else +      remote_port = conn->remote_port; +    result = Curl_proxyCONNECT(conn, FIRSTSOCKET, hostname, +                               remote_port, FALSE);      conn->data->req.protop = prot_save;      if(CURLE_OK != result)        return result; @@ -153,9 +163,14 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,          const char *useragent="";          const char *http = (conn->proxytype == CURLPROXY_HTTP_1_0) ?            "1.0" : "1.1"; -        char *hostheader= /* host:port with IPv6 support */ -          aprintf("%s%s%s:%hu", conn->bits.ipv6_ip?"[":"", -                  hostname, conn->bits.ipv6_ip?"]":"", +        bool ipv6_ip = conn->bits.ipv6_ip; +        char *hostheader; + +        /* the hostname may be different */ +        if(hostname != conn->host.name) +          ipv6_ip = (strchr(hostname, ':') != NULL); +        hostheader= /* host:port with IPv6 support */ +          aprintf("%s%s%s:%hu", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"",                    remote_port);          if(!hostheader) {            Curl_add_buffer_free(req_buffer); diff --git a/lib/multi.c b/lib/multi.c index b1c1f5396..aec377d96 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -1464,9 +1464,15 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,      {        struct Curl_dns_entry *dns = NULL;        struct connectdata *conn = data->easy_conn; +      const char *hostname; + +      if(conn->bits.conn_to_host) +        hostname = conn->conn_to_host.name; +      else +        hostname = conn->host.name;        /* check if we have the name resolved by now */ -      dns = Curl_fetch_addr(conn, conn->host.name, (int)conn->port); +      dns = Curl_fetch_addr(conn, hostname, (int)conn->port);        if(dns) {  #ifdef CURLRES_ASYNCH @@ -2674,6 +2674,9 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,      break;  #endif    } +  case CURLOPT_CONNECT_TO: +    data->set.connect_to = va_arg(param, struct curl_slist *); +    break;    default:      /* unknown tag and its companion, just ignore: */      result = CURLE_UNKNOWN_OPTION; @@ -2729,6 +2732,7 @@ static void conn_free(struct connectdata *conn)    Curl_safefree(conn->allocptr.rtsp_transport);    Curl_safefree(conn->trailer);    Curl_safefree(conn->host.rawalloc); /* host name buffer */ +  Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */    Curl_safefree(conn->proxy.rawalloc); /* proxy name buffer */    Curl_safefree(conn->master_buffer); @@ -2787,6 +2791,7 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection)    Curl_conncache_remove_conn(data->state.conn_cache, conn);    free_fixed_hostname(&conn->host); +  free_fixed_hostname(&conn->conn_to_host);    free_fixed_hostname(&conn->proxy);    Curl_ssl_close(conn, FIRSTSOCKET); @@ -3146,9 +3151,15 @@ ConnectionExists(struct SessionHandle *data,        max_pipeline_length(data->multi):0;      size_t best_pipe_len = max_pipe_len;      struct curl_llist_element *curr; +    const char *hostname; + +    if(needle->bits.conn_to_host) +      hostname = needle->conn_to_host.name; +    else +      hostname = needle->host.name;      infof(data, "Found bundle for host %s: %p [%s]\n", -          needle->host.name, (void *)bundle, +          hostname, (void *)bundle,            (bundle->multiuse== BUNDLE_PIPELINING?             "can pipeline":             (bundle->multiuse== BUNDLE_MULTIPLEX? @@ -3267,6 +3278,16 @@ ConnectionExists(struct SessionHandle *data,          /* don't do mixed proxy and non-proxy connections */          continue; +      if(needle->bits.conn_to_host != check->bits.conn_to_host) +        /* don't mix connections that use the "connect to host" feature and +         * connections that don't use this feature */ +        continue; + +      if(needle->bits.conn_to_port != check->bits.conn_to_port) +        /* don't mix connections that use the "connect to port" feature and +         * connections that don't use this feature */ +        continue; +        if(!canPipeline && check->inuse)          /* this request can't be pipelined but the checked connection is             already in use so we skip it */ @@ -3302,7 +3323,7 @@ ConnectionExists(struct SessionHandle *data,          }        } -      if(!needle->bits.httpproxy || needle->handler->flags&PROTOPT_SSL || +      if(!needle->bits.httpproxy || (needle->handler->flags&PROTOPT_SSL) ||           (needle->bits.httpproxy && check->bits.httpproxy &&            needle->bits.tunnel_proxy && check->bits.tunnel_proxy &&            Curl_raw_equal(needle->proxy.name, check->proxy.name) && @@ -3313,6 +3334,10 @@ ConnectionExists(struct SessionHandle *data,          if((Curl_raw_equal(needle->handler->scheme, check->handler->scheme) ||              (get_protocol_family(check->handler->protocol) ==               needle->handler->protocol && check->tls_upgraded)) && +           (!needle->bits.conn_to_host || Curl_raw_equal( +            needle->conn_to_host.name, check->conn_to_host.name)) && +           (!needle->bits.conn_to_port || +             needle->conn_to_port == check->conn_to_port) &&             Curl_raw_equal(needle->host.name, check->host.name) &&             needle->remote_port == check->remote_port) {            /* The schemes match or the the protocol family is the same and the @@ -3490,16 +3515,27 @@ CURLcode Curl_connected_proxy(struct connectdata *conn,    case CURLPROXY_SOCKS5:    case CURLPROXY_SOCKS5_HOSTNAME:      return Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, -                       conn->host.name, conn->remote_port, +                       conn->bits.conn_to_host ? conn->conn_to_host.name : +                       conn->host.name, +                       conn->bits.conn_to_port ? conn->conn_to_port : +                       conn->remote_port,                         FIRSTSOCKET, conn);    case CURLPROXY_SOCKS4: -    return Curl_SOCKS4(conn->proxyuser, conn->host.name, -                       conn->remote_port, FIRSTSOCKET, conn, FALSE); +    return Curl_SOCKS4(conn->proxyuser, +                       conn->bits.conn_to_host ? conn->conn_to_host.name : +                       conn->host.name, +                       conn->bits.conn_to_port ? conn->conn_to_port : +                       conn->remote_port, +                       FIRSTSOCKET, conn, FALSE);    case CURLPROXY_SOCKS4A: -    return Curl_SOCKS4(conn->proxyuser, conn->host.name, -                       conn->remote_port, FIRSTSOCKET, conn, TRUE); +    return Curl_SOCKS4(conn->proxyuser, +                       conn->bits.conn_to_host ? conn->conn_to_host.name : +                       conn->host.name, +                       conn->bits.conn_to_port ? conn->conn_to_port : +                       conn->remote_port, +                       FIRSTSOCKET, conn, TRUE);  #endif /* CURL_DISABLE_PROXY */    case CURLPROXY_HTTP: @@ -4373,11 +4409,6 @@ static CURLcode setup_connection_internals(struct connectdata *conn)         was very likely already set to the proxy port */      conn->port = p->defport; -  /* only if remote_port was not already parsed off the URL we use the -     default port number */ -  if(conn->remote_port < 0) -    conn->remote_port = (unsigned short)conn->given->defport; -    return CURLE_OK;  } @@ -4652,7 +4683,7 @@ static CURLcode parse_proxy(struct SessionHandle *data,        if(strncmp("%25", ptr, 3))          infof(data, "Please URL encode %% as %%25, see RFC 6874.\n");        ptr++; -      /* Allow unresered characters as defined in RFC 3986 */ +      /* Allow unreserved characters as defined in RFC 3986 */        while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||                       (*ptr == '.') || (*ptr == '_') || (*ptr == '~')))          ptr++; @@ -4679,7 +4710,7 @@ static CURLcode parse_proxy(struct SessionHandle *data,      /* now set the local port number */      port = strtol(prox_portno, &endp, 10);      if((endp && *endp && (*endp != '/') && (*endp != ' ')) || -       (port >= 65536) ) { +       (port < 0) || (port > 65535)) {        /* meant to detect for example invalid IPv6 numerical addresses without           brackets: "2a00:fac0:a000::7:13". Accept a trailing slash only           because we then allow "URL style" with the number followed by a @@ -4702,7 +4733,7 @@ static CURLcode parse_proxy(struct SessionHandle *data,         a slash so we strip everything from the first slash */      atsign = strchr(proxyptr, '/');      if(atsign) -      *atsign = 0x0; /* cut off path part from host name */ +      *atsign = '\0'; /* cut off path part from host name */      if(data->set.proxyport)        /* None given in the proxy string, then get the default one if it is @@ -5106,6 +5137,12 @@ static CURLcode parse_remote_port(struct SessionHandle *data,           use the default port. Firefox and Chrome both do that. */        *portptr = '\0';    } + +  /* only if remote_port was not already parsed off the URL we use the +     default port number */ +  if(conn->remote_port < 0) +    conn->remote_port = (unsigned short)conn->given->defport; +    return CURLE_OK;  } @@ -5211,6 +5248,214 @@ static CURLcode set_login(struct connectdata *conn,    return result;  } +/* + * Parses a "host:port" string to connect to. + * The hostname and the port may be empty; in this case, NULL is returned for + * the hostname and -1 for the port. + */ +static CURLcode parse_connect_to_host_port(struct SessionHandle *data, +                                           const char *host, +                                           char **hostname_result, +                                           int *port_result) +{ +  char *host_dup; +  char *hostptr; +  char *host_portno; +  char *portptr; +  int port = -1; + +  *hostname_result = NULL; +  *port_result = -1; + +  if(!host || !*host) +    return CURLE_OK; + +  host_dup = strdup(host); +  if(!host_dup) +    return CURLE_OUT_OF_MEMORY; + +  hostptr = host_dup; + +  /* start scanning for port number at this point */ +  portptr = hostptr; + +  /* detect and extract RFC6874-style IPv6-addresses */ +  if(*hostptr == '[') { +    char *ptr = ++hostptr; /* advance beyond the initial bracket */ +    while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.'))) +      ptr++; +    if(*ptr == '%') { +      /* There might be a zone identifier */ +      if(strncmp("%25", ptr, 3)) +        infof(data, "Please URL encode %% as %%25, see RFC 6874.\n"); +      ptr++; +      /* Allow unreserved characters as defined in RFC 3986 */ +      while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') || +                     (*ptr == '.') || (*ptr == '_') || (*ptr == '~'))) +        ptr++; +    } +    if(*ptr == ']') +      /* yeps, it ended nicely with a bracket as well */ +      *ptr++ = '\0'; +    else +      infof(data, "Invalid IPv6 address format\n"); +    portptr = ptr; +    /* Note that if this didn't end with a bracket, we still advanced the +     * hostptr first, but I can't see anything wrong with that as no host +     * name nor a numeric can legally start with a bracket. +     */ +  } + +  /* Get port number off server.com:1080 */ +  host_portno = strchr(portptr, ':'); +  if(host_portno) { +    char *endp = NULL; +    *host_portno = '\0'; /* cut off number from host name */ +    host_portno++; +    if(*host_portno) { +      long portparse = strtol(host_portno, &endp, 10); +      if((endp && *endp) || (portparse < 0) || (portparse > 65535)) { +        infof(data, "No valid port number in connect to host string (%s)\n", +              host_portno); +        hostptr = NULL; +        port = -1; +      } +      else +        port = (int)portparse; /* we know it will fit */ +    } +  } + +  /* now, clone the cleaned host name */ +  if(hostptr) { +    *hostname_result = strdup(hostptr); +    if(!*hostname_result) { +      free(host_dup); +      return CURLE_OUT_OF_MEMORY; +    } +  } + +  *port_result = port; + +  free(host_dup); +  return CURLE_OK; +} + +/* + * Parses one "connect to" string in the form: + * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT". + */ +static CURLcode parse_connect_to_string(struct SessionHandle *data, +                                        struct connectdata *conn, +                                        const char *conn_to_host, +                                        char **host_result, +                                        int *port_result) +{ +  CURLcode result = CURLE_OK; +  const char *ptr = conn_to_host; +  int host_match = FALSE; +  int port_match = FALSE; + +  if(*ptr == ':') { +    /* an empty hostname always matches */ +    host_match = TRUE; +    ptr++; +  } +  else { +    /* check whether the URL's hostname matches */ +    size_t hostname_to_match_len; +    char *hostname_to_match = aprintf("%s%s%s", +                                      conn->bits.ipv6_ip ? "[" : "", +                                      conn->host.name, +                                      conn->bits.ipv6_ip ? "]" : ""); +    if(!hostname_to_match) +      return CURLE_OUT_OF_MEMORY; +    hostname_to_match_len = strlen(hostname_to_match); +    host_match = curl_strnequal(ptr, hostname_to_match, hostname_to_match_len); +    free(hostname_to_match); +    ptr += hostname_to_match_len; + +    host_match = host_match && *ptr == ':'; +    ptr++; +  } + +  if(host_match) { +    if(*ptr == ':') { +      /* an empty port always matches */ +      port_match = TRUE; +      ptr++; +    } +    else { +      /* check whether the URL's port matches */ +      char *ptr_next = strchr(ptr, ':'); +      if(ptr_next) { +        char *endp = NULL; +        long port_to_match = strtol(ptr, &endp, 10); +        if((endp == ptr_next) && (port_to_match == conn->remote_port)) { +          port_match = TRUE; +          ptr = ptr_next + 1; +        } +      } +    } +  } + +  if(host_match && port_match) { +    /* parse the hostname and port to connect to */ +    result = parse_connect_to_host_port(data, ptr, host_result, port_result); +  } + +  return result; +} + +/* + * Processes all strings in the "connect to" slist, and uses the "connect + * to host" and "connect to port" of the first string that matches. + */ +static CURLcode parse_connect_to_slist(struct SessionHandle *data, +                                       struct connectdata *conn, +                                       struct curl_slist *conn_to_host) +{ +  CURLcode result = CURLE_OK; +  char *host = NULL; +  int port = 0; + +  while(conn_to_host && !host) { +    result = parse_connect_to_string(data, conn, conn_to_host->data, +                                     &host, &port); +    if(result) +      return result; + +    if(host && *host) { +      bool ipv6host; +      conn->conn_to_host.rawalloc = host; +      conn->conn_to_host.name = host; +      conn->bits.conn_to_host = TRUE; + +      ipv6host = strchr(host, ':') != NULL; +      infof(data, "Connecting to hostname: %s%s%s\n", +            ipv6host ? "[" : "", host, ipv6host ? "]" : ""); +    } +    else { +      /* no "connect to host" */ +      conn->bits.conn_to_host = FALSE; +      free(host); +    } + +    if(port >= 0) { +      conn->conn_to_port = port; +      conn->bits.conn_to_port = TRUE; +      infof(data, "Connecting to port: %d\n", port); +    } +    else { +      /* no "connect to port" */ +      conn->bits.conn_to_port = FALSE; +    } + +    conn_to_host = conn_to_host->next; +  } + +  return result; +} +  /*************************************************************   * Resolve the address of the server or proxy   *************************************************************/ @@ -5262,12 +5507,21 @@ static CURLcode resolve_server(struct SessionHandle *data,      else  #endif      if(!conn->proxy.name || !*conn->proxy.name) { +      struct hostname *connhost; +      if(conn->bits.conn_to_host) +        connhost = &conn->conn_to_host; +      else +        connhost = &conn->host; +        /* If not connecting via a proxy, extract the port from the URL, if it is         * there, thus overriding any defaults that might have been set above. */ -      conn->port =  conn->remote_port; /* it is the same port */ +      if(conn->bits.conn_to_port) +        conn->port = conn->conn_to_port; +      else +        conn->port = conn->remote_port; /* it is the same port */        /* Resolve target host right on */ -      rc = Curl_resolv_timeout(conn, conn->host.name, (int)conn->port, +      rc = Curl_resolv_timeout(conn, connhost->name, (int)conn->port,                                 &hostaddr, timeout_ms);        if(rc == CURLRESOLV_PENDING)          *async = TRUE; @@ -5276,7 +5530,7 @@ static CURLcode resolve_server(struct SessionHandle *data,          result = CURLE_OPERATION_TIMEDOUT;        else if(!hostaddr) { -        failf(data, "Couldn't resolve host '%s'", conn->host.dispname); +        failf(data, "Couldn't resolve host '%s'", connhost->dispname);          result =  CURLE_COULDNT_RESOLVE_HOST;          /* don't return yet, we need to clean up the timeout first */        } @@ -5351,8 +5605,14 @@ static void reuse_conn(struct connectdata *old_conn,    /* host can change, when doing keepalive with a proxy or if the case is       different this time etc */    free_fixed_hostname(&conn->host); +  free_fixed_hostname(&conn->conn_to_host);    Curl_safefree(conn->host.rawalloc); +  Curl_safefree(conn->conn_to_host.rawalloc);    conn->host=old_conn->host; +  conn->bits.conn_to_host = old_conn->bits.conn_to_host; +  conn->conn_to_host = old_conn->conn_to_host; +  conn->bits.conn_to_port = old_conn->bits.conn_to_port; +  conn->conn_to_port = old_conn->conn_to_port;    /* persist connection info in session handle */    Curl_persistconninfo(conn); @@ -5661,13 +5921,48 @@ static CURLcode create_conn(struct SessionHandle *data,      goto out;    /************************************************************* +   * Process the "connect to" linked list of hostname/port mappings. +   * Do this after the remote port number has been fixed in the URL. +   *************************************************************/ +  result = parse_connect_to_slist(data, conn, data->set.connect_to); +  if(result) +    goto out; + +  /*************************************************************     * IDN-fix the hostnames     *************************************************************/    fix_hostname(data, conn, &conn->host); +  if(conn->bits.conn_to_host) +    fix_hostname(data, conn, &conn->conn_to_host);    if(conn->proxy.name && *conn->proxy.name)      fix_hostname(data, conn, &conn->proxy);    /************************************************************* +   * Check whether the host and the "connect to host" are equal. +   * Do this after the hostnames have been IDN-fixed . +   *************************************************************/ +  if(conn->bits.conn_to_host && +      Curl_raw_equal(conn->conn_to_host.name, conn->host.name)) { +    conn->bits.conn_to_host = FALSE; +  } + +  /************************************************************* +   * Check whether the port and the "connect to port" are equal. +   * Do this after the remote port number has been fixed in the URL. +   *************************************************************/ +  if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) { +    conn->bits.conn_to_port = FALSE; +  } + +  /************************************************************* +   * If the "connect to" feature is used with an HTTP proxy, +   * we set the tunnel_proxy bit. +   *************************************************************/ +  if((conn->bits.conn_to_host || conn->bits.conn_to_port) && +      conn->bits.httpproxy) +    conn->bits.tunnel_proxy = TRUE; + +  /*************************************************************     * Setup internals depending on protocol. Needs to be done after     * we figured out what/if proxy to use.     *************************************************************/ diff --git a/lib/urldata.h b/lib/urldata.h index 0efb65160..aea688ced 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -375,10 +375,12 @@ struct ssl_config_data {  /* information stored about one single SSL session */  struct curl_ssl_session {    char *name;       /* host name for which this ID was used */ +  char *conn_to_host; /* host name for the connection (may be NULL) */    void *sessionid;  /* as returned from the SSL layer */    size_t idsize;    /* if known, otherwise 0 */    long age;         /* just a number, the higher the more recent */ -  int remote_port;  /* remote port to connect to */ +  int remote_port;  /* remote port */ +  int conn_to_port; /* remote port for the connection (may be -1) */    struct ssl_config_data ssl_config; /* setup for this session */  }; @@ -490,6 +492,10 @@ struct ConnectBits {    /* always modify bits.close with the connclose() and connkeep() macros! */    bool close; /* if set, we close the connection after this request */    bool reuse; /* if set, this is a re-used connection */ +  bool conn_to_host; /* if set, this connection has a "connect to host" +                        that overrides the host in the URL */ +  bool conn_to_port; /* if set, this connection has a "connect to port" +                        that overrides the port in the URL (remote port) */    bool proxy; /* if set, this transfer is done through a proxy - any type */    bool httpproxy;    /* if set, this transfer is done through a http proxy */    bool user_passwd;    /* do we use user+password for this connection? */ @@ -874,10 +880,14 @@ struct connectdata {    int socktype;  /* SOCK_STREAM or SOCK_DGRAM */    struct hostname host; +  struct hostname conn_to_host; /* the host to connect to. valid only if +                                   bits.conn_to_host is set */    struct hostname proxy;    long port;       /* which port to use locally */ -  int remote_port; /* what remote port to connect to, not the proxy port! */ +  int remote_port; /* the remote port, not the proxy port! */ +  int conn_to_port; /* the remote port to connect to. valid only if +                       bits.conn_to_port is set */    /* 'primary_ip' and 'primary_port' get filled with peer's numerical       ip address and port number whenever an outgoing connection is @@ -1226,11 +1236,13 @@ struct UrlState {                                  bytes / second */    bool this_is_a_follow; /* this is a followed Location: request */ -  char *first_host; /* if set, this should be the host name that we will +  char *first_host; /* host name of the first (not followed) request. +                       if set, this should be the host name that we will                         sent authorization to, no else. Used to make Location:                         following not keep sending user+password... This is                         strdup() data.                      */ +  int first_remote_port; /* remote port of the first (not followed) request */    struct curl_ssl_session *session; /* array of 'max_ssl_sessions' size */    long sessionage;                  /* number of the most recent session */    char *tempwrite;      /* allocated buffer to keep data in when a write @@ -1528,6 +1540,8 @@ struct UserDefined {    struct curl_slist *telnet_options; /* linked list of telnet options */    struct curl_slist *resolve;     /* list of names to add/remove from                                       DNS cache */ +  struct curl_slist *connect_to; /* list of host:port mappings to override +                                    the hostname and port to connect to */    curl_TimeCond timecondition; /* kind of time/date comparison */    time_t timevalue;       /* what time to compare with */    Curl_HttpReq httpreq;   /* what kind of HTTP request (if any) is this */ @@ -1575,7 +1589,6 @@ struct UserDefined {    bool http_set_referer; /* is a custom referer used */    bool http_auto_referer; /* set "correct" referer when following location: */    bool opt_no_body;      /* as set with CURLOPT_NOBODY */ -  bool set_port;         /* custom port number used */    bool upload;           /* upload request */    enum CURL_NETRC_OPTION         use_netrc;        /* defined in include/curl.h */ diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index 36465a7f6..69fb70fc7 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -363,6 +363,12 @@ bool Curl_ssl_getsessionid(struct connectdata *conn,        /* not session ID means blank entry */        continue;      if(Curl_raw_equal(conn->host.name, check->name) && +       ((!conn->bits.conn_to_host && !check->conn_to_host) || +         (conn->bits.conn_to_host && check->conn_to_host && +           Curl_raw_equal(conn->conn_to_host.name, check->conn_to_host))) && +       ((!conn->bits.conn_to_port && check->conn_to_port == -1) || +         (conn->bits.conn_to_port && check->conn_to_port != -1 && +           conn->conn_to_port == check->conn_to_port)) &&         (conn->remote_port == check->remote_port) &&         Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) {        /* yes, we have a session ID! */ @@ -400,6 +406,7 @@ void Curl_ssl_kill_session(struct curl_ssl_session *session)      Curl_free_ssl_config(&session->ssl_config);      Curl_safefree(session->name); +    Curl_safefree(session->conn_to_host);    }  } @@ -442,6 +449,8 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn,    struct curl_ssl_session *store = &data->state.session[0];    long oldest_age=data->state.session[0].age; /* zero if unused */    char *clone_host; +  char *clone_conn_to_host; +  int conn_to_port;    long *general_age;    /* Even though session ID re-use might be disabled, that only disables USING @@ -452,6 +461,21 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn,    if(!clone_host)      return CURLE_OUT_OF_MEMORY; /* bail out */ +  if(conn->bits.conn_to_host) { +    clone_conn_to_host = strdup(conn->conn_to_host.name); +    if(!clone_conn_to_host) { +      free(clone_host); +      return CURLE_OUT_OF_MEMORY; /* bail out */ +    } +  } +  else +    clone_conn_to_host = NULL; + +  if(conn->bits.conn_to_port) +    conn_to_port = conn->conn_to_port; +  else +    conn_to_port = -1; +    /* Now we should add the session ID and the host name to the cache, (remove       the oldest if necessary) */ @@ -484,10 +508,12 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn,    store->age = *general_age;    /* set current age */      /* free it if there's one already present */    free(store->name); +  free(store->conn_to_host);    store->name = clone_host;               /* clone host name */ +  store->conn_to_host = clone_conn_to_host; /* clone connect to host name */ +  store->conn_to_port = conn_to_port; /* connect to port number */    store->remote_port = conn->remote_port; /* port number */ -    /* Unlock */    if(SSLSESSION_SHARED(data))      Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); @@ -495,6 +521,7 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn,    if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) {      store->sessionid = NULL; /* let caller free sessionid */      free(clone_host); +    free(clone_conn_to_host);      return CURLE_OUT_OF_MEMORY;    } | 
