Provided by: manpages-ja_0.5.0.0.20140515+dfsg-2_all bug

名前

       packet - デバイスレベルのパケットインターフェース

書式

       #include <sys/socket.h>
       #include <netpacket/packet.h>
       #include <net/ethernet.h> /* L2 プロトコル */

       packet_socket = socket(AF_PACKET, int socket_type, int protocol);

説明

       packet  ソケットは、デバイスドライバ (OSI レイヤ 2) レベルで 生のパケット (raw packet) を送受信するために
       用いられる。 packet ソケットを使うと、ユーザー空間で物理層の上に プロトコルモジュールを実装することができ
       る。

       socket_type には SOCK_RAWSOCK_DGRAM のいずれかを指定する。 SOCK_RAW はリンクレベルヘッダを含む raw パ
       ケットを、 SOCK_DGRAM  はリンクレベルヘッダが削除された加工済みパケットを示す。  リンクレベルヘッダ情報は
       sockaddr_ll で共通のフォーマットで入手できる。 protocol には IEEE 802.3 プロトコル番号を ネットワークバイ
       トオーダーで指定する。 指定できるプロトコルのリストは、インクルードファイル <linux/if_ether.h> を参照。プ
       ロトコルを htons(ETH_P_ALL) にすると、全てのプロトコルが受信される。 外部から来たパケットのうち指定したプ
       ロトコルのものは、 カーネルに実装されているプロトコルに渡される前の段階で、 packet ソケットに渡される。

       packet ソケットをオープンできるのは、 実効ユーザーID が 0 のプロセスか、 CAP_NET_RAW ケーパビリティを持つ
       プロセスだけである。

       SOCK_RAW  パケットでは、パケットをデバイスドライバと受け渡しする際、 パケットデータに変更が行われることは
       ない。  パケットの受信時には、アドレスの解析だけは行われ、  標準的な  sockaddr_ll  アドレス構造体に渡され
       る。パケットの送信時には、ユーザが指定する  バッファに物理層のヘッダが含まれている必要がある。 パケットは
       そのまま修正を受けずに、行き先アドレスから決定される インターフェースのネットワークドライバにキューイング
       される。  デバイスドライバによっては、他のヘッダを常に追加するものもある。  SOCK_RAW  は  Linux  2.0   の
       obosolete な AF_INET/SOCK_PACKET と似ているが、互換性があるわけではない。

       SOCK_DGRAM    はやや高位のレベルで動作する。物理ヘッダは、パケットがユーザーに   渡される前に削除される。
       SOCK_DGRAM の packet ソケットを通して送られるパケットは、 sockaddr_ll  の行き先アドレスの情報に基づき、適
       切な物理層のヘッダが付加されてから、 キューに送られる。

       デフォルトでは、指定したプロトコル型のパケットはすべて  packet ソケットに送られる。特定のインターフェース
       からのパケットだけを  取得したい場合には、  struct  sockaddr_ll  にアドレスを指定して  bind(2)   を呼び、
       packet ソケットをそのインターフェースに結び付ける (バインドする)。 バインドの際には、アドレスフィールドの
       うち sll_protocolsll_ifindex だけが用いられる。

       connect(2)  操作は packet ソケットではサポートされていない。

       MSG_TRUNC  フラグが  recvmsg(2), recv(2), recvfrom(2)  に渡されると、 (バッファサイズより大きかったとして
       も) 常に実際に通信された パケットの長さが返される。

   アドレスのタイプ
       sockaddr_ll はデバイスに依存しない物理層のアドレスである。

           struct sockaddr_ll {
               unsigned short sll_family;   /* 常に AF_PACKET */
               unsigned short sll_protocol; /* 物理層のプロトコル */
               int            sll_ifindex;  /* インターフェース番号 */
               unsigned short sll_hatype;   /* ARP ハードウェア種別 */
               unsigned char  sll_pkttype;  /* パケット種別 */
               unsigned char  sll_halen;    /* アドレスの長さ */
               unsigned char  sll_addr[8];  /* 物理層のアドレス */
           };

       sll_protocol は標準的なイーサネットプロトコルのタイプで、 ネットワーク バイトオーダーで記述する。  インク
       ルードファイル  <linux/if_ether.h> で定義されている。 これがこのソケットのプロト コルのデフォルトとなる。
       sll_ifindex はそのインターフェースの interface index である (netdevice(7) を参照)。 0 は  (バインドが許可
       されている) 任 意のインターフェースにマッチする。 sll_hatype は、インクルードファイル <linux/if_arp.h> で
       定義されている  ARP  種別である。 sll_pkttype はパケット種別である。指定できる種別は以下のいずれかである:
       PACKET_HOST  (ローカルホスト向けのパケット)、  PACKET_BORADCAST   (物理層   のブロードキャストパケット)、
       PACKET_MULTICAST (物理層のマルチキャストア ドレスに送るパケット)、 PACKET_OTHERHOST (他のホストに向けられ
       たパケット  のうち、  無差別モード  (promiscuous  mode:  後述) のデバイスドライバにより補足 されたもの)、
       PACKET_OUTGOING (ローカルホストから発信され、 packet ソケッ トにループバックしてきたパケット)。  これらの
       種別が意味を持つのは受信時のみ  である。 sll_addrsll_halen は、物理層の (つまり IEEE 802.3 の) アドレ
       スとその長さである。 厳密な解釈はデバイスに依存する。

       パケットを送る場合は、 sll_family, sll_addr,  sll_halen,  sll_ifindex  を指定すれば十分である。  その他の
       フィールドは  0 にしておくべきである。 sll_hatypesll_pkttype には受信したパケットの情報が設定される。
       バインドの際には、 sll_protocolsll_ifindex だけが使用される。

   ソケットオプション
       パケットソケットのオプションは、レベル SOL_PACKET を指定して setsockopt(2) を呼び出すことで設定できる。

       PACKET_ADD_MEMBERSHIP
       PACKET_DROP_MEMBERSHIP
              packet ソケットは、物理層のマルチキャストや 無差別モード (promiscuous mode) を設定して使うことがで
              きる。 PACKET_ADD_MEMBERSHIP はバインドを追加し、 PACKET_DROP_MEMBERSHIP  はバインドを削除する。こ
              れらはいずれも packet_mreq 構造体を引き数に取る。

                  struct packet_mreq {
                      int            mr_ifindex;    /* インターフェース番号 */
                      unsigned short mr_type;       /* 動作 */
                      unsigned short mr_alen;       /* アドレスの長さ */
                      unsigned char  mr_address[8]; /* 物理層のアドレス */
                  };

              mr_ifindex  は、ステータスを変更したいインターフェースの インターフェース番号である。 mr_type パラ
              メータは実行する動作を指定する: PACKET_MR_PROMISC は、共有している媒体からの全てのパケットを受信で
              きるようにする  (しばしば  "無差別モード  (promiscuous  mode)"  と呼ばれる)。  PACKET_MR_MULTICAST
              は、そのソケットを、  mr_addressmr_alen で指定される物理層のマルチキャストブループにバインドす
              る。 PACKET_MR_ALLMULTI は socket を up にして、そのインターフェースに到達したすべての  マルチキャ
              ストパケットを受信できるようにする。

              昔からある  ioctl だけでなく、 SIOCSIFFLAGS, SIOCADDMULTI, SIOCDELMULTI を同じ目的に用いることがで
              きる。

       PACKET_AUXDATA (Linux 2.6.21 以降)
              ブール値のオプションを有効すると、          パケットソケットは、パケットと一緒にメタデータ構造体を
              recvmsg(2) コントロールフィールドで渡す。 この構造体は cmsg(3) を使って読むことができる。 定義は以
              下の通りである。

                  struct tpacket_auxdata {
                      __u32 tp_status;
                      __u32 tp_len;      /* パケット長 */
                      __u32 tp_snaplen;  /* キャプチャした長さ */
                      __u16 tp_mac;
                      __u16 tp_net;
                      __u16 tp_vlan_tci;
                      __u16 tp_padding;
                  };

       PACKET_FANOUT (Linux 3.1 以降)
              スレッドにまたがって処理をスケールさせるため、  パケットソケットはファンアウトグループを構成するこ
              とができる。 このモードでは、 マッチしたそれぞれのパケットはグループ内のいずれか一つのソケットにだ
              けキューイングされる。 ソケットをファンアウトグループに参加させるには、 レベル  SOL_PACKET  でオプ
              ション PACKET_FANOUT を指定して setsockopt(2) を呼び出す。 ネットワーク名前空間毎に最大 65536 個の
              独立したグループを持つことができる。  整数のオプション値の先頭 16 ビットに ID をエンコードすること
              で、  ソケットはグループを選択する。  あるグループへの最初のパケットソケットの参加があった時点で、
              グループは暗黙のうちに作成される。 既存のグループへの参加が成功するためには、 それ以降にそのグルー
              プに参加しようとするパケットソケットは、 プロトコロ、 デバイス設定、ファンアウトモード、フラグが同
              じである必要がある  (下記参照)。 パケットソケットがファンアウトグループから抜けるのは、 そのソケッ
              トをクローズした場合だけである。  ファンアウトグループは最後のソケットがクローズした場合に削除され
              る。

              ファンアウトでは、 複数のソケットにトラフィックを分散させるアルゴリズムを複数サポートしている。 デ
              フォルトのモードである  PACKET_FANOUT_HASH では、同じフローのパケットは同じソケットに送信され、 フ
              ロー単位の順序が維持される。  パケットごとに、パケットフローのハッシュの、そのグループのソケット数
              に対する剰余が計算され、ソケットが選択される。  なお、フローハッシュはネットワーク層のアドレスとト
              ランスポート層のポートフィールドに対するハッシュである     (トランスポート層ポートは存在する場合の
              み)。      負荷分散モード      PACKET_FANOUT_LB     はラウンドロビンアルゴリズムが採用されている。
              PACKET_FANOUT_CPU      では、      パケットが到着した      CPU      に基づいてソケットを選択する。
              PACKET_FANOUT_ROLLOVER はすべてのデータを一つのソケットで処理し、 そのソケットで処理待ち (backlog)
              が発生した場合に次のソケットに移る。  PACKET_FANOUT_RND では擬似乱数発生器を使ってソケットが選択さ
              れる。 PACKET_FANOUT_QM (Linux 3.14 以降で利用可能) では受信 skb に記録された queue_mapping を使っ
              てソケットが選択される。

              ファンアウトモードでは追加のオプションがある。 IP フラグメンテーションが起こると、  同じフローのパ
              ケットのフローハッシュが異なるハッシュを持つことになる。 フラグ PACKET_FANOUT_FLAG_DEFRAG をセット
              すると、  パケットはファンアウトを行う前にフラグメント再構築が行われるようになり、  フラグメントが
              あった場合でも順序が維持される。  ファンアウトモードとオプションは、  整数のオプション値の下位  16
              ビットで指定される。  フラグ PACKET_FANOUT_FLAG_ROLLOVER を指定すると、 バックアップ戦略としてロー
              ルオーバー方式が有効になる。 元のファンアウトアルゴリズムが backlog ソケットを選択していれば、  パ
              ケットは次の利用可能なソケットにロールオーバーされる。

       PACKET_LOSS (PACKET_TX_RING で使用)
              有効にすると、転送エラーの場合にパケットをエラーなしに黙って破棄せず、                ステータスを
              TP_STATUS_WRONG_FORMAT にセットして返る。

       PACKET_RESERVE (PACKET_RX_RING で使用)
              デフォルトでは、パケット受信リングはメタデータ構造体とアライメント用のパディングの直後にパケットを
              書き込む。 この整数オプションを設定すると、パケットの前に追加で領域が予約される。

       PACKET_RX_RING
              非同期でのパケット受信用のメモリマップされたリングバッファを作成する。    パケットソケットはアプリ
              ケーションのアドレス空間に連続する領域を確保し、    そこにパケットスロットの配列を構成し、   (最大
              tp_snaplen 個の) パケットを順にスロットにコピーする。 各パケットの前には tpacket_auxdata  に似たメ
              タデータ構造体が置かれる。  プロトコルフィールドには、データの、メタデータヘッダーの先頭からのオフ
              セットが入る。 tp_net にはネットワーク層へのオフセットが格納される。 パケットソケットが SOCK_DGRAM
              型の場合、 tp_mac も同じである。 SOCK_RAW 型の場合、 tp_net にはリンク層のフレームへのオフセットが
              入る。 パケットソケットとアプリケーションは tp_status フィールドを通してリングの先頭 (head) と末尾
              (tail) の情報を受け渡す。 パケットソケットはすべてのスロットをステータス TP_STATUS_KERNEL で所有し
              ており、  スロットにデータが入ると、パケットソケットはそのスロットのステータスをアプリケーションに
              所有権を渡す状態に変更する。  通常の動作では、新しいステータスは TP_STATUS_USER であり、これは正し
              く受信されたパケットが格納されたことを示している。  アプリケーションがパケットの処理を終えると、ア
              プリケーションはそのスロットのステータスを TP_STATUS_KERNEL に設定し、そのスロットの所有権をソケッ
              トに返す。  パケットソケットは、複数バージョンのパケットリングを実装している。  実装の詳細は Linux
              カーネルソースツリーの Documentation/networking/packet_mmap.txt で説明されている。

       PACKET_STATISTICS
              パケットソケットの統計情報を次の構造体形式で取得する。

                  struct tpacket_stats {
                      unsigned int tp_packets;  /* 総パケット数 */
                      unsigned int tp_drops;    /* ドロップパケット数 */
                  };

              統計情報を取得すると、内部カウンターはリセットされる。 TPACKET_V3 のリングを使う場合には、統計情報
              構造体は違うものになる。

       PACKET_TIMESTAMP (PACKET_RX_RING で使用; Linux 2.6.36 以降)
              パケット受信リングでは常にタイムスタンプがメタデータヘッダーに格納される。  デフォルトでは、タイム
              スタンプはパケットがリングにコピーされた時点で生成されるソフトウェアによるタイムスタンプである。
              この整数オプションによりタイムスタンプの種類を選択できる。 デフォルト以外では、 Linux カーネルソー
              スツリーの Documentation/networking/timestamping.txt に説明がある 2 種類のハードウェアフォーマット
              がサポートされている。

       PACKET_TX_RING (Linux 2.6.31 以降)
              パケット送信用のメモリマップされたリングバッファを作成する。  このオプションは PACKET_RX_RING と同
              様で、同じ引き数を取る。 アプリケーションはステータスが TP_STATUS_AVAILABLE のスロットにパケットを
              書き込み、 TP_STATUS_SEND_REQUEST にステータスを変更することでそのパケットが送信できるようにする。
              パケットの送信準備ができたら、アプリケーションは続けて send(2) 系のシステムコールを呼び出す。 シス
              テムコールの引き数 buflen は無視される。 sendto(2) や sendmsg(2)  を使ってアドレスが渡された場
              合、  ソケットのデフォルト値ではなくそのアドレスが使用される。  送信に成功すると、ソケットはそのス
              ロットを TP_STATUS_AVAILABLE に戻す。 エラーの場合、 PACKET_LOSS  がセットされていなければエラーな
              しでパケットは廃棄される。

       PACKET_VERSION (PACKET_RX_RING で使用; Linux 2.6.27 以降)
              デフォルトでは、 PACKET_RX_RINGTPACKET_V1 のパケット受信リングを作成する。別のバージョンのリン
              グを作成するには、そのリングを作成する前に希望するバージョンが使われるようにこの整数オプションを設
              定すること。

       PACKET_QDISC_BYPASS (Linux 3.14 以降)
              デフォルトでは、パケットはカーネルの  qdisc (トラフィック制御) レイヤー経由で渡される。 これは大半
              のユースケースに合っている。 ネットワークに対して可能な限りパケットを送信する (例えば pkggen  と同
              様の方法で負荷対象のデバイスを試験する) のにパケットソケットを使うトラフィック生成アプライアンスで
              は、この整数オプションを  1 に設定することで qdisc レイヤーを飛ばすことができる。 qdisc レイヤーで
              のパケットバッファが行われなくなるという副作用がある。   これにより、   ネットワークデバイスの送信
              キューの使用量が高い場合にパケット廃棄が起きやすくなる。

   ioctl
       SIOCGSTAMP を用いると、最後に受信したパケットのタイムスタンプを得ることができる。 引き数は struct timeval
       型の変数である。

       さらに、  netdevice(7)  および socket(7)  で定義されている標準の ioctl はいずれも packet ソケットに指定可
       能である。

   エラー処理
       packet ソケットは、パケットをデバイスドライバに渡すときに 起きたエラーしか処理しない。遅延エラー (pending
       error) に関する概念は持っていない。

