[概要]
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 アドレ
スが該当する.
以上をふまえると、おおまかな流れは以下のようになります。
- sockaddr_ll の初期化(送信/受信側) ※ここがポイント
- socket(2) を用いて packet socket を生成
- bind(2) の実行(初期化した送信側 sockaddr_ll を使う)
- 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 を送るプログラムをつけておきますので、
参考にしてください。
[ファイル]
|