ラベル Ssh の投稿を表示しています。 すべての投稿を表示
ラベル Ssh の投稿を表示しています。 すべての投稿を表示

2015年10月1日木曜日

ssh 接続の共有

ssh 接続の共有をしてみました。

環境:
Ubuntu 14.04 (Trusty Tahr) Server

マスターの ssh 接続

マスターを remoteserver に ssh 接続します。

$ ssh -N -M -o "ControlPath=~/.ssh/ctrlmaster_%r@%h:%p" worker@remoteserver
  • 以下のようにコントロール用のソケットファイルができました。

    $ ls -l ~/.ssh/
    total 4
    srw------- 1 worker worker   0 Sep 30 12:51 ctrlmaster_worker@remoteserver:22
    -rw-r--r-- 1 worker worker 444 Sep 30 12:50 known_hosts
    
  • -N を指定しているのでシェルは起動しません。(シェルを起動させたい場合は -N を指定しません。)

  • CTRL-C で終了します。

  • この ssh 接続をスレーブで共有します。


スレーブの ssh 接続

マスターの ssh 接続共有を使って remoteserver に ssh 接続します。

$ ssh -o "ControlPath=~/.ssh/ctrlmaster_%r@%h:%p" worker@remoteserver
  • マスターで指定した ControlPath と同じものを指定します。
  • 共有した ssh を使うのでパスワード無しで remoteserver にログインできます。

おまけ

以下のようにすることでマスター側もスレーブ側も ssh 接続コマンドで -o "ControlPath=~/.ssh/ctrlmaster_%r@%h:%p" を省略することができます。

$ diff -u /etc/ssh/ssh_config.org /etc/ssh/ssh_config
--- /etc/ssh/ssh_config.org     2014-05-13 01:04:32.000000000 +0900
+++ /etc/ssh/ssh_config 2015-10-01 12:40:45.478880000 +0900
@@ -52,3 +52,4 @@
     HashKnownHosts yes
     GSSAPIAuthentication yes
     GSSAPIDelegateCredentials no
+    ControlPath ~/.ssh/ctrlmaster_%r@%h:%p

2015年6月13日土曜日

NAT ルーター越しに ssh するとタイムアウトして接続が切れるのでキープアライブパケットを定期的に流すようにした

ssh で NAT ルーター越しにサーバーに接続してしばらく何もしないで放っておくと、 TCP パケットが流れないので NAT ルーターでタイムアウトして ssh 接続が切れます。

何もしない状態でも ssh サーバーとクライアントの間でキープアライブパケットを定期的に流すようにすればタイムアウトしなくなるようなので試してみました。

環境

Ubuntu 14.04 (Trusty Tahr) Server

素の設定の場合

ssh 関連が Ubuntu の素の設定の場合、 ssh 接続で何もしない状態だとパケットが流れないことを確認してみました。

サーバー側で以下のように対象クライアントからの全ての接続を tcpdump でモニタします。

$ sudo tcpdump -n host XXX.XXX.XXX.XXX
  • XXX.XXX.XXX.XXX は実際にはクライアントの IP アドレスです。

この状態でクライアントからサーバーに ssh 接続してクライアント側で何もしない状態で 10分以上放置しました。

ssh 接続開始時にはもちろん ssh パケットがモニタされましたが、その後はやはり何もパケットが流れていませんでした。

途中の NAT ルーターでタイムアウトして接続も切られてしまいました。


ssh クライアント側の設定でキープアライブパケットを流す設定の場合

クライアント側で以下の設定をします

$ pwd
/etc/ssh

$ diff -u ssh_config.org ssh_config
--- ssh_config.org      2014-04-14 21:13:50.000000000 +0900
+++ ssh_config  2015-06-08 12:31:44.252575367 +0900
@@ -17,6 +17,7 @@
 # ssh_config(5) man page.

 Host *
+    ServerAliveInterval 300
 #   ForwardAgent no
 #   ForwardX11 no
 #   ForwardX11Trusted yes
  • キープアライブパケット送信間隔を 5分に設定しています。

サーバー側で同様に tcpdump でモニタしながらクライアントから ssh すると、以下のように指定した時間間隔 (この場合は 5分間隔) でクライアント (XXX.XXX.XXX.XXX) 側からキープアライブの通信を開始しています。

