概要
EtherフレームはOSI参照モデルのレイヤー2に位置します。 直接通信する機器間でデータをやり取りする為の情報が入ったフレームです。 この記事ではC言語によるEtherフレームの解析を行い、Etherフレームについて理解を深めてみます。
環境構築
CentOSを想定しています。 フレームの取得にはlibpcapというCライブラリを利用します。
yum -y update yum install -y gcc vim wget tar flex byacc wget http://www.tcpdump.org/release/libpcap-1.6.2.tar.gz tar zxvf libpcap-1.6.2.tar.gz cd libpcap-1.6.2 ./configure make -j 8 make install
Etherフレームについて
フレームフォーマット
Etherフレームの内容(IEEE802.3形式)は以下となっています。
概要 | サイズ | 説明 |
---|---|---|
プリアンブル | 7byte | タイミングを取るための固定ビット列 |
SFD | 1byte | タイミング用。 次のビットからデータが開始されるよ的な。 |
宛先MAC | 6byte | 通信先の機器を識別する為の番号 |
送信元MAC | 6byte | 通信元の機器を識別する為の番号 |
Etherタイプ | 2byte | 上位のプロトコルを表す値。 但し1500以下だったらデータサイズを表す |
データ | 可変 | カプセル化した中身のデータ |
FCS | 2byte | 受け取り側でエラーが発生してないかをチェックする用 |
Etherタイプ(一部)
defineはnet/ethernet.hに定義されています。 以下はその値と説明についてです。
値 | define | 説明 |
---|---|---|
0x0000-0x05DC | - | フレームの長さ |
0x0800 | ETHERTYPE_IP | IPパケット |
0x0806 | ETHERTYPE_ARP | ARPパケット |
0x8100 | ETHERTYPE_VLAN | dot1Q VLANフレーム |
0x86DD | ETHERTYPE_IPV6 | IPv6パケット |
Etherフレーム構造体
CでEtherフレームを扱う場合、net/ethernet.hに構造体が定義されています。
struct ether_header { u_int8_t ether_dhost[ETH_ALEN]; /* destination eth addr */ u_int8_t ether_shost[ETH_ALEN]; /* source ether addr */ u_int16_t ether_type; /* packet type ID field */ } __attribute__ ((__packed__));
EtherフレームのDump
フレームの受信処理はコチラを参照してください。 以下ではフレームを受信した後、コールバック関数内でEtherヘッダ内容をDump表示しています。
#include <netinet/if_ether.h> #include <arpa/inet.h> #include <string.h> char * convmac_tostr(u_char *,char *,size_t); void start_pktfunc( u_char *user, // pcap_loop関数の第4引数 const struct pcap_pkthdr *h , // 受信したPacketの補足情報 const u_char *p // 受信したpacketへのポインタ ){ char dmac[18] = {0}; char smac[18] = {0}; struct ether_header *eth_hdr = (struct ether_header *)p; printf("ether header---------\n"); printf("dest mac %s\n",convmac_tostr(eth_hdr->ether_dhost,dmac,sizeof(dmac))); printf("src mac %s\n",convmac_tostr(eth_hdr->ether_shost,smac,sizeof(smac))); printf("ether type %x\n\n",ntohs(eth_hdr->ether_type)); } char * convmac_tostr(u_char *hwaddr,char *mac,size_t size){ snprintf(mac,size,"%02x:%02x:%02x:%02x:%02x:%02x", hwaddr[0],hwaddr[1],hwaddr[2], hwaddr[3],hwaddr[4],hwaddr[5]); return mac; }