エラー

       EADDRNOTAVAIL
              不明なマルチキャストグループアドレスが渡された。

       EFAULT ユーザが渡したメモリアドレスが不正。

       EINVAL 引き数が不正。

       EMSGSIZE
              パケットがインターフェースの MTU より大きい。

       ENETDOWN
              インターフェースが up でない。

       ENOBUFS
              パケットに割り当てるメモリが足りない。

       ENODEV デバイス名が不明。あるいはインターフェースアドレスで指定された    インターフェースインデックスが不
              明。

       ENOENT パケットを一つも受信していない。

       ENOTCONN
              インターフェースアドレスが渡されなかった。

       ENXIO  インターフェースアドレスに不正なインターフェースインデックスが含まれている。

       EPERM  この操作を行うのに必要な権限をユーザが持っていない。

              上記以外のエラーが、低レベルのドライバで生成されることがある。

バージョン

       AF_PACKET は Linux 2.2 の新機能である。これより古いバージョンの Linux では SOCK_PACKET のみをサポートして
       いた。

       インクルードファイル  <netpacket/packet.h> が存在するのは glibc 2.1 以降である。 それ以前のシステムでは以
       下のようにする必要がある:

           #include <asm/types.h>
           #include <linux/if_packet.h>
           #include <linux/if_ether.h>  /* The L2 protocols */

