suricata
decode-vlan.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2013 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \ingroup decode
20  *
21  * @{
22  */
23 
24 
25 /**
26  * \file
27  *
28  * \author Breno Silva <breno.silva@gmail.com>
29  *
30  * Decode 802.1q
31  */
32 
33 #include "suricata-common.h"
34 #include "decode.h"
35 #include "decode-vlan.h"
36 #include "decode-events.h"
37 
38 #include "flow.h"
39 
40 #include "util-unittest.h"
41 #include "util-debug.h"
42 
43 #include "pkt-var.h"
44 #include "util-profiling.h"
45 #include "host.h"
46 
47 static int DecodeIEEE8021ah(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
48  uint8_t *pkt, uint16_t len, PacketQueue *pq);
49 
50 /**
51  * \internal
52  * \brief this function is used to decode IEEE802.1q packets
53  *
54  * \param tv pointer to the thread vars
55  * \param dtv pointer code thread vars
56  * \param p pointer to the packet struct
57  * \param pkt pointer to the raw packet
58  * \param len packet len
59  * \param pq pointer to the packet queue
60  *
61  */
62 int DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint32_t len, PacketQueue *pq)
63 {
64  uint32_t proto;
65 
66  if (p->vlan_idx == 0)
67  StatsIncr(tv, dtv->counter_vlan);
68  else if (p->vlan_idx == 1)
69  StatsIncr(tv, dtv->counter_vlan_qinq);
70 
71  if(len < VLAN_HEADER_LEN) {
73  return TM_ECODE_FAILED;
74  }
75  if (p->vlan_idx >= 2) {
77  return TM_ECODE_FAILED;
78  }
79 
80  p->vlanh[p->vlan_idx] = (VLANHdr *)pkt;
81  if(p->vlanh[p->vlan_idx] == NULL)
82  return TM_ECODE_FAILED;
83 
84  proto = GET_VLAN_PROTO(p->vlanh[p->vlan_idx]);
85 
86  SCLogDebug("p %p pkt %p VLAN protocol %04x VLAN PRI %d VLAN CFI %d VLAN ID %d Len: %" PRIu32 "",
87  p, pkt, proto, GET_VLAN_PRIORITY(p->vlanh[p->vlan_idx]),
88  GET_VLAN_CFI(p->vlanh[p->vlan_idx]), GET_VLAN_ID(p->vlanh[p->vlan_idx]), len);
89 
90  /* only store the id for flow hashing if it's not disabled. */
91  if (dtv->vlan_disabled == 0)
92  p->vlan_id[p->vlan_idx] = (uint16_t)GET_VLAN_ID(p->vlanh[p->vlan_idx]);
93 
94  p->vlan_idx++;
95 
96  switch (proto) {
97  case ETHERNET_TYPE_IP:
98  if (unlikely(len > VLAN_HEADER_LEN + USHRT_MAX)) {
99  return TM_ECODE_FAILED;
100  }
101 
102  DecodeIPV4(tv, dtv, p, pkt + VLAN_HEADER_LEN,
103  len - VLAN_HEADER_LEN, pq);
104  break;
105  case ETHERNET_TYPE_IPV6:
106  if (unlikely(len > VLAN_HEADER_LEN + USHRT_MAX)) {
107  return TM_ECODE_FAILED;
108  }
109  DecodeIPV6(tv, dtv, p, pkt + VLAN_HEADER_LEN,
110  len - VLAN_HEADER_LEN, pq);
111  break;
113  DecodePPPOESession(tv, dtv, p, pkt + VLAN_HEADER_LEN,
114  len - VLAN_HEADER_LEN, pq);
115  break;
117  DecodePPPOEDiscovery(tv, dtv, p, pkt + VLAN_HEADER_LEN,
118  len - VLAN_HEADER_LEN, pq);
119  break;
120  case ETHERNET_TYPE_VLAN:
122  if (p->vlan_idx >= 2) {
124  return TM_ECODE_OK;
125  } else {
126  DecodeVLAN(tv, dtv, p, pkt + VLAN_HEADER_LEN,
127  len - VLAN_HEADER_LEN, pq);
128  }
129  break;
131  DecodeIEEE8021ah(tv, dtv, p, pkt + VLAN_HEADER_LEN,
132  len - VLAN_HEADER_LEN, pq);
133  break;
134  case ETHERNET_TYPE_ARP:
135  break;
136  default:
137  SCLogDebug("unknown VLAN type: %" PRIx32 "", proto);
139  return TM_ECODE_OK;
140  }
141 
142  return TM_ECODE_OK;
143 }
144 
145 uint16_t DecodeVLANGetId(const Packet *p, uint8_t layer)
146 {
147  if (unlikely(layer > 1))
148  return 0;
150  if (p->vlanh[layer] == NULL && (p->vlan_idx >= (layer + 1))) {
151  return p->vlan_id[layer];
152  } else {
153  return GET_VLAN_ID(p->vlanh[layer]);
154  }
155  return 0;
156 }
157 
158 typedef struct IEEE8021ahHdr_ {
159  uint32_t flags;
160  uint8_t c_destination[6];
161  uint8_t c_source[6];
162  uint16_t type; /**< next protocol */
163 } __attribute__((__packed__)) IEEE8021ahHdr;
164 
165 #define IEEE8021AH_HEADER_LEN sizeof(IEEE8021ahHdr)
166 
167 static int DecodeIEEE8021ah(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq)
168 {
169  StatsIncr(tv, dtv->counter_ieee8021ah);
170 
171  if (len < IEEE8021AH_HEADER_LEN) {
173  return TM_ECODE_FAILED;
174  }
175 
176  IEEE8021ahHdr *hdr = (IEEE8021ahHdr *)pkt;
177  uint16_t next_proto = SCNtohs(hdr->type);
178 
179  switch (next_proto) {
180  case ETHERNET_TYPE_VLAN:
181  case ETHERNET_TYPE_8021QINQ: {
182  DecodeVLAN(tv, dtv, p, pkt + IEEE8021AH_HEADER_LEN,
183  len - IEEE8021AH_HEADER_LEN, pq);
184  break;
185  }
186  }
187  return TM_ECODE_OK;
188 }
189 
190 #ifdef UNITTESTS
191 /** \todo Must GRE+VLAN and Multi-Vlan packets to
192  * create more tests
193  */
194 
195 /**
196  * \test DecodeVLANTest01 test if vlan header is too small.
197  *
198  * \retval 1 on success
199  * \retval 0 on failure
200  */
201 static int DecodeVLANtest01 (void)
202 {
203  uint8_t raw_vlan[] = { 0x00, 0x20, 0x08 };
204  Packet *p = PacketGetFromAlloc();
205  if (unlikely(p == NULL))
206  return 0;
207  ThreadVars tv;
208  DecodeThreadVars dtv;
209 
210  memset(&tv, 0, sizeof(ThreadVars));
211  memset(&dtv, 0, sizeof(DecodeThreadVars));
212 
213  DecodeVLAN(&tv, &dtv, p, raw_vlan, sizeof(raw_vlan), NULL);
214 
216  SCFree(p);
217  return 1;
218  }
219 
220  SCFree(p);
221  return 0;
222 }
223 
224 /**
225  * \test DecodeVLANTest02 test if vlan header has unknown type.
226  *
227  * \retval 1 on success
228  * \retval 0 on failure
229  */
230 static int DecodeVLANtest02 (void)
231 {
232  uint8_t raw_vlan[] = {
233  0x00, 0x20, 0x01, 0x00, 0x45, 0x00, 0x00, 0x34,
234  0x3b, 0x36, 0x40, 0x00, 0x40, 0x06, 0xb7, 0xc9,
235  0x83, 0x97, 0x20, 0x81, 0x83, 0x97, 0x20, 0x15,
236  0x04, 0x8a, 0x17, 0x70, 0x4e, 0x14, 0xdf, 0x55,
237  0x4d, 0x3d, 0x5a, 0x61, 0x80, 0x10, 0x6b, 0x50,
238  0x3c, 0x4c, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a,
239  0x00, 0x04, 0xf0, 0xc8, 0x01, 0x99, 0xa3, 0xf3};
240  Packet *p = PacketGetFromAlloc();
241  if (unlikely(p == NULL))
242  return 0;
243  ThreadVars tv;
244  DecodeThreadVars dtv;
245 
246  memset(&tv, 0, sizeof(ThreadVars));
247  memset(&dtv, 0, sizeof(DecodeThreadVars));
248 
249  DecodeVLAN(&tv, &dtv, p, raw_vlan, sizeof(raw_vlan), NULL);
250 
251 
253  SCFree(p);
254  return 1;
255  }
256 
257  SCFree(p);
258  return 0;
259 }
260 
261 /**
262  * \test DecodeVLANTest02 test a good vlan header.
263  *
264  * \retval 1 on success
265  * \retval 0 on failure
266  */
267 static int DecodeVLANtest03 (void)
268 {
269  uint8_t raw_vlan[] = {
270  0x00, 0x20, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34,
271  0x3b, 0x36, 0x40, 0x00, 0x40, 0x06, 0xb7, 0xc9,
272  0x83, 0x97, 0x20, 0x81, 0x83, 0x97, 0x20, 0x15,
273  0x04, 0x8a, 0x17, 0x70, 0x4e, 0x14, 0xdf, 0x55,
274  0x4d, 0x3d, 0x5a, 0x61, 0x80, 0x10, 0x6b, 0x50,
275  0x3c, 0x4c, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a,
276  0x00, 0x04, 0xf0, 0xc8, 0x01, 0x99, 0xa3, 0xf3};
277  Packet *p = PacketGetFromAlloc();
278  if (unlikely(p == NULL))
279  return 0;
280  ThreadVars tv;
281  DecodeThreadVars dtv;
282 
283  memset(&tv, 0, sizeof(ThreadVars));
284  memset(&dtv, 0, sizeof(DecodeThreadVars));
285 
287 
288  DecodeVLAN(&tv, &dtv, p, raw_vlan, sizeof(raw_vlan), NULL);
289 
290 
291  if(p->vlanh[0] == NULL) {
292  goto error;
293  }
294 
296  goto error;
297  }
298 
300  goto error;
301  }
302 
303  PACKET_RECYCLE(p);
304  FlowShutdown();
305  SCFree(p);
306  return 1;
307 
308 error:
309  PACKET_RECYCLE(p);
310  FlowShutdown();
311  SCFree(p);
312  return 0;
313 }
314 #endif /* UNITTESTS */
315 
317 {
318 #ifdef UNITTESTS
319  UtRegisterTest("DecodeVLANtest01", DecodeVLANtest01);
320  UtRegisterTest("DecodeVLANtest02", DecodeVLANtest02);
321  UtRegisterTest("DecodeVLANtest03", DecodeVLANtest03);
322 #endif /* UNITTESTS */
323 }
324 
325 /**
326  * @}
327  */
int DecodePPPOESession(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint32_t len, PacketQueue *pq)
Main decoding function for PPPOE Session packets.
Definition: decode-pppoe.c:129
#define ETHERNET_TYPE_8021AH
#define ENGINE_SET_EVENT(p, e)
Definition: decode.h:1000
#define SCLogDebug(...)
Definition: util-debug.h:335
uint16_t DecodeVLANGetId(const Packet *p, uint8_t layer)
Definition: decode-vlan.c:145
uint16_t counter_ieee8021ah
Definition: decode.h:673
#define ENGINE_ISSET_EVENT(p, e)
Definition: decode.h:1015
#define unlikely(expr)
Definition: util-optimize.h:35
uint32_t flags
Definition: decode-vlan.c:159
uint16_t counter_vlan_qinq
Definition: decode.h:672
int DecodePPPOEDiscovery(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint32_t len, PacketQueue *pq)
Main decoding function for PPPOE Discovery packets.
Definition: decode-pppoe.c:50
#define FLOW_QUIET
Definition: flow.h:37
#define ETHERNET_TYPE_VLAN
Definition: decode-vlan.h:31
#define PACKET_RECYCLE(p)
Definition: decode.h:827
#define VLAN_HEADER_LEN
Definition: decode-vlan.h:50
#define GET_VLAN_PROTO(vlanh)
Definition: decode-vlan.h:37
uint16_t vlan_id[2]
Definition: decode.h:434
uint16_t counter_vlan
Definition: decode.h:671
#define ETHERNET_TYPE_8021AD
int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq)
Definition: decode-ipv4.c:533
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq)
Definition: decode-ipv6.c:584
#define ETHERNET_TYPE_ARP
#define ETHERNET_TYPE_IP
#define ETHERNET_TYPE_PPPOE_DISC
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Structure to hold thread specific data for all decode modules.
Definition: decode.h:642
#define GET_VLAN_ID(vlanh)
Definition: decode-vlan.h:36
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition: counters.c:163
#define GET_VLAN_PRIORITY(vlanh)
Definition: decode-vlan.h:34
void DecodeVLANRegisterTests(void)
Definition: decode-vlan.c:316
uint8_t c_source[6]
Definition: decode-vlan.c:161
#define GET_VLAN_CFI(vlanh)
Definition: decode-vlan.h:35
uint8_t proto
int DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint32_t len, PacketQueue *pq)
Definition: decode-vlan.c:62
#define ETHERNET_TYPE_PPPOE_SESS
uint8_t vlan_idx
Definition: decode.h:435
uint16_t type
Definition: decode-vlan.c:162
#define SCFree(a)
Definition: util-mem.h:236
#define SCNtohs(x)
VLANHdr * vlanh[2]
Definition: decode.h:541
void FlowShutdown(void)
shutdown the flow engine
Definition: flow.c:599
uint8_t len
Per thread variable structure.
Definition: threadvars.h:57
#define ETHERNET_TYPE_IPV6
uint8_t c_destination[6]
Definition: decode-vlan.c:160
#define ETHERNET_TYPE_8021QINQ
#define ENGINE_SET_INVALID_EVENT(p, e)
Definition: decode.h:1008
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:140
struct IEEE8021ahHdr_ __attribute__((__packed__))
DNP3 link header.
Definition: decode-vlan.c:163
#define IEEE8021AH_HEADER_LEN
void FlowInitConfig(char quiet)
initialize the configuration
Definition: flow.c:444