SysAdmin Anywhere:UDPホールパンチを使用してリモートデスクトップを実装する

はじめに



システム管理者は本来怠け者です。 彼らは同じことを100回やるのが好きではありません。 最小限の介入で機能するように、すべてを自動化する必要があります。 そして、私はそのようなものです。



私自身と私の種類の生活を楽にするために、異なる管理ツールを単純な名前SysAdminを持つ1つの製品に組み合わせたプログラムが作成されました。 これには、マルチドメインネットワークのサポート、レポート、インベントリ、およびさまざまなMMCに散在している、またはサードパーティ製品に含まれている他の多くの有用なものが含まれています。 仕事がずっと便利になりました。 このプログラムはすでにバージョン5.3に成長しており、インターフェースをMetroスタイルに変更しました。 ただし、残念ながら、ドメインに含まれていないコンピューターを管理する方法はありません。



しかし、私はもっと欲しかった:











経験から:

仕事のためには、全国各地に支社があるVPNネットワークを作成する必要がありました。 強力なVPN機器が中央オフィスに設置され、同じ会社の機器がローカルに計画されましたが、より簡単でした。 インターネット接続、ローカルエリアネットワーク、設置された機器などに関するすべてを調べる必要がありました。 VPN機器を準備し、それらを送信して接続します。動作します。 状況のばかげたところは、実際にそれをすることが私にとってであり、出張がなく、地上のユーザーのレベルが非常に多様だったということでした。 もちろん、すべてが実装されましたが、通信や電話での会話には多くの時間がかかりました。




前述の制限のため、実装には仲介者が必要でした。 クライアント部分はリモートコンピューターにインストールされます。これにより、ファイアウォールでブロックされていない仲介者との接続が作成されます。 最もリモートのマシンによって開始されます。 管理者は、仲介者のアドレスに接続し、リモートコンピューターにアクセスするために、そのアドレスのみを知る必要があります。 このような仲介者のおかげで、多くの利点が得られます。











長い間、仲介業者のプラットフォームを探す必要はありませんでした。 ところで、Microsoft Azureはこれに適していました。 さらに、実験のために30日間アクセスすることができました。



そのため、この時点でシステム管理からプログラミングに焦点を変更したため、自分でサービスを作成することにしました。

同僚が加わり、一緒にプロトタイプサービスの開発を始めました。 テスト期間中に、リモートクライアントとクラウドサービス間の相互作用の実行可能なモデルを作成するというタスクに直面しました。 Azure SDKを使用して、さらに開発を続けることができます。







最も困難なことは、リモートコンピューターとクラウドサービスの間の永続的な接続を整理することでした。 長くて退屈な実験の結果として(クラウドへの展開には具体的な時間がかかります)、目標を達成する自信を与えた実用的なソリューションが登場しました。



ネットワーク機器から何も設定することなく、リモートコンピューターをクラウドに接続することができました。 私たちにとってこれは突破口でした。



ここでのタスクは、管理者からクラウドにコマンドを転送し、次にコンピューターにコマンドを転送し、管理者から回答を取得することでした。 普遍的な解決策はWMIを使用することであるという事実に落ち着きました。 さらに、クラウドサービスはWMIについて何も認識すべきではありません。 そのタスクは転送です。 これは、クラウドサービス自体とリモートコンピューター上のクライアントソフトウェアを可能な限り更新するために考案されました(現在、コンソールのボタンを押すことで最新バージョンに更新されます)。



例:

インストールされたサービスのリスト(Select * From Win32_Service)に加えて、値が必要なフィールドのセットに対する要求が管理者から送信されます。 これらはすべてJSONでシリアル化され、パッケージ化され、暗号化されてクラウドに送信されます。 クラウドでは、データはキューに書き込まれ、リモートコンピューターが接続されているサービスのインスタンスによってキューから取り出されます。

リクエストを受け取ったクライアントはそれを実現します。 結果はJSONによってシリアル化され、パッケージ化され、暗号化され、逆の順序で管理者に渡されます。




WMIの使用は、要求だけに限定されず、関数とプロシージャの呼び出しが実装されます。 たとえば、任意のサービスを停止できます。







すべてがシンプルに思えますが、スケーラブルなソリューションを作成することを計画している場合、クラウド内のサービスの複数のインスタンスを操作せずにできないことを忘れないでください。 それらを使用するには、開発の経験をある程度修正する必要があります。 1つのインスタンスではなく、複数のインスタンスがあり、それらが並行して動作することを常に念頭に置いてください。 あなたが排他的な何かをしたい場合-それについて残りのコピーに通知することを忘れないでください。 たとえば、請求。 各インスタンスがデータベースを通過し、クライアントのバランスを再計算するたびに非常に不快になり、毎回それを減らします。 このオプションは、発生する可能性のある例として示されていますが、現在この問題を解決するために現在取り組んでいます。







