プロキシーまたはその仕組み

多くのプロキシプログラムはサービスに頼っていますが、誰もがその仕組みを知っているわけではありません。 それらの基礎と実際の実装に組み込まれているアルゴリズムについてお話します。



どこから始まったの



5年ちょっと前、私は学生寮に住んでいて、インターネットへのアクセスはプロキシサーバー(以下、プロキシと呼びます)を介して行われました。 通常のユーザーの観点からは、これはあまり便利ではありません。 ほとんどのプログラムは、プロキシを操作する方法を知りません。後者の可能性は非常に限られています。 しかし、彼らが言うように、「私たちは持っているものを持っています」。 幸いなことに、他のプログラムをプロキシで動作させるために設計されたソフトウェア製品があります(以降、プロキシ)。 私もこれらの1つを使用しました。



当時、友人と私は「新世界の剣」というゲームにはまっています。 ゲームはプロキシと友達になりませんでした。 基本的に、問題はゲームの保護システムにあります。 使用可能なプロキシが試されましたが、役に立ちませんでした。 私の友人は彼の代理を書くことに決め、このプロセスに私を引き付けました。 ソケットとプロキシがどのように機能するかについてのアイデアがあり、「それがどのように機能するか」というアルゴリズムをかなり迅速に作成しました。 私のアルゴリズムとDelphi開発環境で武装した友人が最初のプロキシ実装を作成し、プロキシゲームとの友人の作成に成功しました。



時間が経ちました。 開発とソースコードは失われます。 そして、プロキシの必要性がどれほど悪かったのです(企業は、従業員のプロキシを介してインターネットを配布したいのです)。 何もする必要はありません。最初から書く必要がありました。 そして、プロジェクト「azimuth-proxyfier」が生まれました。そのデバイスについては後で説明します。 (記事の最後にあるソースへのリンク)



すべてが非常に簡単です



HTTP / 1.1プロトコルのドキュメントを見ると、HTTPS(Webサーバーへの安全な接続)をサポートするために導入されたすばらしいCONNECTメソッドが見つかります。 次のように機能します。

  1. プロキシは、リソース(リモートソケット)への接続要求を送信します。
  2. 許可されている場合(承認など)、プロキシは指定されたリソースへの接続を試みます。
  3. すべてが正常であれば、肯定的な回答が送信されます。 その後、データはユーザーとリモートリソース間を行き来します。


ダイアログの例(リクエストとレスポンスは空の文字列で終わり、その後生データ):

CONNECT 205.188.11.33:443 HTTP/1.1 Connection: Keep-alive Host: 205.188.11.33:443 HTTP/1.1 200 Connection established <RAWDATA>
      
      





プロキシはブリッジとして機能します。 そして、このチャネルは、ソケットとリモートソケットの間のTCPチャネルです。

必要なもの:

  1. プロキシ要求を送信し、応答を処理するコードを記述します。 そして、これはすべて、ソケットライブラリからの接続機能のハンドラーになるはずです。
  2. どういうわけか、コードをアプリケーションのアドレス空間にロードし(プロキシと友達にしたい)、それを機能させる必要があります。


上記のポイントを実装するための多くのオプションがあります。 私の場合、ターゲットプラットフォームはWindowsです。 この場合、アプリケーションのディレクトリから動的ライブラリをロードし、次にシステムからロードするシステムの興味深い機能があります。 原則として、ソケットを備えたアプリケーションはws2_32.dllまたはwsock32.dllライブラリを介して動作します (以前のバージョンのWindowsとの互換性のために存在します)。 そして、これらのライブラリーの「アダプター」は、同様の名前と同様の機能セットで作成されました。 実際、システムにはwininet.dllネットワークといくつかのソケットオプションを操作するための高レベルライブラリもありますが、保守性が強く、ほとんどの場合、Berkeleyソケット(WindowsではWinsock 1)を使用し続けます。



「アダプター」のロード時に、後者は「実際の」ライブラリーをロードし、2つを除くすべての関数呼び出しのブロードキャストを開始します。 最初はconnectです。 私たちのアプリケーションは、プロキシの存在について実際には何も知りません。 直接IPアドレスに接続しようとしています。 そして、このアドレスはパラメーターを渡します。 ここですべての作業を行う必要があります。 コードは、実際の接続アドレスが送信される別のアドレス(プロキシアドレス)に接続します。 「2番目の機能は何ですか?」と尋ねます。 宛先アドレスがプログラムでユーザーによって入力された場合(およびその他の場合)、ドメイン名が使用されます(たとえば、「www.example.org」)。 ただし、 接続機能はドメイン名の操作方法を知りません。 これは、 gethostbyname関数が必要な場所です(その助けを借りて、ドメイン名がIPアドレスに変換されます)。 ここでは、ドメイン名の形式で要求されたアドレスを記憶し、偽のアドレスを返します。 接続関数では、逆変換を行います。 プロキシのリクエストを送信するとき、IPとドメイン名の両方のアドレスを指定できます。



実装に精通したい方は、ソースコードを読むか、完成した製品を使用してください。プロジェクトページhttp://code.google.com/p/azimuth-proxyfier/へようこそ(プロジェクトはC言語で実装され、BSDライセンスで配布されます) 。



このアルゴリズムはほとんどのオペレーティングシステムで有効であり、コードの実装方法を理解するだけで十分です。



ご清聴ありがとうございました。



All Articles