vague memory

うろ覚えを無くしていこうともがき苦しむ人の備忘録

Macで HTTP Proxy 経由のSSH

macOS からWindows を経由して SSH する機会があったため、調査した内容を残しておきます。
Web上で色々情報が見つかったのですが、現在では古い情報も混ざっているため自分用に整理した内容です。

f:id:htnosm:20190115014841j:plain



要件

macOS -> win_proxy(Windows) -> web(Linux)

上記のように直接接続が許可されていない、win_proxy(WindowsProxyサーバ)の背後のweb(Linuxサーバ)に対し、 macOSからSSH接続を行います。

HTTP CONNECT メソッドで接続を確立しトンネルすることで SSH での接続が可能になります。
環境は以下の通りです。

結果

Nmap付属のncatを使用すると最も環境に依存せずに実現可能と思います。

--proxy-type オプションで "http" を指定します。

Specify proxy type ("http" or "socks4" or "socks5")

$ ssh -o ProxyCommand='ncat --proxy-type http --proxy win_proxy:3128 %h %p' -i ~/.ssh/id_rsa ubuntu@web

# ssh config
Host    web
        Hostname        web
        User            ubuntu
        IdentityFile    ~/.ssh/id_rsa
        ProxyCommand ncat --proxy-type http --proxy win_proxy:3128 %h %p
        ServerAliveInterval 10

Linuxでのncコマンド

-X オプションで "connect" を指定します。

Supported protocols are “4” (SOCKS v.4), “5” (SOCKS v.5) and “connect” (HTTPS proxy).
If the protocol is not specified, SOCKS version 5 is used.

ssh ProxyCommand='nc -X connect -x win_proxy:3128 %h %p' -i ~/.ssh/id_rsa ubuntu@web

# ssh config
Host    web
        Hostname        web
        User            ubuntu
        IdentityFile    ~/.ssh/id_rsa
        ProxyCommand nc -X connect -x win_proxy:3128 %h %p
        ServerAliveInterval 10

Macでのncコマンド

macOS 標準搭載のncコマンドでは接続エラーを解消できずでした。

nc: Proxy error: "HTTP/1.1 200 Connection established" 
ssh_exchange_identification: Connection closed by remote host 

間にLinux等を挟む事で無理やり繋ぐ事は可能です。

ssh ProxyCommand='ssh bastion_linux nc --proxy-type http --proxy win_proxy:3128 %h %p' -i ~/.ssh/id_rsa ubuntu@web

# ssh_config
Host    bastion_linux
        Hostname    bastion_linux
        User        hoge

Host    web
        Hostname        web
        User            ubuntu
        IdentityFile    ~/.ssh/id_rsa
        ProxyCommand ssh bastion_linux nc --proxy-type http --proxy win_proxy:3128 %h %p
        ServerAliveInterval 10

調査

以下メモレベルですが、上記Nmap付属のncat使用に至った経緯です。
無駄に長いので折り畳みます。

HTTP Proxy 経由のSSH

OpenSSH で利用するには以下のいずれかが必要になります。

  • connect コマンド (connect.c)
  • netcat(nc) コマンド
    • Macは標準導入されている。派生コマンドが多数(後述)
  • -W オプション
    • OpenSSH 5.4 以降 で利用可能な模様
  • connect-proxy
    • Debian/Ubuntu であれば apt で導入可能な模様
    • Redhat系は RPMForge から connect を入れる事例が多い(しかし、既に RPMForge/RepoForge は無い物と考えた方が良い)

netcat(nc)色々

nc コマンドは色々な派生バージョンがあり、どれを指しているのかは環境・オプションにより異なっているようです。

- Ncat(Nmap付属)
    - Nmapの一部として開発された。GPLライセンス。
- OpenBSD netcat
    - 0から書き直されたnetcat互換ツールでIPv6に対応しているnetcat。BSDライセンス。
- GNU netcat
    - 0から書き直されたnetcat互換ツール。GPLライセンス。
- Netcat Darwin Port
    - Mac OS Xで使用可能なnetcatである。
