Download raw body.
nc(1): SOCKS4A support
Hi,
OpenSSH supports the SOCKS protocol via ssh(1)'s -D option. This
supports SOCKS4, SOCKS4A and SOCKS5.
nc(1) supports SOCKS4 and SOCKS5 (and HTTP CONNECT) but not SOCKS4A,
but I'd like to ensure that SOCKS4A is tested while I refactor some
code in ssh(1).
So this adds SOCKS4A support for nc(1) and adds use of it to the
ssh(1) regression tests.
FYI SOCKS4A is a simple extension to SOCKS4 that allows passing
the destination host as a hostname (SOCKS4 only allows passing IPv4
addresses).
ok?
Index: regress/usr.bin/ssh/dynamic-forward.sh
===================================================================
RCS file: /cvs/src/regress/usr.bin/ssh/dynamic-forward.sh,v
diff -u -p -r1.17 dynamic-forward.sh
--- regress/usr.bin/ssh/dynamic-forward.sh 8 Mar 2024 11:34:10 -0000 1.17
+++ regress/usr.bin/ssh/dynamic-forward.sh 21 May 2025 08:26:04 -0000
@@ -48,7 +48,7 @@ stop_ssh() {
check_socks() {
direction=$1
expect_success=$2
- for s in 4 5; do
+ for s in 4A 4 5; do
for h in 127.0.0.1 localhost; do
trace "testing ssh socks version $s host $h (-$direction)"
${REAL_SSH} -q -F $OBJ/ssh_config -o \
Index: usr.bin/nc/nc.1
===================================================================
RCS file: /cvs/src/usr.bin/nc/nc.1,v
diff -u -p -r1.98 nc.1
--- usr.bin/nc/nc.1 1 Apr 2024 12:40:18 -0000 1.98
+++ usr.bin/nc/nc.1 21 May 2025 08:26:04 -0000
@@ -338,12 +338,18 @@ when talking to the proxy server.
Supported protocols are
.Cm 4
(SOCKS v.4),
+.Cm 4A
+(SOCKS v.4A),
.Cm 5
(SOCKS v.5)
and
.Cm connect
(HTTPS proxy).
If the protocol is not specified, SOCKS version 5 is used.
+Note that the SOCKS v.4 protocol is very limited and can only be used when
+the destination host can be resolved to an IPv4 address.
+The other protocols pass the destination as a string to be interpreted
+by the remote proxy and do not have this limitiation.
.It Fl x Ar proxy_address Ns Op : Ns Ar port
Connect to
.Ar destination
Index: usr.bin/nc/netcat.c
===================================================================
RCS file: /cvs/src/usr.bin/nc/netcat.c,v
diff -u -p -r1.229 netcat.c
--- usr.bin/nc/netcat.c 2 Nov 2024 17:19:27 -0000 1.229
+++ usr.bin/nc/netcat.c 21 May 2025 08:26:04 -0000
@@ -190,6 +190,8 @@ main(int argc, char *argv[])
socksv = -1; /* HTTP proxy CONNECT */
else if (strcmp(optarg, "4") == 0)
socksv = 4; /* SOCKS v.4 */
+ else if (strcasecmp(optarg, "4A") == 0)
+ socksv = 44; /* SOCKS v.4A */
else if (strcmp(optarg, "5") == 0)
socksv = 5; /* SOCKS v.5 */
else
Index: usr.bin/nc/socks.c
===================================================================
RCS file: /cvs/src/usr.bin/nc/socks.c,v
diff -u -p -r1.31 socks.c
--- usr.bin/nc/socks.c 8 Jun 2022 20:20:26 -0000 1.31
+++ usr.bin/nc/socks.c 21 May 2025 08:26:04 -0000
@@ -293,7 +293,7 @@ socks_connect(const char *host, const ch
default:
errx(1, "connection failed, unsupported address type");
}
- } else if (socksv == 4) {
+ } else if (socksv == 4 || socksv == 44) {
/* This will exit on lookup failure */
decode_addrport(host, port, (struct sockaddr *)&addr,
sizeof(addr), 1, 0);
@@ -302,10 +302,22 @@ socks_connect(const char *host, const ch
buf[0] = SOCKS_V4;
buf[1] = SOCKS_CONNECT; /* connect */
memcpy(buf + 2, &in4->sin_port, sizeof in4->sin_port);
- memcpy(buf + 4, &in4->sin_addr, sizeof in4->sin_addr);
+ if (socksv == 4) {
+ memcpy(buf + 4, &in4->sin_addr, sizeof in4->sin_addr);
+ } else {
+ /* SOCKS4A uses addr of 0.0.0.x, and hostname later */
+ buf[4] = buf[5] = buf[6] = 0;
+ buf[7] = 1;
+ }
buf[8] = 0; /* empty username */
wlen = 9;
-
+ if (socksv == 44) {
+ /* SOCKS4A has nul-terminated hostname after user */
+ if (strlcpy(buf + 9, host,
+ sizeof(buf) - 9) >= sizeof(buf) - 9)
+ errx(1, "hostname too big");
+ wlen = 9 + strlen(host) + 1;
+ }
cnt = atomicio(vwrite, proxyfd, buf, wlen);
if (cnt != wlen)
err(1, "write failed (%zu/%zu)", cnt, wlen);
nc(1): SOCKS4A support