diff options
Diffstat (limited to 'contrib/impcap/eth_parser.c')
-rw-r--r-- | contrib/impcap/eth_parser.c | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/contrib/impcap/eth_parser.c b/contrib/impcap/eth_parser.c new file mode 100644 index 0000000..4bda2d5 --- /dev/null +++ b/contrib/impcap/eth_parser.c @@ -0,0 +1,179 @@ +/* eth_parser.c + * + * This file contains functions to parse Ethernet II headers. + * + * File begun on 2018-11-13 + * + * Created by: + * - Théo Bertin (theo.bertin@advens.fr) + * + * With: + * - François Bernard (francois.bernard@isen.yncrea.fr) + * - Tianyu Geng (tianyu.geng@isen.yncrea.fr) + * + * This file is part of rsyslog. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * -or- + * see COPYING.ASL20 in the source distribution + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "config.h" +#include "parsers.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpacked" +#pragma GCC diagnostic ignored "-Wattributes" +struct __attribute__ ((__packed__)) eth_header_s { + uint8_t addrDst[6]; + uint8_t addrSrc[6]; + uint16_t type; +}; + +struct __attribute__ ((__packed__)) vlan_header_s { + uint8_t addrDst[6]; + uint8_t addrSrc[6]; + uint16_t vlanCode; + uint16_t vlanTag; + uint16_t type; +}; +#pragma GCC diagnostic pop + +typedef struct eth_header_s eth_header_t; +typedef struct vlan_header_s vlan_header_t; + + +/* + * Get an ethernet header type as uint16_t + * and return the correspondence as string + * NOTE : Only most common types are present, to complete if needed + */ +static const char *eth_type_to_string(uint16_t eth_type) { + switch (eth_type) { + case 0x00bb: // Extreme Networks Discovery Protocol + return "EDP"; + case 0x0200: // PUP protocol + return "PUP"; + case 0x0800: // IP protocol + return "IP"; + case 0x0806: // address resolution protocol + return "ARP"; + case 0x88a2: // AoE protocol + return "AOE"; + case 0x2000: // Cisco Discovery Protocol + return "CDP"; + case 0x2004: // Cisco Dynamic Trunking Protocol + return "DTP"; + case 0x8035: // reverse addr resolution protocol + return "REVARP"; + case 0x8100: // IEEE 802.1Q VLAN tagging + return "802.1Q"; + case 0x88a8: // IEEE 802.1ad + return "802.1AD"; + case 0x9100: // Legacy QinQ + return "QINQ1"; + case 0x9200: // Legacy QinQ + return "QINQ2"; + case 0x8137: // Internetwork Packet Exchange + return "IPX"; + case 0x86DD: // IPv6 protocol + return "IPv6"; + case 0x880B: // PPP + return "PPP"; + case 0x8847: // MPLS + return "MPLS"; + case 0x8848: // MPLS Multicast + return "MPLS_MCAST"; + case 0x8863: // PPP Over Ethernet Discovery Stage + return "PPPoE_DISC"; + case 0x8864: // PPP Over Ethernet Session Stage + return "PPPoE"; + case 0x88CC: // Link Layer Discovery Protocol + return "LLDP"; + case 0x6558: // Transparent Ethernet Bridging + return "TEB"; + default: + return "UNKNOWN"; + } +} + + +/* + * This function parses the bytes in the received packet to extract Ethernet II metadata. + * + * its parameters are: + * - a pointer on the list of bytes representing the packet + * the first byte must be the beginning of the ETH header + * - the size of the list passed as first parameter + * - a pointer on a json_object, containing all the metadata recovered so far + * this is also where ETH metadata will be added + * + * This function returns a structure containing the data unprocessed by this parser + * or the ones after (as a list of bytes), and the length of this data. +*/ +data_ret_t *eth_parse(const uchar *packet, int pktSize, struct json_object *jparent) { + DBGPRINTF("entered eth_parse\n"); + DBGPRINTF("packet size %d\n", pktSize); + if (pktSize < 14) { /* too short for eth header */ + DBGPRINTF("ETH packet too small : %d\n", pktSize); + RETURN_DATA_AFTER(0) + } + + eth_header_t *eth_header = (eth_header_t *)packet; + char ethMacSrc[20], ethMacDst[20]; + uint8_t hdrLen = 14; + + ether_ntoa_r((struct ether_addr *)eth_header->addrSrc, ethMacSrc); + ether_ntoa_r((struct ether_addr *)eth_header->addrDst, ethMacDst); + + json_object_object_add(jparent, "ETH_src", json_object_new_string((char *)ethMacSrc)); + json_object_object_add(jparent, "ETH_dst", json_object_new_string((char *)ethMacDst)); + + uint16_t ethType = (uint16_t)ntohs(eth_header->type); + + if (ethType == ETHERTYPE_VLAN) { + vlan_header_t *vlan_header = (vlan_header_t *)packet; + json_object_object_add(jparent, "ETH_tag", json_object_new_int(ntohs(vlan_header->vlanTag))); + ethType = (uint16_t)ntohs(vlan_header->type); + hdrLen += 4; + } + + data_ret_t *ret; + + if (ethType < 1500) { + /* this is a LLC header */ + json_object_object_add(jparent, "ETH_len", json_object_new_int(ethType)); + ret = llc_parse(packet + hdrLen, pktSize - hdrLen, jparent); + + /* packet has the minimum allowed size, so the remaining data is + * most likely padding, this should not appear as data, so remove it + * */ + //TODO this is a quick win, a more elaborate solution would be to check if all data + // is indeed zero, but that would take more processing time + if (pktSize <= 60 && ret->pData != NULL) { + if (!ret->pData[0]) ret->size = 0; + } + return ret; + } + + json_object_object_add(jparent, "ETH_type", json_object_new_int(ethType)); + json_object_object_add(jparent, "ETH_typestr", json_object_new_string((char *)eth_type_to_string(ethType))); + ret = eth_proto_parse(ethType, (packet + hdrLen), (pktSize - hdrLen), jparent); + + /* packet has the minimum allowed size, so the remaining data is + * most likely padding, this should not appear as data, so remove it */ + if (pktSize <= 60 && ret->pData != NULL) { + if (!ret->pData[0]) ret->size = 0; + } + return ret; +} |