本物のsock_raw

画像



生のソケットは、プログラマに他のソケットAPIよりも多くのオプションを提供します。 これらの「幅広い」機会については誰もが知っていますが、それらの多かれ少なかれ体系的な説明はインターネットでは一般的ではありません。 このギャップを埋め、未加工のソケットの目的と、ネットワークソフトウェアで使用するためのオプションに対処してみましょう。



したがって、生のソケットは、次のようなシステムコールを使用するときに使用できる特別なタイプのソケットです。



int socket = socket(AF_INET, SOCK_RAW, IPPROTO_*);
      
      





私は抵抗することはできず、ソケット呼び出しで考えられる引数とその概念的な意味について少し余談します。 ソケットAPIは、一般化されたプログラミングインターフェイス、つまり さまざまなネットワークメカニズム、または単にホスト内の相互作用で動作することを可能にするインターフェイス。 呼び出しの最初の引数は、いわゆる 通信ドメイン。 ソケットAPIの作成者は、通話で指定する通信ドメインAF_INETをTCP / IP(IPv4)ベースのインターワーキングに割り当てました。 2番目の引数は、ソケットのタイプを指定します。ソケットは、提供するデータ転送のセマンティクスに従ってタイプされます(SOCK_STREAM-ストリーミング、SOCK_DGRAM-データグラム)。 この場合、ソケットタイプSOCK_RAWが使用されます。これはおそらく、2番目の引数が転送のセマンティクスではなく、特別な低レベル機能へのアクセスを意味する場合のルールからの唯一の逸脱です。 最後に、3番目の引数はプロトコルを指定します。 ほとんどが呼び出しの3番目の引数として使用できる定数のリストは、ファイル/usr/src/linux-*/include/linux/in.hにあります。*はカーネルバージョンです。 最も一般的に使用される定数は、IPPROTO_TCP、IPPROTO_UDP、IPPROTO_ICMP、IPPOROTO_IGMP、IPPROTO_RAWです。



rawソケットの操作を開始すると、少なくとも2つの機能(データがどのようにカプセル化され、IPヘッダーにアクセスできるか)がすぐにわかります。 rawソケットを使用して送信されたデータは、トランスポート層をバイパスして、IPデータグラムのペイロードフィールドに直接カプセル化されます。 ヘッダーについては、データグラムの送信と受信という2つの状況を区別すると便利です。 rawソケットを使用するユーザーアプリケーションは、ヘッダーを含むIPデータグラム全体を常に受信します。 同時に、データグラムのヘッダーフィールドの有効性に必要なチェックはすべてカーネルによって実行され、アプリケーションは未加工のソケットを介してデータグラムを受信することはありません。これは、たとえば、IPプロトコルの無効なバージョン(つまり、IPv4とは異なるバージョン)を示します。



画像



生のソケットを介してデータを送信する場合、プログラマはIPヘッダーを作成するタスクをカーネルにシフトするか、ヘッダーを自分で作成するかを選択できます。 IP_HDRINCLソケットオプションを使用すると、2番目の方法が可能です(Linuxでは、socket()呼び出しの3番目の引数としてIPPROTO_RAW定数を使用すると、このオプションが自動的にオンになる状況があります)。 ただし、IP_HDRINCLオプションを使用した場合でも、カーネルはプログラマを「支援」します。 そのため、Total LengthおよびHeader Checksumデータグラムのヘッダーフィールドは常にカーネルによって自動的に入力され、プログラマーが値をゼロのままにしておくと、Source AddressおよびIdentificationフィールドはカーネルによって入力されます。 独自のデータグラムヘッダーを作成する機能は、主に「台無しにされた」ソースIPアドレスを持つパケットを送信するために使用されます。



生のソケットは、ある程度制限されたパケットキャプチャメカニズムとして使用できます。 これにはいくつかの理由があります。 まず、受信パケットのコピーのみがrawソケットを介して受信できますが、このマシンでは生成されず、通過(ルーティング)されません。 次に、すべてのIPトラフィックではなく、特定のプロトコルIDを持つ未加工のIPデータグラムのみが未加工のソケットを介して受信できます(プロトコルIDは、ソケットの作成に使用されるsocket()システムコールの3番目の引数に対応します)。 最後に、FreeBSDのrawソケット(Linuxを除く)の特徴的な機能は、カーネルがそれを処理する方法を知らない場合にのみIPデータグラムを取得できることです(以下で説明するICMPおよびIGMPプロトコルパケットを除く)。 つまり、カーネルは、指定されたプロトコルIDを持つIPデータグラムを処理するように設計されたコードを実装しません。 また、次の事実は興味深いものです。同じパラメータを持つ複数のrawソケットが作成された場合、各ソケットは着信パケットの独自のコピーを受け取ります。



ネットワークスキャナを作成する場合、rawソケットは不可欠です。 たとえば、次のような呼び出しを使用できます。



 int socket = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
      
      







次に、TCPセグメントを作成し、送信して生のソケットを送信するだけです。 送信元IPアドレスを偽造する可能性があることを忘れないでください。このコンテキストでは便利です。 同様に、カーネルネットワークスタックをファジングするプログラムを作成できます。 たとえば、設計されたトランスポートレベルパッケージには、必要なフィールドに明らかに無効な値が含まれている場合があります。



生のソケットでTCPを使用する場合、次のことを理解する価値があります。 TCPプロトコルの動作を完全に再現することはできません。未加工のソケットが提供する機能に基づいて、これを成功させることはできません。 できる最大のことは、このタイプの着信トラフィック(Linux上)を受け入れ、確立または確立されたTCP接続の一部であると思われる、別々に取得された発信TCPセグメントを送信することです。



最後に、生のソケットを使用する別の側面に言及する価値があります。 ICMPやIGMPなど、動作が主にカーネル自体によって制御されるプロトコルがあります。 場合によっては、ユーザーアプリケーションからこれらのプロトコルへのアクセスは非常に便利です。



 int socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); int socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
      
      







これにより、ping、クラシックトレーサ(ICMP)などのユーティリティ、およびIGMPサブスクリプションを操作できるユーティリティが作成されます。



したがって、すべての事実をまとめて、生のソケットの目的について結論を下すことができます。 このメカニズムは、実装する必要がある場合に役立ちます。







生のソケットが提供する機能が、元々はネットワーク攻撃を行うためのソフトウェアの作成を促進することを意図していたとは想像しにくいです。 むしろ、このメカニズムが必要な理由は、かなり平和的な目標として機能しました。 ただし、生のソケットの機能は、最終的に、ハッカーソフトウェアに応用されています。





関連リソースへの関連リンク



SOCK_RAWわかりやすい

http://sock-raw.org/papers/sock_raw



4.2bsdネットワーキング実装ノート(1983年7月改訂)

http://www.eecs.berkeley.edu/Pubs/TechRpts/1983/CSD-83-146



Linux manページ、SOCKET(2)

http://man7.org/linux/man-pages/man2/socket.2.html



Linux manページ、SOCKET(7)

ttp://man7.org/linux/man-pages/man7/socket.7.html



Linux manページ、RAW(7)

http://man7.org/linux/man-pages/man7/raw.7.html



All Articles