12:53:21.433323 IP XXX.XXX.XXX.XXX.63308 > YYY.YYY.YYY.YYY: Flags [P.], seq 52:104, ack 37, win 350, options [nop,nop,TS val 2979620 ecr 153068638], length 52
12:53:21.433474 IP YYY.YYY.YYY.YYY > XXX.XXX.XXX.XXX.63308: Flags [P.], seq 37:73, ack 104, win 297, options [nop,nop,TS val 153143671 ecr 2979620], length 36
12:53:21.463697 IP XXX.XXX.XXX.XXX.63308 > YYY.YYY.YYY.YYY: Flags [.], ack 73, win 350, options [nop,nop,TS val 2979628 ecr 153143671], length 0

12:58:21.559894 IP XXX.XXX.XXX.XXX.63308 > YYY.YYY.YYY.YYY: Flags [P.], seq 104:156, ack 73, win 350, options [nop,nop,TS val 3054653 ecr 153143671], length 52
12:58:21.560022 IP YYY.YYY.YYY.YYY > XXX.XXX.XXX.XXX.63308: Flags [P.], seq 73:109, ack 156, win 297, options [nop,nop,TS val 153218703 ecr 3054653], length 36
12:58:21.606306 IP XXX.XXX.XXX.XXX.63308 > YYY.YYY.YYY.YYY: Flags [.], ack 109, win 350, options [nop,nop,TS val 3054665 ecr 153218703], length 0
  • XXX.XXX.XXX.XXX は実際にはクライアントの IP アドレスです。
  • YYY.YYY.YYY.YYY は実際にはサーバーの IP アドレスです。

この状態で ssh クライアント側で何もせず 1時間以上放置してみましたが、途中の NAT ルーターでタイムアウトしなくなり、接続も切れなくなりました。


ssh サーバー側の設定でキープアライブパケットを流す設定の場合

クライアント側で 「ssh クライアント側の設定でキープアライブパケットを流す設定の場合」 で設定した /etc/ssh/ssh_config を元に戻します。

サーバー側で以下の設定をします

$ pwd
/etc/ssh

$ diff -u sshd_config.org sshd_config
--- sshd_config.org     2014-12-22 05:38:21.425887766 +0900
+++ sshd_config 2015-06-12 12:35:16.744721457 +0900
@@ -86,3 +86,5 @@
 # PAM authentication, then enable this but set PasswordAuthentication
 # and ChallengeResponseAuthentication to 'no'.
 UsePAM yes
+
+ClientAliveInterval 300
  • キープアライブパケット送信間隔を 5分に設定しています。

sshd を再起動

$ sudo service ssh restart

サーバー側で同様に tcpdump でモニタしながらクライアントから ssh すると、以下のように指定した時間間隔 (この場合は 5分間隔) でサーバー (YYY.YYY.YYY.YYY) 側からキープアライブの通信を開始しています。

12:46:48.115453 IP YYY.YYY.YYY.YYY > XXX.XXX.XXX.XXX.63423: Flags [P.], seq 4462:4530, ack 3102, win 277, options [nop,nop,TS val 239445342 ecr 66098], length 68
12:46:48.142194 IP XXX.XXX.XXX.XXX.63423 > YYY.YYY.YYY.YYY: Flags [.], ack 4530, win 311, options [nop,nop,TS val 141143 ecr 239445342], length 0
12:46:48.142238 IP XXX.XXX.XXX.XXX.63423 > YYY.YYY.YYY.YYY: Flags [P.], seq 3102:3138, ack 4530, win 311, options [nop,nop,TS val 141143 ecr 239445342], length 36
12:46:48.179373 IP YYY.YYY.YYY.YYY > XXX.XXX.XXX.XXX.63423: Flags [.], ack 3138, win 277, options [nop,nop,TS val 239445358 ecr 141143], length 0

12:51:48.242408 IP YYY.YYY.YYY.YYY > XXX.XXX.XXX.XXX.63423: Flags [P.], seq 4530:4598, ack 3138, win 277, options [nop,nop,TS val 239520373 ecr 141143], length 68
12:51:48.281817 IP XXX.XXX.XXX.XXX.63423 > YYY.YYY.YYY.YYY: Flags [P.], seq 3138:3174, ack 4598, win 311, options [nop,nop,TS val 216179 ecr 239520373], length 36
12:51:48.281870 IP YYY.YYY.YYY.YYY > XXX.XXX.XXX.XXX.63423: Flags [.], ack 3174, win 277, options [nop,nop,TS val 239520383 ecr 216179], length 0
  • XXX.XXX.XXX.XXX は実際にはクライアントの IP アドレスです。
  • YYY.YYY.YYY.YYY は実際にはサーバーの IP アドレスです。

