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  const 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  */
63  const uint8_t *pkt, uint32_t len, PacketQueue *pq)
64 {
65  uint32_t proto;
66 
67  if (p->vlan_idx == 0)
68  StatsIncr(tv, dtv->counter_vlan);
69  else if (p->vlan_idx == 1)
70  StatsIncr(tv, dtv->counter_vlan_qinq);
71 
72  if(len < VLAN_HEADER_LEN) {
74  return TM_ECODE_FAILED;
75  }
76  if (p->vlan_idx >= 2) {
78  return TM_ECODE_FAILED;
79  }
80 
81  VLANHdr *vlan_hdr = (VLANHdr *)pkt;
82  if(vlan_hdr == NULL)
83  return TM_ECODE_FAILED;
84 
85  proto = GET_VLAN_PROTO(vlan_hdr);
86 
87  SCLogDebug("p %p pkt %p VLAN protocol %04x VLAN PRI %d VLAN CFI %d VLAN ID %d Len: %" PRIu32 "",
88  p, pkt, proto, GET_VLAN_PRIORITY(vlan_hdr), GET_VLAN_CFI(vlan_hdr),
89  GET_VLAN_ID(vlan_hdr), len);
90 
91  p->vlan_id[p->vlan_idx++] = (uint16_t)GET_VLAN_ID(vlan_hdr);
92 
93  switch (proto) {
94  case ETHERNET_TYPE_IP:
95  if (unlikely(len > VLAN_HEADER_LEN + USHRT_MAX)) {
96  return TM_ECODE_FAILED;
97  }
98 
99  DecodeIPV4(tv, dtv, p, pkt + VLAN_HEADER_LEN,
100  len - VLAN_HEADER_LEN, pq);
101  break;
102  case ETHERNET_TYPE_IPV6:
103  if (unlikely(len > VLAN_HEADER_LEN + USHRT_MAX)) {
104  return TM_ECODE_FAILED;
105  }
106  DecodeIPV6(tv, dtv, p, pkt + VLAN_HEADER_LEN,
107  len - VLAN_HEADER_LEN, pq);
108  break;
110  DecodePPPOESession(tv, dtv, p, pkt + VLAN_HEADER_LEN,
111  len - VLAN_HEADER_LEN, pq);
112  break;
114  DecodePPPOEDiscovery(tv, dtv, p, pkt + VLAN_HEADER_LEN,
115  len - VLAN_HEADER_LEN, pq);
116  break;
117  case ETHERNET_TYPE_VLAN:
119  if (p->vlan_idx >= 2) {
121  return TM_ECODE_OK;
122  } else {
123  DecodeVLAN(tv, dtv, p, pkt + VLAN_HEADER_LEN,
124  len - VLAN_HEADER_LEN, pq);
125  }
126  break;
128  DecodeIEEE8021ah(tv, dtv, p, pkt + VLAN_HEADER_LEN,
129  len - VLAN_HEADER_LEN, pq);
130  break;
131  case ETHERNET_TYPE_ARP:
132  break;
135  DecodeMPLS(tv, dtv, p, pkt + VLAN_HEADER_LEN,
136  len - VLAN_HEADER_LEN, pq);
137  break;
138  default:
139  SCLogDebug("unknown VLAN type: %" PRIx32 "", proto);
141  return TM_ECODE_OK;
142  }
143 
144  return TM_ECODE_OK;
145 }
146 
147 uint16_t DecodeVLANGetId(const Packet *p, uint8_t layer)
148 {
149  if (unlikely(layer > 1))
150  return 0;
151  if (p->vlan_idx > layer) {
152  return p->vlan_id[layer];
153  }
154  return 0;
155 }
156 
157 typedef struct IEEE8021ahHdr_ {
158  uint32_t flags;
159  uint8_t c_destination[6];
160  uint8_t c_source[6];
161  uint16_t type; /**< next protocol */
162 } __attribute__((__packed__)) IEEE8021ahHdr;
163 
164 #define IEEE8021AH_HEADER_LEN sizeof(IEEE8021ahHdr)
165 
166 static int DecodeIEEE8021ah(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
167  const 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->vlan_id[0] == 0) {
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  */
#define ETHERNET_TYPE_8021AH
#define ENGINE_SET_EVENT(p, e)
Definition: decode.h:992
#define SCLogDebug(...)
Definition: util-debug.h:335
uint16_t DecodeVLANGetId(const Packet *p, uint8_t layer)
Definition: decode-vlan.c:147
uint16_t counter_ieee8021ah
Definition: decode.h:662
int DecodePPPOEDiscovery(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len, PacketQueue *pq)
Main decoding function for PPPOE Discovery packets.
Definition: decode-pppoe.c:50
#define ENGINE_ISSET_EVENT(p, e)
Definition: decode.h:1007
#define unlikely(expr)
Definition: util-optimize.h:35
int DecodePPPOESession(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len, PacketQueue *pq)
Main decoding function for PPPOE Session packets.
Definition: decode-pppoe.c:130
uint32_t flags
Definition: decode-vlan.c:158
uint16_t counter_vlan_qinq
Definition: decode.h:660
#define FLOW_QUIET
Definition: flow.h:38
#define ETHERNET_TYPE_VLAN
Definition: decode-vlan.h:31
#define PACKET_RECYCLE(p)
Definition: decode.h:814
#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:435
uint16_t counter_vlan
Definition: decode.h:659
#define ETHERNET_TYPE_8021AD
#define ETHERNET_TYPE_ARP
#define ETHERNET_TYPE_IP
int DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len, PacketQueue *pq)
Definition: decode-vlan.c:62
#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:632
#define GET_VLAN_ID(vlanh)
Definition: decode-vlan.h:36
#define ETHERNET_TYPE_MPLS_MULTICAST
Definition: decode-mpls.h:30
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition: counters.c:168
#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:160
#define GET_VLAN_CFI(vlanh)
Definition: decode-vlan.h:35
uint8_t proto
#define ETHERNET_TYPE_PPPOE_SESS
uint8_t vlan_idx
Definition: decode.h:436
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len, PacketQueue *pq)
Definition: decode-ipv6.c:585
uint16_t type
Definition: decode-vlan.c:161
#define SCFree(a)
Definition: util-mem.h:322
#define SCNtohs(x)
int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len, PacketQueue *pq)
Definition: decode-ipv4.c:532
void FlowShutdown(void)
shutdown the flow engine
Definition: flow.c:670
int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len, PacketQueue *pq)
Definition: decode-mpls.c:47
uint8_t len
Per thread variable structure.
Definition: threadvars.h:57
#define ETHERNET_TYPE_IPV6
#define ETHERNET_TYPE_MPLS_UNICAST
Definition: decode-mpls.h:29
uint8_t c_destination[6]
Definition: decode-vlan.c:159
#define ETHERNET_TYPE_8021QINQ
#define ENGINE_SET_INVALID_EVENT(p, e)
Definition: decode.h:1000
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:141
struct IEEE8021ahHdr_ __attribute__((__packed__))
DNP3 link header.
Definition: decode-vlan.c:162
#define IEEE8021AH_HEADER_LEN
void FlowInitConfig(char quiet)
initialize the configuration
Definition: flow.c:515