サービスを作成する際、ほとんどの場合、リモートデスクトップにアクセスする必要はないという事実から始めました。 プロセス、サービスなどを直接制御するだけで十分です。 これは、Webインターフェースを介して行う方が速くて簡単です。







それにもかかわらず、リモートデスクトップは非常に人気があり、その実装にはコンピューター間の直接接続が必要です。 画面の更新の遅延が数秒に達する可能性があるため、クラウドを介してこのような量の情報を転送することは非合理的です。



UDPホールパンチングの実装



最も興味深いタスクは、リモートデスクトップアクセスシステムの実装です。 時間を節約するために、既製のVNC実装を採用することが決定されましたが、独自の問題が発生しました。クライアントとVNCサーバーを直接接続することは不可能でした。 唯一の解決策は、トラフィックを中継することをタスクとする仲介者を作成することでした。 したがって、VNCクライアントとサーバーはローカルで動作すると「考え」ますが、実際にはそれらの間のすべてのトラフィックはインターネットを介して送信されます。







NATトラベサル


質問は未解決のままでした:仲介者間で情報を転送する方法は? 頭に浮かぶ最初のオプション-クラウドを介してすべてを駆動する-は、そのような非効率的な方法がどれほど高価かということです。 すべてを直接接続することをお勧めします。 ここで、標準的なNATトラバーサルの問題に遭遇します。







ネットワークアドレス変換(NAT)により、クライアント間の直接接続を確立できなくなります。 NATは、インターネットからアクセスできないローカルアドレスを外部アドレスに変換するプロセスです。 NATをバイパスする標準的な方法がいくつかあります:ポートを開く、VPNを上げる。



残念ながら、それらのどれも私たちに合っていません。 すぐに必要なすべてのコンポーネントのインストールが複雑になります(さらに、管理者の助けを借りずに、最も上級のユーザーが作業マシンにクライアントをインストールできるようにする必要があります)。 したがって、UDPホールパンチングメカニズムを使用します。



UDPホールパンチング


UDPホールパンチは、NATの背後にある2台のコンピューターを直接接続する方法です。 接続を開始するには、サードパーティ(両方のコンピューターから見えるサーバー)が必要です。 一般的に使用されるパブリックSTUNサーバー。



したがって、私たちのタスクは、リモートマシン上のクライアントとコンソールを直接接続することです。 これを行うには、いくつかの手順を実行する必要があります。











コードではどのように見えますか?


理論的には、すべてが単純です。 実際にはどのように見えますか?







上の画像からわかるように、もう少し複雑です。 まず、アプリケーションから接続要求を送信します。接続要求は、クラウドを介してクライアントマシン上のアプリケーションに送信されます(ステップ1および2)。 クライアントマシンは、STUNサーバーに外部アドレスとポートを要求します(ステップ3および4)。 ネットワークには多くのSTUNプロトコルの実装があります。



string address = String.Empty; udpClient = new UdpClient(); udpClient.AllowNatTraversal(true); ResultSTUN result = ClientSTUN.Query("stun.ekiga.net", 3478, udpClient.Client); if (result.NetType == UDP_BLOCKED) { /*   */ } else { address = result.PublicEndPoint.ToString(); }
      
      







なぜなら このソリューションではUDPを使用していますが、同じソケットを使用してクライアントに接続できます(これにより、TCPと区別されます)。



これらの簡単な操作の後、アドレスにはクライアントマシンの外部アドレスとポートが含まれます(またはエラーメッセージ)。 この貴重な情報は、クラウドを介して管理コンソールに送信されます(ステップ5および6)。 ポートとアドレスを知って接続を作成することは、すでに技術的な問題です。 これで、必要なすべての情報を転送できます。



NATトラバーサルのタスクはUDPを使用して簡単かつエレガントに解決されますが、TCPのすべての利点(パケット配信の保証、データの整合性、重複の欠如など)が必要な場合はどうでしょうか。 最初に思い浮かぶのは、UDPの上にプロトコルを書くことです。 当然、この問題に最初に遭遇するのは私たちではありません。 したがって、短い検索の後、 Lindgren.Networkのようなソリューションを見つけることができます。これは最終的にアプリケーションで使用されます。






All Articles