SSH through a proxy server in one command line
This post shows you how to SSH through a proxy server.
Prerequisites
The local client is required to have OpenBSD netcat installed.
There are 2 versions of netcat. Traditional netcat and OpenBSD netcat. This tutorial explicitly requires OpenBSD netcat. Traditional netcat won't work. See their difference here.
In macOS:
# nc -h
usage: nc [-46AacCDdEFhklMnOortUuvz] [-K tc] [-b boundif] [-i interval] [-p source_port]
[--apple-recv-anyif] [--apple-awdl-unres]
[--apple-boundif ifbound]
[--apple-no-cellular] [--apple-no-expensive]
[--apple-no-flowadv] [--apple-tcp-timeout conntimo]
[--apple-tcp-keepalive keepidle] [--apple-tcp-keepintvl keepintvl]
[--apple-tcp-keepcnt keepcnt] [--apple-tclass tclass]
[--tcp-adp-rtimo num_probes] [--apple-initcoproc-allow]
[--apple-tcp-adp-wtimo num_probes]
[--setsockopt-later] [--apple-no-connectx]
[--apple-delegate-pid pid] [--apple-delegate-uuid uuid]
[--apple-kao] [--apple-ext-bk-idle]
[--apple-netsvctype svc] [---apple-nowakefromsleep]
[--apple-notify-ack] [--apple-sockev]
[--apple-tos tos] [--apple-tos-cmsg]
[-s source_ip_address] [-w timeout] [-X proxy_version]
[-x proxy_address[:port]] [hostname] [port[s]]
Command Summary:
-4 Use IPv4
-6 Use IPv6
-A Set SO_RECV_ANYIF on socket
--apple-recv-anyif
-a Set SO_AWDL_UNRESTRICTED on socket
--apple-awdl-unres
-b ifbound Bind socket to interface
--apple-boundif ifbound
-C Don't use cellular connection
-c Send CRLF as line-ending
--apple-no-cellular
-D Enable the debug socket option
-d Detach from stdin
-E Don't use expensive interfaces
--apple-no-expensive
-F Do not use flow advisory (flow adv enabled by default)
--apple-no-flowadv
-G conntimo Connection timeout in seconds
--apple-tcp-timeout conntimo
-H keepidle Initial idle timeout in seconds
--apple-tcp-keepalive keepidle
-h This help text
-I keepintvl Interval for repeating idle timeouts in seconds
--apple-tcp-keepintvl keepintvl
-i secs Delay interval for lines sent, ports scanned
-J keepcnt Number of times to repeat idle timeout
--apple-tcp-keepcnt keepcnt
-K tclass Specify traffic class
--apple-tclass tclass
-k Keep inbound sockets open for multiple connects
-L num_probes Number of probes to send before generating a read timeout event
--tcp-adp-rtimo num_probes
-l Listen mode, for inbound connects
-m Set SO_INTCOPROC_ALLOW on socket
--apple-initcoproc-allow
-N num_probes Number of probes to send before generating a write timeout event
--apple-tcp-adp-wtimo num_probes
-o Issue socket options after connect/bind
-n Suppress name/port resolutions
--setsockopt-later
-O Use old-style connect instead of connectx
--apple-no-connectx
--apple-delegate-pid pid Set socket as delegate using pid
-p port Specify local port for remote connects (cannot use with -l)
-r Randomize remote ports
-s addr Local source address
-t Answer TELNET negotiation
-U Use UNIX domain socket
-u UDP mode
-v Verbose
-w secs Timeout for connects and final net reads
-X proto Proxy protocol: "4", "5" (SOCKS) or "connect"
-x addr[:port] Specify proxy address and port
-z Zero-I/O mode [used for scanning]
--apple-delegate-uuid uuid Set socket as delegate using uuid
--apple-ecn mode Set the ECN mode
--apple-ext-bk-idle Extended background idle time
--apple-kao Set keep alive offload
--apple-netsvctype Set the network service type
--apple-nowakefromsleep n No wake from sleep (when n >= 2 generate KEV_SOCKET_CLOSED)
--apple-notify-ack Receive events when data gets acknowledged
--apple-sockev Receive and print socket events
--apple-tos tos Set the IP_TOS or IPV6_TCLASS option
--apple-tos-cmsg Set the IP_TOS or IPV6_TCLASS option via cmsg
--apple-no-reuseport Do not use the SO_REUSPORT socket option
Port numbers can be individual or ranges: lo-hi [inclusive]
In Linux, with OpenBSD netcat:
# nc -h
OpenBSD netcat (Debian patchlevel 1)
usage: nc [-46CDdFhklNnrStUuvZz] [-I length] [-i interval] [-M ttl]
[-m minttl] [-O length] [-P proxy_username] [-p source_port]
[-q seconds] [-s sourceaddr] [-T keyword] [-V rtable] [-W recvlimit]
[-w timeout] [-X proxy_protocol] [-x proxy_address[:port]]
[destination] [port]
Command Summary:
-4 Use IPv4
-6 Use IPv6
-b Allow broadcast
-C Send CRLF as line-ending
-D Enable the debug socket option
-d Detach from stdin
-F Pass socket fd
-h This help text
-I length TCP receive buffer length
-i interval Delay interval for lines sent, ports scanned
-k Keep inbound sockets open for multiple connects
-l Listen mode, for inbound connects
-M ttl Outgoing TTL / Hop Limit
-m minttl Minimum incoming TTL / Hop Limit
-N Shutdown the network socket after EOF on stdin
-n Suppress name/port resolutions
-O length TCP send buffer length
-P proxyuser Username for proxy authentication
-p port Specify local port for remote connects
-q secs quit after EOF on stdin and delay of secs
-r Randomize remote ports
-S Enable the TCP MD5 signature option
-s sourceaddr Local source address
-T keyword TOS value
-t Answer TELNET negotiation
-U Use UNIX domain socket
-u UDP mode
-V rtable Specify alternate routing table
-v Verbose
-W recvlimit Terminate after receiving a number of packets
-w timeout Timeout for connects and final net reads
-X proto Proxy protocol: "4", "5" (SOCKS) or "connect"
-x addr[:port] Specify proxy address and port
-Z DCCP mode
-z Zero-I/O mode [used for scanning]
Port numbers can be individual or ranges: lo-hi [inclusive]
In Linux, with GNU netcat:
# nc --help
GNU netcat 0.7.1, a rewrite of the famous networking tool.
Basic usages:
connect to somewhere: nc [options] hostname port [port] ...
listen for inbound: nc -l -p port [options] [hostname] [port] ...
tunnel to somewhere: nc -L hostname:port -p port [options]
Mandatory arguments to long options are mandatory for short options too.
Options:
-c, --close close connection on EOF from stdin
-e, --exec=PROGRAM program to exec after connect
-g, --gateway=LIST source-routing hop point[s], up to 8
-G, --pointer=NUM source-routing pointer: 4, 8, 12, ...
-h, --help display this help and exit
-i, --interval=SECS delay interval for lines sent, ports scanned
-l, --listen listen mode, for inbound connects
-L, --tunnel=ADDRESS:PORT forward local port to remote address
-n, --dont-resolve numeric-only IP addresses, no DNS
-o, --output=FILE output hexdump traffic to FILE (implies -x)
-p, --local-port=NUM local port number
-r, --randomize randomize local and remote ports
-s, --source=ADDRESS local source address (ip or hostname)
-t, --tcp TCP mode (default)
-T, --telnet answer using TELNET negotiation
-u, --udp UDP mode
-v, --verbose verbose (use twice to be more verbose)
-V, --version output version information and exit
-x, --hexdump hexdump incoming and outgoing traffic
-w, --wait=SECS timeout for connects and final net reads
-z, --zero zero-I/O mode (used for scanning)
Remote port number can also be specified as range. Example: '1-1024'
Install netcat
In Ubuntu: use netcat-openbsd
(not netcat-traditional
)
sudo apt install -yq netcat-openbsd
In Arch Linux: use openbsd-netcat
(not netcat
)
sudo pacman -Sy openbsd-netcat
(Optional) Start the proxy server at local
If you already have a proxy server running, you can skip this section.
To use an existing remote server, called proxy.server
with ssh access as a SOCKS proxy, use the following command line.
ssh -D 12345 -CqNT proxy.server
-D
sock channel port specifier-C
: compress data-q
: quiet mode, no warning-N
: open SSH connection with no command to be executed-T
: do not allocate a TTY-terminal, save a tiny amount of memory
For more reliable command options in practice (such as -o "ServerAliveInterval 30" -o "ServerAliveCountMax 100"
flag, autossh
, etc.), check this post.
This command opens a SOCKS server at localhost at port 12345
. Note: this port must be available at the local client.
Use the SSH command through the SOCKS proxy server
To ssh to a proxied server at proxied.server
, through a SOCKS v5 proxy server localhost
at port 12345
, use the following command line:
ssh -o ProxyCommand="nc -X 5 -x localhost:12345 %h %p" proxied.server
If you are using the GNU version of netcat (while we require the OpenBSD version), there will be an error.
nc: invalid option -- 'X'
Try `nc --help' for more information.
kex_exchange_identification: Connection closed by remote host
Connection closed by UNKNOWN port 65535
To fix it, you can install the netcat OpenBSD version.