suricata
decode-nsh.c
Go to the documentation of this file.
1/* Copyright (C) 2020-2021 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 * \file
26 *
27 * \author Carl Smith <carl.smith@alliedtelesis.co.nz>
28 *
29 * Decodes Network Service Header (NSH)
30 */
31
32#include "suricata-common.h"
33#include "suricata.h"
34#include "decode.h"
35#include "decode-events.h"
36#include "decode-nsh.h"
37
38#include "util-validate.h"
39#include "util-unittest.h"
40#include "util-debug.h"
41
42/**
43 * \brief Function to decode NSH packets
44 */
45
46int DecodeNSH(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
47{
48 DEBUG_VALIDATE_BUG_ON(pkt == NULL);
49
51
52 /* Check minimum header size */
53 if (len < sizeof(NshHdr)) {
55 return TM_ECODE_FAILED;
56 }
57 if (!PacketIncreaseCheckLayers(p)) {
58 return TM_ECODE_FAILED;
59 }
60
61 /* Sanity check the header version */
62 const NshHdr *hdr = (const NshHdr *)pkt;
63 uint16_t version = SCNtohs(hdr->ver_flags_len) >> 14;
64 if (version != 0) {
66 return TM_ECODE_OK;
67 }
68
69 /* Should always be some data after the header */
70 uint16_t length = (SCNtohs(hdr->ver_flags_len) & 0x003f) * 4;
71 if (length >= len) {
73 return TM_ECODE_FAILED;
74 }
75
76 /* Check for valid MD types */
77 uint8_t md_type = hdr->md_type;
78 if (md_type == 0 || md_type == 0xF) {
79 /* We should silently ignore these packets */
81 return TM_ECODE_OK;
82 } else if (md_type == 1) {
83 /* Fixed header length format */
84 if (length != 24) {
86 return TM_ECODE_FAILED;
87 }
88 } else if (md_type != 2) {
89 /* Not variable header length either */
91 return TM_ECODE_OK;
92 }
93
94 /* Now we can safely read the rest of the header */
95 uint8_t next_protocol = hdr->next_protocol;
96#ifdef DEBUG
97 if (SCLogDebugEnabled()) {
98 uint32_t spi_si = SCNtohl(hdr->spi_si);
99 uint32_t spi = ((spi_si & 0xFFFFFF00) >> 8);
100 uint8_t si = (uint8_t)(spi_si & 0xFF);
101 SCLogDebug("NSH: version %u length %u spi %u si %u next_protocol %u", version, length, spi,
102 si, next_protocol);
103 }
104#endif /* DEBUG */
105
106 /* Try to decode the payload */
107 switch (next_protocol) {
109 if (len - length > USHRT_MAX) {
110 return TM_ECODE_FAILED;
111 }
112 return DecodeIPV4(tv, dtv, p, pkt + length, (uint16_t)(len - length));
114 if (len - length > USHRT_MAX) {
115 return TM_ECODE_FAILED;
116 }
117 return DecodeIPV6(tv, dtv, p, pkt + length, (uint16_t)(len - length));
119 return DecodeEthernet(tv, dtv, p, pkt + length, len - length);
121 return DecodeMPLS(tv, dtv, p, pkt + length, len - length);
123 default:
124 SCLogDebug("NSH next protocol %u not supported", next_protocol);
126 break;
127 }
128 return TM_ECODE_OK;
129}
130
131#ifdef UNITTESTS
132
133static uint8_t valid_nsh_packet[] = { 0x00, 0x04, 0x02, 0x01, 0x00, 0x00, 0x02, 0x02, 0x45, 0x10,
134 0x00, 0x3c, 0x78, 0x8f, 0x40, 0x00, 0x3f, 0x06, 0x79, 0x05, 0x0b, 0x06, 0x06, 0x06, 0x33, 0x06,
135 0x06, 0x06, 0xbd, 0x2e, 0x00, 0x16, 0xc9, 0xee, 0x07, 0x62, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02,
136 0x16, 0xd0, 0x2f, 0x36, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0xa9, 0x5f,
137 0x7f, 0xed, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07 };
138
139static int DecodeNSHTestHeaderTooSmall(void)
140{
143 Packet *p;
144
145 p = PacketGetFromAlloc();
146 FAIL_IF_NULL(p);
147 memset(&dtv, 0, sizeof(DecodeThreadVars));
148 memset(&tv, 0, sizeof(ThreadVars));
149
150 /* A packet that is too small to have a complete NSH header */
151 DecodeNSH(&tv, &dtv, p, valid_nsh_packet, 7);
153
154 SCFree(p);
155 PASS;
156}
157
158static int DecodeNSHTestUnsupportedVersion(void)
159{
162 Packet *p;
163
164 p = PacketGetFromAlloc();
165 FAIL_IF_NULL(p);
166 memset(&dtv, 0, sizeof(DecodeThreadVars));
167 memset(&tv, 0, sizeof(ThreadVars));
168
169 /* Non-zero version field */
170 valid_nsh_packet[0] = 0xFF;
171 DecodeNSH(&tv, &dtv, p, valid_nsh_packet, sizeof(valid_nsh_packet));
172 valid_nsh_packet[0] = 0x00;
174
175 SCFree(p);
176 PASS;
177}
178
179static int DecodeNSHTestPacketTooSmall(void)
180{
183 Packet *p;
184
185 p = PacketGetFromAlloc();
186 FAIL_IF_NULL(p);
187 memset(&dtv, 0, sizeof(DecodeThreadVars));
188 memset(&tv, 0, sizeof(ThreadVars));
189
190 /* A packet that has no payload */
191 DecodeNSH(&tv, &dtv, p, valid_nsh_packet, 8);
193
194 SCFree(p);
195 PASS;
196}
197
198static int DecodeNSHTestReservedType(void)
199{
202 Packet *p;
203
204 p = PacketGetFromAlloc();
205 FAIL_IF_NULL(p);
206 memset(&dtv, 0, sizeof(DecodeThreadVars));
207 memset(&tv, 0, sizeof(ThreadVars));
208
209 /* Reserved type */
210 valid_nsh_packet[2] = 0x00;
211 DecodeNSH(&tv, &dtv, p, valid_nsh_packet, sizeof(valid_nsh_packet));
212 valid_nsh_packet[2] = 0x02;
214
215 SCFree(p);
216 PASS;
217}
218
219static int DecodeNSHTestInvalidType(void)
220{
223 Packet *p;
224
225 p = PacketGetFromAlloc();
226 FAIL_IF_NULL(p);
227 memset(&dtv, 0, sizeof(DecodeThreadVars));
228 memset(&tv, 0, sizeof(ThreadVars));
229
230 /* Type length mismatch */
231 valid_nsh_packet[2] = 0x01;
232 DecodeNSH(&tv, &dtv, p, valid_nsh_packet, sizeof(valid_nsh_packet));
233 valid_nsh_packet[2] = 0x02;
235 SCFree(p);
236 PASS;
237}
238
239static int DecodeNSHTestUnsupportedType(void)
240{
243 Packet *p;
244
245 p = PacketGetFromAlloc();
246 FAIL_IF_NULL(p);
247 memset(&dtv, 0, sizeof(DecodeThreadVars));
248 memset(&tv, 0, sizeof(ThreadVars));
249
250 /* Unsupported type */
251 valid_nsh_packet[2] = 0x03;
252 DecodeNSH(&tv, &dtv, p, valid_nsh_packet, sizeof(valid_nsh_packet));
253 valid_nsh_packet[2] = 0x02;
255
256 SCFree(p);
257 PASS;
258}
259
260static int DecodeNSHTestUnknownPayload(void)
261{
264 Packet *p;
265
266 p = PacketGetFromAlloc();
267 FAIL_IF_NULL(p);
268 memset(&dtv, 0, sizeof(DecodeThreadVars));
269 memset(&tv, 0, sizeof(ThreadVars));
270
271 /* Unknown type */
272 valid_nsh_packet[3] = 0x99;
273 DecodeNSH(&tv, &dtv, p, valid_nsh_packet, sizeof(valid_nsh_packet));
274 valid_nsh_packet[3] = 0x01;
276
277 SCFree(p);
278 PASS;
279}
280
281#endif /* UNITTESTS */
282
284{
285#ifdef UNITTESTS
286 UtRegisterTest("DecodeNSHTestHeaderTooSmall", DecodeNSHTestHeaderTooSmall);
287 UtRegisterTest("DecodeNSHTestUnsupportedVersion", DecodeNSHTestUnsupportedVersion);
288 UtRegisterTest("DecodeNSHTestPacketTooSmall", DecodeNSHTestPacketTooSmall);
289 UtRegisterTest("DecodeNSHTestReservedType", DecodeNSHTestReservedType);
290 UtRegisterTest("DecodeNSHTestInvalidType", DecodeNSHTestInvalidType);
291 UtRegisterTest("DecodeNSHTestUnsupportedType", DecodeNSHTestUnsupportedType);
292 UtRegisterTest("DecodeNSHTestUnknownPayload", DecodeNSHTestUnknownPayload);
293#endif /* UNITTESTS */
294}
uint8_t len
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition counters.c:166
uint32_t spi
Definition decode-esp.h:0
int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
@ NSH_BAD_HEADER_LENGTH
@ NSH_RESERVED_TYPE
@ NSH_HEADER_TOO_SMALL
@ NSH_UNSUPPORTED_VERSION
@ NSH_UNKNOWN_PAYLOAD
@ NSH_UNSUPPORTED_TYPE
uint8_t version
Definition decode-gre.h:1
int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition decode-mpls.c:49
int DecodeNSH(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Function to decode NSH packets.
Definition decode-nsh.c:46
void DecodeNSHRegisterTests(void)
Definition decode-nsh.c:283
uint32_t spi_si
Definition decode-nsh.h:3
#define NSH_NEXT_PROTO_MPLS
Definition decode-nsh.h:33
#define NSH_NEXT_PROTO_ETHERNET
Definition decode-nsh.h:31
#define NSH_NEXT_PROTO_IPV6
Definition decode-nsh.h:30
#define NSH_NEXT_PROTO_IPV4
Definition decode-nsh.h:29
uint8_t next_protocol
Definition decode-nsh.h:2
uint8_t md_type
Definition decode-nsh.h:1
#define NSH_NEXT_PROTO_NSH
Definition decode-nsh.h:32
#define ENGINE_SET_INVALID_EVENT(p, e)
Definition decode.h:1194
#define ENGINE_ISSET_EVENT(p, e)
Definition decode.h:1199
#define ENGINE_SET_EVENT(p, e)
Definition decode.h:1186
DecodeThreadVars * dtv
ThreadVars * tv
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
#define PASS
Pass the test.
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition decode.c:258
Structure to hold thread specific data for all decode modules.
Definition decode.h:963
uint16_t counter_nsh
Definition decode.h:1015
Per thread variable structure.
Definition threadvars.h:58
#define SCNtohs(x)
#define SCNtohl(x)
@ TM_ECODE_FAILED
@ TM_ECODE_OK
int SCLogDebugEnabled(void)
Returns whether debug messages are enabled to be logged or not.
Definition util-debug.c:767
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCFree(p)
Definition util-mem.h:61
#define DEBUG_VALIDATE_BUG_ON(exp)