この状態で ssh クライアント側で何もせず 1時間以上放置してみましたが、途中の NAT ルーターでタイムアウトしなくなり、接続も切れなくなりました。


2014年7月18日金曜日

ssh 接続時に IPv6 のポートを転送しないようにする

環境
Ubuntu 14.04 Desktop 日本語 Remix

最近 ssh でポート転送をすると

$ ssh user@Server -L 5901:localhost:5901
bind: Cannot assign requested address

というようにワーニングっぽいメッセージが表示されるようになりました。

実際はちゃんと ssh もポート転送もできていて実害はないのでそのままにしていましたが、気になるので調べました。

思い出してみると、このメッセージが出だしたのは「 IPv6 を無効にする 」を実施した頃からなので、ssh クライアント側で無効にしている IPv6 の TCP ポートを転送しようとして失敗しているのではないかと想定されます。

man ページを見てみると、ワーニングを出さない方法がいろいろありました。

方法その1: ssh のオプションで接続時のアドレスに IPv4 のみを使うようにする

ssh の -4 オプションというものがありました。
$ man ssh
... snip ...
         -4      Forces ssh to use IPv4 addresses only.
... snip ...

これで ssh 接続時に IPv4 のみを使う (IPv6 を使わない) ようにできるようです。

ワーニングメッセージが出なくなりました。

$ ssh user@Server -L 5901:localhost:5901 -4

方法その2: 127.0.0.1 の指定ポートのみを転送するようにする

指定したアドレスのポートのみを転送することができるようです。
$ man ssh
... snip ...
     -L [bind_address:]port:host:hostport
... snip ...

bind_address に localhost を指定するといけそうです。

期待が外れて、これはいけませんでした。

$ ssh user@Server -L localhost:5901:localhost:5901
bind: Cannot assign requested address

しかし、bind_address に 127.0.0.1 を指定した場合はなぜかいけました。

$ ssh user@Server -L 127.0.0.1:5901:localhost:5901

方法その3: sshd_config ファイルの設定で ssh 接続時のアドレスに IPv4 のみを使うようにする

ssh_config の man ページを見てみると...

$ man ssh_config
... snip ...
     AddressFamily
         t    Specifies which address family to use when connecting.  Valid arguments
             are “any”, “inet” (use IPv4 only), or “inet6” (use IPv6 only).
... snip ...

これも使えそうです。ssh の -4 オプションと同様に ssh 接続時に IPv4 のみを使う (IPv6 を使わない) ようにできるようです。

$ pwd
/etc/ssh

$ diff -U 0 ssh_config.org ssh_config
--- ssh_config.org      2014-04-14 21:13:50.000000000 +0900
+++ ssh_config  2014-07-18 21:23:13.546925882 +0900
@@ -33 +33 @@
-#   AddressFamily any
+    AddressFamily inet

いけました。

$ ssh user@Server -L 5901:localhost:5901

ssh_config を編集せずコマンドラインのオプションでも指定できます。

$ ssh user@Server -L 5901:localhost:5901 -o AddressFamily=inet

2014年6月15日日曜日

ssh できなかったので MTU を調整

サーバーに ssh しようとしたらうまく接続できなかったので調べてみました。

環境

Server/Client Ubuntu Version
ssh サーバー側 Ubuntu 14.04 Server
ssh クライアント側 Ubuntu 14.04 日本語 Remix

ssh できない事象

ssh クライアントから ssh サーバーに接続できません。

v オプションを付けて ssh しようとすると、以下のように 「 debug1: expecting SSH2_MSG_KEX_ECDH_REPLY 」で止まっています。

$ ssh -v SshServer
... snip ...
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: server->client aes128-ctr hmac-md5-etm@openssh.com none
debug1: kex: client->server aes128-ctr hmac-md5-etm@openssh.com none
debug1: sending SSH2_MSG_KEX_ECDH_INIT
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY

いろいろググると MTU が関係している場合もあるようです。今回の環境ではサーバー側にファイヤーウォールがあったり、クライアント側は (多分) PPPoE の光回線だったりするので MTU が原因であることは十分に考えられます。

クライアント側 MTU の調整

MTU の値を確認してみます。
$ ifconfig wlan0 | grep MTU
          UP BROADCAST RUNNING MULTICAST  MTU:1500  メトリック:1

クライアント側は無線 LAN なのでインタフェースは wlan0 です。MTU は通常の 1500 でした。

試しに MTU をずっと小さな値 (1000) にしてみました。
$ sudo ifconfig wlan0 mtu 1000

