← Commit list

47d2019fb0

Joshua Rogers
Joshua Rogers
2026-09-22
SUCCESS Duration: 416s

Subject

socks: track SOCKS5 authentication per socket, not per connection

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

lib/socks.c+8 -2
@@ -586,6 +586,10 @@ static CURLproxycode socks5_req0_init(struct Curl_cfilter *cf,
/* disable username/password auth */
Curl_creds_unlink(&sx->creds);
+ if(cf->sockindex == FIRSTSOCKET)
+ /* the reuse of this connection depends on how this negotiation ends */
+ cf->conn->bits.socks5_authenticated = FALSE;
+
req[0] = 5; /* version */
nauths = 0;
if(!data->set.socks5_auth_only) {
@@ -647,7 +651,8 @@ static CURLproxycode socks5_check_resp0(struct socks_ctx *sx,
return CURLPX_OK;
case 1:
if(data->set.socks5auth & CURLAUTH_GSSAPI) {
- cf->conn->bits.socks5_authenticated = TRUE;
+ if(cf->sockindex == FIRSTSOCKET)
+ cf->conn->bits.socks5_authenticated = TRUE;
sxstate(sx, cf, data, SOCKS5_ST_GSSAPI_INIT);
return CURLPX_OK;
}
@@ -656,7 +661,8 @@ static CURLproxycode socks5_check_resp0(struct socks_ctx *sx,
case 2:
/* regular name + password authentication */
if(data->set.socks5auth & CURLAUTH_BASIC) {
- cf->conn->bits.socks5_authenticated = TRUE;
+ if(cf->sockindex == FIRSTSOCKET)
+ cf->conn->bits.socks5_authenticated = TRUE;
sxstate(sx, cf, data, SOCKS5_ST_AUTH_INIT);
return CURLPX_OK;
}
lib/urldata.h+1 -1
@@ -184,7 +184,7 @@ struct ConnectBits {
BIT(connect_only);
#ifndef CURL_DISABLE_PROXY
BIT(origin_is_proxy); /* if set, the connection's origin is a proxy */
- BIT(socks5_authenticated); /* SOCKS5 negotiated an authentication method */
+ BIT(socks5_authenticated); /* SOCKS5 authenticated on FIRSTSOCKET */
#endif
/* always modify bits.close with the connclose() and connkeep() macros! */
BIT(close); /* if set, we close the connection after this request */
tests/data/Makefile.am+1 -0
@@ -1742,6 +1742,7 @@ TESTCASES = \
test1742 \
test1743 \
test1744 \
+ test1745 \
test1790 \
test1791 \
test1800 \
tests/data/test1745+61 -0
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="US-ASCII"?>
+<testcase>
+<info>
+<keywords>
+FTP
+PASV
+RETR
+SOCKS5
+</keywords>
+</info>
+
+# Server-side
+<reply>
+<data>
+silly content
+</data>
+<servercmd>
+method 0
+method2 2
+user silly
+password person
+</servercmd>
+</reply>
+
+# Client-side
+<client>
+<features>
+proxy
+</features>
+<server>
+ftp
+socks5
+</server>
+<tool>
+lib%TESTNUMBER
+</tool>
+<name>
+SOCKS5 CURLAUTH_ONLY ignores auth done for the FTP data socket
+</name>
+<command>
+ftp://%HOSTIP:%FTPPORT/%TESTNUMBER %HOSTIP:%SOCKSPORT
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<errorcode>
+97
+</errorcode>
+<protocol crlf="yes">
+USER anonymous
+PASS [email protected]
+PWD
+EPSV
+TYPE I
+SIZE %TESTNUMBER
+RETR %TESTNUMBER
+QUIT
+</protocol>
+</verify>
+</testcase>
tests/libtest/Makefile.inc+1 -0
@@ -248,6 +248,7 @@ TESTS_C = \
lib1686.c \
lib1742.c \
lib1744.c \
+ lib1745.c \
lib1791.c \
lib1900.c \
lib1901.c \
tests/libtest/lib1745.c+74 -0
@@ -0,0 +1,74 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+/*
+ * argv1 = FTP URL
+ * argv2 = SOCKS5 proxy
+ */
+
+#include "first.h"
+
+static CURLcode test_lib1745(const char *URL)
+{
+ CURLcode result = CURLE_OK;
+ CURL *curl = NULL;
+
+ if(test_argc < 2)
+ return TEST_ERR_MAJOR_BAD;
+
+ res_global_init(CURL_GLOBAL_ALL);
+ if(result)
+ return result;
+
+ curl = curl_easy_init();
+ if(!curl) {
+ curl_mfprintf(stderr, "curl_easy_init() failed\n");
+ curl_global_cleanup();
+ return TEST_ERR_MAJOR_BAD;
+ }
+
+ start_test_timing();
+
+ easy_setopt(curl, CURLOPT_URL, URL);
+ easy_setopt(curl, CURLOPT_PROXY, libtest_arg2);
+ easy_setopt(curl, CURLOPT_PROXYTYPE, (long)CURLPROXY_SOCKS5);
+ easy_setopt(curl, CURLOPT_PROXYUSERPWD, "silly:person");
+
+ /* the proxy picks no authentication for the control connection and
+ username/password for the data connection */
+ result = curl_easy_perform(curl);
+ if(result)
+ goto test_cleanup;
+
+ /* the control connection did not authenticate, so it must not be
+ reused for this one */
+ easy_setopt(curl, CURLOPT_SOCKS5_AUTH,
+ (long)(CURLAUTH_BASIC | CURLAUTH_ONLY));
+ result = curl_easy_perform(curl);
+
+test_cleanup:
+
+ curl_easy_cleanup(curl);
+ curl_global_cleanup();
+ return result;
+}
tests/server/socksd.c+17 -0
@@ -49,6 +49,8 @@
* 0 - no auth
* 1 - GSSAPI (not supported)
* 2 - user + password
+ * "method2 [number]" - connect method to respond with on the second
+ * connection, defaults to the "method" one
* "response [number]" - the decimal number to respond to a connect
* SOCKS5: 0 is OK, SOCKS4: 90 is ok
*
@@ -58,6 +60,7 @@
static const char *backendaddr = "127.0.0.1";
static uint16_t backendport = 0; /* default is use client's */
+static unsigned int connections; /* number of clients served */
struct socksd_configurable {
unsigned char version; /* initial version byte in the request must match
@@ -66,6 +69,7 @@ struct socksd_configurable {
unsigned char nmethods_max; /* maximum number of nmethods to expect */
unsigned char responseversion;
unsigned char responsemethod;
+ unsigned char responsemethod2;
unsigned char reqcmd;
unsigned char connectrep;
uint16_t port; /* backend port */
@@ -79,6 +83,7 @@ struct socksd_configurable {
#define CONFIG_NMETHODS_MAX 3
#define CONFIG_RESPONSEVERSION CONFIG_VERSION
#define CONFIG_RESPONSEMETHOD 0 /* no auth */
+#define CONFIG_RESPONSEMETHOD2 0xff /* unset, use CONFIG_RESPONSEMETHOD */
#define CONFIG_REQCMD 1 /* CONNECT */
#define CONFIG_PORT backendport
#define CONFIG_ADDR backendaddr
@@ -96,6 +101,7 @@ static void socksd_resetdefaults(void)
s_config.nmethods_max = CONFIG_NMETHODS_MAX;
s_config.responseversion = CONFIG_RESPONSEVERSION;
s_config.responsemethod = CONFIG_RESPONSEMETHOD;
+ s_config.responsemethod2 = CONFIG_RESPONSEMETHOD2;
s_config.reqcmd = CONFIG_REQCMD;
s_config.connectrep = CONFIG_CONNECTREP;
s_config.port = CONFIG_PORT;
@@ -175,6 +181,13 @@ static void socksd_getconfig(void)
logmsg("method [%d] set", s_config.responsemethod);
}
}
+ else if(!strcmp(key, "method2")) {
+ pval = value;
+ if(!curlx_str_number(&pval, &num, 0xff)) {
+ s_config.responsemethod2 = (unsigned char)num;
+ logmsg("method2 [%d] set", s_config.responsemethod2);
+ }
+ }
else if(!strcmp(key, "response")) {
pval = value;
if(!curlx_str_number(&pval, &num, 0xff)) {
@@ -303,6 +316,10 @@ static curl_socket_t sockit(curl_socket_t fd)
socksd_getconfig();
+ if((++connections == 2) && (s_config.responsemethod2 !=
+ CONFIG_RESPONSEMETHOD2))
+ s_config.responsemethod = s_config.responsemethod2;
+
rc = sread(fd, buffer, sizeof(buffer));
if(rc <= 0) {
logmsg("SOCKS identifier message missing, recv returned %zd", rc);