blank
packet socket プログラミング

[概要]

Linux では多機能で柔軟なネットワークプログラムを実装するために Packet socket が用意されています。パケットキャプチャ用のライブラ リ libpcap は Packet socket の受信の機能を用いて実装されています。 Packet socket については、受信については解説等がありますが、送信 についてはほとんど解説がありません。

ここでは Packet socket を使ってデータを送信する方法を ARP Request を送信プログラムを元にして解説します。

[解説]

基本的な情報は man 7 ip, man 7 packet にだいたい書かれているので socket プログラミングの経験があればある程度イメージできると思い ます。packet socket を利用する場合と通常の socketを利用する場合 の違いは、socket(2) の引数の違い以外には、bind(2)でバインドする アドレス(sockaddr)の設定の仕方だけです。

Linux では device independent phsycal layer address を使って packet socket を利用します(man 7 packet 参照)。 これは sockaddr_ll として定義されており、以下のようになっています。

struct sockaddr_ll
{
     unsigned short  sll_family;    /* Always AF_PACKET */
     unsigned short  sll_protocol;  /* Physical layer protocol */
     int             sll_ifindex;   /* Interface number */
     unsigned short  sll_hatype;    /* Header type */
     unsigned char   sll_pkttype;   /* Packet type */
     unsigned char   sll_halen;     /* Length of address */
     unsigned char   sll_addr[8];   /* Physical layer address */
};
  • sll_family : 常に AF_PACKET 固定.
  • sll_protocol : 利用したい物理層でのプロトコルを指定. /usr/include/linux/if_ether.h 等で定義されている.
  • sll_ifindex : インターフェース名. ioctl()等で取得する.
  • sll_hattype : ヘッダ種別. 使いたいプロトコルによって異な る。/usr/include/linux/if_arp.h 等で定義されている.
  • sll_pkttype : パケット種別. PACKET_HOST, PACKET_BROADCAST 等がある. /usr/include/linux/if_packet.h で定義されている.
  • sll_halen : ヘッダ長. 使いたいプロトコルによって異な る. /usr/include/linux/if_arp.h 等で定義されている.
  • sll_addr[8] : 各プロトコル用アドレス. ARP なら MAC アドレ スが該当する.
以上をふまえると、おおまかな流れは以下のようになります。
  1. sockaddr_ll の初期化(送信/受信側) ※ここがポイント
  2. socket(2) を用いて packet socket を生成
  3. bind(2) の実行(初期化した送信側 sockaddr_ll を使う)
  4. sendto(2) でデータ送信
ARP Request を送るプログラムでは sockaddr_ll の設定は以下のよう になります。
    struct sockaddr_ll ll_from, ll_to;

    /* 送信側 */
    ll_from->sll_family = AF_PACKET;
    ll_from->sll_protocol = htons(ETH_P_ARP);
    ll_from->sll_hatype = ARPHRD_ETHER;
    ll_from->sll_pkttype = PACKET_HOST;
    ll_from->sll_halen = ETH_ALEN;

    /* 受信側 */
    ll_to->sll_family = AF_PACKET;
    ll_to->sll_protocol = htons(ETH_P_ARP);
    ll_to->sll_hatype = ARPHRD_ETHER;
    ll_to->sll_pkttype = PACKET_BROADCAST;
    ll_to->sll_halen = ETH_ALEN;

    /*
     * ioctl() でインターフェース情報を取得;
     * sll_ifindex にインターフェースインデックスを代入;
     * sll_addr[8] に MAC アドレスを代入;
     */

次に socket(2) で Packet socket を作成しますが、domain は PF_PACKET, protocol は sll_protocol で指定したプロトコルをネット ワークバイトオーダで指定します。

     sockfd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP));

ここまでできれば、あとは通常の socket を用いたプログラミングと同 じです。bind(2) で ll_from と sockfd をバインドし、sendto(2) で 送りたいデータを送るだけです。

最後に、実際の ARP Request を送るプログラムをつけておきますので、 参考にしてください。

[ファイル]