1 /* eth_parser.c
2 *
3 * This file contains functions to parse Ethernet II headers.
4 *
5 * File begun on 2018-11-13
6 *
7 * Created by:
8 * - Théo Bertin (theo.bertin@advens.fr)
9 *
10 * With:
11 * - François Bernard (francois.bernard@isen.yncrea.fr)
12 * - Tianyu Geng (tianyu.geng@isen.yncrea.fr)
13 *
14 * This file is part of rsyslog.
15 *
16 * Licensed under the Apache License, Version 2.0 (the "License");
17 * you may not use this file except in compliance with the License.
18 * You may obtain a copy of the License at
19 *
20 * http://www.apache.org/licenses/LICENSE-2.0
21 * -or-
22 * see COPYING.ASL20 in the source distribution
23 *
24 * Unless required by applicable law or agreed to in writing, software
25 * distributed under the License is distributed on an "AS IS" BASIS,
26 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27 * See the License for the specific language governing permissions and
28 * limitations under the License.
29 */
30
31 #include "config.h"
32 #include "parsers.h"
33
34 #pragma GCC diagnostic push
35 #pragma GCC diagnostic ignored "-Wpacked"
36 #pragma GCC diagnostic ignored "-Wattributes"
37 struct __attribute__ ((__packed__)) eth_header_s {
38 uint8_t addrDst[6];
39 uint8_t addrSrc[6];
40 uint16_t type;
41 };
42
43 struct __attribute__ ((__packed__)) vlan_header_s {
44 uint8_t addrDst[6];
45 uint8_t addrSrc[6];
46 uint16_t vlanCode;
47 uint16_t vlanTag;
48 uint16_t type;
49 };
50 #pragma GCC diagnostic pop
51
52 typedef struct eth_header_s eth_header_t;
53 typedef struct vlan_header_s vlan_header_t;
54
55
56 /*
57 * Get an ethernet header type as uint16_t
58 * and return the correspondence as string
59 * NOTE : Only most common types are present, to complete if needed
60 */
eth_type_to_string(uint16_t eth_type)61 static const char *eth_type_to_string(uint16_t eth_type) {
62 switch (eth_type) {
63 case 0x00bb: // Extreme Networks Discovery Protocol
64 return "EDP";
65 case 0x0200: // PUP protocol
66 return "PUP";
67 case 0x0800: // IP protocol
68 return "IP";
69 case 0x0806: // address resolution protocol
70 return "ARP";
71 case 0x88a2: // AoE protocol
72 return "AOE";
73 case 0x2000: // Cisco Discovery Protocol
74 return "CDP";
75 case 0x2004: // Cisco Dynamic Trunking Protocol
76 return "DTP";
77 case 0x8035: // reverse addr resolution protocol
78 return "REVARP";
79 case 0x8100: // IEEE 802.1Q VLAN tagging
80 return "802.1Q";
81 case 0x88a8: // IEEE 802.1ad
82 return "802.1AD";
83 case 0x9100: // Legacy QinQ
84 return "QINQ1";
85 case 0x9200: // Legacy QinQ
86 return "QINQ2";
87 case 0x8137: // Internetwork Packet Exchange
88 return "IPX";
89 case 0x86DD: // IPv6 protocol
90 return "IPv6";
91 case 0x880B: // PPP
92 return "PPP";
93 case 0x8847: // MPLS
94 return "MPLS";
95 case 0x8848: // MPLS Multicast
96 return "MPLS_MCAST";
97 case 0x8863: // PPP Over Ethernet Discovery Stage
98 return "PPPoE_DISC";
99 case 0x8864: // PPP Over Ethernet Session Stage
100 return "PPPoE";
101 case 0x88CC: // Link Layer Discovery Protocol
102 return "LLDP";
103 case 0x6558: // Transparent Ethernet Bridging
104 return "TEB";
105 default:
106 return "UNKNOWN";
107 }
108 }
109
110
111 /*
112 * This function parses the bytes in the received packet to extract Ethernet II metadata.
113 *
114 * its parameters are:
115 * - a pointer on the list of bytes representing the packet
116 * the first byte must be the beginning of the ETH header
117 * - the size of the list passed as first parameter
118 * - a pointer on a json_object, containing all the metadata recovered so far
119 * this is also where ETH metadata will be added
120 *
121 * This function returns a structure containing the data unprocessed by this parser
122 * or the ones after (as a list of bytes), and the length of this data.
123 */
eth_parse(const uchar * packet,int pktSize,struct json_object * jparent)124 data_ret_t *eth_parse(const uchar *packet, int pktSize, struct json_object *jparent) {
125 DBGPRINTF("entered eth_parse\n");
126 DBGPRINTF("packet size %d\n", pktSize);
127 if (pktSize < 14) { /* too short for eth header */
128 DBGPRINTF("ETH packet too small : %d\n", pktSize);
129 RETURN_DATA_AFTER(0)
130 }
131
132 eth_header_t *eth_header = (eth_header_t *)packet;
133 char ethMacSrc[20], ethMacDst[20];
134 uint8_t hdrLen = 14;
135
136 ether_ntoa_r((struct ether_addr *)eth_header->addrSrc, ethMacSrc);
137 ether_ntoa_r((struct ether_addr *)eth_header->addrDst, ethMacDst);
138
139 json_object_object_add(jparent, "ETH_src", json_object_new_string((char *)ethMacSrc));
140 json_object_object_add(jparent, "ETH_dst", json_object_new_string((char *)ethMacDst));
141
142 uint16_t ethType = (uint16_t)ntohs(eth_header->type);
143
144 if (ethType == ETHERTYPE_VLAN) {
145 vlan_header_t *vlan_header = (vlan_header_t *)packet;
146 json_object_object_add(jparent, "ETH_tag", json_object_new_int(ntohs(vlan_header->vlanTag)));
147 ethType = (uint16_t)ntohs(vlan_header->type);
148 hdrLen += 4;
149 }
150
151 data_ret_t *ret;
152
153 if (ethType < 1500) {
154 /* this is a LLC header */
155 json_object_object_add(jparent, "ETH_len", json_object_new_int(ethType));
156 ret = llc_parse(packet + hdrLen, pktSize - hdrLen, jparent);
157
158 /* packet has the minimum allowed size, so the remaining data is
159 * most likely padding, this should not appear as data, so remove it
160 * */
161 //TODO this is a quick win, a more elaborate solution would be to check if all data
162 // is indeed zero, but that would take more processing time
163 if (pktSize <= 60 && ret->pData != NULL) {
164 if (!ret->pData[0]) ret->size = 0;
165 }
166 return ret;
167 }
168
169 json_object_object_add(jparent, "ETH_type", json_object_new_int(ethType));
170 json_object_object_add(jparent, "ETH_typestr", json_object_new_string((char *)eth_type_to_string(ethType)));
171 ret = eth_proto_parse(ethType, (packet + hdrLen), (pktSize - hdrLen), jparent);
172
173 /* packet has the minimum allowed size, so the remaining data is
174 * most likely padding, this should not appear as data, so remove it */
175 if (pktSize <= 60 && ret->pData != NULL) {
176 if (!ret->pData[0]) ret->size = 0;
177 }
178 return ret;
179 }
180