$ ifconfig wlan0 | grep MTU
          UP BROADCAST RUNNING MULTICAST  MTU:1000  メトリック:1

この MTU だと ssh できました。

MTU が原因だとわかったので、最適な MTU 値を探ります。

まず、MTU を 1500 に戻します。
$ sudo ifconfig wlan0 mtu 1500

$ ifconfig wlan0 | grep MTU
          UP BROADCAST RUNNING MULTICAST  MTU:1500  メトリック:1
データサイズを MTU と同じ 1500 バイトにしてフラグメント禁止の ping を google.com に打ってみます。
$ ping -c 1 -M do -s 1500 google.com
PING google.com (173.194.38.36) 1500(1528) bytes of data.
ping: local error: Message too long, mtu=1500

--- google.com ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms

ping は失敗しました。

「 PING google.com (173.194.38.36) 1500(1528) bytes of data. 」のメッセージより、ping データサイズを 1500 バイトにすると IP パケットサイズが 1528 バイトとなり、オーバーヘッドは 1528 - 1500 = 28 バイトだとわかりました。

「 ping: local error: Message too long, mtu=1500 」のメッセージより、クライアント PC のインターフェースからパケットを出せていないことがわかります。

これは MTU が 1500 なのに、それ以上の 1528 バイトのフラグメント禁止 IP パケットを送出しようとしたことが原因です。

パケットサイズが 1500 バイトになるようにフラグメント禁止の ping を打ってみます。

オーバーヘッドが 28バイトなので、ping のデータサイズは 1500 - 28 = 1472 バイトです。

$ ping -c 1 -M do -s 1472 google.com
PING google.com (173.194.38.40) 1472(1500) bytes of data.
From XXX.XXX.XXX.XXX icmp_seq=1 Frag needed and DF set (mtu = 1454)

--- google.com ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms

これも ping は失敗しました。

「 From XXX.XXX.XXX.XXX icmp_seq=1 Frag needed and DF set (mtu = 1454) 」のメッセージより XXX.XXX.XXX.XXX (クライアント側の光回線のブロードバンドルーターの IP アドレスです。) での MTU が 1454 で、この箇所でひっかかっていることがわかりました。

パケットサイズが 1454 バイトになるようにフラグメント禁止の ping を打ってみます。

ping のデータサイズは 1454 - 28 = 1426 バイトです。

$ ping -c 1 -M do -s 1426 google.com
PING google.com (173.194.38.46) 1426(1454) bytes of data.
1434 bytes from kix01s04-in-f14.1e100.net (173.194.38.46): icmp_seq=1 ttl=55 time=5.31 ms

--- google.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 5.319/5.319/5.319/0.000 ms

ping は成功しました。クライアント PC の wlan0 の MTU 最適値は 1454 であることがわかりました。

クライアント PC の wlan0 の MTU 値を 1454 に設定します。

これまでは ifconfig コマンドで MTU 値を設定していましたが、PC を再起動すると 初期値の 1500 に戻ってしまいます。

PC を再起動しても MTU の値が 1454 となるように以下の内容の /etc/network/if-up.d/mtu を設置します。

#!/bin/sh

/sbin/ifconfig wlan0 mtu 1454

このファイルに実行権を付けます。

$ sudo chmod +x /etc/network/if-up.d/mtu

PC を再起動して、wlan0 の MTU が 1454 になったことを確認します。

しかし、まだサーバーに ssh できません。最初と同様に「 debug1: expecting SSH2_MSG_KEX_ECDH_REPLY 」の部分で止まったままです。

サーバー側 MTU の調整

クライアント側と同様に MTU の値を調査すると最適値は 1318 でしたのでこの値に変更しました。

これで無事、クライアント PC からサーバーに ssh できるようになりました。

今回のケースではサーバー側の MTU を変更するだけで ssh できるようになったのかもしれませんが、一応クライアント側の MTU も最適な値のままにしておきました。


2013年9月22日日曜日

sshd で IPv6 をリッスンしないようにする

/var/log/auth.log を見ていたら
Sep 21 21:40:02 Server sshd[26755]: Server listening on 0.0.0.0 port 8071.
Sep 21 21:40:02 Server sshd[26755]: Server listening on :: port 8071.
サーバーで使ってるのは IPv4 だけなのに、IPv6 もリッスンしてました。
/ssh/sshd_config のそれらしい箇所は
#ListenAddress ::
#ListenAddress 0.0.0.0
IPv4, IPv6 どちらもコメントになってたので
#ListenAddress ::
ListenAddress 0.0.0.0
というように IPv4 だけコメントをはずしたら IPv4 だけをリッスンするようになりました。

