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  int ov[MAX_SUBSTRINGS];
137  char arg1[6] = "";
138  char arg2[6] = "";
139  char arg3[6] = "";
140 
141  int ret = DetectParsePcreExec(&parse_regex, ttlstr, 0, 0, ov, MAX_SUBSTRINGS);
142  if (ret < 2 || ret > 4) {
143  SCLogError(SC_ERR_PCRE_MATCH, "parse error, ret %" PRId32 "", ret);
144  return NULL;
145  }
146 
147  int res = pcre_copy_substring((char *) ttlstr, ov, MAX_SUBSTRINGS, 1, arg1, sizeof(arg1));
148  if (res < 0) {
149  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
150  return NULL;
151  }
152  SCLogDebug("arg1 \"%s\"", arg1);
153 
154  if (ret >= 3) {
155  res = pcre_copy_substring((char *) ttlstr, ov, MAX_SUBSTRINGS, 2, arg2, sizeof(arg2));
156  if (res < 0) {
157  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
158  return NULL;
159  }
160  SCLogDebug("arg2 \"%s\"", arg2);
161 
162  if (ret >= 4) {
163  res = pcre_copy_substring((char *) ttlstr, ov, MAX_SUBSTRINGS, 3, arg3, sizeof(arg3));
164  if (res < 0) {
165  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
166  return NULL;
167  }
168  SCLogDebug("arg3 \"%s\"", arg3);
169  }
170  }
171 
172  uint8_t ttl1 = 0;
173  uint8_t ttl2 = 0;
174  int mode = 0;
175 
176  if (strlen(arg2) > 0) {
177  switch (arg2[0]) {
178  case '<':
179  if (strlen(arg3) == 0)
180  return NULL;
181 
182  mode = DETECT_TTL_LT;
183  if (StringParseUint8(&ttl1, 10, 0, (const char *)arg3) < 0) {
184  SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid first ttl "
185  "value: \"%s\"", arg3);
186  return NULL;
187  }
188  SCLogDebug("ttl is %d",ttl1);
189  if (strlen(arg1) > 0)
190  return NULL;
191 
192  break;
193  case '>':
194  if (strlen(arg3) == 0)
195  return NULL;
196 
197  mode = DETECT_TTL_GT;
198  if (StringParseUint8(&ttl1, 10, 0, (const char *)arg3) < 0) {
199  SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid first ttl "
200  "value: \"%s\"", arg3);
201  return NULL;
202  }
203  SCLogDebug("ttl is %d",ttl1);
204  if (strlen(arg1) > 0)
205  return NULL;
206 
207  break;
208  case '-':
209  if (strlen(arg1) == 0 || strlen(arg3) == 0)
210  return NULL;
211 
212  mode = DETECT_TTL_RA;
213 
214  if (StringParseUint8(&ttl1, 10, 0, (const char *)arg1) < 0) {
215  SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid first ttl "
216  "value: \"%s\"", arg1);
217  return NULL;
218  }
219  if (StringParseUint8(&ttl2, 10, 0, (const char *)arg3) < 0) {
220  SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid second ttl "
221  "value: \"%s\"", arg3);
222  return NULL;
223  }
224  SCLogDebug("ttl is %d to %d",ttl1, ttl2);
225  if (ttl1 >= ttl2) {
226  SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid ttl range");
227  return NULL;
228  }
229  break;
230  default:
231  mode = DETECT_TTL_EQ;
232 
233  if ((strlen(arg2) > 0) ||
234  (strlen(arg3) > 0) ||
235  (strlen(arg1) == 0))
236  return NULL;
237  if (StringParseUint8(&ttl1, 10, 0, (const char *)arg1) < 0) {
238  SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid first ttl "
239  "value: \"%s\"", arg1);
240  return NULL;
241  }
242  break;
243  }
244  } else {
245  mode = DETECT_TTL_EQ;
246 
247  if ((strlen(arg3) > 0) ||
248  (strlen(arg1) == 0))
249  return NULL;
250  if (StringParseUint8(&ttl1, 10, 0, (const char *)arg1) < 0) {
251  SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid first ttl "
252  "value: \"%s\"", arg1);
253  return NULL;
254  }
255  }
256 
257  DetectTtlData *ttld = SCMalloc(sizeof(DetectTtlData));
258  if (unlikely(ttld == NULL))
259  return NULL;
260  ttld->ttl1 = (uint8_t)ttl1;
261  ttld->ttl2 = (uint8_t)ttl2;
262  ttld->mode = mode;
263 
264  return ttld;
265 }
266 
267 /**
268  * \brief this function is used to attld the parsed ttl data into the current signature
269  *
270  * \param de_ctx pointer to the Detection Engine Context
271  * \param s pointer to the Current Signature
272  * \param ttlstr pointer to the user provided ttl options
273  *
274  * \retval 0 on Success
275  * \retval -1 on Failure
276  */
277 static int DetectTtlSetup (DetectEngineCtx *de_ctx, Signature *s, const char *ttlstr)
278 {
279  DetectTtlData *ttld = DetectTtlParse(ttlstr);
280  if (ttld == NULL)
281  return -1;
282 
283  SigMatch *sm = SigMatchAlloc();
284  if (sm == NULL) {
285  DetectTtlFree(de_ctx, ttld);
286  return -1;
287  }
288 
289  sm->type = DETECT_TTL;
290  sm->ctx = (SigMatchCtx *)ttld;
291 
294  return 0;
295 }
296 
297 /**
298  * \brief this function will free memory associated with DetectTtlData
299  *
300  * \param ptr pointer to DetectTtlData
301  */
303 {
304  DetectTtlData *ttld = (DetectTtlData *)ptr;
305  SCFree(ttld);
306 }
307 
308 /* prefilter code */
309 
310 static void
311 PrefilterPacketTtlMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
312 {
313  if (PKT_IS_PSEUDOPKT(p)) {
314  SCReturn;
315  }
316 
317  uint8_t pttl;
318  if (PKT_IS_IPV4(p)) {
319  pttl = IPV4_GET_IPTTL(p);
320  } else if (PKT_IS_IPV6(p)) {
321  pttl = IPV6_GET_HLIM(p);
322  } else {
323  SCLogDebug("Packet is of not IPv4 or IPv6");
324  return;
325  }
326 
327  const PrefilterPacketHeaderCtx *ctx = pectx;
328  if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE)
329  return;
330 
331  if (TtlMatch(pttl, ctx->v1.u8[0], ctx->v1.u8[1], ctx->v1.u8[2]))
332  {
333  SCLogDebug("packet matches ttl/hl %u", pttl);
334  PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt);
335  }
336 }
337 
338 static void
339 PrefilterPacketTtlSet(PrefilterPacketHeaderValue *v, void *smctx)
340 {
341  const DetectTtlData *a = smctx;
342  v->u8[0] = a->mode;
343  v->u8[1] = a->ttl1;
344  v->u8[2] = a->ttl2;
345 }
346 
347 static bool
348 PrefilterPacketTtlCompare(PrefilterPacketHeaderValue v, void *smctx)
349 {
350  const DetectTtlData *a = smctx;
351  if (v.u8[0] == a->mode &&
352  v.u8[1] == a->ttl1 &&
353  v.u8[2] == a->ttl2)
354  return TRUE;
355  return FALSE;
356 }
357 
358 static int PrefilterSetupTtl(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
359 {
361  PrefilterPacketTtlSet,
362  PrefilterPacketTtlCompare,
363  PrefilterPacketTtlMatch);
364 }
365 
366 static bool PrefilterTtlIsPrefilterable(const Signature *s)
367 {
368  const SigMatch *sm;
369  for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) {
370  switch (sm->type) {
371  case DETECT_TTL:
372  return TRUE;
373  }
374  }
375  return FALSE;
376 }
377 
378 #ifdef UNITTESTS
379 #include "tests/detect-ttl.c"
380 #endif
util-byte.h
SigTableElmt_::url
const char * url
Definition: detect.h:1214
DETECT_TTL
@ DETECT_TTL
Definition: detect-engine-register.h:43
SigTableElmt_::desc
const char * desc
Definition: detect.h:1213
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1201
SigTableElmt_::name
const char * name
Definition: detect.h:1211
PKT_IS_PSEUDOPKT
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition: decode.h:1147
PKT_IS_IPV6
#define PKT_IS_IPV6(p)
Definition: decode.h:258
stream-tcp.h
SigGroupHead_
Container for matching data for a signature group.
Definition: detect.h:1347
MAX_SUBSTRINGS
#define MAX_SUBSTRINGS
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
DetectEngineThreadCtx_::pmq
PrefilterRuleStore pmq
Definition: detect.h:1111
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:767
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:1196
SigTableElmt_::SetupPrefilter
int(* SetupPrefilter)(DetectEngineCtx *de_ctx, struct SigGroupHead_ *sgh)
Definition: detect.h:1199
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:1010
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:2493
detect.h
SigMatch_::next
struct SigMatch_ * next
Definition: detect.h:324
DETECT_SM_LIST_MATCH
@ DETECT_SM_LIST_MATCH
Definition: detect.h:89
TRUE
#define TRUE
Definition: suricata-common.h:33
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:323
FALSE
#define FALSE
Definition: suricata-common.h:34
SCReturn
#define SCReturn
Definition: util-debug.h:302
Signature_::flags
uint32_t flags
Definition: detect.h:529
DetectParsePcreExec
int DetectParsePcreExec(DetectParseRegex *parse_regex, const char *str, int start_offset, int options, int *ovector, int ovector_size)
Definition: detect-parse.c:2423
Packet_
Definition: decode.h:414
Signature_::init_data
SignatureInitData * init_data
Definition: detect.h:597
SigTableElmt_::Match
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1179
SignatureInitData_::smlists
struct SigMatch_ ** smlists
Definition: detect.h:522
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
SigMatch_::type
uint8_t type
Definition: detect.h:321
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:315
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_table
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect-parse.c:73
DetectParseRegex_
Definition: detect-parse.h:42
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:407
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:1198
DetectTtlFree
void DetectTtlFree(DetectEngineCtx *, void *)
this function will free memory associated with DetectTtlData
Definition: detect-ttl.c:302
detect-parse.h
Signature_
Signature container.
Definition: detect.h:528
SigMatch_
a single match condition for a signature
Definition: detect.h:320
IPV6_GET_HLIM
#define IPV6_GET_HLIM(p)
Definition: decode-ipv6.h:90
StringParseUint8
int StringParseUint8(uint8_t *res, int base, uint16_t len, const char *str)
Definition: util-byte.c:359
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:257
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:146
SigTableElmt_::RegisterTests
void(* RegisterTests)(void)
Definition: detect.h:1203
SIG_FLAG_REQUIRE_PACKET
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:223