]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
socks filter: pass operation parameters
authorStefan Eissing <stefan@eissing.org>
Fri, 24 Apr 2026 08:38:22 +0000 (10:38 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Fri, 24 Apr 2026 15:50:10 +0000 (17:50 +0200)
Pass all operations parameters to a SOCKS filter at creation
time, not relying on "global" connectdata values.

Eliminate modifications to `conn->ip_version` when local resolving
for SOCKS4.

Do not retrieve the socket for GSSAPI blocking calls from connectdata,
but from the filters "below" the SOCKS one.

Closes #21436

lib/connect.c
lib/socks.c
lib/socks.h

index 3d1aec1f706c83161f4fb3af52d4589bdea7010d..b8d200b149aabe8ba4007e8a1019aaa4d085cca3 100644 (file)
@@ -374,7 +374,27 @@ connect_sub_chain:
   /* sub-chain connected, do we need to add more? */
 #ifndef CURL_DISABLE_PROXY
   if(ctx->state < CF_SETUP_CNNCT_SOCKS && cf->conn->bits.socksproxy) {
-    result = Curl_cf_socks_proxy_insert_after(cf, data);
+    /* for the secondary socket (FTP), use the "connect to host"
+     * but ignore the "connect to port" (use the secondary port)
+     */
+    const char *hostname =
+      cf->conn->bits.httpproxy ?
+      cf->conn->http_proxy.host.name :
+      cf->conn->bits.conn_to_host ?
+      cf->conn->conn_to_host.name :
+      cf->sockindex == SECONDARYSOCKET ?
+      cf->conn->secondaryhostname : cf->conn->host.name;
+    uint16_t port =
+      cf->conn->bits.httpproxy ? cf->conn->http_proxy.port :
+      cf->sockindex == SECONDARYSOCKET ? cf->conn->secondary_port :
+      cf->conn->bits.conn_to_port ? cf->conn->conn_to_port :
+      cf->conn->remote_port;
+    const char *user = cf->conn->socks_proxy.user;
+    const char *passwd = cf->conn->socks_proxy.passwd;
+
+    result = Curl_cf_socks_proxy_insert_after(
+      cf, data, hostname, port, cf->conn->ip_version,
+      cf->conn->socks_proxy.proxytype, user, passwd);
     if(result)
       return result;
     ctx->state = CF_SETUP_CNNCT_SOCKS;
index 57e5a50f7a68979d93af0d5f2a2ce544f0d6e2ff..b3da5be0a36723db55e3ae92990acdf46696b190 100644 (file)
@@ -95,19 +95,21 @@ static const char * const cf_socks_statename[] = {
 #define SOCKS_CHUNKS        1
 
 
-struct socks_state {
+struct socks_ctx {
   enum socks_state_t state;
   struct bufq iobuf;
-  const char *hostname;
   uint16_t remote_port;
-  const char *proxy_user;
-  const char *proxy_password;
+  const char *user;
+  const char *passwd;
   CURLproxycode presult;
   uint32_t resolv_id;
+  uint8_t ip_version;
+  uint8_t proxy_type;
   unsigned char version;
   BIT(resolve_local);
   BIT(start_resolving);
   BIT(socks4a);
+  char hostname[1];
 };
 
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
@@ -129,13 +131,15 @@ CURLcode Curl_blockread_all(struct Curl_cfilter *cf,
   *pnread = 0;
   for(;;) {
     timediff_t timeout_ms = Curl_timeleft_ms(data);
+    curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
+
     if(timeout_ms < 0) {
       /* we already got the timeout */
       return CURLE_OPERATION_TIMEDOUT;
     }
     if(!timeout_ms)
       timeout_ms = TIMEDIFF_T_MAX;
-    if(SOCKET_READABLE(cf->conn->sock[cf->sockindex], timeout_ms) <= 0)
+    if(SOCKET_READABLE(sock, timeout_ms) <= 0)
       return CURLE_OPERATION_TIMEDOUT;
     result = Curl_conn_cf_recv(cf->next, data, buf, blen, &nread);
     if(result == CURLE_AGAIN)
@@ -164,7 +168,7 @@ CURLcode Curl_blockread_all(struct Curl_cfilter *cf,
 #endif
 
 /* always use this function to change state, to make debugging easier */
-static void socksstate(struct socks_state *sx,
+static void socksstate(struct socks_ctx *sx,
                        struct Curl_cfilter *cf,
                        struct Curl_easy *data,
                        enum socks_state_t state
@@ -191,7 +195,7 @@ static void socksstate(struct socks_state *sx,
 #endif
 }
 
-static CURLproxycode socks_failed(struct socks_state *sx,
+static CURLproxycode socks_failed(struct socks_ctx *sx,
                                   struct Curl_cfilter *cf,
                                   struct Curl_easy *data,
                                   CURLproxycode presult)
@@ -201,7 +205,7 @@ static CURLproxycode socks_failed(struct socks_state *sx,
   return presult;
 }
 
-static CURLproxycode socks_flush(struct socks_state *sx,
+static CURLproxycode socks_flush(struct socks_ctx *sx,
                                  struct Curl_cfilter *cf,
                                  struct Curl_easy *data,
                                  bool *done)
@@ -225,7 +229,7 @@ static CURLproxycode socks_flush(struct socks_state *sx,
   return CURLPX_OK;
 }
 
-static CURLproxycode socks_recv(struct socks_state *sx,
+static CURLproxycode socks_recv(struct socks_ctx *sx,
                                 struct Curl_cfilter *cf,
                                 struct Curl_easy *data,
                                 size_t min_bytes,
@@ -259,7 +263,7 @@ static CURLproxycode socks_recv(struct socks_state *sx,
   return CURLPX_OK;
 }
 
-static CURLproxycode socks4_req_add_hd(struct socks_state *sx,
+static CURLproxycode socks4_req_add_hd(struct socks_ctx *sx,
                                        struct Curl_easy *data)
 {
   unsigned char buf[4];
@@ -278,14 +282,14 @@ static CURLproxycode socks4_req_add_hd(struct socks_state *sx,
   return CURLPX_OK;
 }
 
-static CURLproxycode socks4_req_add_user(struct socks_state *sx,
+static CURLproxycode socks4_req_add_user(struct socks_ctx *sx,
                                          struct Curl_easy *data)
 {
   CURLcode result;
   size_t nwritten;
 
-  if(sx->proxy_user) {
-    size_t plen = strlen(sx->proxy_user);
+  if(sx->user) {
+    size_t plen = strlen(sx->user);
     if(plen > 255) {
       /* there is no real size limit to this field in the protocol, but
          SOCKS5 limits the proxy user field to 255 bytes and it seems likely
@@ -294,7 +298,7 @@ static CURLproxycode socks4_req_add_user(struct socks_state *sx,
       return CURLPX_LONG_USER;
     }
     /* add proxy name WITH trailing zero */
-    result = Curl_bufq_cwrite(&sx->iobuf, sx->proxy_user, plen + 1,
+    result = Curl_bufq_cwrite(&sx->iobuf, sx->user, plen + 1,
                               &nwritten);
     if(result || (nwritten != (plen + 1)))
       return CURLPX_SEND_REQUEST;
@@ -309,7 +313,7 @@ static CURLproxycode socks4_req_add_user(struct socks_state *sx,
   return CURLPX_OK;
 }
 
-static CURLproxycode socks4_resolving(struct socks_state *sx,
+static CURLproxycode socks4_resolving(struct socks_ctx *sx,
                                       struct Curl_cfilter *cf,
                                       struct Curl_easy *data,
                                       bool *done)
@@ -323,9 +327,8 @@ static CURLproxycode socks4_resolving(struct socks_state *sx,
   if(sx->start_resolving) {
     /* need to resolve hostname to add destination address */
     sx->start_resolving = FALSE;
-    DEBUGASSERT(sx->hostname && *sx->hostname);
     result = Curl_cf_dns_insert_after(
-      cf, data, Curl_resolv_dns_queries(data, cf->conn->ip_version),
+      cf, data, Curl_resolv_dns_queries(data, sx->ip_version),
       sx->hostname, sx->remote_port, TRNSPRT_TCP, TRUE);
     if(result) {
       failf(data, "unable to create DNS filter for socks");
@@ -370,7 +373,7 @@ static CURLproxycode socks4_resolving(struct socks_state *sx,
   return CURLPX_OK;
 }
 
-static CURLproxycode socks4_check_resp(struct socks_state *sx,
+static CURLproxycode socks4_check_resp(struct socks_ctx *sx,
                                        struct Curl_cfilter *cf,
                                        struct Curl_easy *data)
 {
@@ -459,7 +462,7 @@ static CURLproxycode socks4_check_resp(struct socks_state *sx,
  *   Nonsupport "Identification Protocol (RFC1413)"
  */
 static CURLproxycode socks4_connect(struct Curl_cfilter *cf,
-                                    struct socks_state *sx,
+                                    struct socks_ctx *sx,
                                     struct Curl_easy *data)
 {
   size_t nwritten;
@@ -477,16 +480,14 @@ process_state:
   case SOCKS4_ST_START:
     Curl_bufq_reset(&sx->iobuf);
     sx->start_resolving = FALSE;
-    sx->socks4a = (cf->conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A);
+    sx->socks4a = (sx->proxy_type == CURLPROXY_SOCKS4A);
     sx->resolve_local = !sx->socks4a;
     sx->presult = CURLPX_OK;
 
     /* SOCKS4 can only do IPv4, insist! */
-    cf->conn->ip_version = CURL_IPRESOLVE_V4;
-    CURL_TRC_CF(data, cf, "SOCKS4%s communication to%s %s:%u",
-                sx->socks4a ? "a" : "",
-                cf->conn->bits.httpproxy ? " HTTP proxy" : "",
-                sx->hostname, sx->remote_port);
+    sx->ip_version = CURL_IPRESOLVE_V4;
+    CURL_TRC_CF(data, cf, "SOCKS4%s connecting to %s:%u",
+                sx->socks4a ? "a" : "", sx->hostname, sx->remote_port);
 
     /*
      * Compose socks4 request
@@ -579,7 +580,7 @@ process_state:
 }
 
 static CURLproxycode socks5_req0_init(struct Curl_cfilter *cf,
-                                      struct socks_state *sx,
+                                      struct socks_ctx *sx,
                                       struct Curl_easy *data)
 {
   const unsigned char auth = data->set.socks5auth;
@@ -601,7 +602,7 @@ static CURLproxycode socks5_req0_init(struct Curl_cfilter *cf,
           "CURLOPT_SOCKS5_AUTH: %u", auth);
   if(!(auth & CURLAUTH_BASIC))
     /* disable username/password auth */
-    sx->proxy_user = NULL;
+    sx->user = NULL;
 
   req[0] = 5;   /* version */
   nauths = 1;
@@ -612,7 +613,7 @@ static CURLproxycode socks5_req0_init(struct Curl_cfilter *cf,
     req[1 + nauths] = 1; /* GSS-API */
   }
 #endif
-  if(sx->proxy_user) {
+  if(sx->user) {
     ++nauths;
     req[1 + nauths] = 2; /* username/password */
   }
@@ -625,7 +626,7 @@ static CURLproxycode socks5_req0_init(struct Curl_cfilter *cf,
   return CURLPX_OK;
 }
 
-static CURLproxycode socks5_check_resp0(struct socks_state *sx,
+static CURLproxycode socks5_check_resp0(struct socks_ctx *sx,
                                         struct Curl_cfilter *cf,
                                         struct Curl_easy *data)
 {
@@ -677,7 +678,7 @@ static CURLproxycode socks5_check_resp0(struct socks_state *sx,
 }
 
 static CURLproxycode socks5_auth_init(struct Curl_cfilter *cf,
-                                      struct socks_state *sx,
+                                      struct socks_ctx *sx,
                                       struct Curl_easy *data)
 {
   /* Needs username and password */
@@ -685,9 +686,9 @@ static CURLproxycode socks5_auth_init(struct Curl_cfilter *cf,
   unsigned char buf[2];
   CURLcode result;
 
-  if(sx->proxy_user && sx->proxy_password) {
-    ulen = strlen(sx->proxy_user);
-    plen = strlen(sx->proxy_password);
+  if(sx->user && sx->passwd) {
+    ulen = strlen(sx->user);
+    plen = strlen(sx->passwd);
     /* the lengths must fit in a single byte */
     if(ulen > 255) {
       failf(data, "Excessive username length for proxy auth");
@@ -712,7 +713,7 @@ static CURLproxycode socks5_auth_init(struct Curl_cfilter *cf,
   if(result || (nwritten != 2))
     return CURLPX_SEND_REQUEST;
   if(ulen) {
-    result = Curl_bufq_cwrite(&sx->iobuf, sx->proxy_user, ulen, &nwritten);
+    result = Curl_bufq_cwrite(&sx->iobuf, sx->user, ulen, &nwritten);
     if(result || (nwritten != ulen))
       return CURLPX_SEND_REQUEST;
   }
@@ -721,7 +722,7 @@ static CURLproxycode socks5_auth_init(struct Curl_cfilter *cf,
   if(result || (nwritten != 1))
     return CURLPX_SEND_REQUEST;
   if(plen) {
-    result = Curl_bufq_cwrite(&sx->iobuf, sx->proxy_password, plen, &nwritten);
+    result = Curl_bufq_cwrite(&sx->iobuf, sx->passwd, plen, &nwritten);
     if(result || (nwritten != plen))
       return CURLPX_SEND_REQUEST;
   }
@@ -729,7 +730,7 @@ static CURLproxycode socks5_auth_init(struct Curl_cfilter *cf,
   return CURLPX_OK;
 }
 
-static CURLproxycode socks5_check_auth_resp(struct socks_state *sx,
+static CURLproxycode socks5_check_auth_resp(struct socks_ctx *sx,
                                             struct Curl_cfilter *cf,
                                             struct Curl_easy *data)
 {
@@ -754,7 +755,7 @@ static CURLproxycode socks5_check_auth_resp(struct socks_state *sx,
   return CURLPX_OK;
 }
 
-static CURLproxycode socks5_req1_init(struct socks_state *sx,
+static CURLproxycode socks5_req1_init(struct socks_ctx *sx,
                                       struct Curl_cfilter *cf,
                                       struct Curl_easy *data)
 {
@@ -823,7 +824,7 @@ static CURLproxycode socks5_req1_init(struct socks_state *sx,
   return CURLPX_OK;
 }
 
-static CURLproxycode socks5_resolving(struct socks_state *sx,
+static CURLproxycode socks5_resolving(struct socks_ctx *sx,
                                       struct Curl_cfilter *cf,
                                       struct Curl_easy *data,
                                       bool *done)
@@ -842,9 +843,8 @@ static CURLproxycode socks5_resolving(struct socks_state *sx,
   if(sx->start_resolving) {
     /* need to resolve hostname to add destination address */
     sx->start_resolving = FALSE;
-    DEBUGASSERT(sx->hostname && *sx->hostname);
     result = Curl_cf_dns_insert_after(
-      cf, data, Curl_resolv_dns_queries(data, cf->conn->ip_version),
+      cf, data, Curl_resolv_dns_queries(data, sx->ip_version),
       sx->hostname, sx->remote_port, TRNSPRT_TCP, TRUE);
     if(result) {
       failf(data, "unable to create DNS filter for socks");
@@ -928,7 +928,7 @@ out:
   return presult;
 }
 
-static CURLproxycode socks5_recv_resp1(struct socks_state *sx,
+static CURLproxycode socks5_recv_resp1(struct socks_ctx *sx,
                                        struct Curl_cfilter *cf,
                                        struct Curl_easy *data,
                                        bool *done)
@@ -1027,7 +1027,7 @@ static CURLproxycode socks5_recv_resp1(struct socks_state *sx,
  * destination server.
  */
 static CURLproxycode socks5_connect(struct Curl_cfilter *cf,
-                                    struct socks_state *sx,
+                                    struct socks_ctx *sx,
                                     struct Curl_easy *data)
 {
   CURLproxycode presult;
@@ -1037,14 +1037,13 @@ process_state:
   switch(sx->state) {
   case SOCKS_ST_INIT:
     sx->version = 5;
-    sx->resolve_local = (cf->conn->socks_proxy.proxytype == CURLPROXY_SOCKS5);
+    sx->resolve_local = (sx->proxy_type == CURLPROXY_SOCKS5);
     sxstate(sx, cf, data, SOCKS5_ST_START);
     FALLTHROUGH();
 
   case SOCKS5_ST_START:
-    if(cf->conn->bits.httpproxy)
-      CURL_TRC_CF(data, cf, "SOCKS5: connecting to HTTP proxy %s port %u",
-                  sx->hostname, sx->remote_port);
+    CURL_TRC_CF(data, cf, "SOCKS5: connecting to %s:%u",
+                sx->hostname, sx->remote_port);
     presult = socks5_req0_init(cf, sx, data);
     if(presult)
       return socks_failed(sx, cf, data, presult);
@@ -1179,13 +1178,11 @@ process_state:
   }
 }
 
-static void socks_proxy_cf_free(struct Curl_cfilter *cf)
+static void socks_proxy_ctx_free(struct socks_ctx *ctx)
 {
-  struct socks_state *sxstate = cf->ctx;
-  if(sxstate) {
-    Curl_bufq_free(&sxstate->iobuf);
-    curlx_free(sxstate);
-    cf->ctx = NULL;
+  if(ctx) {
+    Curl_bufq_free(&ctx->iobuf);
+    curlx_free(ctx);
   }
 }
 
@@ -1200,11 +1197,9 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf,
                                        struct Curl_easy *data,
                                        bool *done)
 {
-  CURLcode result;
-  struct connectdata *conn = cf->conn;
-  int sockindex = cf->sockindex;
-  struct socks_state *sx = cf->ctx;
+  struct socks_ctx *ctx = cf->ctx;
   CURLproxycode pxresult = CURLPX_OK;
+  CURLcode result;
 
   if(cf->connected) {
     *done = TRUE;
@@ -1215,47 +1210,19 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf,
   if(result || !*done)
     return result;
 
-  if(!sx) {
-    cf->ctx = sx = curlx_calloc(1, sizeof(*sx));
-    if(!sx) {
-      result = CURLE_OUT_OF_MEMORY;
-      goto out;
-    }
-
-    /* for the secondary socket (FTP), use the "connect to host"
-     * but ignore the "connect to port" (use the secondary port)
-     */
-    sx->hostname =
-      conn->bits.httpproxy ?
-      conn->http_proxy.host.name :
-      conn->bits.conn_to_host ?
-      conn->conn_to_host.name :
-      sockindex == SECONDARYSOCKET ?
-      conn->secondaryhostname : conn->host.name;
-    sx->remote_port =
-      conn->bits.httpproxy ? conn->http_proxy.port :
-      sockindex == SECONDARYSOCKET ? conn->secondary_port :
-      conn->bits.conn_to_port ? conn->conn_to_port :
-      (uint16_t)conn->remote_port;
-    sx->proxy_user = conn->socks_proxy.user;
-    sx->proxy_password = conn->socks_proxy.passwd;
-    Curl_bufq_init2(&sx->iobuf, SOCKS_CHUNK_SIZE, SOCKS_CHUNKS,
-                    BUFQ_OPT_SOFT_LIMIT);
-  }
-
-  switch(conn->socks_proxy.proxytype) {
+  switch(ctx->proxy_type) {
   case CURLPROXY_SOCKS5:
   case CURLPROXY_SOCKS5_HOSTNAME:
-    pxresult = socks5_connect(cf, sx, data);
+    pxresult = socks5_connect(cf, ctx, data);
     break;
 
   case CURLPROXY_SOCKS4:
   case CURLPROXY_SOCKS4A:
-    pxresult = socks4_connect(cf, sx, data);
+    pxresult = socks4_connect(cf, ctx, data);
     break;
 
   default:
-    failf(data, "unknown proxytype option given");
+    DEBUGASSERT(0); /* should not come here, checked it at creation time */
     result = CURLE_COULDNT_CONNECT;
     goto out;
   }
@@ -1265,7 +1232,7 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf,
     data->info.pxcode = pxresult;
     goto out;
   }
-  else if(sx->state != SOCKS_ST_SUCCESS)
+  else if(ctx->state != SOCKS_ST_SUCCESS)
     goto out;
 
 #ifdef CURLVERBOSE
@@ -1275,20 +1242,23 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf,
     if(!Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad))
       infof(data, "Opened %sSOCKS connection from %s port %d to %s port %d "
             "(via %s port %u)",
-            (sockindex == SECONDARYSOCKET) ? "2nd " : "",
+            (cf->sockindex == SECONDARYSOCKET) ? "2nd " : "",
             ipquad.local_ip, ipquad.local_port,
-            sx->hostname, sx->remote_port,
+            ctx->hostname, ctx->remote_port,
             ipquad.remote_ip, ipquad.remote_port);
     else
       infof(data, "Opened %sSOCKS connection",
-            (sockindex == SECONDARYSOCKET) ? "2nd " : "");
+            (cf->sockindex == SECONDARYSOCKET) ? "2nd " : "");
   }
 #endif
-  socks_proxy_cf_free(cf);
   cf->connected = TRUE;
 
 out:
   *done = (bool)cf->connected;
+  if(*done || result) {
+    ctx->user = NULL;
+    ctx->passwd = NULL;
+  }
   return result;
 }
 
@@ -1296,7 +1266,7 @@ static CURLcode socks_cf_adjust_pollset(struct Curl_cfilter *cf,
                                         struct Curl_easy *data,
                                         struct easy_pollset *ps)
 {
-  struct socks_state *sx = cf->ctx;
+  struct socks_ctx *sx = cf->ctx;
   CURLcode result = CURLE_OK;
 
   if(!cf->connected && sx) {
@@ -1323,24 +1293,24 @@ static CURLcode socks_cf_adjust_pollset(struct Curl_cfilter *cf,
 static void socks_proxy_cf_close(struct Curl_cfilter *cf,
                                  struct Curl_easy *data)
 {
-  DEBUGASSERT(cf->next);
   cf->connected = FALSE;
-  socks_proxy_cf_free(cf);
-  cf->next->cft->do_close(cf->next, data);
+  if(cf->next)
+    cf->next->cft->do_close(cf->next, data);
 }
 
 static void socks_proxy_cf_destroy(struct Curl_cfilter *cf,
                                    struct Curl_easy *data)
 {
   (void)data;
-  socks_proxy_cf_free(cf);
+  socks_proxy_ctx_free(cf->ctx);
+  cf->ctx = NULL;
 }
 
 static CURLcode socks_cf_query(struct Curl_cfilter *cf,
                                struct Curl_easy *data,
                                int query, int *pres1, void *pres2)
 {
-  struct socks_state *sx = cf->ctx;
+  struct socks_ctx *sx = cf->ctx;
 
   switch(query) {
   case CF_QUERY_HOST_PORT:
@@ -1383,15 +1353,53 @@ struct Curl_cftype Curl_cft_socks_proxy = {
 };
 
 CURLcode Curl_cf_socks_proxy_insert_after(struct Curl_cfilter *cf_at,
-                                          struct Curl_easy *data)
+                                          struct Curl_easy *data,
+                                          const char *hostname,
+                                          uint16_t port,
+                                          uint8_t ip_version,
+                                          uint8_t proxy_type,
+                                          const char *user,
+                                          const char *passwd)
 {
   struct Curl_cfilter *cf;
+  struct socks_ctx *ctx;
+  size_t hostlen = hostname ? strlen(hostname) : 0;
   CURLcode result;
 
-  (void)data;
-  result = Curl_cf_create(&cf, &Curl_cft_socks_proxy, NULL);
+  if(!hostlen)
+    return CURLE_FAILED_INIT;
+
+  switch(proxy_type) {
+  case CURLPROXY_SOCKS5:
+  case CURLPROXY_SOCKS5_HOSTNAME:
+  case CURLPROXY_SOCKS4:
+  case CURLPROXY_SOCKS4A:
+    break; /* all supported */
+  default:
+    failf(data, "unknown proxytype %d option given", proxy_type);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  /* NUL byte already part of struct size */
+  ctx = curlx_calloc(1, sizeof(*ctx) + hostlen);
+  if(!ctx) {
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  memcpy(ctx->hostname, hostname, hostlen);
+  ctx->remote_port = port;
+  ctx->ip_version = ip_version;
+  ctx->proxy_type = proxy_type;
+  ctx->user = user;
+  ctx->passwd = passwd;
+  Curl_bufq_init2(&ctx->iobuf, SOCKS_CHUNK_SIZE, SOCKS_CHUNKS,
+                  BUFQ_OPT_SOFT_LIMIT);
+
+  result = Curl_cf_create(&cf, &Curl_cft_socks_proxy, ctx);
   if(!result)
     Curl_conn_cf_insert_after(cf_at, cf);
+  else
+    socks_proxy_ctx_free(ctx);
   return result;
 }
 
index 520fb75ddbadb6e4bf469f9e1c02588b3a074329..ea368326d2bff987fb165131970389d45a5f1ee1 100644 (file)
@@ -46,8 +46,19 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
                                       struct Curl_easy *data);
 #endif
 
+/* Insert a SOCKS filter after `cf_at` for connecting to `hostname`
+ * and `port` with optional credentials.
+ * Credentials are NOT duplicated and are
+ * expected to exist during connect phase.
+ */
 CURLcode Curl_cf_socks_proxy_insert_after(struct Curl_cfilter *cf_at,
-                                          struct Curl_easy *data);
+                                          struct Curl_easy *data,
+                                          const char *hostname,
+                                          uint16_t port,
+                                          uint8_t ip_version,
+                                          uint8_t proxy_type,
+                                          const char *user,
+                                          const char *passwd);
 
 extern struct Curl_cftype Curl_cft_socks_proxy;