Provided by: manpages-ja_0.5.0.0.20221215+dfsg-1_all bug

名前

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

書式

       #include <sys/socket.h>
       #include <linux/if_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 ソ
       ケットに渡される。

       In order to create a packet socket, a process must have the CAP_NET_RAW capability in  the
       user namespace that governs its network namespace.

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

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

       By  default, all packets of the specified protocol type are passed to a packet socket.  To
       get packets only from a specific interface use bind(2) specifying an address in  a  struct
       sockaddr_ll  to  bind  the  packet  socket  to  an interface.  Fields used for binding are
       sll_family (should be AF_PACKET), sll_protocol, and sll_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 is the standard ethernet protocol type in network byte order as defined in
          the <linux/if_ether.h> include file.  It defaults to the socket's protocol.

       *  sll_ifindex is the interface index of the interface (see netdevice(7)); 0  matches  any
          interface  (only  permitted  for binding).  sll_hatype is an ARP type as defined in the
          <linux/if_arp.h> include file.

       *  sll_pkttype contains the packet  type.   Valid  types  are  PACKET_HOST  for  a  packet
          addressed  to  the  local host, PACKET_BROADCAST for a physical-layer broadcast packet,
          PACKET_MULTICAST  for  a  packet  sent   to   a   physical-layer   multicast   address,
          PACKET_OTHERHOST  for  a  packet  to  some  other host that has been caught by a device
          driver in promiscuous mode, and PACKET_OUTGOING for a packet originating from the local
          host  that  is  looped  back  to  a  packet  socket.   These  types make sense only for
          receiving.

       *  sll_addr and sll_halen contain the physical-layer (e.g., IEEE 802.3)  address  and  its
          length.  The exact interpretation depends on the device.

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

   ソケットオプション
       パケットソケットのオプションは、レベル  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;      /* packet length */
                      __u32 tp_snaplen;  /* captured length */
                      __u16 tp_mac;
                      __u16 tp_net;
                      __u16 tp_vlan_tci;
                      __u16 tp_vlan_tpid; /* Since Linux 3.14; earlier, these
                                             were unused padding bytes */
                  };

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

              Fanout supports multiple algorithms to spread traffic between sockets, as follows:

              *  The  default  mode,  PACKET_FANOUT_HASH, sends packets from the same flow to the
                 same socket to maintain per-flow ordering.  For each packet, it chooses a socket
                 by  taking the packet flow hash modulo the number of sockets in the group, where
                 a flow hash is a hash over network-layer address  and  optional  transport-layer
                 port fields.

              *  The load-balance mode PACKET_FANOUT_LB implements a round-robin algorithm.

              *  PACKET_FANOUT_CPU  selects  the  socket based on the CPU that the packet arrived
                 on.

              *  PACKET_FANOUT_ROLLOVER processes all data on a single socket, moving to the next
                 when one becomes backlogged.

              *  PACKET_FANOUT_RND selects the socket using a pseudo-random number generator.

              *  PACKET_FANOUT_QM  (available  since  Linux  3.14)   selects the socket using the
                 recorded queue_mapping of the received skb.

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

       PACKET_LOSS (PACKET_TX_RING で使用)
              送信リングで不正な形式のパケットに遭遇した場合、         デフォルトではそのリングの
              tp_statusTP_STATUS_WRONG_FORMAT に戻し、その送信を直ちに中止する。 不正な形式の
              パケットにより、そのパケット自身とその以降にキューに入れられたパケットの送信がブ
              ロックされる。形式エラーを修正し、関連する tp_statusTP_STATUS_SEND_REQUEST に設
              定し直し、send(2)     を使って送信処理を再開しなければならない。     しかしながら、
              PACKET_LOSS がセットされている場合、 不正な形式のパケットはすべてスキップされ、  そ
              の送信リングの  tp_statusTP_STATUS_AVAILABLE に設定し直され、送信処理は継続され
              る。

       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_statusTP_STATUS_KERNEL  のすべてのスロットを所有しており、 スロットにデータが入ると、
              パケットソケットはそのスロットのステータスをアプリケーションに所有権を渡す状態に変
              更する。 通常の動作では、 新しい tp_status で少なくとも TP_STATUS_USER ビットがセッ
              トされていれば、 受信されたパケットが格納されたことを示している。  アプリケーション
              がパケットの処理を終えると、アプリケーションはそのスロットの      tp_statusTP_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.rst  に説明がある  2 種類のハードウェアフォー
              マットがサポートされている。

       PACKET_TX_RING (Linux 2.6.31 以降)
              パケット送信用のメモリーマップされたリングバッファーを作成する。   このオプションは
              PACKET_RX_RING    と同様で、同じ引数を取る。    アプリケーションは   tp_statusTP_STATUS_AVAILABLE       のスロットにパケットを書き込み、       tp_statusTP_STATUS_SEND_REQUEST  に変更することでそのパケットの送信を予約する。 パケットの送
              信準備ができたら、アプリケーションは続けて  send(2)  系のシステムコールを呼び出す。
              システムコールの引数 buflen は無視される。 sendto(2) や sendmsg(2) を使ってアド
              レスが渡された場合、 ソケットのデフォルト値ではなくそのアドレスが使用される。  送信
              に成功すると、ソケットはそのスロットの tp_statusTP_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 の
       みをサポートしていた。

注意

       移植性の必要なプログラムでは、 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 に影響をうけない。

   移植性
       In Linux 2.0, the only way to get a packet socket was with the call:

           socket(AF_INET, SOCK_PACKET, protocol)

       This is still supported, but deprecated and strongly  discouraged.   The  main  difference
       between the two methods is that SOCK_PACKET uses the old struct sockaddr_pkt to specify an
       interface, which doesn't provide physical-layer independence.

           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 であり、 新しくコードを書く時には用いるべきでない。

バグ

       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> インクルードファイルにある。

       Linux カーネルのソースツリー。 Documentation/networking/filter.rst  には  Berkeley  Packet
       Filters                             をパケットソケットにどのように適用するかの説明がある。
       /tools/testing/selftests/net/psock_tpacket.c には、 PACKET_RX_RINGPACKET_TX_RING  の利
       用可能なすべてのバージョンのサンプルソースコードがある。

この文書について

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