3389
Windows のリモートデスクトップが待ち受けるポート。サービスが起動しないときは既に誰かに取られていて、クライアントが回り続けるときは黙って捨てられています。
自分の環境の行をそのまま実行してください。ポートを掴んでいるプロセス名と、バインドしているアドレスが出ます。たいていはそれだけで答えが分かります。
netstat -ano | findstr ":3389"これは Microsoft 自身の RDP トラブルシューティングガイドが使っている手順そのものです。`-a` ですべての接続と待ち受けポートを表示し、`-n` でアドレスとポートを数値のまま保ち、`-o` で所有プロセス ID を最後の列に足します。探すのは Local Address が `:3389` で終わり State が LISTENING の行です。`0.0.0.0:3389` は全インターフェイス、`127.0.0.1:3389` ならループバックのみで、リモートのセッションは絶対に受けられません。次に PID を引くのは素の `tasklist` ではなく `tasklist /svc | findstr "1234"` です。リスナーは `svchost.exe` の中にいるので、その裏のサービスが `TermService` だと分かるのは `/svc` の列だけです。PID が別のものなら、そのプログラムが先にポートを取っています。RDP ではなくそちらを動かしてください。
qwinsta犯人探しの前にこれを実行してください。答えている問いが違います——そもそもリスナーは存在するのか。`rdp-tcp` という名前の行が State `Listen` で出ていれば RDP のリスナーは動いていて、問題はもっと外側、ファイアウォールか経路か認証情報にあります。その行がなければリスナーは一度も上がっておらず、`netstat` に 3389 が出ないのは他のプロセスとはまったく関係のない理由です。その場合は Remote Desktop Services(`TermService`)と Remote Desktop Services UserMode Port Redirector(`UmRdpService`)が動いているか、そして `fDenyTSConnections` が `0` かを確認してください。
sudo ss -tlnp 'sport = :3389'3389 で待ち受けている Linux マシンは、Microsoft の何かではなく xrdp か同種のサーバーを動かしています。`-t` で TCP ソケット、`-l` で待ち受けのみ、`-n` でサービス名の解決を飛ばし、`-p` で所有プロセスを出します。`sport = :3389` は送信元ポートのフィルタです。Local Address:Port の列がバインド先で、`0.0.0.0:3389` はネットワークに届き、`127.0.0.1:3389` はループバックのみ、これは xrdp を SSH トンネル越しに使う想定のときの通常の構成です。持ち主は `users:(("xrdp",pid=987,fd=11))` と出ます。`ss` がなければ `sudo netstat -tlnp | grep :3389` が、スラッシュ区切りの pid/program の列で同じ答えを出します。どちらも自分の所有でないプロセスを名指しするには特権が必要です。
sudo lsof -nP -iTCP:3389 -sTCP:LISTENmacOS が同梱しているのは RDP クライアントであってサーバーではないので、ここで待ち受けているものがあれば、それはコンテナか、VM の転送ポートか、自分で入れたサードパーティのサーバーです。`-n` と `-P` でアドレスもポートも数値のまま、`-iTCP:3389` でポートを選び、`-sTCP:LISTEN` でリスナーだけに絞ります。COMMAND と PID が持ち主で、NAME がバインドアドレス。`127.0.0.1:3389` はループバックのみ、`*:3389` は全インターフェイスです。COMMAND が `com.docker.backend` ならコンテナの公開ポートなので、プロセスではなくコンテナを止めてください。何も出ない(lsof は終了コード 1)なら誰も待ち受けておらず、ポートは本当に空いています。
`nmap -Pn -p 3389 host.example.com` は、クライアントが実際にいる場所からそのポートがどう見えるかを教えてくれます。`-Pn` はホスト探索を飛ばすので、ping を無視するホストもスキャンされます。三つの答えの意味は nmap がきっちり定義しています。`open` は対象上のアプリケーションが待ち受けている、`closed` はホストは答えたがそこで何も待ち受けていない、`filtered` はファイアウォールやフィルタ、その他のネットワーク上の障害物がプローブを塞いでいて nmap にはどちらか判断できない、です。RDP ではこの区別がそのまま診断になります。`closed` ならサーバー側(サービス停止、`fDenyTSConnections` が 1、`PortNumber` の変更)、`filtered` なら Windows ファイアウォールのルールかクラウドのセキュリティグループを見に行くことになります。`--reason` でリセットが返ってきたのか何も来なかったのかが分かり、`-sV` を付ければハンドシェイクを読ませられます。スキャンは自分が責任を持つホストにだけ。
| 出ているもの | 意味 |
|---|---|
The client spins, then shows the generic dialog listing three reasons: remote access is not enabled, the computer is turned off, or it is not available on the network | あのダイアログは何でも受けの表示で、三つのうちどれなのかは教えてくれません。代わりに順番に潰していってください。対象で `qwinsta` を実行して `rdp-tcp` の行が `Listen` か、`netstat -ano | findstr ":3389"` に LISTENING の行があるか、`fDenyTSConnections` が `0` か、そしてファイアウォール。一段ずつ、ダイアログが選べなかった理由を一つずつ消していけます。 |
The connection is refused immediately — the handshake gets an instant reset | ホストには届いていて、誰も待ち受けていません。`TermService` が停止しているか、リモートデスクトップが無効(`fDenyTSConnections` が `1`、設定画面のチェックボックスを上書きするグループポリシーがそこに固定している可能性もあります)か、`WinStations\RDP-Tcp` の `PortNumber` が変えられていてリスナーがまったく別の場所にいるかです。最後のケースは `qwinsta` が 1 行で見分けます。リスナーは存在するのに、あなたが叩いた番号にいない、という形で出ます。 |
The client waits many seconds and then reports a timeout | 何も答えていないので、拒否ではなく破棄です。Windows ファイアウォールのリモートデスクトップの受信規則、クラウドのセキュリティグループやネットワークセキュリティグループ、あるいは経路上のどこかのネットワーク ACL です。拒否は即座、破棄は遅いので、待ち時間そのものが証拠になります。`nmap --reason` が `closed` ではなく `filtered` を返せば確定です。 |
Only one usage of each socket address (protocol/network address/port) is normally permitted | Windows のエラー 10048、`EADDRINUSE` の現地語版です。リモートデスクトップサービスが起動する前に、別の何かが 3389 を掴みました。Microsoft の手順に従ってください。`netstat -ano | findstr ":3389"` で PID を取り、`tasklist /svc | findstr "<pid>"` でその裏のサービスを見ます。持ち主が `TermService` でないなら、推奨される直し方は RDP を動かすことではなく、そのプログラムのほうを動かすことです。 |
netstat shows nothing on 3389 and the listener still cannot bind | 占有ではなく予約で、これは Windows における権限失敗の形です。探すべきプロセスが存在しません。`netsh interface ipv4 show excludedportrange protocol=tcp` が、Hyper-V・WSL2・Docker Desktop・Windows の NAT サービスが起動時に確保する動的ポートの帯を一覧します。3389 がそのどれかに入っていたら、確保したサービスを再起動してください。プロセスを kill しても何も起きません。そもそも存在しないからです。 |
The identity of the remote computer cannot be verified. Do you want to connect anyway? | 素の状態のマシンでは想定内で、ネットワークの障害ではありません。サービスが自分のために生成した RDP の自己署名証明書を提示されていて、どのクライアントもそれを検証できません。セッションは暗号化されているが認証されていない、つまり向こう側にいるのがどのホストなのかは何も証明できていない、ということです。それが重要ならリスナーに本物の証明書を発行してください。そして以前は信頼された証明書が入っていたホストでこの警告が出たなら、それは煩わしさではなく発見として扱ってください。 |
The session connects but is far laggier than the same link used to be | TCP の 3389 は開いていて、UDP の 3389 が開いていません。Microsoft の UDP トランスポート拡張はグラフィックスとマルチメディアに同じ番号を使い、それが上がらないとセッションは黙って TCP だけにフォールバックします。ファイアウォールのルールが TCP だけでなく両方のプロトコルを覆っているか確認してください。 |
IANA は 3389 を `ms-wbt-server`(Microsoft の Windows-Based Terminal の略)として TCP・UDP 両方で登録していて、Windows は実際に両方を使います。セッションを運ぶのは TCP、グラフィックスとマルチメディアを UDP に載せるのが Microsoft の UDP Transport Extension で、その仕様書はターミナルサーバー側の受信 UDP 接続要求の既定ポートも 3389 だと記しています。TCP しか開けていないファイアウォールのせいで、接続はできるのに品質の悪い回線で目に見えて悪化する、という現象が起きるのはこのためです。Windows ではこのリスナーは普通のプログラムではありません。リモートデスクトップサービス、つまり `TermService` のもので、これは `svchost.exe` の中にホストされています。だから素の `tasklist` で PID を引いても `svchost.exe` としか出ず、何の役にも立ちません。`tasklist /svc` ならサービス名まで出ます。残りはレジストリの三つの事実で決まります。`HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server` の `fDenyTSConnections` は、リモートデスクトップが有効なら `0`、無効なら `1` で、設定画面のチェックボックスがどう見えていようとグループポリシーがこれを `1` に固定していることがあります。`...\Terminal Server\WinStations\RDP-Tcp` の `PortNumber` が、実際にポートを決めている値です。そして `qwinsta` は、`rdp-tcp` のリスナーが `Listen` 状態まで到達したかどうかを教えてくれます。これはサービスが動いているかどうかとは別の問いです。Windows の外では、xrdp のようなサードパーティのサーバーが同じ番号を使うので、3389 で応答する Linux ホストは Microsoft の何かではなく、そちらを動かしています。
3389 を公開インターネットに出さないでください。ここの歴史は理屈ではなく具体的です。CVE-2019-0708、通称 BlueKeep は、Windows 7・Server 2008・Server 2008 R2 のリモートデスクトップサービスにあった認証前のリモートコード実行の欠陥でした。認証情報もユーザー操作もソーシャルエンジニアリングも不要で、脆弱なリスナーに到達できさえすればよかったので、ワーム化しました。Microsoft はサポート終了済みのリリースにも修正を出し、脆弱なコードが動く前に認証を強制するという理由で、ネットワークレベル認証が部分的な緩和策になると注記しています。`PortNumber` でリスナーを別の番号に動かすのは防御になりません。Microsoft 自身のトラブルシューティング文書が RDP を別のポートで動かすことを推奨していませんし、サービスを指紋で判定するスキャナーは番号に関係なく見つけます。クリックして通り過ぎる TLS の警告も防御ではありません。あそこで出ているのは通常、サービスが自分で生成してコンピューター証明書ストアのリモートデスクトップの下に置いた自己署名証明書なので、それを受け入れても、これからドメインのパスワードを打ち込む相手が何者かは何一つ検証できていません。RDP は VPN か RD ゲートウェイ、踏み台の後ろに置き、送信元アドレスで絞り、ネットワークレベル認証を必須にし、相手が誰かが重要なら、自己署名証明書をクライアントが本当に検証できる発行済みの証明書に置き換えてください。
どれもブラウザ内で完結します。アップロードは発生しません。
3389 を調べているとき、ついでに確認することになりがちなポートです。
ほぼ権限の問題です。lsof や ss はソケット自体は出しますが、他ユーザーのプロセスは所有者の列を伏せるので、システムアカウントやコンテナランタイム、launchd が起動したサーバーは sudo を付け直すまで持ち主不明のリスナーに見えます。Windows は逆で、netstat には何も出ないのに bind だけ失敗します。これは Hyper-V や WSL2、Docker Desktop が起動時に予約したポート帯に当たっている状態です。
何なのかを先に見てください。取り残された開発サーバーなら問題ありませんが、書き込み中のデータベースは別ですし、他が依存しているシステムサービスも同様です。持ち主がコンテナならコンテナごと停止してください。ホストから見えるプロセスを kill してもランタイムが再起動するだけです。どうしても止められないものなら、自分のサービスを別のポートへ移すほうが早く片付きます。
0.0.0.0 ではなく 127.0.0.1 にバインドしているからです。各ページのコマンドがプロセス名と並べてバインド先アドレスを出しているのはこのためで、ループバックにバインドしたものはファイアウォールの設定に関係なく自分のマシンからしか届きません。最近は意図的にそれを既定にしているフレームワークも多いので、たいていはバグではなくフラグの問題です。すでに 0.0.0.0 なのに届かないなら、次に疑うのはホストのファイアウォールかクラウドのセキュリティグループです。
ほとんどなりません。インターネット全体を舐めるスキャナーはポート範囲を丸ごと走査し続けているので、稼げるのは数時間であって安全ではなく、代わりに関係者全員がその番号を覚える羽目になります。既定ポートを狙う無差別スキャンのログが減るという効果は確かにありますが、それだけです。結果を変えるのは認証と、送信元アドレスを絞ったファイアウォールと、そもそも外に出さないことです。
ポート 3389 でまだ詰まっていますか。ポート一覧をすべて見る。あるいは上に戻って、実際に出たエラー文から追ってください。