suricata
detect-ttl.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-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  * \file
20  *
21  * \author Gurvinder Singh <gurvindersighdahiya@gmail.com>
22  * \author Victor Julien <victor@inliniac.net>
23  *
24  * Implements the ttl keyword including prefilter support.
25  */
26 
27 #include "suricata-common.h"
28 #include "stream-tcp.h"
29 
30 #include "detect.h"
31 #include "detect-parse.h"
33 
34 #include "detect-ttl.h"
35 #include "util-debug.h"
36 #include "util-byte.h"
37 
38 /**
39  * \brief Regex for parsing our ttl options
40  */
41 #define PARSE_REGEX "^\\s*([0-9]*)?\\s*([<>=-]+)?\\s*([0-9]+)?\\s*$"
42 
43 static DetectParseRegex parse_regex;
44 
45 /* prototypes */
46 static int DetectTtlMatch (DetectEngineThreadCtx *, Packet *,
47  const Signature *, const SigMatchCtx *);
48 static int DetectTtlSetup (DetectEngineCtx *, Signature *, const char *);
49 void DetectTtlFree (DetectEngineCtx *, void *);
50 #ifdef UNITTESTS
51 void DetectTtlRegisterTests (void);
52 #endif
53 static int PrefilterSetupTtl(DetectEngineCtx *de_ctx, SigGroupHead *sgh);
54 static bool PrefilterTtlIsPrefilterable(const Signature *s);
55 
56 /**
57  * \brief Registration function for ttl: keyword
58  */
59 
61 {
63  sigmatch_table[DETECT_TTL].desc = "check for a specific IP time-to-live value";
64  sigmatch_table[DETECT_TTL].url = "/rules/header-keywords.html#ttl";
65  sigmatch_table[DETECT_TTL].Match = DetectTtlMatch;
66  sigmatch_table[DETECT_TTL].Setup = DetectTtlSetup;
68 #ifdef UNITTESTS
70 #endif
71  sigmatch_table[DETECT_TTL].SupportsPrefilter = PrefilterTtlIsPrefilterable;
72  sigmatch_table[DETECT_TTL].SetupPrefilter = PrefilterSetupTtl;
73 
74  DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
75  return;
76 }
77 
78 static inline int TtlMatch(const uint8_t pttl, const uint8_t mode,
79  const uint8_t dttl1, const uint8_t dttl2)
80 {
81  if (mode == DETECT_TTL_EQ && pttl == dttl1)
82  return 1;
83  else if (mode == DETECT_TTL_LT && pttl < dttl1)
84  return 1;
85  else if (mode == DETECT_TTL_GT && pttl > dttl1)
86  return 1;
87  else if (mode == DETECT_TTL_RA && (pttl > dttl1 && pttl < dttl2))
88  return 1;
89 
90  return 0;
91 }
92 
93 /**
94  * \brief This function is used to match TTL rule option on a packet with
95  * those passed via ttl
96  *
97  * \param t pointer to thread vars
98  * \param det_ctx pointer to the pattern matcher thread
99  * \param p pointer to the current packet
100  * \param m pointer to the sigmatch that we will cast into DetectTtlData
101  *
102  * \retval 0 no match
103  * \retval 1 match
104  */
105 static int DetectTtlMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
106  const Signature *s, const SigMatchCtx *ctx)
107 {
108  if (PKT_IS_PSEUDOPKT(p))
109  return 0;
110 
111  uint8_t pttl;
112  if (PKT_IS_IPV4(p)) {
113  pttl = IPV4_GET_IPTTL(p);
114  } else if (PKT_IS_IPV6(p)) {
115  pttl = IPV6_GET_HLIM(p);
116  } else {
117  SCLogDebug("Packet is of not IPv4 or IPv6");
118  return 0;
119  }
120 
121  const DetectTtlData *ttld = (const DetectTtlData *)ctx;
122  return TtlMatch(pttl, ttld->mode, ttld->ttl1, ttld->ttl2);
123 }
124 
125 /**
126  * \brief This function is used to parse ttl options passed via ttl: keyword
127  *
128  * \param ttlstr Pointer to the user provided ttl options
129  *
130  * \retval ttld pointer to DetectTtlData on success
131  * \retval NULL on failure
132  */
133 
134 static DetectTtlData *DetectTtlParse (const char *ttlstr)
135 {
136  size_t pcre2len;
137  char arg1[6] = "";
138  char arg2[6] = "";
139  char arg3[6] = "";
140 
141  int ret = DetectParsePcreExec(&parse_regex, ttlstr, 0, 0);
142  if (ret < 2 || ret > 4) {
143  SCLogError(SC_ERR_PCRE_MATCH, "parse error, ret %" PRId32 "", ret);
144  return NULL;
145  }
146 
147  pcre2len = sizeof(arg1);
148  int res = pcre2_substring_copy_bynumber(parse_regex.match, 1, (PCRE2_UCHAR8 *)arg1, &pcre2len);
149  if (res < 0) {
150  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre2_substring_copy_bynumber failed");
151  return NULL;
152  }
153  SCLogDebug("arg1 \"%s\"", arg1);
154 
155  if (ret >= 3) {
156  pcre2len = sizeof(arg2);
157  res = pcre2_substring_copy_bynumber(parse_regex.match, 2, (PCRE2_UCHAR8 *)arg2, &pcre2len);
158  if (res < 0) {
159  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre2_substring_copy_bynumber failed");
160  return NULL;
161  }
162  SCLogDebug("arg2 \"%s\"", arg2);
163 
164  if (ret >= 4) {
165  pcre2len = sizeof(arg3);
166  res = pcre2_substring_copy_bynumber(
167  parse_regex.match, 3, (PCRE2_UCHAR8 *)arg3, &pcre2len);
168  if (res < 0) {
169  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre2_substring_copy_bynumber failed");
170  return NULL;
171  }
172  SCLogDebug("arg3 \"%s\"", arg3);
173  }
174  }
175 
176  uint8_t ttl1 = 0;
177  uint8_t ttl2 = 0;
178  int mode = 0;
179 
180  if (strlen(arg2) > 0) {
181  switch (arg2[0]) {
182  case '<':
183  if (strlen(arg3) == 0)
184  return NULL;
185 
186  mode = DETECT_TTL_LT;
187  if (StringParseUint8(&ttl1, 10, 0, (const char *)arg3) < 0) {
188  SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid first ttl "
189  "value: \"%s\"", arg3);
190  return NULL;
191  }
192  SCLogDebug("ttl is %d",ttl1);
193  if (strlen(arg1) > 0)
194  return NULL;
195 
196  break;
197  case '>':
198  if (strlen(arg3) == 0)
199  return NULL;
200 
201  mode = DETECT_TTL_GT;
202  if (StringParseUint8(&ttl1, 10, 0, (const char *)arg3) < 0) {
203  SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid first ttl "
204  "value: \"%s\"", arg3);
205  return NULL;
206  }
207  SCLogDebug("ttl is %d",ttl1);
208  if (strlen(arg1) > 0)
209  return NULL;
210 
211  break;
212  case '-':
213  if (strlen(arg1) == 0 || strlen(arg3) == 0)
214  return NULL;
215 
216  mode = DETECT_TTL_RA;
217 
218  if (StringParseUint8(&ttl1, 10, 0, (const char *)arg1) < 0) {
219  SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid first ttl "
220  "value: \"%s\"", arg1);
221  return NULL;
222  }
223  if (StringParseUint8(&ttl2, 10, 0, (const char *)arg3) < 0) {
224  SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid second ttl "
225  "value: \"%s\"", arg3);
226  return NULL;
227  }
228  SCLogDebug("ttl is %d to %d",ttl1, ttl2);
229  if (ttl1 >= ttl2) {
230  SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid ttl range");
231  return NULL;
232  }
233  break;
234  default:
235  mode = DETECT_TTL_EQ;
236 
237  if ((strlen(arg2) > 0) ||
238  (strlen(arg3) > 0) ||
239  (strlen(arg1) == 0))
240  return NULL;
241  if (StringParseUint8(&ttl1, 10, 0, (const char *)arg1) < 0) {
242  SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid first ttl "
243  "value: \"%s\"", arg1);
244  return NULL;
245  }
246  break;
247  }
248  } else {
249  mode = DETECT_TTL_EQ;
250 
251  if ((strlen(arg3) > 0) ||
252  (strlen(arg1) == 0))
253  return NULL;
254  if (StringParseUint8(&ttl1, 10, 0, (const char *)arg1) < 0) {
255  SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid first ttl "
256  "value: \"%s\"", arg1);
257  return NULL;
258  }
259  }
260 
261  DetectTtlData *ttld = SCMalloc(sizeof(DetectTtlData));
262  if (unlikely(ttld == NULL))
263  return NULL;
264  ttld->ttl1 = (uint8_t)ttl1;
265  ttld->ttl2 = (uint8_t)ttl2;
266  ttld->mode = mode;
267 
268  return ttld;
269 }
270 
271 /**
272  * \brief this function is used to attld the parsed ttl data into the current signature
273  *
274  * \param de_ctx pointer to the Detection Engine Context
275  * \param s pointer to the Current Signature
276  * \param ttlstr pointer to the user provided ttl options
277  *
278  * \retval 0 on Success
279  * \retval -1 on Failure
280  */
281 static int DetectTtlSetup (DetectEngineCtx *de_ctx, Signature *s, const char *ttlstr)
282 {
283  DetectTtlData *ttld = DetectTtlParse(ttlstr);
284  if (ttld == NULL)
285  return -1;
286 
287  SigMatch *sm = SigMatchAlloc();
288  if (sm == NULL) {
289  DetectTtlFree(de_ctx, ttld);
290  return -1;
291  }
292 
293  sm->type = DETECT_TTL;
294  sm->ctx = (SigMatchCtx *)ttld;
295 
298  return 0;
299 }
300 
301 /**
302  * \brief this function will free memory associated with DetectTtlData
303  *
304  * \param ptr pointer to DetectTtlData
305  */
307 {
308  DetectTtlData *ttld = (DetectTtlData *)ptr;
309  SCFree(ttld);
310 }
311 
312 /* prefilter code */
313 
314 static void
315 PrefilterPacketTtlMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
316 {
317  if (PKT_IS_PSEUDOPKT(p)) {
318  SCReturn;
319  }
320 
321  uint8_t pttl;
322  if (PKT_IS_IPV4(p)) {
323  pttl = IPV4_GET_IPTTL(p);
324  } else if (PKT_IS_IPV6(p)) {
325  pttl = IPV6_GET_HLIM(p);
326  } else {
327  SCLogDebug("Packet is of not IPv4 or IPv6");
328  return;
329  }
330 
331  const PrefilterPacketHeaderCtx *ctx = pectx;
332  if (!PrefilterPacketHeaderExtraMatch(ctx, p))
333  return;
334 
335  if (TtlMatch(pttl, ctx->v1.u8[0], ctx->v1.u8[1], ctx->v1.u8[2]))
336  {
337  SCLogDebug("packet matches ttl/hl %u", pttl);
338  PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt);
339  }
340 }
341 
342 static void
343 PrefilterPacketTtlSet(PrefilterPacketHeaderValue *v, void *smctx)
344 {
345  const DetectTtlData *a = smctx;
346  v->u8[0] = a->mode;
347  v->u8[1] = a->ttl1;
348  v->u8[2] = a->ttl2;
349 }
350 
351 static bool
352 PrefilterPacketTtlCompare(PrefilterPacketHeaderValue v, void *smctx)
353 {
354  const DetectTtlData *a = smctx;
355  if (v.u8[0] == a->mode &&
356  v.u8[1] == a->ttl1 &&
357  v.u8[2] == a->ttl2)
358  return true;
359  return false;
360 }
361 
362 static int PrefilterSetupTtl(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
363 {
365  PrefilterPacketTtlSet,
366  PrefilterPacketTtlCompare,
367  PrefilterPacketTtlMatch);
368 }
369 
370 static bool PrefilterTtlIsPrefilterable(const Signature *s)
371 {
372  const SigMatch *sm;
373  for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) {
374  switch (sm->type) {
375  case DETECT_TTL:
376  return true;
377  }
378  }
379  return false;
380 }
381 
382 #ifdef UNITTESTS
383 #include "tests/detect-ttl.c"
384 #endif
util-byte.h
DetectParseRegex::match
pcre2_match_data * match
Definition: detect-parse.h:45
SigTableElmt_::url
const char * url
Definition: detect.h:1270
DETECT_TTL
@ DETECT_TTL
Definition: detect-engine-register.h:43
SigTableElmt_::desc
const char * desc
Definition: detect.h:1269
DetectParsePcreExec
int DetectParsePcreExec(DetectParseRegex *parse_regex, const char *str, int start_offset, int options)
Definition: detect-parse.c:2474
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1257
DetectParseRegex
Definition: detect-parse.h:42
SigTableElmt_::name
const char * name
Definition: detect.h:1267
PKT_IS_PSEUDOPKT
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition: decode.h:1224
PKT_IS_IPV6
#define PKT_IS_IPV6(p)
Definition: decode.h:263
stream-tcp.h
SigGroupHead_
Container for matching data for a signature group.
Definition: detect.h:1425
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
DetectEngineThreadCtx_::pmq
PrefilterRuleStore pmq
Definition: detect.h:1167
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:811
SC_ERR_INVALID_SIGNATURE
@ SC_ERR_INVALID_SIGNATURE
Definition: util-error.h:69
PrefilterPacketHeaderCtx_::sigs_array
SigIntId * sigs_array
Definition: detect-engine-prefilter-common.h:41
PrefilterPacketHeaderValue::u8
uint8_t u8[16]
Definition: detect-engine-prefilter-common.h:22
DetectTtlData_
Definition: detect-ttl.h:32
PrefilterPacketHeaderCtx_::sigs_cnt
uint32_t sigs_cnt
Definition: detect-engine-prefilter-common.h:40
SC_ERR_PCRE_GET_SUBSTRING
@ SC_ERR_PCRE_GET_SUBSTRING
Definition: util-error.h:34
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1252
SigTableElmt_::SetupPrefilter
int(* SetupPrefilter)(DetectEngineCtx *de_ctx, struct SigGroupHead_ *sgh)
Definition: detect.h:1255
StringParseUint8
int StringParseUint8(uint8_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:359
DetectTtlData_::ttl2
uint8_t ttl2
Definition: detect-ttl.h:34
PrefilterPacketHeaderCtx_
Definition: detect-engine-prefilter-common.h:33
util-debug.h
SC_ERR_PCRE_MATCH
@ SC_ERR_PCRE_MATCH
Definition: util-error.h:32
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:17
PARSE_REGEX
#define PARSE_REGEX
Regex for parsing our ttl options.
Definition: detect-ttl.c:41
DetectEngineThreadCtx_
Definition: detect.h:1060
DetectTtlData_::ttl1
uint8_t ttl1
Definition: detect-ttl.h:33
res
PoolThreadReserved res
Definition: stream-tcp-private.h:0
DetectSetupParseRegexes
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
Definition: detect-parse.c:2597
detect.h
SigMatch_::next
struct SigMatch_ * next
Definition: detect.h:325
DETECT_SM_LIST_MATCH
@ DETECT_SM_LIST_MATCH
Definition: detect.h:89
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:324
SCReturn
#define SCReturn
Definition: util-debug.h:302
Signature_::flags
uint32_t flags
Definition: detect.h:549
Packet_
Definition: decode.h:427
Signature_::init_data
SignatureInitData * init_data
Definition: detect.h:619
SigTableElmt_::Match
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1235
SignatureInitData_::smlists
struct SigMatch_ ** smlists
Definition: detect.h:542
SigMatchAlloc
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:235
detect-ttl.c
detect-ttl.h
DetectTtlData_::mode
uint8_t mode
Definition: detect-ttl.h:36
PrefilterPacketHeaderCtx_::v1
PrefilterPacketHeaderValue v1
Definition: detect-engine-prefilter-common.h:34
DETECT_TTL_EQ
#define DETECT_TTL_EQ
Definition: detect-ttl.h:28
SigMatchCtx_
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:316
DETECT_TTL_RA
#define DETECT_TTL_RA
Definition: detect-ttl.h:30
DetectTtlRegisterTests
void DetectTtlRegisterTests(void)
this function registers unit tests for DetectTtl
Definition: detect-ttl.c:209
suricata-common.h
SigMatch_::type
uint16_t type
Definition: detect.h:322
sigmatch_table
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect-parse.c:73
DETECT_TTL_GT
#define DETECT_TTL_GT
Definition: detect-ttl.h:29
SCLogError
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:257
PrefilterSetupPacketHeader
int PrefilterSetupPacketHeader(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int sm_type, void(*Set)(PrefilterPacketHeaderValue *v, void *), bool(*Compare)(PrefilterPacketHeaderValue v, void *), void(*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
Definition: detect-engine-prefilter-common.c:417
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
SCFree
#define SCFree(p)
Definition: util-mem.h:61
SigTableElmt_::SupportsPrefilter
bool(* SupportsPrefilter)(const Signature *s)
Definition: detect.h:1254
DetectTtlFree
void DetectTtlFree(DetectEngineCtx *, void *)
this function will free memory associated with DetectTtlData
Definition: detect-ttl.c:306
detect-parse.h
Signature_
Signature container.
Definition: detect.h:548
SigMatch_
a single match condition for a signature
Definition: detect.h:321
IPV6_GET_HLIM
#define IPV6_GET_HLIM(p)
Definition: decode-ipv6.h:90
PrefilterPacketHeaderValue
Definition: detect-engine-prefilter-common.h:21
detect-engine-prefilter-common.h
DETECT_TTL_LT
#define DETECT_TTL_LT
Definition: detect-ttl.h:27
PKT_IS_IPV4
#define PKT_IS_IPV4(p)
Definition: decode.h:262
DetectTtlRegister
void DetectTtlRegister(void)
Registration function for ttl: keyword.
Definition: detect-ttl.c:60
SigMatchAppendSMToList
void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:349
IPV4_GET_IPTTL
#define IPV4_GET_IPTTL(p)
Definition: decode-ipv4.h:145
SigTableElmt_::RegisterTests
void(* RegisterTests)(void)
Definition: detect.h:1259
SIG_FLAG_REQUIRE_PACKET
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:223