/src/suricata7/src/decode-vlan.c
Line | Count | Source |
1 | | /* Copyright (C) 2007-2022 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 "util-validate.h" |
39 | | #include "util-unittest.h" |
40 | | #include "util-debug.h" |
41 | | |
42 | | /** |
43 | | * \internal |
44 | | * \brief this function is used to decode IEEE802.1q packets |
45 | | * |
46 | | * \param tv pointer to the thread vars |
47 | | * \param dtv pointer code thread vars |
48 | | * \param p pointer to the packet struct |
49 | | * \param pkt pointer to the raw packet |
50 | | * \param len packet len |
51 | | * \param pq pointer to the packet queue |
52 | | * |
53 | | */ |
54 | | int DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, |
55 | | const uint8_t *pkt, uint32_t len) |
56 | 435k | { |
57 | 435k | DEBUG_VALIDATE_BUG_ON(pkt == NULL); |
58 | | |
59 | 435k | uint16_t proto; |
60 | | |
61 | 435k | if (p->vlan_idx == 0) |
62 | 425k | StatsIncr(tv, dtv->counter_vlan); |
63 | 9.96k | else if (p->vlan_idx == 1) |
64 | 8.27k | StatsIncr(tv, dtv->counter_vlan_qinq); |
65 | 1.69k | else if (p->vlan_idx == 2) |
66 | 1.69k | StatsIncr(tv, dtv->counter_vlan_qinqinq); |
67 | | |
68 | 435k | if(len < VLAN_HEADER_LEN) { |
69 | 862 | ENGINE_SET_INVALID_EVENT(p, VLAN_HEADER_TOO_SMALL); |
70 | 862 | return TM_ECODE_FAILED; |
71 | 862 | } |
72 | 434k | if (!PacketIncreaseCheckLayers(p)) { |
73 | 82 | return TM_ECODE_FAILED; |
74 | 82 | } |
75 | 434k | if (p->vlan_idx > VLAN_MAX_LAYER_IDX) { |
76 | 0 | ENGINE_SET_EVENT(p,VLAN_HEADER_TOO_MANY_LAYERS); |
77 | 0 | return TM_ECODE_FAILED; |
78 | 0 | } |
79 | | |
80 | 434k | VLANHdr *vlan_hdr = (VLANHdr *)pkt; |
81 | | |
82 | 434k | proto = GET_VLAN_PROTO(vlan_hdr); |
83 | | |
84 | 434k | SCLogDebug("p %p pkt %p VLAN protocol %04x VLAN PRI %d VLAN CFI %d VLAN ID %d Len: %" PRIu32 "", |
85 | 434k | p, pkt, proto, GET_VLAN_PRIORITY(vlan_hdr), GET_VLAN_CFI(vlan_hdr), |
86 | 434k | GET_VLAN_ID(vlan_hdr), len); |
87 | | |
88 | 434k | p->vlan_id[p->vlan_idx++] = (uint16_t)GET_VLAN_ID(vlan_hdr); |
89 | | |
90 | 434k | if (DecodeNetworkLayer(tv, dtv, proto, p, |
91 | 434k | pkt + VLAN_HEADER_LEN, len - VLAN_HEADER_LEN) == false) { |
92 | 10.1k | ENGINE_SET_INVALID_EVENT(p, VLAN_UNKNOWN_TYPE); |
93 | 10.1k | return TM_ECODE_FAILED; |
94 | 10.1k | } |
95 | 423k | return TM_ECODE_OK; |
96 | 434k | } |
97 | | |
98 | | typedef struct IEEE8021ahHdr_ { |
99 | | uint32_t flags; |
100 | | uint8_t c_destination[6]; |
101 | | uint8_t c_source[6]; |
102 | | uint16_t type; /**< next protocol */ |
103 | | } __attribute__((__packed__)) IEEE8021ahHdr; |
104 | | |
105 | 12.1k | #define IEEE8021AH_HEADER_LEN sizeof(IEEE8021ahHdr) |
106 | | |
107 | | int DecodeIEEE8021ah(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, |
108 | | const uint8_t *pkt, uint32_t len) |
109 | 4.82k | { |
110 | 4.82k | DEBUG_VALIDATE_BUG_ON(pkt == NULL); |
111 | | |
112 | 4.82k | StatsIncr(tv, dtv->counter_ieee8021ah); |
113 | | |
114 | 4.82k | if (len < IEEE8021AH_HEADER_LEN) { |
115 | 1.16k | ENGINE_SET_INVALID_EVENT(p, IEEE8021AH_HEADER_TOO_SMALL); |
116 | 1.16k | return TM_ECODE_FAILED; |
117 | 1.16k | } |
118 | | |
119 | 3.65k | IEEE8021ahHdr *hdr = (IEEE8021ahHdr *)pkt; |
120 | 3.65k | const uint16_t next_proto = SCNtohs(hdr->type); |
121 | | |
122 | 3.65k | DecodeNetworkLayer(tv, dtv, next_proto, p, |
123 | 3.65k | pkt + IEEE8021AH_HEADER_LEN, len - IEEE8021AH_HEADER_LEN); |
124 | | |
125 | 3.65k | return TM_ECODE_OK; |
126 | 4.82k | } |
127 | | |
128 | | #ifdef UNITTESTS |
129 | | #include "util-unittest-helper.h" |
130 | | #include "packet.h" |
131 | | |
132 | | /** \todo Must GRE+VLAN and Multi-Vlan packets to |
133 | | * create more tests |
134 | | */ |
135 | | |
136 | | /** |
137 | | * \test DecodeVLANTest01 test if vlan header is too small. |
138 | | * |
139 | | * \retval 1 on success |
140 | | * \retval 0 on failure |
141 | | */ |
142 | | static int DecodeVLANtest01 (void) |
143 | | { |
144 | | uint8_t raw_vlan[] = { 0x00, 0x20, 0x08 }; |
145 | | Packet *p = PacketGetFromAlloc(); |
146 | | if (unlikely(p == NULL)) |
147 | | return 0; |
148 | | ThreadVars tv; |
149 | | DecodeThreadVars dtv; |
150 | | |
151 | | memset(&tv, 0, sizeof(ThreadVars)); |
152 | | memset(&dtv, 0, sizeof(DecodeThreadVars)); |
153 | | |
154 | | DecodeVLAN(&tv, &dtv, p, raw_vlan, sizeof(raw_vlan)); |
155 | | |
156 | | if(ENGINE_ISSET_EVENT(p,VLAN_HEADER_TOO_SMALL)) { |
157 | | SCFree(p); |
158 | | return 1; |
159 | | } |
160 | | |
161 | | SCFree(p); |
162 | | return 0; |
163 | | } |
164 | | |
165 | | /** |
166 | | * \test DecodeVLANTest02 test if vlan header has unknown type. |
167 | | * |
168 | | * \retval 1 on success |
169 | | * \retval 0 on failure |
170 | | */ |
171 | | static int DecodeVLANtest02 (void) |
172 | | { |
173 | | uint8_t raw_vlan[] = { |
174 | | 0x00, 0x20, 0x01, 0x00, 0x45, 0x00, 0x00, 0x34, |
175 | | 0x3b, 0x36, 0x40, 0x00, 0x40, 0x06, 0xb7, 0xc9, |
176 | | 0x83, 0x97, 0x20, 0x81, 0x83, 0x97, 0x20, 0x15, |
177 | | 0x04, 0x8a, 0x17, 0x70, 0x4e, 0x14, 0xdf, 0x55, |
178 | | 0x4d, 0x3d, 0x5a, 0x61, 0x80, 0x10, 0x6b, 0x50, |
179 | | 0x3c, 0x4c, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, |
180 | | 0x00, 0x04, 0xf0, 0xc8, 0x01, 0x99, 0xa3, 0xf3}; |
181 | | Packet *p = PacketGetFromAlloc(); |
182 | | if (unlikely(p == NULL)) |
183 | | return 0; |
184 | | ThreadVars tv; |
185 | | DecodeThreadVars dtv; |
186 | | |
187 | | memset(&tv, 0, sizeof(ThreadVars)); |
188 | | memset(&dtv, 0, sizeof(DecodeThreadVars)); |
189 | | |
190 | | DecodeVLAN(&tv, &dtv, p, raw_vlan, sizeof(raw_vlan)); |
191 | | |
192 | | |
193 | | if(ENGINE_ISSET_EVENT(p,VLAN_UNKNOWN_TYPE)) { |
194 | | SCFree(p); |
195 | | return 1; |
196 | | } |
197 | | |
198 | | SCFree(p); |
199 | | return 0; |
200 | | } |
201 | | |
202 | | /** |
203 | | * \test DecodeVLANTest02 test a good vlan header. |
204 | | * |
205 | | * \retval 1 on success |
206 | | * \retval 0 on failure |
207 | | */ |
208 | | static int DecodeVLANtest03 (void) |
209 | | { |
210 | | uint8_t raw_vlan[] = { |
211 | | 0x00, 0x20, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, |
212 | | 0x3b, 0x36, 0x40, 0x00, 0x40, 0x06, 0xb7, 0xc9, |
213 | | 0x83, 0x97, 0x20, 0x81, 0x83, 0x97, 0x20, 0x15, |
214 | | 0x04, 0x8a, 0x17, 0x70, 0x4e, 0x14, 0xdf, 0x55, |
215 | | 0x4d, 0x3d, 0x5a, 0x61, 0x80, 0x10, 0x6b, 0x50, |
216 | | 0x3c, 0x4c, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, |
217 | | 0x00, 0x04, 0xf0, 0xc8, 0x01, 0x99, 0xa3, 0xf3}; |
218 | | Packet *p = PacketGetFromAlloc(); |
219 | | if (unlikely(p == NULL)) |
220 | | return 0; |
221 | | ThreadVars tv; |
222 | | DecodeThreadVars dtv; |
223 | | |
224 | | memset(&tv, 0, sizeof(ThreadVars)); |
225 | | memset(&dtv, 0, sizeof(DecodeThreadVars)); |
226 | | |
227 | | FlowInitConfig(FLOW_QUIET); |
228 | | |
229 | | DecodeVLAN(&tv, &dtv, p, raw_vlan, sizeof(raw_vlan)); |
230 | | |
231 | | |
232 | | if(p->vlan_id[0] == 0) { |
233 | | goto error; |
234 | | } |
235 | | |
236 | | if(ENGINE_ISSET_EVENT(p,VLAN_HEADER_TOO_SMALL)) { |
237 | | goto error; |
238 | | } |
239 | | |
240 | | if(ENGINE_ISSET_EVENT(p,VLAN_UNKNOWN_TYPE)) { |
241 | | goto error; |
242 | | } |
243 | | |
244 | | PacketRecycle(p); |
245 | | FlowShutdown(); |
246 | | SCFree(p); |
247 | | return 1; |
248 | | |
249 | | error: |
250 | | PacketRecycle(p); |
251 | | FlowShutdown(); |
252 | | SCFree(p); |
253 | | return 0; |
254 | | } |
255 | | #endif /* UNITTESTS */ |
256 | | |
257 | | void DecodeVLANRegisterTests(void) |
258 | 0 | { |
259 | | #ifdef UNITTESTS |
260 | | UtRegisterTest("DecodeVLANtest01", DecodeVLANtest01); |
261 | | UtRegisterTest("DecodeVLANtest02", DecodeVLANtest02); |
262 | | UtRegisterTest("DecodeVLANtest03", DecodeVLANtest03); |
263 | | #endif /* UNITTESTS */ |
264 | 0 | } |
265 | | |
266 | | /** |
267 | | * @} |
268 | | */ |