▼最近の豪華なX11環境でsshを使ってXプロトコルを中継する▼

昔なら単純に 6000番ポートを中継するだけで

	local% ssh -R 6010:localhost:6000 remote
	remote% setenv DISPLAY=localhost:10
	remote% _
Xを中継できたのですが、最近の統合デスクトップ環境では うまくいかなかったりします。 最近のXのGUI環境はセキュリティが堅くなっているためでもあります。

[V ineでR ed Hat]

$Id: ssh-x.html,v 1.10 2011-05-11 12:37:57+09 kabe Exp kabe $


▼ssh先が X11Forwarding yes になっている場合

※remote機の /etc/ssh/sshd_configで、X11Forwarding yes と 設定されている、場合。 デフォルトはOSによって微妙に違う。

この環境なら一番簡単。

	local% ssh -X remote
	remote%  _
だけでXクライアントはそのまま起動できる。

	remote: sshd <==:10== xclock
	         |
	         V
	local:  ssh -X remote =unix:0=> Xserver

▽内部動作

sshd側で X11Forwarding yes になっていると、 ssh -X では以下のことをしてくれる。

従ってremote側にも最低 xauth コマンドがないと機能しない。 sshd_config(5) に XAuthLocation 設定があるのはこのため。

なお、xauth周りの加工は local 側の Xサーバが -auth オプションで起動されている場合に必要なもの。 Xサーバに -auth-nolisten tcp もつけていない場合は xhost +localhost とTCP forwarding だけでもつながるようにはなる (はず)。

cf. Xsecurity(7), Xserver(1)


▼ssh先が X11Forwarding no になっている場合

ssh -X remote してもDISPLAYは設定されず、 何も起こらない。

こういった場合は、
おおかた X11Forwarding yes でsshd側がやってくれていたことを 手動でやればよいのだが、

remote の DISPLAY=localhost:10 を local の DISPLAY=unix:0 に転送するのが ssh -Rではできない。 ので、下のいずれかの対処をする:

・ 一旦 ssh -X localhost して、XのunixソケットをTCPに変換する。
local機に X11Forwarding yes なsshdが入っていることが前提。
・ localのXサーバの -nolisten tcp オプションを外す
gdm では /etc/X11/gdm/custom.conf で DisallowTCP=false にする。 これは gdmsetupでも設定可能。 local機の 6000番ポートにつなげられる人がちょっかい出せるようになるので、 おすすめされていない。 (xauthが有効な限りDoS以外の害はなさそうだが)

なお WindowsとかのXサーバを使っているなら、localの6000番ポートは 開いているはずなので 最初からlocalhost:6000に転送すればよい。

localにて env DISPLAY=localhost:10 xhost などが動くことを確認したら、 以下のような感じで接続する。

	local% xauth list 
	.......unix:10 MIT-MAGIC-COOKIE-1 xxxxxx.....xxxxxxx
	local% ssh -R 6010:localhost:6010 remote
	remote% setenv DISPLAY localhost:10
	remote% xauth remove unix:10		#ゴミ掃除
	remote% xauth add unix:10 MIT-MAGIC-COOKIE-1 xxxxxx.....xxxxxxx
	remote% xhost
	(接続拒否されなければOK)
	remote: sshd <==:10== xclock
	         |
	         V
	local:  ssh -R =localhost:6010=> sshd
	local:                            v
	local:                           ssh -X localhost =unix:0=> Xserver

xauth add を手動で実行する場合、cookieの値は 最初に ssh -X した先の xauth list の値を使うこと。

なお、ssh -R を多段でつなぐ場合、 xauth add を手動で叩くのは最終目的地 (Xのクライアントを動かす機械) だけでよい。

ssh -X が行うX11転送では、末端まで同じ cookie は使わず、 架空の cookie を新しく作って使用し、転送毎にcookieを入替えている。 (cf. ssh(1) の X11 and TCP forwarding項)
さすがに -R ではこのcookie入替えは再現できないので、 localとremote側で同じcookieを設定するしかない。


▼エラーメッセージ対応

remote% xhost
xhost:  unable to open display ""

DISPLAY環境変数が設定されていない。

ssh -X で入ってこうなる場合は、remote側の sshd が X11Forwarding no に設定されている。 もしくは、remote側にxauthコマンドが無い。(素の*BSDなど)
remoteの管理者にsshd_config(5)を変えてもらうか、代替策を使う。

