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 
55  /* Sanity check the header version */
56  const NshHdr *hdr = (const NshHdr *)pkt;
57  uint16_t version = SCNtohs(hdr->ver_flags_len) >> 14;
58  if (version != 0) {
60  return TM_ECODE_OK;
61  }
62 
63  /* Should always be some data after the header */
64  uint16_t length = (SCNtohs(hdr->ver_flags_len) & 0x003f) * 4;
65  if (length >= len) {
67  return TM_ECODE_FAILED;
68  }
69 
70  /* Check for valid MD types */
71  uint8_t md_type = hdr->md_type;
72  if (md_type == 0 || md_type == 0xF) {
73  /* We should silently ignore these packets */
75  return TM_ECODE_OK;
76  } else if (md_type == 1) {
77  /* Fixed header length format */
78  if (length != 24) {
80  return TM_ECODE_FAILED;
81  }
82  } else if (md_type != 2) {
83  /* Not variable header length either */
85  return TM_ECODE_OK;
86  }
87 
88  /* Now we can safely read the rest of the header */
89  uint8_t next_protocol = hdr->next_protocol;
90 #ifdef DEBUG
91  if (SCLogDebugEnabled()) {
92  uint32_t spi_si = SCNtohl(hdr->spi_si);
93  uint32_t spi = ((spi_si & 0xFFFFFF00) >> 8);
94  uint8_t si = (uint8_t)(spi_si & 0xFF);
95  SCLogDebug("NSH: version %u length %u spi %u si %u next_protocol %u", version, length, spi,
96  si, next_protocol);
97  }
98 #endif /* DEBUG */
99 
100  /* Try to decode the payload */
101  switch (next_protocol) {
102  case NSH_NEXT_PROTO_IPV4:
103  return DecodeIPV4(tv, dtv, p, pkt + length, len - length);
104  case NSH_NEXT_PROTO_IPV6:
105  return DecodeIPV6(tv, dtv, p, pkt + length, len - length);
107  return DecodeEthernet(tv, dtv, p, pkt + length, len - length);
108  case NSH_NEXT_PROTO_MPLS:
109  return DecodeMPLS(tv, dtv, p, pkt + length, len - length);
110  case NSH_NEXT_PROTO_NSH:
111  default:
112  SCLogDebug("NSH next protocol %u not supported", next_protocol);
114  break;
115  }
116  return TM_ECODE_OK;
117 }
118 
119 #ifdef UNITTESTS
120 
121 static uint8_t valid_nsh_packet[] = { 0x00, 0x04, 0x02, 0x01, 0x00, 0x00, 0x02, 0x02, 0x45, 0x10,
122  0x00, 0x3c, 0x78, 0x8f, 0x40, 0x00, 0x3f, 0x06, 0x79, 0x05, 0x0b, 0x06, 0x06, 0x06, 0x33, 0x06,
123  0x06, 0x06, 0xbd, 0x2e, 0x00, 0x16, 0xc9, 0xee, 0x07, 0x62, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02,
124  0x16, 0xd0, 0x2f, 0x36, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0xa9, 0x5f,
125  0x7f, 0xed, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07 };
126 
127 static int DecodeNSHTestHeaderTooSmall(void)
128 {
129  ThreadVars tv;
131  Packet *p;
132 
134  FAIL_IF_NULL(p);
135  memset(&dtv, 0, sizeof(DecodeThreadVars));
136  memset(&tv, 0, sizeof(ThreadVars));
137  memset(p, 0, SIZE_OF_PACKET);
138 
139  /* A packet that is too small to have a complete NSH header */
140  DecodeNSH(&tv, &dtv, p, valid_nsh_packet, 7);
142 
143  SCFree(p);
144  PASS;
145 }
146 
147 static int DecodeNSHTestUnsupportedVersion(void)
148 {
149  ThreadVars tv;
151  Packet *p;
152 
154  FAIL_IF_NULL(p);
155  memset(&dtv, 0, sizeof(DecodeThreadVars));
156  memset(&tv, 0, sizeof(ThreadVars));
157  memset(p, 0, SIZE_OF_PACKET);
158 
159  /* Non-zero version field */
160  valid_nsh_packet[0] = 0xFF;
161  DecodeNSH(&tv, &dtv, p, valid_nsh_packet, sizeof(valid_nsh_packet));
162  valid_nsh_packet[0] = 0x00;
164 
165  SCFree(p);
166  PASS;
167 }
168 
169 static int DecodeNSHTestPacketTooSmall(void)
170 {
171  ThreadVars tv;
173  Packet *p;
174 
176  FAIL_IF_NULL(p);
177  memset(&dtv, 0, sizeof(DecodeThreadVars));
178  memset(&tv, 0, sizeof(ThreadVars));
179  memset(p, 0, SIZE_OF_PACKET);
180 
181  /* A packet that has no payload */
182  DecodeNSH(&tv, &dtv, p, valid_nsh_packet, 8);
184 
185  SCFree(p);
186  PASS;
187 }
188 
189 static int DecodeNSHTestReservedType(void)
190 {
191  ThreadVars tv;
193  Packet *p;
194 
196  FAIL_IF_NULL(p);
197  memset(&dtv, 0, sizeof(DecodeThreadVars));
198  memset(&tv, 0, sizeof(ThreadVars));
199  memset(p, 0, SIZE_OF_PACKET);
200 
201  /* Reserved type */
202  valid_nsh_packet[2] = 0x00;
203  DecodeNSH(&tv, &dtv, p, valid_nsh_packet, sizeof(valid_nsh_packet));
204  valid_nsh_packet[2] = 0x02;
206 
207  SCFree(p);
208  PASS;
209 }
210 
211 static int DecodeNSHTestInvalidType(void)
212 {
213  ThreadVars tv;
215  Packet *p;
216 
218  FAIL_IF_NULL(p);
219  memset(&dtv, 0, sizeof(DecodeThreadVars));
220  memset(&tv, 0, sizeof(ThreadVars));
221  memset(p, 0, SIZE_OF_PACKET);
222 
223  /* Type length mismatch */
224  valid_nsh_packet[2] = 0x01;
225  DecodeNSH(&tv, &dtv, p, valid_nsh_packet, sizeof(valid_nsh_packet));
226  valid_nsh_packet[2] = 0x02;
228  SCFree(p);
229  PASS;
230 }
231 
232 static int DecodeNSHTestUnsupportedType(void)
233 {
234  ThreadVars tv;
236  Packet *p;
237 
239  FAIL_IF_NULL(p);
240  memset(&dtv, 0, sizeof(DecodeThreadVars));
241  memset(&tv, 0, sizeof(ThreadVars));
242  memset(p, 0, SIZE_OF_PACKET);
243 
244  /* Unsupported type */
245  valid_nsh_packet[2] = 0x03;
246  DecodeNSH(&tv, &dtv, p, valid_nsh_packet, sizeof(valid_nsh_packet));
247  valid_nsh_packet[2] = 0x02;
249 
250  SCFree(p);
251  PASS;
252 }
253 
254 static int DecodeNSHTestUnknownPayload(void)
255 {
256  ThreadVars tv;
258  Packet *p;
259 
261  FAIL_IF_NULL(p);
262  memset(&dtv, 0, sizeof(DecodeThreadVars));
263  memset(&tv, 0, sizeof(ThreadVars));
264  memset(p, 0, SIZE_OF_PACKET);
265 
266  /* Unknown type */
267  valid_nsh_packet[3] = 0x99;
268  DecodeNSH(&tv, &dtv, p, valid_nsh_packet, sizeof(valid_nsh_packet));
269  valid_nsh_packet[3] = 0x01;
271 
272  SCFree(p);
273  PASS;
274 }
275 
276 #endif /* UNITTESTS */
277 
279 {
280 #ifdef UNITTESTS
281  UtRegisterTest("DecodeNSHTestHeaderTooSmall", DecodeNSHTestHeaderTooSmall);
282  UtRegisterTest("DecodeNSHTestUnsupportedVersion", DecodeNSHTestUnsupportedVersion);
283  UtRegisterTest("DecodeNSHTestPacketTooSmall", DecodeNSHTestPacketTooSmall);
284  UtRegisterTest("DecodeNSHTestReservedType", DecodeNSHTestReservedType);
285  UtRegisterTest("DecodeNSHTestInvalidType", DecodeNSHTestInvalidType);
286  UtRegisterTest("DecodeNSHTestUnsupportedType", DecodeNSHTestUnsupportedType);
287  UtRegisterTest("DecodeNSHTestUnknownPayload", DecodeNSHTestUnknownPayload);
288 #endif /* UNITTESTS */
289 }
ENGINE_SET_EVENT
#define ENGINE_SET_EVENT(p, e)
Definition: decode.h:1007
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:1022
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
DecodeNSHRegisterTests
void DecodeNSHRegisterTests(void)
Definition: decode-nsh.c:278
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
NSH_HEADER_TOO_SMALL
@ NSH_HEADER_TOO_SMALL
Definition: decode-events.h:204
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:628
Packet_
Definition: decode.h:415
DecodeThreadVars_::counter_nsh
uint16_t counter_nsh
Definition: decode.h:672
DecodeIPV6
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
Definition: decode-ipv6.c:580
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:208
NSH_UNSUPPORTED_VERSION
@ NSH_UNSUPPORTED_VERSION
Definition: decode-events.h:205
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:207
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:209
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:632
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:206
suricata.h
ENGINE_SET_INVALID_EVENT
#define ENGINE_SET_INVALID_EVENT(p, e)
Definition: decode.h:1015
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