以太网数据帧解码

以太网数据帧解码

先了解数据链路层的数据构成(数据链路层会在包头和包尾添加数据,这里仅介绍包头的数据)。数据链路层数据由6位目标MAC地址,6位源MAC地址以及2位的下层协议标识组成。
数据帧头的数据结构如下:

typedef struct EthernetHdr_ {
  uint8_t eth_dst[6]; // 目标 MAC 地址
  uint8_t eth_src[6]; // 源 MAC 地址
  uint16_t eth_type;  // 上层协议类型
} __attribute__((__packed__)) EthernetHdr;

获取数据链路层数据

suricata 数据进入decode-ethernet.c中的DecodeEthernet()进行数据帧的解码,检查数据包长度后记录数据链路层数据头指针(解码数据包未新开辟空间,而是通过构造相应的结构体,在需要使用相应数据时使用结构体数据偏移取出数据)。

// 解析链路层数据
p->ethh = (EthernetHdr *)pkt;
if (unlikely(p->ethh == NULL))
  return TM_ECODE_FAILED;

p为Package,用于保存数据包相应的数据,但是具体的生命周期不知道是多少。在package中保存了部分数据。

选择剩余数据的解码方式

在数据链路层数据的最后有下层协议的标识,通过标识我们可以使用对应的函数来对后面数据进行进一步解码。

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));
}

你可能感兴趣的:(以太网数据帧解码)