suricata
detect-ttl.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2018 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 
37 /**
38  * \brief Regex for parsing our ttl options
39  */
40 #define PARSE_REGEX "^\\s*([0-9]*)?\\s*([<>=-]+)?\\s*([0-9]+)?\\s*$"
41 
42 static pcre *parse_regex;
43 static pcre_extra *parse_regex_study;
44 
45 /* prototypes */
46 static int DetectTtlMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *,
47  const Signature *, const SigMatchCtx *);
48 static int DetectTtlSetup (DetectEngineCtx *, Signature *, const char *);
49 void DetectTtlFree (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 = DOC_URL DOC_VERSION "/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, &parse_regex_study);
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 (ThreadVars *t, 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 #define MAX_SUBSTRINGS 30
137  int ov[MAX_SUBSTRINGS];
138  char arg1[6] = "";
139  char arg2[6] = "";
140  char arg3[6] = "";
141 
142  int ret = pcre_exec(parse_regex, parse_regex_study, ttlstr, strlen(ttlstr), 0, 0, ov, MAX_SUBSTRINGS);
143  if (ret < 2 || ret > 4) {
144  SCLogError(SC_ERR_PCRE_MATCH, "parse error, ret %" PRId32 "", ret);
145  return NULL;
146  }
147 
148  int res = pcre_copy_substring((char *) ttlstr, ov, MAX_SUBSTRINGS, 1, arg1, sizeof(arg1));
149  if (res < 0) {
150  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
151  return NULL;
152  }
153  SCLogDebug("arg1 \"%s\"", arg1);
154 
155  if (ret >= 3) {
156  res = pcre_copy_substring((char *) ttlstr, ov, MAX_SUBSTRINGS, 2, arg2, sizeof(arg2));
157  if (res < 0) {
158  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
159  return NULL;
160  }
161  SCLogDebug("arg2 \"%s\"", arg2);
162 
163  if (ret >= 4) {
164  res = pcre_copy_substring((char *) ttlstr, ov, MAX_SUBSTRINGS, 3, arg3, sizeof(arg3));
165  if (res < 0) {
166  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
167  return NULL;
168  }
169  SCLogDebug("arg3 \"%s\"", arg3);
170  }
171  }
172 
173  int ttl1 = 0;
174  int ttl2 = 0;
175  int mode = 0;
176 
177  if (strlen(arg2) > 0) {
178  switch (arg2[0]) {
179  case '<':
180  if (strlen(arg3) == 0)
181  return NULL;
182 
183  mode = DETECT_TTL_LT;
184  ttl1 = atoi(arg3);
185 
186  SCLogDebug("ttl is %"PRIu8"",ttl1);
187  if (strlen(arg1) > 0)
188  return NULL;
189 
190  break;
191  case '>':
192  if (strlen(arg3) == 0)
193  return NULL;
194 
195  mode = DETECT_TTL_GT;
196  ttl1 = atoi(arg3);
197 
198  SCLogDebug("ttl is %"PRIu8"",ttl1);
199  if (strlen(arg1) > 0)
200  return NULL;
201 
202  break;
203  case '-':
204  if (strlen(arg1) == 0 || strlen(arg3) == 0)
205  return NULL;
206 
207  mode = DETECT_TTL_RA;
208  ttl1 = atoi(arg1);
209  ttl2 = atoi(arg3);
210 
211  SCLogDebug("ttl is %"PRIu8" to %"PRIu8"",ttl1, ttl2);
212  if (ttl1 >= ttl2) {
213  SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid ttl range");
214  return NULL;
215  }
216  break;
217  default:
218  mode = DETECT_TTL_EQ;
219 
220  if ((strlen(arg2) > 0) ||
221  (strlen(arg3) > 0) ||
222  (strlen(arg1) == 0))
223  return NULL;
224 
225  ttl1 = atoi(arg1);
226  break;
227  }
228  } else {
229  mode = DETECT_TTL_EQ;
230 
231  if ((strlen(arg3) > 0) ||
232  (strlen(arg1) == 0))
233  return NULL;
234 
235  ttl1 = atoi(arg1);
236  }
237 
238  if (ttl1 < 0 || ttl1 > UCHAR_MAX ||
239  ttl2 < 0 || ttl2 > UCHAR_MAX) {
240  SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid ttl value(s)");
241  return NULL;
242  }
243 
244  DetectTtlData *ttld = SCMalloc(sizeof(DetectTtlData));
245  if (unlikely(ttld == NULL))
246  return NULL;
247  ttld->ttl1 = (uint8_t)ttl1;
248  ttld->ttl2 = (uint8_t)ttl2;
249  ttld->mode = mode;
250 
251  return ttld;
252 }
253 
254 /**
255  * \brief this function is used to attld the parsed ttl data into the current signature
256  *
257  * \param de_ctx pointer to the Detection Engine Context
258  * \param s pointer to the Current Signature
259  * \param ttlstr pointer to the user provided ttl options
260  *
261  * \retval 0 on Success
262  * \retval -1 on Failure
263  */
264 static int DetectTtlSetup (DetectEngineCtx *de_ctx, Signature *s, const char *ttlstr)
265 {
266  DetectTtlData *ttld = DetectTtlParse(ttlstr);
267  if (ttld == NULL)
268  return -1;
269 
270  SigMatch *sm = SigMatchAlloc();
271  if (sm == NULL) {
272  DetectTtlFree(ttld);
273  return -1;
274  }
275 
276  sm->type = DETECT_TTL;
277  sm->ctx = (SigMatchCtx *)ttld;
278 
281  return 0;
282 }
283 
284 /**
285  * \brief this function will free memory associated with DetectTtlData
286  *
287  * \param ptr pointer to DetectTtlData
288  */
289 void DetectTtlFree(void *ptr)
290 {
291  DetectTtlData *ttld = (DetectTtlData *)ptr;
292  SCFree(ttld);
293 }
294 
295 /* prefilter code */
296 
297 static void
298 PrefilterPacketTtlMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
299 {
300  if (PKT_IS_PSEUDOPKT(p)) {
301  SCReturn;
302  }
303 
304  uint8_t pttl;
305  if (PKT_IS_IPV4(p)) {
306  pttl = IPV4_GET_IPTTL(p);
307  } else if (PKT_IS_IPV6(p)) {
308  pttl = IPV6_GET_HLIM(p);
309  } else {
310  SCLogDebug("Packet is of not IPv4 or IPv6");
311  return;
312  }
313 
314  const PrefilterPacketHeaderCtx *ctx = pectx;
315  if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE)
316  return;
317 
318  if (TtlMatch(pttl, ctx->v1.u8[0], ctx->v1.u8[1], ctx->v1.u8[2]))
319  {
320  SCLogDebug("packet matches ttl/hl %u", pttl);
321  PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt);
322  }
323 }
324 
325 static void
326 PrefilterPacketTtlSet(PrefilterPacketHeaderValue *v, void *smctx)
327 {
328  const DetectTtlData *a = smctx;
329  v->u8[0] = a->mode;
330  v->u8[1] = a->ttl1;
331  v->u8[2] = a->ttl2;
332 }
333 
334 static _Bool
335 PrefilterPacketTtlCompare(PrefilterPacketHeaderValue v, void *smctx)
336 {
337  const DetectTtlData *a = smctx;
338  if (v.u8[0] == a->mode &&
339  v.u8[1] == a->ttl1 &&
340  v.u8[2] == a->ttl2)
341  return TRUE;
342  return FALSE;
343 }
344 
345 static int PrefilterSetupTtl(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
346 {
347  return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_TTL,
348  PrefilterPacketTtlSet,
349  PrefilterPacketTtlCompare,
350  PrefilterPacketTtlMatch);
351 }
352 
353 static _Bool PrefilterTtlIsPrefilterable(const Signature *s)
354 {
355  const SigMatch *sm;
356  for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) {
357  switch (sm->type) {
358  case DETECT_TTL:
359  return TRUE;
360  }
361  }
362  return FALSE;
363 }
364 
365 #ifdef UNITTESTS
366 #include "tests/detect-ttl.c"
367 #endif
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1403
SignatureInitData * init_data
Definition: detect.h:560
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1146
#define SCLogDebug(...)
Definition: util-debug.h:335
void DetectTtlRegister(void)
Registration function for ttl: keyword.
Definition: detect-ttl.c:60
int(* SetupPrefilter)(DetectEngineCtx *de_ctx, struct SigGroupHead_ *sgh)
Definition: detect.h:1149
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))
uint32_t flags
Definition: detect.h:493
_Bool(* SupportsPrefilter)(const Signature *s)
Definition: detect.h:1148
#define FALSE
#define unlikely(expr)
Definition: util-optimize.h:35
#define IPV6_GET_HLIM(p)
Definition: decode-ipv6.h:89
#define PKT_IS_IPV6(p)
Definition: decode.h:251
Container for matching data for a signature group.
Definition: detect.h:1295
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:230
const char * name
Definition: detect.h:1160
Signature container.
Definition: detect.h:492
#define PARSE_REGEX
Regex for parsing our ttl options.
Definition: detect-ttl.c:40
#define TRUE
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:319
#define PKT_IS_IPV4(p)
Definition: decode.h:250
struct SigMatch_ * next
Definition: detect.h:328
main detection engine ctx
Definition: detect.h:720
uint8_t ttl1
Definition: detect-ttl.h:33
void DetectTtlFree(void *)
this function will free memory associated with DetectTtlData
Definition: detect-ttl.c:289
void(* Free)(void *)
Definition: detect.h:1151
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
void DetectSetupParseRegexes(const char *parse_str, pcre **parse_regex, pcre_extra **parse_regex_study)
PrefilterRuleStore pmq
Definition: detect.h:1061
uint8_t mode
Definition: detect-ttl.h:36
uint8_t ttl2
Definition: detect-ttl.h:34
uint8_t type
Definition: detect.h:325
const char * desc
Definition: detect.h:1162
void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:282
struct SigMatch_ ** smlists
Definition: detect.h:486
void DetectTtlRegisterTests(void)
this function registers unit tests for DetectTtl
Definition: detect-ttl.c:209
#define DETECT_TTL_EQ
Definition: detect-ttl.h:28
SigMatchCtx * ctx
Definition: detect.h:327
#define SCMalloc(a)
Definition: util-mem.h:174
#define SCFree(a)
Definition: util-mem.h:236
PoolThreadReserved res
#define DETECT_TTL_GT
Definition: detect-ttl.h:29
#define MAX_SUBSTRINGS
int(* Match)(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1129
#define DETECT_TTL_RA
Definition: detect-ttl.h:30
const char * url
Definition: detect.h:1163
#define DOC_URL
Definition: suricata.h:86
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition: decode.h:1140
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:226
#define SCReturn
Definition: util-debug.h:339
Per thread variable structure.
Definition: threadvars.h:57
#define DOC_VERSION
Definition: suricata.h:91
#define DETECT_TTL_LT
Definition: detect-ttl.h:27
void(* RegisterTests)(void)
Definition: detect.h:1152
a single match condition for a signature
Definition: detect.h:324
#define IPV4_GET_IPTTL(p)
Definition: decode-ipv4.h:146