以太網(wǎng)數(shù)據(jù)幀解碼
先了解數(shù)據(jù)鏈路層的數(shù)據(jù)構(gòu)成(數(shù)據(jù)鏈路層會(huì)在包頭和包尾添加數(shù)據(jù),這里僅介紹包頭的數(shù)據(jù))。數(shù)據(jù)鏈路層數(shù)據(jù)由6位目標(biāo)MAC地址,6位源MAC地址以及2位的下層協(xié)議標(biāo)識(shí)組成。
數(shù)據(jù)幀頭的數(shù)據(jù)結(jié)構(gòu)如下:
typedef struct EthernetHdr_ {
uint8_t eth_dst[6]; // 目標(biāo) MAC 地址
uint8_t eth_src[6]; // 源 MAC 地址
uint16_t eth_type; // 上層協(xié)議類型
} __attribute__((__packed__)) EthernetHdr;
獲取數(shù)據(jù)鏈路層數(shù)據(jù)
suricata 數(shù)據(jù)進(jìn)入decode-ethernet.c中的DecodeEthernet()進(jìn)行數(shù)據(jù)幀的解碼,檢查數(shù)據(jù)包長(zhǎng)度后記錄數(shù)據(jù)鏈路層數(shù)據(jù)頭指針(解碼數(shù)據(jù)包未新開辟空間,而是通過構(gòu)造相應(yīng)的結(jié)構(gòu)體,在需要使用相應(yīng)數(shù)據(jù)時(shí)使用結(jié)構(gòu)體數(shù)據(jù)偏移取出數(shù)據(jù))。
// 解析鏈路層數(shù)據(jù)
p->ethh = (EthernetHdr *)pkt;
if (unlikely(p->ethh == NULL))
return TM_ECODE_FAILED;
p為Package,用于保存數(shù)據(jù)包相應(yīng)的數(shù)據(jù),但是具體的生命周期不知道是多少。在package中保存了部分?jǐn)?shù)據(jù)。
選擇剩余數(shù)據(jù)的解碼方式
在數(shù)據(jù)鏈路層數(shù)據(jù)的最后有下層協(xié)議的標(biāo)識(shí),通過標(biāo)識(shí)我們可以使用對(duì)應(yīng)的函數(shù)來對(duì)后面數(shù)據(jù)進(jìn)行進(jìn)一步解碼。
switch (ntohs(p->ethh->eth_type)) {
case ETHERNET_TYPE_IP:
//printf("DecodeEthernet ip4\n");
DecodeIPV4(tv, dtv, p, pkt + ETHERNET_HEADER_LEN,
len - ETHERNET_HEADER_LEN, pq);
break;
case ETHERNET_TYPE_IPV6:
//printf("DecodeEthernet ip6\n");
DecodeIPV6(tv, dtv, p, pkt + ETHERNET_HEADER_LEN,
len - ETHERNET_HEADER_LEN, pq);
break;
case ETHERNET_TYPE_PPPOE_SESS:
//printf("DecodeEthernet PPPOE Session\n");
DecodePPPOESession(tv, dtv, p, pkt + ETHERNET_HEADER_LEN,
len - ETHERNET_HEADER_LEN, pq);
break;
case ETHERNET_TYPE_PPPOE_DISC:
//printf("DecodeEthernet PPPOE Discovery\n");
DecodePPPOEDiscovery(tv, dtv, p, pkt + ETHERNET_HEADER_LEN,
len - ETHERNET_HEADER_LEN, pq);
break;
case ETHERNET_TYPE_VLAN:
case ETHERNET_TYPE_8021QINQ:
DecodeVLAN(tv, dtv, p, pkt + ETHERNET_HEADER_LEN,
len - ETHERNET_HEADER_LEN, pq);
break;
case ETHERNET_TYPE_MPLS_UNICAST:
case ETHERNET_TYPE_MPLS_MULTICAST:
DecodeMPLS(tv, dtv, p, pkt + ETHERNET_HEADER_LEN,
len - ETHERNET_HEADER_LEN, pq);
break;
case ETHERNET_TYPE_DCE:
if (unlikely(len < ETHERNET_DCE_HEADER_LEN)) {
ENGINE_SET_INVALID_EVENT(p, DCE_PKT_TOO_SMALL);
} else {
DecodeEthernet(tv, dtv, p, pkt + ETHERNET_DCE_HEADER_LEN,
len - ETHERNET_DCE_HEADER_LEN, pq);
}
break;
default:
SCLogDebug("p %p pkt %p ether type %04x not supported", p,
pkt, ntohs(p->ethh->eth_type));
}