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  VLANHdr *vlan_hdr = (VLANHdr *)pkt;
81  if(vlan_hdr == NULL)
82  return TM_ECODE_FAILED;
83 
84  proto = GET_VLAN_PROTO(vlan_hdr);
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(vlan_hdr), GET_VLAN_CFI(vlan_hdr),
88  GET_VLAN_ID(vlan_hdr), len);
89 
90  p->vlan_id[p->vlan_idx++] = (uint16_t)GET_VLAN_ID(vlan_hdr);
91 
92  switch (proto) {
93  case ETHERNET_TYPE_IP:
94  if (unlikely(len > VLAN_HEADER_LEN + USHRT_MAX)) {
95  return TM_ECODE_FAILED;
96  }
97 
98  DecodeIPV4(tv, dtv, p, pkt + VLAN_HEADER_LEN,
99  len - VLAN_HEADER_LEN, pq);
100  break;
101  case ETHERNET_TYPE_IPV6:
102  if (unlikely(len > VLAN_HEADER_LEN + USHRT_MAX)) {
103  return TM_ECODE_FAILED;
104  }
105  DecodeIPV6(tv, dtv, p, pkt + VLAN_HEADER_LEN,
106  len - VLAN_HEADER_LEN, pq);
107  break;
109  DecodePPPOESession(tv, dtv, p, pkt + VLAN_HEADER_LEN,
110  len - VLAN_HEADER_LEN, pq);
111  break;
113  DecodePPPOEDiscovery(tv, dtv, p, pkt + VLAN_HEADER_LEN,
114  len - VLAN_HEADER_LEN, pq);
115  break;
116  case ETHERNET_TYPE_VLAN:
118  if (p->vlan_idx >= 2) {
120  return TM_ECODE_OK;
121  } else {
122  DecodeVLAN(tv, dtv, p, pkt + VLAN_HEADER_LEN,
123  len - VLAN_HEADER_LEN, pq);
124  }
125  break;
127  DecodeIEEE8021ah(tv, dtv, p, pkt + VLAN_HEADER_LEN,
128  len - VLAN_HEADER_LEN, pq);
129  break;
130  case ETHERNET_TYPE_ARP:
131  break;
132  default:
133  SCLogDebug("unknown VLAN type: %" PRIx32 "", proto);
135  return TM_ECODE_OK;
136  }
137 
138  return TM_ECODE_OK;
139 }
140 
141 uint16_t DecodeVLANGetId(const Packet *p, uint8_t layer)
142 {
143  if (unlikely(layer > 1))
144  return 0;
145  if (p->vlan_idx > layer) {
146  return p->vlan_id[layer];
147  }
148  return 0;
149 }
150 
151 typedef struct IEEE8021ahHdr_ {
152  uint32_t flags;
153  uint8_t c_destination[6];
154  uint8_t c_source[6];
155  uint16_t type; /**< next protocol */
156 } __attribute__((__packed__)) IEEE8021ahHdr;
157 
158 #define IEEE8021AH_HEADER_LEN sizeof(IEEE8021ahHdr)
159 
160 static int DecodeIEEE8021ah(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq)
161 {
162  StatsIncr(tv, dtv->counter_ieee8021ah);
163 
164  if (len < IEEE8021AH_HEADER_LEN) {
166  return TM_ECODE_FAILED;
167  }
168 
169  IEEE8021ahHdr *hdr = (IEEE8021ahHdr *)pkt;
170  uint16_t next_proto = SCNtohs(hdr->type);
171 
172  switch (next_proto) {
173  case ETHERNET_TYPE_VLAN:
174  case ETHERNET_TYPE_8021QINQ: {
175  DecodeVLAN(tv, dtv, p, pkt + IEEE8021AH_HEADER_LEN,
176  len - IEEE8021AH_HEADER_LEN, pq);
177  break;
178  }
179  }
180  return TM_ECODE_OK;
181 }
182 
183 #ifdef UNITTESTS
184 /** \todo Must GRE+VLAN and Multi-Vlan packets to
185  * create more tests
186  */
187 
188 /**
189  * \test DecodeVLANTest01 test if vlan header is too small.
190  *
191  * \retval 1 on success
192  * \retval 0 on failure
193  */
194 static int DecodeVLANtest01 (void)
195 {
196  uint8_t raw_vlan[] = { 0x00, 0x20, 0x08 };
197  Packet *p = PacketGetFromAlloc();
198  if (unlikely(p == NULL))
199  return 0;
200  ThreadVars tv;
201  DecodeThreadVars dtv;
202 
203  memset(&tv, 0, sizeof(ThreadVars));
204  memset(&dtv, 0, sizeof(DecodeThreadVars));
205 
206  DecodeVLAN(&tv, &dtv, p, raw_vlan, sizeof(raw_vlan), NULL);
207 
209  SCFree(p);
210  return 1;
211  }
212 
213  SCFree(p);
214  return 0;
215 }
216 
217 /**
218  * \test DecodeVLANTest02 test if vlan header has unknown type.
219  *
220  * \retval 1 on success
221  * \retval 0 on failure
222  */
223 static int DecodeVLANtest02 (void)
224 {
225  uint8_t raw_vlan[] = {
226  0x00, 0x20, 0x01, 0x00, 0x45, 0x00, 0x00, 0x34,
227  0x3b, 0x36, 0x40, 0x00, 0x40, 0x06, 0xb7, 0xc9,
228  0x83, 0x97, 0x20, 0x81, 0x83, 0x97, 0x20, 0x15,
229  0x04, 0x8a, 0x17, 0x70, 0x4e, 0x14, 0xdf, 0x55,
230  0x4d, 0x3d, 0x5a, 0x61, 0x80, 0x10, 0x6b, 0x50,
231  0x3c, 0x4c, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a,
232  0x00, 0x04, 0xf0, 0xc8, 0x01, 0x99, 0xa3, 0xf3};
233  Packet *p = PacketGetFromAlloc();
234  if (unlikely(p == NULL))
235  return 0;
236  ThreadVars tv;
237  DecodeThreadVars dtv;
238 
239  memset(&tv, 0, sizeof(ThreadVars));
240  memset(&dtv, 0, sizeof(DecodeThreadVars));
241 
242  DecodeVLAN(&tv, &dtv, p, raw_vlan, sizeof(raw_vlan), NULL);
243 
244 
246  SCFree(p);
247  return 1;
248  }
249 
250  SCFree(p);
251  return 0;
252 }
253 
254 /**
255  * \test DecodeVLANTest02 test a good vlan header.
256  *
257  * \retval 1 on success
258  * \retval 0 on failure
259  */
260 static int DecodeVLANtest03 (void)
261 {
262  uint8_t raw_vlan[] = {
263  0x00, 0x20, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34,
264  0x3b, 0x36, 0x40, 0x00, 0x40, 0x06, 0xb7, 0xc9,
265  0x83, 0x97, 0x20, 0x81, 0x83, 0x97, 0x20, 0x15,
266  0x04, 0x8a, 0x17, 0x70, 0x4e, 0x14, 0xdf, 0x55,
267  0x4d, 0x3d, 0x5a, 0x61, 0x80, 0x10, 0x6b, 0x50,
268  0x3c, 0x4c, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a,
269  0x00, 0x04, 0xf0, 0xc8, 0x01, 0x99, 0xa3, 0xf3};
270  Packet *p = PacketGetFromAlloc();
271  if (unlikely(p == NULL))
272  return 0;
273  ThreadVars tv;
274  DecodeThreadVars dtv;
275 
276  memset(&tv, 0, sizeof(ThreadVars));
277  memset(&dtv, 0, sizeof(DecodeThreadVars));
278 
280 
281  DecodeVLAN(&tv, &dtv, p, raw_vlan, sizeof(raw_vlan), NULL);
282 
283 
284  if(p->vlan_id[0] == 0) {
285  goto error;
286  }
287 
289  goto error;
290  }
291 
293  goto error;
294  }
295 
296  PACKET_RECYCLE(p);
297  FlowShutdown();
298  SCFree(p);
299  return 1;
300 
301 error:
302  PACKET_RECYCLE(p);
303  FlowShutdown();
304  SCFree(p);
305  return 0;
306 }
307 #endif /* UNITTESTS */
308 
310 {
311 #ifdef UNITTESTS
312  UtRegisterTest("DecodeVLANtest01", DecodeVLANtest01);
313  UtRegisterTest("DecodeVLANtest02", DecodeVLANtest02);
314  UtRegisterTest("DecodeVLANtest03", DecodeVLANtest03);
315 #endif /* UNITTESTS */
316 }
317 
318 /**
319  * @}
320  */
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:989
#define SCLogDebug(...)
Definition: util-debug.h:335
uint16_t DecodeVLANGetId(const Packet *p, uint8_t layer)
Definition: decode-vlan.c:141
uint16_t counter_ieee8021ah
Definition: decode.h:662
#define ENGINE_ISSET_EVENT(p, e)
Definition: decode.h:1004
#define unlikely(expr)
Definition: util-optimize.h:35
uint32_t flags
Definition: decode-vlan.c:152
uint16_t counter_vlan_qinq
Definition: decode.h:660
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: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
int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq)
Definition: decode-ipv4.c:532
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq)
Definition: decode-ipv6.c:583
#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:632
#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:309
uint8_t c_source[6]
Definition: decode-vlan.c:154
#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:436
uint16_t type
Definition: decode-vlan.c:155
#define SCFree(a)
Definition: util-mem.h:322
#define SCNtohs(x)
void FlowShutdown(void)
shutdown the flow engine
Definition: flow.c:667
uint8_t len
Per thread variable structure.
Definition: threadvars.h:57
#define ETHERNET_TYPE_IPV6
uint8_t c_destination[6]
Definition: decode-vlan.c:153
#define ETHERNET_TYPE_8021QINQ
#define ENGINE_SET_INVALID_EVENT(p, e)
Definition: decode.h:997
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:141
struct IEEE8021ahHdr_ __attribute__((__packed__))
DNP3 link header.
Definition: decode-vlan.c:156
#define IEEE8021AH_HEADER_LEN
void FlowInitConfig(char quiet)
initialize the configuration
Definition: flow.c:512