ssh -R の場合は手でsetenv DISPLAY localhost:10 するだけ。

remote% xhost
xhost:  unable to open display "localhost:10"

localhost:6010 番ポートで待っているサービスが無い。
remote に入るとき、 ssh -X か -R を忘れている。
まれに、localhostが索けないという事例もある。

remote% xhost
X connection to localhost:10.0 broken (explicit kill or server shutdown)

localhost:6010 はあるのだが、転送先の Xサーバポート(local上のlocalhost:6000番など) が無い。 考えられる原因:

remote% xhost
X11 connection rejected because of wrong authentication.
X connection to localhost:10.0 broken (explicit kill or server shutdown)

remote側でxauth addをやっていない。

対処:remote側で手動で xauth add を発行する。 (ssh -X + X11Forwarding yesなら自動でやってくれる)

なお、X11 connection rejected because of wrong authentication.は xhostコマンドやXサーバではなく、 local側で動いているsshが出しているもの。

なお、ssh -XのX中継器は必ず xauth 式の認証を要求するので、 xhost + での認証解除(手抜き)は効かない。 多段 ssh で -R と -X を混ぜて使う際は注意。


▼lbxproxyで帯域節約

遠い場所のXクライアントを起動すると、Xのプロトコル量も 結構馬鹿にならないので、lbxproxy(1)で 帯域圧縮もそれなりに有効。

lbxproxyは、sshした先の最終目的地で起動するのがよい。 lbxproxyを通った後に帯域圧縮されるので、 Xクライアントから見て海を渡る前に通っていないと意味がない。 また、データ圧縮に関してはlbxproxyにやらせるより ssh -C で行ったほうが効率がよいかもしれない。

	remote% echo $DISPLAY		# 圧縮前のクライアント接続先
	localhost:10
	remote% xauth list		# cookieを確認
	host/unix:10  MIT-MAGIC-COOKIE-1  xxxx....xxxx
	remote% lbxproxy -nocomp :11 &	# ここは無圧縮。番号を指定しなかった場合は:63になる
	Using port number '11'
	remote% setenv DISPLAY localhost:11	# lbxproxyに接続先変更
	remote% xauth add unix:11 MIT-MAGIC-COOKIE-1  xxxx....xxxx
	remote% xhost			# 拒否されなければ成功
	remote: sshd <=:10== lbxproxy <=:11== xclock
	         |
	         | (低速回線)
	         V
	local:  ssh -X -C ==unix:0=> Xserver

▼付録:remoteのGDMログイン画面をローカルに出す

	remote% gdmflexiserver --xnest --no-lock

Xnestがremote側で動く。
Xnestをローカルで動かしたとしても、転送されるXプロトコルの量は 大して変わらない。これが一番簡単。

GDMはデフォルトではXDMCPは無効になっているし、UDPであるXDMCPを sshで中継するのは基本的に不可能。ので、 ローカルでXnestするにしてもXDMCPはあまり現実的ではない。

(Xnestとgdmgreeterを手動で上げてもログイン画面でログイン名入力が出来ない?)

▽エラー対処

gdmgreeter --xnest --no-lock --debugで 起動して、メッセージを見てみる。

原因:xauth にて、 unix:0 のエントリがない。

バグかどうかは不明なものの、gdmflexiserverはGDMに対し、 Xnestを使う場合でも常に unix:0 のcookieで問い合わせを行う。 対処:中継しているDISPLAYのcookieと同じものをunix:0 にも仕込む。

$ xauth add unix:10  MIT-MAGIC-COOKIE-1  M491CC00K1EM491CC00K1EM491CC00K1E
$ xauth list
remote/unix:10  MIT-MAGIC-COOKIE-1  M491CC00K1EM491CC00K1EM491CC00K1E
remote/unix:0  MIT-MAGIC-COOKIE-1  M491CC00K1EM491CC00K1EM491CC00K1E
$ _

対処:DISPLAY環境変数を変えてみる。

ログの"127" は本来 "127.0.0.1:10" などになるはずなのだが、 gdmflexiserverのバグなのか DISPLAY=127.0.0.1:10 がうまく解釈できない。 DISPLAY=:10 とか DISPLAY=localhost:10 で試してみる。


かべ@sra-tohoku.co.jp