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 
46 int 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) {
108  case NSH_NEXT_PROTO_IPV4:
109  return DecodeIPV4(tv, dtv, p, pkt + length, len - length);
110  case NSH_NEXT_PROTO_IPV6:
111  return DecodeIPV6(tv, dtv, p, pkt + length, len - length);
113  return DecodeEthernet(tv, dtv, p, pkt + length, len - length);
114  case NSH_NEXT_PROTO_MPLS:
115  return DecodeMPLS(tv, dtv, p, pkt + length, len - length);
116  case NSH_NEXT_PROTO_NSH:
117  default:
118  SCLogDebug("NSH next protocol %u not supported", next_protocol);
120  break;
121  }
122  return TM_ECODE_OK;
123 }
124 
125 #ifdef UNITTESTS
126 
127 static uint8_t valid_nsh_packet[] = { 0x00, 0x04, 0x02, 0x01, 0x00, 0x00, 0x02, 0x02, 0x45, 0x10,
128  0x00, 0x3c, 0x78, 0x8f, 0x40, 0x00, 0x3f, 0x06, 0x79, 0x05, 0x0b, 0x06, 0x06, 0x06, 0x33, 0x06,
129  0x06, 0x06, 0xbd, 0x2e, 0x00, 0x16, 0xc9, 0xee, 0x07, 0x62, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02,
130  0x16, 0xd0, 0x2f, 0x36, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0xa9, 0x5f,
131  0x7f, 0xed, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07 };
132 
133 static int DecodeNSHTestHeaderTooSmall(void)
134 {
135  ThreadVars tv;
137  Packet *p;
138 
140  FAIL_IF_NULL(p);
141  memset(&dtv, 0, sizeof(DecodeThreadVars));
142  memset(&tv, 0, sizeof(ThreadVars));
143  memset(p, 0, SIZE_OF_PACKET);
144 
145  /* A packet that is too small to have a complete NSH header */
146  DecodeNSH(&tv, &dtv, p, valid_nsh_packet, 7);
148 
149  SCFree(p);
150  PASS;
151 }
152 
153 static int DecodeNSHTestUnsupportedVersion(void)
154 {
155  ThreadVars tv;
157  Packet *p;
158 
160  FAIL_IF_NULL(p);
161  memset(&dtv, 0, sizeof(DecodeThreadVars));
162  memset(&tv, 0, sizeof(ThreadVars));
163  memset(p, 0, SIZE_OF_PACKET);
164 
165  /* Non-zero version field */
166  valid_nsh_packet[0] = 0xFF;
167  DecodeNSH(&tv, &dtv, p, valid_nsh_packet, sizeof(valid_nsh_packet));
168  valid_nsh_packet[0] = 0x00;
170 
171  SCFree(p);
172  PASS;
173 }
174 
175 static int DecodeNSHTestPacketTooSmall(void)
176 {
177  ThreadVars tv;
179  Packet *p;
180 
182  FAIL_IF_NULL(p);
183  memset(&dtv, 0, sizeof(DecodeThreadVars));
184  memset(&tv, 0, sizeof(ThreadVars));
185  memset(p, 0, SIZE_OF_PACKET);
186 
187  /* A packet that has no payload */
188  DecodeNSH(&tv, &dtv, p, valid_nsh_packet, 8);
190 
191  SCFree(p);
192  PASS;
193 }
194 
195 static int DecodeNSHTestReservedType(void)
196 {
197  ThreadVars tv;
199  Packet *p;
200 
202  FAIL_IF_NULL(p);
203  memset(&dtv, 0, sizeof(DecodeThreadVars));
204  memset(&tv, 0, sizeof(ThreadVars));
205  memset(p, 0, SIZE_OF_PACKET);
206 
207  /* Reserved type */
208  valid_nsh_packet[2] = 0x00;
209  DecodeNSH(&tv, &dtv, p, valid_nsh_packet, sizeof(valid_nsh_packet));
210  valid_nsh_packet[2] = 0x02;
212 
213  SCFree(p);
214  PASS;
215 }
216 
217 static int DecodeNSHTestInvalidType(void)
218 {
219  ThreadVars tv;
221  Packet *p;
222 
224  FAIL_IF_NULL(p);
225  memset(&dtv, 0, sizeof(DecodeThreadVars));
226  memset(&tv, 0, sizeof(ThreadVars));
227  memset(p, 0, SIZE_OF_PACKET);
228 
229  /* Type length mismatch */
230  valid_nsh_packet[2] = 0x01;
231  DecodeNSH(&tv, &dtv, p, valid_nsh_packet, sizeof(valid_nsh_packet));
232  valid_nsh_packet[2] = 0x02;
234  SCFree(p);
235  PASS;
236 }
237 
238 static int DecodeNSHTestUnsupportedType(void)
239 {
240  ThreadVars tv;
242  Packet *p;
243 
245  FAIL_IF_NULL(p);
246  memset(&dtv, 0, sizeof(DecodeThreadVars));
247  memset(&tv, 0, sizeof(ThreadVars));
248  memset(p, 0, SIZE_OF_PACKET);
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 
260 static int DecodeNSHTestUnknownPayload(void)
261 {
262  ThreadVars tv;
264  Packet *p;
265 
267  FAIL_IF_NULL(p);
268  memset(&dtv, 0, sizeof(DecodeThreadVars));
269  memset(&tv, 0, sizeof(ThreadVars));
270  memset(p, 0, SIZE_OF_PACKET);
271 
272  /* Unknown type */
273  valid_nsh_packet[3] = 0x99;
274  DecodeNSH(&tv, &dtv, p, valid_nsh_packet, sizeof(valid_nsh_packet));
275  valid_nsh_packet[3] = 0x01;
277 
278  SCFree(p);
279  PASS;
280 }
281 
282 #endif /* UNITTESTS */
283 
285 {
286 #ifdef UNITTESTS
287  UtRegisterTest("DecodeNSHTestHeaderTooSmall", DecodeNSHTestHeaderTooSmall);
288  UtRegisterTest("DecodeNSHTestUnsupportedVersion", DecodeNSHTestUnsupportedVersion);
289  UtRegisterTest("DecodeNSHTestPacketTooSmall", DecodeNSHTestPacketTooSmall);
290  UtRegisterTest("DecodeNSHTestReservedType", DecodeNSHTestReservedType);
291  UtRegisterTest("DecodeNSHTestInvalidType", DecodeNSHTestInvalidType);
292  UtRegisterTest("DecodeNSHTestUnsupportedType", DecodeNSHTestUnsupportedType);
293  UtRegisterTest("DecodeNSHTestUnknownPayload", DecodeNSHTestUnknownPayload);
294 #endif /* UNITTESTS */
295 }
ENGINE_SET_EVENT
#define ENGINE_SET_EVENT(p, e)
Definition: decode.h:1036
len
uint8_t len
Definition: app-layer-dnp3.h:2
FAIL_IF_NULL
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
NSH_NEXT_PROTO_ETHERNET
#define NSH_NEXT_PROTO_ETHERNET
Definition: decode-nsh.h:34
StatsIncr
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition: counters.c:169
DecodeNSH
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
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
ENGINE_ISSET_EVENT
#define ENGINE_ISSET_EVENT(p, e)
Definition: decode.h:1051
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
NSH_BAD_HEADER_LENGTH
@ NSH_BAD_HEADER_LENGTH
Definition: decode-events.h:214
NSH_UNSUPPORTED_VERSION
@ NSH_UNSUPPORTED_VERSION
Definition: decode-events.h:213
DecodeNSHRegisterTests
void DecodeNSHRegisterTests(void)
Definition: decode-nsh.c:284
NSH_NEXT_PROTO_IPV4
#define NSH_NEXT_PROTO_IPV4
Definition: decode-nsh.h:32
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:81
util-unittest.h
FAIL_IF_NOT
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:82
NSH_UNSUPPORTED_TYPE
@ NSH_UNSUPPORTED_TYPE
Definition: decode-events.h:216
TM_ECODE_OK
@ TM_ECODE_OK
Definition: tm-threads-common.h:80
decode.h
util-debug.h
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
spi
uint32_t spi
Definition: decode-esp.h:0
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
NSH_UNKNOWN_PAYLOAD
@ NSH_UNKNOWN_PAYLOAD
Definition: decode-events.h:217
DecodeMPLS
int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-mpls.c:49
SIZE_OF_PACKET
#define SIZE_OF_PACKET
Definition: decode.h:634
Packet_
Definition: decode.h:414
DecodeThreadVars_::counter_nsh
uint16_t counter_nsh
Definition: decode.h:680
DecodeIPV6
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
Definition: decode-ipv6.c:570
next_protocol
uint8_t next_protocol
Definition: decode-nsh.h:2
NSH_HEADER_TOO_SMALL
@ NSH_HEADER_TOO_SMALL
Definition: decode-events.h:212
decode-nsh.h
decode-events.h
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:30
SCNtohs
#define SCNtohs(x)
Definition: suricata-common.h:395
suricata-common.h
version
uint8_t version
Definition: decode-gre.h:1
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:29
util-validate.h
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
NSH_NEXT_PROTO_NSH
#define NSH_NEXT_PROTO_NSH
Definition: decode-nsh.h:35
md_type
uint8_t md_type
Definition: decode-nsh.h:1
SCFree
#define SCFree(p)
Definition: util-mem.h:61
SCNtohl
#define SCNtohl(x)
Definition: suricata-common.h:394
DecodeThreadVars_
Structure to hold thread specific data for all decode modules.
Definition: decode.h:638
NSH_NEXT_PROTO_IPV6
#define NSH_NEXT_PROTO_IPV6
Definition: decode-nsh.h:33
suricata.h
ENGINE_SET_INVALID_EVENT
#define ENGINE_SET_INVALID_EVENT(p, e)
Definition: decode.h:1044
NSH_NEXT_PROTO_MPLS
#define NSH_NEXT_PROTO_MPLS
Definition: decode-nsh.h:36
spi_si
uint32_t spi_si
Definition: decode-nsh.h:3
DecodeIPV4
int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
Definition: decode-ipv4.c:517
NSH_RESERVED_TYPE
@ NSH_RESERVED_TYPE
Definition: decode-events.h:215
SCLogDebugEnabled
int SCLogDebugEnabled(void)
Returns whether debug messages are enabled to be logged or not.
Definition: util-debug.c:656
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:111
DecodeEthernet
int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-ethernet.c:42