suricata
decode-nsh.c
Go to the documentation of this file.
1 /* Copyright (C) 2020 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-unittest.h"
39 #include "util-debug.h"
40 
41 /**
42  * \brief Function to decode NSH packets
43  */
44 
45 int DecodeNSH(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
46 {
48 
49  /* Check mimimum header size */
50  if (len < sizeof(NshHdr)) {
52  return TM_ECODE_FAILED;
53  }
54  if (!PacketIncreaseCheckLayers(p)) {
55  return TM_ECODE_FAILED;
56  }
57 
58  /* Sanity check the header version */
59  const NshHdr *hdr = (const NshHdr *)pkt;
60  uint16_t version = SCNtohs(hdr->ver_flags_len) >> 14;
61  if (version != 0) {
63  return TM_ECODE_OK;
64  }
65 
66  /* Should always be some data after the header */
67  uint16_t length = (SCNtohs(hdr->ver_flags_len) & 0x003f) * 4;
68  if (length >= len) {
70  return TM_ECODE_FAILED;
71  }
72 
73  /* Check for valid MD types */
74  uint8_t md_type = hdr->md_type;
75  if (md_type == 0 || md_type == 0xF) {
76  /* We should silently ignore these packets */
78  return TM_ECODE_OK;
79  } else if (md_type == 1) {
80  /* Fixed header length format */
81  if (length != 24) {
83  return TM_ECODE_FAILED;
84  }
85  } else if (md_type != 2) {
86  /* Not variable header length either */
88  return TM_ECODE_OK;
89  }
90 
91  /* Now we can safely read the rest of the header */
92  uint8_t next_protocol = hdr->next_protocol;
93 #ifdef DEBUG
94  if (SCLogDebugEnabled()) {
95  uint32_t spi_si = SCNtohl(hdr->spi_si);
96  uint32_t spi = ((spi_si & 0xFFFFFF00) >> 8);
97  uint8_t si = (uint8_t)(spi_si & 0xFF);
98  SCLogDebug("NSH: version %u length %u spi %u si %u next_protocol %u", version, length, spi,
99  si, next_protocol);
100  }
101 #endif /* DEBUG */
102 
103  /* Try to decode the payload */
104  switch (next_protocol) {
105  case NSH_NEXT_PROTO_IPV4:
106  return DecodeIPV4(tv, dtv, p, pkt + length, len - length);
107  case NSH_NEXT_PROTO_IPV6:
108  return DecodeIPV6(tv, dtv, p, pkt + length, len - length);
110  return DecodeEthernet(tv, dtv, p, pkt + length, len - length);
111  case NSH_NEXT_PROTO_MPLS:
112  return DecodeMPLS(tv, dtv, p, pkt + length, len - length);
113  case NSH_NEXT_PROTO_NSH:
114  default:
115  SCLogDebug("NSH next protocol %u not supported", next_protocol);
117  break;
118  }
119  return TM_ECODE_OK;
120 }
121 
122 #ifdef UNITTESTS
123 
124 static uint8_t valid_nsh_packet[] = { 0x00, 0x04, 0x02, 0x01, 0x00, 0x00, 0x02, 0x02, 0x45, 0x10,
125  0x00, 0x3c, 0x78, 0x8f, 0x40, 0x00, 0x3f, 0x06, 0x79, 0x05, 0x0b, 0x06, 0x06, 0x06, 0x33, 0x06,
126  0x06, 0x06, 0xbd, 0x2e, 0x00, 0x16, 0xc9, 0xee, 0x07, 0x62, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02,
127  0x16, 0xd0, 0x2f, 0x36, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0xa9, 0x5f,
128  0x7f, 0xed, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07 };
129 
130 static int DecodeNSHTestHeaderTooSmall(void)
131 {
132  ThreadVars tv;
134  Packet *p;
135 
137  FAIL_IF_NULL(p);
138  memset(&dtv, 0, sizeof(DecodeThreadVars));
139  memset(&tv, 0, sizeof(ThreadVars));
140  memset(p, 0, SIZE_OF_PACKET);
141 
142  /* A packet that is too small to have a complete NSH header */
143  DecodeNSH(&tv, &dtv, p, valid_nsh_packet, 7);
145 
146  SCFree(p);
147  PASS;
148 }
149 
150 static int DecodeNSHTestUnsupportedVersion(void)
151 {
152  ThreadVars tv;
154  Packet *p;
155 
157  FAIL_IF_NULL(p);
158  memset(&dtv, 0, sizeof(DecodeThreadVars));
159  memset(&tv, 0, sizeof(ThreadVars));
160  memset(p, 0, SIZE_OF_PACKET);
161 
162  /* Non-zero version field */
163  valid_nsh_packet[0] = 0xFF;
164  DecodeNSH(&tv, &dtv, p, valid_nsh_packet, sizeof(valid_nsh_packet));
165  valid_nsh_packet[0] = 0x00;
167 
168  SCFree(p);
169  PASS;
170 }
171 
172 static int DecodeNSHTestPacketTooSmall(void)
173 {
174  ThreadVars tv;
176  Packet *p;
177 
179  FAIL_IF_NULL(p);
180  memset(&dtv, 0, sizeof(DecodeThreadVars));
181  memset(&tv, 0, sizeof(ThreadVars));
182  memset(p, 0, SIZE_OF_PACKET);
183 
184  /* A packet that has no payload */
185  DecodeNSH(&tv, &dtv, p, valid_nsh_packet, 8);
187 
188  SCFree(p);
189  PASS;
190 }
191 
192 static int DecodeNSHTestReservedType(void)
193 {
194  ThreadVars tv;
196  Packet *p;
197 
199  FAIL_IF_NULL(p);
200  memset(&dtv, 0, sizeof(DecodeThreadVars));
201  memset(&tv, 0, sizeof(ThreadVars));
202  memset(p, 0, SIZE_OF_PACKET);
203 
204  /* Reserved type */
205  valid_nsh_packet[2] = 0x00;
206  DecodeNSH(&tv, &dtv, p, valid_nsh_packet, sizeof(valid_nsh_packet));
207  valid_nsh_packet[2] = 0x02;
209 
210  SCFree(p);
211  PASS;
212 }
213 
214 static int DecodeNSHTestInvalidType(void)
215 {
216  ThreadVars tv;
218  Packet *p;
219 
221  FAIL_IF_NULL(p);
222  memset(&dtv, 0, sizeof(DecodeThreadVars));
223  memset(&tv, 0, sizeof(ThreadVars));
224  memset(p, 0, SIZE_OF_PACKET);
225 
226  /* Type length mismatch */
227  valid_nsh_packet[2] = 0x01;
228  DecodeNSH(&tv, &dtv, p, valid_nsh_packet, sizeof(valid_nsh_packet));
229  valid_nsh_packet[2] = 0x02;
231  SCFree(p);
232  PASS;
233 }
234 
235 static int DecodeNSHTestUnsupportedType(void)
236 {
237  ThreadVars tv;
239  Packet *p;
240 
242  FAIL_IF_NULL(p);
243  memset(&dtv, 0, sizeof(DecodeThreadVars));
244  memset(&tv, 0, sizeof(ThreadVars));
245  memset(p, 0, SIZE_OF_PACKET);
246 
247  /* Unsupported type */
248  valid_nsh_packet[2] = 0x03;
249  DecodeNSH(&tv, &dtv, p, valid_nsh_packet, sizeof(valid_nsh_packet));
250  valid_nsh_packet[2] = 0x02;
252 
253  SCFree(p);
254  PASS;
255 }
256 
257 static int DecodeNSHTestUnknownPayload(void)
258 {
259  ThreadVars tv;
261  Packet *p;
262 
264  FAIL_IF_NULL(p);
265  memset(&dtv, 0, sizeof(DecodeThreadVars));
266  memset(&tv, 0, sizeof(ThreadVars));
267  memset(p, 0, SIZE_OF_PACKET);
268 
269  /* Unknown type */
270  valid_nsh_packet[3] = 0x99;
271  DecodeNSH(&tv, &dtv, p, valid_nsh_packet, sizeof(valid_nsh_packet));
272  valid_nsh_packet[3] = 0x01;
274 
275  SCFree(p);
276  PASS;
277 }
278 
279 #endif /* UNITTESTS */
280 
282 {
283 #ifdef UNITTESTS
284  UtRegisterTest("DecodeNSHTestHeaderTooSmall", DecodeNSHTestHeaderTooSmall);
285  UtRegisterTest("DecodeNSHTestUnsupportedVersion", DecodeNSHTestUnsupportedVersion);
286  UtRegisterTest("DecodeNSHTestPacketTooSmall", DecodeNSHTestPacketTooSmall);
287  UtRegisterTest("DecodeNSHTestReservedType", DecodeNSHTestReservedType);
288  UtRegisterTest("DecodeNSHTestInvalidType", DecodeNSHTestInvalidType);
289  UtRegisterTest("DecodeNSHTestUnsupportedType", DecodeNSHTestUnsupportedType);
290  UtRegisterTest("DecodeNSHTestUnknownPayload", DecodeNSHTestUnknownPayload);
291 #endif /* UNITTESTS */
292 }
ENGINE_SET_EVENT
#define ENGINE_SET_EVENT(p, e)
Definition: decode.h:1020
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:45
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:1035
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
DecodeNSHRegisterTests
void DecodeNSHRegisterTests(void)
Definition: decode-nsh.c:281
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 to true.
Definition: util-unittest.h:82
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
NSH_HEADER_TOO_SMALL
@ NSH_HEADER_TOO_SMALL
Definition: decode-events.h:207
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
DecodeMPLS
int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-mpls.c:47
SIZE_OF_PACKET
#define SIZE_OF_PACKET
Definition: decode.h:635
Packet_
Definition: decode.h:415
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:564
next_protocol
uint8_t next_protocol
Definition: decode-nsh.h:2
decode-nsh.h
decode-events.h
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:30
length
uint16_t length
Definition: app-layer-modbus.c:2
SCNtohs
#define SCNtohs(x)
Definition: suricata-common.h:395
suricata-common.h
NSH_UNSUPPORTED_TYPE
@ NSH_UNSUPPORTED_TYPE
Definition: decode-events.h:211
NSH_UNSUPPORTED_VERSION
@ NSH_UNSUPPORTED_VERSION
Definition: decode-events.h:208
version
uint8_t version
Definition: decode-gre.h:1
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:29
NSH_RESERVED_TYPE
@ NSH_RESERVED_TYPE
Definition: decode-events.h:210
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
NSH_UNKNOWN_PAYLOAD
@ NSH_UNKNOWN_PAYLOAD
Definition: decode-events.h:212
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:639
NSH_NEXT_PROTO_IPV6
#define NSH_NEXT_PROTO_IPV6
Definition: decode-nsh.h:33
NSH_BAD_HEADER_LENGTH
@ NSH_BAD_HEADER_LENGTH
Definition: decode-events.h:209
suricata.h
ENGINE_SET_INVALID_EVENT
#define ENGINE_SET_INVALID_EVENT(p, e)
Definition: decode.h:1028
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
SCLogDebugEnabled
int SCLogDebugEnabled(void)
Returns whether debug messages are enabled to be logged or not.
Definition: util-debug.c:662
DecodeEthernet
int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-ethernet.c:41