2012年11月27日火曜日

ssh の SOCKS プロキシ

$ ssh -D 1080 UserA@SocksSshServer
とすると localhost の 1080 ポートが SOCKS プロキシのポートになります
実際の SOCKS プロキシ経由の接続は SocksSshServer が接続元になります

例えば、SOCKS プロキシ経由で ssh 接続する場合は
$ ssh -o 'ProxyCommand nc -x localhost:1080 %h %p' UserB@TargetServer
とします。

2012年9月23日日曜日

ssh で sudo 実行

リモートの Ubuntu に ssh で sudo でコマンドを実行しようとすると
$ ssh user@server sudo ls -la
user@server's password: 
sudo: no tty present and no askpass program specified
というように怒られてコマンドを実行できません。
tty が割り当てられているか askpass プログラムが指定されているかのどちらかであれば実行できるようです。
今回はリモートから ssh で sudo コマンドを実行するので askpass プログラムで対応するのは難しそうです。
askpass 以外で調べてみたら回避方法がいろいろありました。


回避方法その1

tty が割り当てられるようにすれば良いようなので
$ ssh -t user@server sudo ls -la
user@server's password:    # server に ssh する時のパスワードを入力
[sudo] password for user:  # sudo のためにパスワードを入力
...
というように ssh に -t オプションを指定するとうまくいきました。

なお、-t を指定ない場合は
$ ssh user@server tty
user@server's password: 
tty ではありません
というように確かに tty が割り当てられていません。

-t を指定する場合は
$ ssh -t user@server tty
user@server's password: 
/dev/pts/4
Connection to server closed.
今回のケースでは /dev/pts/4 が割り当てられました。


回避方法その2

visudo コマンドで sudoers ファイルに
Defaults        visiblepw
を追加すると
$ ssh user@server sudo ls -la
user@server's password:               # server に ssh する時のパスワードを入力
[sudo] password for user: ごにょごにょ # sudo のためにパスワードを入力
...
というように、うまく sudo できるのですが visible なパスワードだけに sudo 実行時に入力するパスワードが見えてしまいます。

sudoers の man ページで visiblepw の箇所を参照すると...
$ man sudoers
...
       visiblepw       By default, sudo will refuse to run if the user must
                       enter a password but it is not possible to disable
                       echo on the terminal.  If the visiblepw flag is set,
                       sudo will prompt for a password even when it would be
                       visible on the screen.  This makes it possible to run
                       things like "rsh somehost sudo ls" since rsh(1) does
                       not allocate a tty.  This flag is off by default.
...
パスワード入力が必要な場合に端末上でエコーをしないようにする (パスワードを見えないようにする) ことができない場合には初期状態では sudo を実行できないようです。
セキュリティ上の理由でしょうね。
visiblepw を設定するとパスワードが見えてしまう場合でも sudo を実行できるようになるんですね。
なお、tty が割り当てられていない場合も、端末上でエコーをしないようにすることができないからだめだったのかな。


回避方法その3

sudo コマンドに -S オプションを付けて実行
$ ssh user@server sudo -S ls -la
user@server's password:               # server に ssh する時のパスワードを入力
[sudo] password for user: ごにょごにょ # sudo のためにパスワードを入力
...
これもパスワードが見えてしまいますが sudo 実行できます。

sudo の man ページで該当箇所を参照すると...
$ man sudo
...
       -S          The -S (stdin) option causes sudo to read the password
                   from the standard input instead of the terminal device.
...
端末 (tty のことかな) からパスワードを読み込む代わりに標準入力から読み込むようになるようです。
上の「回避方法その2」の場合もバスワードを見えなくすることができる tty を使えない場合に、見えても良い標準入力からパスワードを入力するってことでよさそうなので、今回の場合は「回避方法その2」と「回避方法その3」は動作は同じとなるようです。



おまけ:

今回は
sudo: no tty present and no askpass program specified
というメッセージで ssh + sudo が実行できなかったのですが、
sudo: sorry, you must have a tty to run sudo
というメッセージで実行できな場合もあります。
これは sudoers ファイルで
Defaults        requiretty
が指定されている場合で、tty が割り当てられていないと sudo を実行できないので「回避方法その2」、「回避方法その3」では回避できず、「回避方法その1」で ssh に -t オプションを付けて tty が割り当てられるようにしないと sudo 実行できません。
なお、Ubuntu のデフォルトでは requiretty は指定されていないようです。