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

名前

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

書式

       #include <sys/socket.h>
       #include <netpacket/packet.h>
       #include <net/ethernet.h> /* the L2 protocols */

       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 だけが使用され
       る。

   ソケットオプション
       packet ソケットは、物理層のマルチキャストや 無差別モード (promiscuous mode) を設定して使う
       ことができる。  これには  SOL_PACKET  と以下のオプションのいずれかを指定して setsockopt(2)
       を呼べばよい。   バインドを追加する場合は   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  を同じ目的に用いる
       ことができる。

   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 はデバイスの名前を NULL 終端された文字列で与えたもの
       (例: 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.54 の一部 である。プロジェクト
       の説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。