注意

       移植性の必要なプログラムでは、 pcap(3)  経由で  AF_PACKET  を用いることをお薦めする。ただし、この方法では
       AF_PACKET の機能すべてを利用することはできない。

       SOCK_DGRAM  packet ソケットは、IEEE 802.3 フレームの IEEE 802.2 LLC ヘッダの 生成や解析を行おうとしない。
       ETH_P_802_3 が送信プロトコルに指定されると、カーネルは 802.3 フレームを 生成して length  フィールドに書き
       込む。  完全に準拠したパケットを得るためにはユーザーが  LLC  ヘッダを 与える必要がある。到着した 802.3 パ
       ケットでは、 DSAP/SSAP protocol の各フィールドは多重化 (multiplex)  されていない。  代わりにこれらは  LLC
       ヘッダが前置された  ETH_P_802_2 プロトコルとして与えられる。したがって、 ETH_P_802_3 にバインドすることは
       できない。かわりに  ETH_P_802_2  にバインドし、自分自身でプロトコルの多重化を行うこと。  送信のデフォルト
       は、プロトコルフィールドを持つ 標準の Ethernet DIX encapsulation である。

       packet ソケットは入出力の firewall chain に影響をうけない。

   移植性
       Linux  2.0  では、  packet ソケットを得る方法は socket(AF_INET, SOCK_PACKET, protocol) を呼ぶやり方しかな
       かった。この方法はまだサポートされているが、       用いないことを強く推奨する。現在の方法との主な違いは、
       SOCK_PACKET ではインターフェースの指定に古い struct sockaddr_pkt を用いる点である。これには物理層からの独
       立性がない。

           struct sockaddr_pkt {
               unsigned short spkt_family;
               unsigned char  spkt_device[14];
               unsigned short spkt_protocol;
           };

       spkt_family はデバイスのタイプ、 spkt_protocol<sys/if_ether.h> で定義されている IEEE 802.3 プロトコル
       タイプ、 spkt_device はデバイスの名前をヌル終端された文字列で与えたもの (例: eth0) である。

       この構造体は obsolete であり、 新しくコードを書く時には用いるべきでない。

バグ

       glibc 2.1 には SOL_PACKET の定義がない。回避策としては、以下のようにするとよい。

           #ifndef SOL_PACKET
           #define SOL_PACKET 263
           #endif

       この問題は新しいバージョンの glibc では修正されている。 libc5 のシステムにはこの問題はない。

       IEEE 802.2/803.3 の LLC の扱い方は、バグと考えても良いだろう。

       ソケットフィルターについて記載されていない。

       MSG_TRUNC   recvmsg(2)   拡張は非常にまずい対処であり、制御メッセージで置き換えるべきである。  今のところ
       SOCK_DGRAM 経由でパケットについていた宛先アドレスを得る方法がない。

関連項目

       socket(2), pcap(3), capabilities(7), ip(7), raw(7), socket(7)

       標準 IP Ethernet encapsulation に関しては RFC 894 を、 IEEE 802.3 IP encapsulation に関しては RFC 1700 を
       参照。

       物理層のプロトコルに関する記述は <linux/if_ether.h> インクルードファイルにある。

この文書について

       この man ページは Linux man-pages プロジェクトのリリース 3.65 の一部 である。プロジェクトの説明とバグ報告
       に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。

Linux                                              2014-02-26                                          PACKET(7)