- Windows版netcat
    - Windows上で使用可能なnetcatである。
- Jetcat
    - netcatの一部の機能をJavaで実現したものである。

Ncat(Nmap付属)

環境依存が最も少ないのではないかと思われる物です。

Mac OS X 用のバイナリもあります。 今回使用した端末は諸事情によりソフトウェアのインストールが行えなかったため実際には未確認です。
Linux上での接続は確認できました。オプション等は同じようなので、同様に接続可能と思われます。
proxy-type オプションに http 指定して接続します。

# インストール
$ sudo rpm -vhU https://nmap.org/dist/ncat-7.70-1.x86_64.rpm
Retrieving https://nmap.org/dist/ncat-7.70-1.x86_64.rpm
Preparing...                          ################################# [100%]
Updating / installing...
   1:ncat-2:7.70-1                    ################################# [100%]
$ which ncat
/usr/bin/ncat
# ヘルプ
$ ncat --help
Ncat 7.70 ( https://nmap.org/ncat )
Usage: ncat [options] [hostname] [port]

Options taking a time assume seconds. Append 'ms' for milliseconds,
's' for seconds, 'm' for minutes, or 'h' for hours (e.g. 500ms).
  -4                         Use IPv4 only
  -6                         Use IPv6 only
  -U, --unixsock             Use Unix domain sockets only
  -C, --crlf                 Use CRLF for EOL sequence
  -c, --sh-exec <command>    Executes the given command via /bin/sh
  -e, --exec <command>       Executes the given command
      --lua-exec <filename>  Executes the given Lua script
  -g hop1[,hop2,...]         Loose source routing hop points (8 max)
  -G <n>                     Loose source routing hop pointer (4, 8, 12, ...)
  -m, --max-conns <n>        Maximum <n> simultaneous connections
  -h, --help                 Display this help screen
  -d, --delay <time>         Wait between read/writes
  -o, --output <filename>    Dump session data to a file
  -x, --hex-dump <filename>  Dump session data as hex to a file
  -i, --idle-timeout <time>  Idle read/write timeout
  -p, --source-port port     Specify source port to use
  -s, --source addr          Specify source address to use (doesn't affect -l)
  -l, --listen               Bind and listen for incoming connections
  -k, --keep-open            Accept multiple connections in listen mode
  -n, --nodns                Do not resolve hostnames via DNS
  -t, --telnet               Answer Telnet negotiations
  -u, --udp                  Use UDP instead of default TCP
      --sctp                 Use SCTP instead of default TCP
  -v, --verbose              Set verbosity level (can be used several times)
  -w, --wait <time>          Connect timeout
  -z                         Zero-I/O mode, report connection status only
      --append-output        Append rather than clobber specified output files
      --send-only            Only send data, ignoring received; quit on EOF
      --recv-only            Only receive data, never send anything
      --allow                Allow only given hosts to connect to Ncat
      --allowfile            A file of hosts allowed to connect to Ncat
      --deny                 Deny given hosts from connecting to Ncat
      --denyfile             A file of hosts denied from connecting to Ncat
      --broker               Enable Ncat's connection brokering mode
      --chat                 Start a simple Ncat chat server
      --proxy <addr[:port]>  Specify address of host to proxy through
      --proxy-type <type>    Specify proxy type ("http" or "socks4" or "socks5")
      --proxy-auth <auth>    Authenticate with HTTP or SOCKS proxy server
      --ssl                  Connect or listen with SSL
      --ssl-cert             Specify SSL certificate file (PEM) for listening
      --ssl-key              Specify SSL private key (PEM) for listening
      --ssl-verify           Verify trust and domain name of certificates
      --ssl-trustfile        PEM file containing trusted SSL certificates
      --ssl-ciphers          Cipherlist containing SSL ciphers to use
      --ssl-alpn             ALPN protocol list to use.
      --version              Display Ncat's version information and exit

See the ncat(1) manpage for full options, descriptions and usage examples

OpenBSD netcat

Linux に標準導入されているコマンドを指している物と思われます。

Amazon Linux の例
$ yum list installed nc
nc.x86_64    1.84-24.8.amzn1    installed
[ec2-user@ip-172-30-2-241 ~]$
$ which nc
/usr/bin/nc
# help 抜粋
$ nc -h
usage: nc [-46DdhklnrStUuvzC] [-i interval] [-p source_port]
      [-s source_ip_address] [-T ToS] [-w timeout] [-X proxy_version]
      [-x proxy_address[:port]] [hostname] [port[s]]

# man 抜粋
NC(1)                                                            BSD General Commands Manual                                                           NC(1)

NAME
     nc — arbitrary TCP and UDP connections and listens

SYNOPSIS
     nc [-46DdhklnrStUuvzC] [-i interval] [-p source_port] [-s source_ip_address] [-T ToS] [-w timeout] [-X proxy_protocol] [-x proxy_address[:port]]
        [hostname] [port[s]]

DESCRIPTION
     The nc (or netcat) utility is used for just about anything under the sun involving TCP or UDP.  It can open TCP connections, send UDP packets, listen
     on arbitrary TCP and UDP ports, do port scanning, and deal with both IPv4 and IPv6.  Unlike telnet(1), nc scripts nicely, and separates error messages
     onto standard error instead of sending them to standard output, as telnet(1) does with some.
・・・
SEE ALSO
     cat(1), ssh(1)

AUTHORS
     Original implementation by *Hobbit* ⟨hobbit@avian.org⟩.
     Rewritten with IPv6 support by Eric Jackson <ericj@monkey.org>.

CAVEATS
     UDP port scans will always succeed (i.e. report the port as open), rendering the -uz combination of flags relatively useless.

BSD                                                                    August 22, 2006                                                                   BSD
Ubuntu の例
$ dpkg -l | grep netcat
ii  netcat-openbsd                   1.105-7ubuntu1                             amd64        TCP/IP swiss army knife
$ which nc
/bin/nc
$ ls -l /bin/nc
lrwxrwxrwx 1 root root 20 Sep 12 13:39 /bin/nc -> /etc/alternatives/nc
$ ls -l /etc/alternatives/nc
lrwxrwxrwx 1 root root 15 Sep 12 13:39 /etc/alternatives/nc -> /bin/nc.openbsd
$ ls -l /bin/nc.openbsd
-rwxr-xr-x 1 root root 31248 Dec  4  2012 /bin/nc.openbsd
# help
$ nc
This is nc from the netcat-openbsd package. An alternative nc is available
in the netcat-traditional package.
usage: nc [-46bCDdhjklnrStUuvZz] [-I length] [-i interval] [-O length]
      [-P proxy_username] [-p source_port] [-q seconds] [-s source]
      [-T toskeyword] [-V rtable] [-w timeout] [-X proxy_protocol]
      [-x proxy_address[:port]] [destination] [port]

# man(抜粋)
$ man nc |cat
NC(1)                    BSD General Commands Manual                    NC(1)

NAME
     nc — arbitrary TCP and UDP connections and listens

SYNOPSIS
     nc [-46bCDdhklnrStUuvZz] [-I length] [-i interval] [-O length]
        [-P proxy_username] [-p source_port] [-q seconds] [-s source]
        [-T toskeyword] [-V rtable] [-w timeout] [-X proxy_protocol] [-x
        proxy_address[:port]] [destination] [port]

DESCRIPTION
     The nc (or netcat) utility is used for just about anything under the sun
     involving TCP, UDP, or UNIX-domain sockets.  It can open TCP connec‐
     tions, send UDP packets, listen on arbitrary TCP and UDP ports, do port
     scanning, and deal with both IPv4 and IPv6.  Unlike telnet(1), nc
     scripts nicely, and separates error messages onto standard error instead
     of sending them to standard output, as telnet(1) does with some.
・・・
SEE ALSO
     cat(1), ssh(1)

AUTHORS
     Original implementation by *Hobbit* ⟨hobbit@avian.org⟩.
     Rewritten with IPv6 support by Eric Jackson <ericj@monkey.org>.
     Modified for Debian port by Aron Xu ⟨aron@debian.org⟩.

CAVEATS
     UDP port scans using the -uz combination of flags will always report
     success irrespective of the target machine's state.  However, in con‐
     junction with a traffic sniffer either on the target machine or an
     intermediary device, the -uz combination could be useful for communica‐
     tions diagnostics.  Note that the amount of UDP traffic generated may be
     limited either due to hardware resources and/or configuration settings.

BSD                            February 7, 2012                           BSD

Netcat Darwin Port

Macで標準導入されているncコマンドを指すと思われます。

$ which nc
/usr/bin/nc
# help(stringsからの)抜粋
・・・
This help text
%s%s
-i secs
Delay interval for lines sent, ports scanned
Keep inbound sockets open for multiple connects
Listen mode, for inbound connects
%s%s
Suppress name/port resolutions
%s%s%s
-p port
Specify local port for remote connects (cannot use with -l)
Randomize remote ports
-s addr
Local source address
Answer TELNET negotiation
Use UNIX domain socket
UDP mode
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
Zero-I/O mode [used for scanning]
%s%s
Port numbers can be individual or ranges: lo-hi [inclusive]
Set SO_RECV_ANYIF on socket
Set SO_AWDL_UNRESTRICTED on socket
-b ifbound
Bind socket to interface
Don't use cellular connection
Don't use expensive interfaces
Do not use flow advisory (flow adv enabled by default)
-G conntimo
Connection timeout in seconds
-H keepidle
Initial idle timeout in seconds
-I keepintvl
Interval for repeating idle timeouts in seconds
-J keepcnt
Number of times to repeat idle timeout
-K tclass
Specify traffic class
-L num_probes Number of probes to send before generating a read timeout event
Set SO_INTCOPROC_ALLOW on socket
Use MULTIPATH domain socket
-N num_probes Number of probes to send before generating a write timeout event
Use old-style connect instead of connectx
Issue socket options after connect/bind
--apple-delegate-pid pid
Set socket as delegate using pid
--apple-delegate-uuid uuid
Set socket as delegate using uuid
--apple-ext-bk-idle
Extended background idle time
--apple-ecn
Set the ECN mode
--apple-sockev
Receive and print socket events
--apple-notify-ack
Receive events when data gets acknowledged
--apple-tos
Set the IP_TOS or IPV6_TCLASS option
--apple-netsvctype
Set the network service type
usage: nc [-46AacCDdEFhklMnOortUuvz] [-K tc] [-b boundif] [-i interval] [-p source_port] [--apple-delegate-pid pid] [--apple-delegate-uuid uuid]
  [-s source_ip_address] [-w timeout] [-X proxy_version]
  [-x proxy_address[:port]] [hostname] [port[s]]
・・・
@(#)PROGRAM:nc  PROJECT:netcat-41

今回、この標準コマンドで繋ぐことができれば話が早かったのですが、 弊端末からは接続できない(以下エラーが解消できない)状態でした。
同様のNW構成としたLinux端末からは接続可能、また、接続可能な事例もいくつか見られましたので、環境・バージョンの問題かと思われます。

nc: Proxy error: "HTTP/1.1 200 Connection established" 
ssh_exchange_identification: Connection closed by remote host 

GNU netcat

brew でインストール可能です。 proxy_version のオプションが無く、http_proxyの指定ができないようでした。

$ brew install netcat

$ brew list netcat
/usr/local/Cellar/netcat/0.7.1/bin/nc
/usr/local/Cellar/netcat/0.7.1/bin/netcat
/usr/local/Cellar/netcat/0.7.1/share/info/netcat.info
/usr/local/Cellar/netcat/0.7.1/share/man/ (2 files)
$ which netcat
/usr/local/bin/netcat
$ ls /usr/local/Cellar/netcat/0.7.1/bin/
nc@     netcat*
# help
$ netcat --help
GNU netcat 0.7.1, a rewrite of the famous networking tool.
Basic usages:
connect to somewhere:  netcat [options] hostname port [port] ...
listen for inbound:    netcat -l -p port [options] [hostname] [port] ...
tunnel to somewhere:   netcat -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'