raw - Linux の IPv4 raw ソケット
#include <sys/socket.h>
#include <netinet/in.h>
raw_socket = socket(AF_INET, SOCK_RAW, int protocol);
raw
ソケットを使うと、新しい
IPv4
プロトコルをユーザー空間で
実装できるようになる。
raw
ソケットは、リンクレベルヘッダーを
含まない raw
データグラムの送受信ができる。
IPv4
レイヤは、扱っているソケットで
IP_HDRINCL
ソケットオプションが有効になっていなければ、
パケットを送信するときに
IP
ヘッダーを生成する。
IP_HDRINCL
オプションが有効になっているときは、パケットには
IP
ヘッダーが含まれていなければならない。
受信時には、 IP
ヘッダーは常にパケットに含まれている。
In order to create a raw socket, a process must have the
CAP_NET_RAW
capability in the user namespace that governs its network namespace.
All packets or errors matching the
protocol number specified for the raw
socket are passed to this socket. For a list of the allowed protocols, see the
IANA list of assigned protocol numbers at
http://www.iana.org/assignments/protocol-numbers/
and
getprotobyname(3).
IPPROTO_RAW
のプロトコルは暗黙のうちに
IP_HDRINCL
を有効にするので、
渡されたヘッダーで指定された、あらゆる
IP
プロトコルを送信できる。
IPPROTO_RAW
経由でのあらゆる IP
プロトコルの受信は、
raw
ソケットを用いては行えない。
IP
ヘッダーフィールド。
IP_HDRINCL
によって送信時に変更される。 |
|
IP チェックサム |
常に変更される |
ソースアドレス |
元の値が 0
の時に変更される |
パケット ID |
元の値が 0
の時に変更される |
全体の長さ |
常に変更される |
IP_HERINCL
が指定されていて、 IP
ヘッダーに 0
でない送信先アドレスが記入されていた場合は、
その送信先アドレスがパケットの経路を決めるのに用いられる。
MSG_DONTROUTE
が指定されている時には、
送信先アドレスはローカルなインターフェースを参照するものでなければならない。
さもないと、ルーティングテーブルの参照はいずれにせよ行われるが、
ゲートウェイが必要な経路は無視される。
IP_HDRINCL
がセットされていなければ、
raw ソケットの IP
ヘッダーオプションを
setsockopt(2)
を用いて設定することができる。詳細な情報は
ip(7) を見よ。
Linux 2.2 以降では、 IP
ヘッダーの全てのフィールドとオプションとを
IP
ソケットオプションによって設定できる。したがって
raw
ソケットが必要になるのは、新しいプロトコルを設計する場合か、
ユーザーインターフェースを持たないプロトコル
(ICMP など) を扱う場合に
限られる。
パケットは、受信されるとまずプロトコルにバインドしている
raw ソケットに渡され、
その後で他のプロトコルハンドラー
(カーネルのプロトコルモジュールなど)
に渡される。
For sending and receiving datagrams (
sendto(2),
recvfrom(2), and
similar), raw sockets use the standard
sockaddr_in address structure
defined in
ip(7). The
sin_port field could be used to specify
the IP protocol number, but it is ignored for sending in Linux 2.2 and later,
and should be always set to 0 (see BUGS). For incoming packets,
sin_port is set to zero.
raw
ソケットのオプションは、
IPPROTO_RAW
ファミリーフラグを与えて
setsockopt(2)
を呼べば設定でき、
getsockopt(2)
を呼べば取得できる。
- ICMP_FILTER
-
IPPROTO_ICMP
プロトコルにバインドされた
raw
ソケットのための特殊なフィルタを有効にする。
この値は ICMP
メッセージのタイプそれぞれに対して、どれをフィルターアウト
するかを表したビットセットである。デフォルトでは
ICMP
メッセージは全くフィルターしない。
さらに、データグラムソケットに使える全ての
ip(7) SOL_IP
ソケットオプションがサポートされている。
ネットワークで生じたエラーがユーザーに渡されるのは、
ソケットが接続済みの場合か
IP_RECVERR
フラグが有効になっている場合に限られる。
接続済みのソケットに対しては、
EMSGSIZE および
EPROTO
だけが渡される
(互換性のため)。
IP_RECVERR
を設定すると、全てのネットワークエラーがエラーキューに保存される。
- EACCES
- ユーザーが broadcast
フラグを設定していないソケットを用いて
ブロードキャストアドレスに送信を行おうとした。
- EFAULT
- 不正なメモリーアドレスが与えられた。
- EINVAL
- 引数が不正。
- EMSGSIZE
- パケットが大きすぎる。
Path MTU Discoverry
が有効になっている (
IP_MTU_DISCOVER
ソケットフラグ)
か、パケットのサイズが
IPv4 で許されている
パケットサイズの最大値
64 KB を越えている。
- EOPNOTSUPP
- ソケット呼び出しに不正なフラグ
( MSG_OOB など)
が渡された。
- EPERM
- ユーザーは raw
ソケットをオープンする権限を持っていない。
実行ユーザー ID が 0
のプロセスか、
CAP_NET_RAW
属性を持つプロセスだけがこれを行うことができる。
- EPROTO
- パラメーターの問題を報告する
ICMP
エラーを受け取った。
IP_RECVERR と
ICMP_FILTER は Linux 2.2
で登場した。これらは
Linux での拡張であり、
移植性の必要なプログラムでは用いるべきでない。
Linux 2.0 では
SO_BSDCOMPAT
ソケットオプションをセットすると、
BSD の raw
ソケットにあるバグに互換性を取ることができた
— Linux 2.2
以降では、このオプションはもはや効力を持たない。
デフォルトでは、raw
ソケットは Path MTU Discovery
を行う。
つまり、カーネルは特定の宛先
IP アドレスの MTU (Maximum Transmission Unit;
最大転送単位)
を記録し、raw
パケットの書き込みが
MTU を超えた場合
EMSGSIZE
を返す。
EMSGSIZE
を返された場合、アプリケーションはパケットサイズを小さくすべきである。
ソケットオプション
IP_MTU_DISCOVER または
/proc/sys/net/ipv4/ip_no_pmtu_disc
ファイルを使って Path MTU
Discovery
を無効にすることもできる
(詳細は
ip(7) を参照)。 Path
MTU Discovery
を無効にした場合は、パケットサイズが
インターフェースの MTU
よりも大きいと raw
ソケットはそのパケットを
フラグメント化して送出する。
しかしながら、性能と信頼性の理由から
Path MTU Discovery を
無効にするのは推奨できない。
bind(2)
システムコールを用いると、
raw ソケットを
特定のローカルアドレスにバインドさせることができる。
このバインドがされていない場合は、指定した
IP プロトコルの
すべてのパケットが受信される。
さらに、
SO_BINDTODEVICE
を用いれば raw
ソケットを特定のネットワークデバイスに
バインドさせることもできる。
socket(7) を見よ。
IPPROTO_RAW
ソケットは送信専用である。もしどうしてもすべての
IP パケットを
受信したい場合は、
packet(7) ソケットを
ETH_P_IP
プロトコルで用いること。
packet ソケットは raw
ソケットのように IP
フラグメントを再構成しないことに注意。
datagram
ソケットに対するすべての
ICMP
パケットを受信したい場合は、
特定のソケットに対して
IP_RECVERR
を用いるほうが良い場合が多い。
ip(7) を見よ。
raw ソケットは、 Linux
のすべての IP
プロトコルを受信することができる。
ICMP や TCP
のように、カーネル内部にプロトコルモジュールを持つような
ものも可能である。この場合には、パケットはカーネルモジュールと
raw
ソケットの両方に渡される
(raw
ソケットが複数あればそれぞれに渡される)。
移植性の必要なプログラムではこの機能に依存するべきではない。
他の多くの BSD
におけるソケットの実装ではこの点において制限がある。
Linux
はユーザーから渡されたヘッダーを決して変更しない
(ただし
IP_HDRINCL
の説明にあるように、
0
をいくつか埋める場合を除く)。
これは他の多くの raw
ソケットの実装では異なる。
一般に raw
ソケットは移植性がないことが多いので、
移植性が必要なプログラムでは避けるべきである。
raw
ソケットへの送信では、
IP プロトコルを
sin_port
から取得できなければならない。この機能は
Linux 2.2
では使えなくなった。
IP_HDRINCL
を用いれば同様のことが実現できる。
透過プロクシ (transparent proxy)
拡張については記述していない。
IP_HDRINCL
オプションがセットされているとデータグラムはフラグメント化されず、
インターフェースの MTU
の大きさに制限される。
送信用の IP
プロトコルの設定を
sin_port
にしておく機能は Linux 2.2
から使えなくなった。
ソケットにバインドされているプロトコルか、最初の
socket(2)
コールによって指定されたプロトコルが常に用いられる。
recvmsg(2),
sendmsg(2),
capabilities(7),
ip(7),
socket(7)
Path MTU discovery に関しては
RFC 1191 を参照。 IP
プロトコルに関しては
RFC 791
とインクルードファイル
<linux/ip.h> を参照。
この man ページは Linux
man-pages
プロジェクトのリリース
5.10
の一部である。プロジェクトの説明とバグ報告に関する情報は
https://www.kernel.org/doc/man-pages/
に書かれている。