suricata
detect-classtype.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2010 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 Anoop Saldanha <anoopsaldanha@gmail.com>
22  *
23  * Implements classtype keyword.
24  */
25 
26 #include "suricata-common.h"
27 #include "decode.h"
28 
29 #include "detect.h"
30 #include "detect-parse.h"
31 #include "detect-engine.h"
32 #include "detect-engine-mpm.h"
33 #include "detect-classtype.h"
34 #include "flow-var.h"
36 #include "util-error.h"
37 #include "util-debug.h"
38 #include "util-unittest.h"
39 
40 #define PARSE_REGEX "^\\s*([a-zA-Z][a-zA-Z0-9-_]*)\\s*$"
41 
42 static pcre *regex = NULL;
43 static pcre_extra *regex_study = NULL;
44 
45 static int DetectClasstypeSetup(DetectEngineCtx *, Signature *, const char *);
46 static void DetectClasstypeRegisterTests(void);
47 
48 /**
49  * \brief Registers the handler functions for the "Classtype" keyword.
50  */
52 {
53  sigmatch_table[DETECT_CLASSTYPE].name = "classtype";
54  sigmatch_table[DETECT_CLASSTYPE].desc = "information about the classification of rules and alerts";
55  sigmatch_table[DETECT_CLASSTYPE].url = DOC_URL DOC_VERSION "/rules/meta.html#classtype";
57  sigmatch_table[DETECT_CLASSTYPE].Setup = DetectClasstypeSetup;
59  sigmatch_table[DETECT_CLASSTYPE].RegisterTests = DetectClasstypeRegisterTests;
60 
61  DetectSetupParseRegexes(PARSE_REGEX, &regex, &regex_study);
62 }
63 
64 /**
65  * \brief Parses the raw string supplied with the "Classtype" keyword.
66  *
67  * \param Pointer to the string to be parsed.
68  *
69  * \retval bool success or failure.
70  */
71 static int DetectClasstypeParseRawString(const char *rawstr, char *out, size_t outsize)
72 {
73 #define MAX_SUBSTRINGS 30
74  int ret = 0;
75  int ov[MAX_SUBSTRINGS];
76  size_t len = strlen(rawstr);
77 
78  ret = pcre_exec(regex, regex_study, rawstr, len, 0, 0, ov, 30);
79  if (ret < 0) {
80  SCLogError(SC_ERR_PCRE_MATCH, "Invalid Classtype in Signature");
81  goto end;
82  }
83 
84  ret = pcre_copy_substring((char *)rawstr, ov, 30, 1, out, outsize);
85  if (ret < 0) {
86  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
87  goto end;
88  }
89 
90  return 0;
91  end:
92  return -1;
93 }
94 
95 /**
96  * \brief The setup function that would be called when the Signature parsing
97  * module encounters the "Classtype" keyword.
98  *
99  * \param de_ctx Pointer to the Detection Engine Context.
100  * \param s Pointer the current Signature instance that is being parsed.
101  * \param rawstr Pointer to the argument supplied to the classtype keyword.
102  *
103  * \retval 0 On success
104  * \retval -1 On failure
105  */
106 static int DetectClasstypeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
107 {
108  char parsed_ct_name[1024] = "";
109  SCClassConfClasstype *ct = NULL;
110 
111  if (DetectClasstypeParseRawString(rawstr, parsed_ct_name, sizeof(parsed_ct_name)) < -1) {
112  SCLogError(SC_ERR_PCRE_PARSE, "Error parsing classtype argument supplied with the "
113  "classtype keyword");
114  goto error;
115  }
116 
117  ct = SCClassConfGetClasstype(parsed_ct_name, de_ctx);
118  if (ct == NULL) {
119  SCLogError(SC_ERR_UNKNOWN_VALUE, "Unknown Classtype: \"%s\". Invalidating the Signature",
120  parsed_ct_name);
121  goto error;
122  }
123 
124  if ((s->class > 0) || (s->class_msg != NULL))
125  {
126  SCLogError(SC_ERR_INVALID_RULE_ARGUMENT, "duplicated 'classtype' keyword detected");
127  goto error;
128  }
129 
130  /* if we have retrieved the classtype, assign the message to be displayed
131  * for this Signature by fast.log, if a Packet matches this Signature */
132  s->class = ct->classtype_id;
133  s->class_msg = ct->classtype_desc;
134 
135  /* if a priority keyword has appeared before the classtype, s->prio would
136  * hold a value which is != -1, in which case we don't overwrite the value.
137  * Otherwise, overwrite the value */
138  if (s->prio == -1)
139  s->prio = ct->priority;
140 
141  return 0;
142 
143  error:
144  return -1;
145 }
146 
147 /*------------------------------Unittests-------------------------------------*/
148 
149 #ifdef UNITTESTS
150 
151 /**
152  * \test Check that supplying an invalid classtype in the rule, results in the
153  * rule being invalidated.
154  */
155 static int DetectClasstypeTest01(void)
156 {
157  int result = 0;
158 
160  if (de_ctx == NULL) {
161  goto end;
162  }
163 
166 
167  de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any "
168  "(msg:\"Classtype test\"; "
169  "Classtype:not_available; sid:1;)");
170  if (de_ctx->sig_list == NULL)
171  result = 1;
172 
173  DetectEngineCtxFree(de_ctx);
174 
175 end:
176  return result;
177 }
178 
179 /**
180  * \test Check that both valid and invalid classtypes in a rule are handled
181  * properly, with rules containing invalid classtypes being rejected
182  * and the ones containing valid classtypes parsed and returned.
183  */
184 static int DetectClasstypeTest02(void)
185 {
186  int result = 0;
187  Signature *last = NULL;
188  Signature *sig = NULL;
189 
191  if (de_ctx == NULL) {
192  goto end;
193  }
194 
197 
198  sig = SigInit(de_ctx, "alert tcp any any -> any any "
199  "(msg:\"Classtype test\"; Classtype:bad-unknown; sid:1;)");
200  if (sig == NULL) {
201  printf("first sig failed to parse: ");
202  result = 0;
203  goto end;
204  }
205  de_ctx->sig_list = last = sig;
206  result = (sig != NULL);
207 
208  sig = SigInit(de_ctx, "alert tcp any any -> any any "
209  "(msg:\"Classtype test\"; Classtype:not-there; sid:1;)");
210  last->next = sig;
211  result &= (sig == NULL);
212 
213  sig = SigInit(de_ctx, "alert tcp any any -> any any "
214  "(msg:\"Classtype test\"; Classtype:Bad-UnkNown; sid:1;)");
215  if (sig == NULL) {
216  printf("second sig failed to parse: ");
217  result = 0;
218  goto end;
219  }
220  last->next = sig;
221  last = sig;
222  result &= (sig != NULL);
223 
224  sig = SigInit(de_ctx, "alert tcp any any -> any any "
225  "(msg:\"Classtype test\"; Classtype:nothing-wrong; sid:1;)");
226  if (sig == NULL) {
227  result = 0;
228  goto end;
229  }
230  last->next = sig;
231  last = sig;
232  result &= (sig != NULL);
233 
234  sig = SigInit(de_ctx, "alert tcp any any -> any any "
235  "(msg:\"Classtype test\"; Classtype:attempted_dos; sid:1;)");
236  last->next = sig;
237  result &= (sig == NULL);
238 
239  SigCleanSignatures(de_ctx);
240  DetectEngineCtxFree(de_ctx);
241 
242 end:
243  return result;
244 }
245 
246 /**
247  * \test Check that the signatures are assigned priority based on classtype they
248  * are given.
249  */
250 static int DetectClasstypeTest03(void)
251 {
252  int result = 0;
253  Signature *last = NULL;
254  Signature *sig = NULL;
255 
257  if (de_ctx == NULL) {
258  goto end;
259  }
260 
263 
264  sig = SigInit(de_ctx, "alert tcp any any -> any any "
265  "(msg:\"Classtype test\"; Classtype:bad-unknown; priority:1; sid:1;)");
266  if (sig == NULL) {
267  result = 0;
268  goto end;
269  }
270  de_ctx->sig_list = last = sig;
271  result = (sig != NULL);
272  result &= (sig->prio == 1);
273 
274  sig = SigInit(de_ctx, "alert tcp any any -> any any "
275  "(msg:\"Classtype test\"; Classtype:unKnoWn; "
276  "priority:3; sid:1;)");
277  if (sig == NULL) {
278  result = 0;
279  goto end;
280  }
281  last->next = sig;
282  last = sig;
283  result &= (sig != NULL);
284  result &= (sig->prio == 3);
285 
286  sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Classtype test\"; "
287  "Classtype:nothing-wrong; priority:1; sid:1;)");
288  if (sig == NULL) {
289  result = 0;
290  goto end;
291  }
292  last->next = sig;
293  last = sig;
294  result &= (sig != NULL);
295  result &= (sig->prio == 1);
296 
297 
298  SigCleanSignatures(de_ctx);
299  DetectEngineCtxFree(de_ctx);
300 
301 end:
302  return result;
303 }
304 
305 #endif /* UNITTESTS */
306 
307 /**
308  * \brief This function registers unit tests for Classification Config API.
309  */
310 static void DetectClasstypeRegisterTests(void)
311 {
312 
313 #ifdef UNITTESTS
314 
315  UtRegisterTest("DetectClasstypeTest01", DetectClasstypeTest01);
316  UtRegisterTest("DetectClasstypeTest02", DetectClasstypeTest02);
317  UtRegisterTest("DetectClasstypeTest03", DetectClasstypeTest03);
318 
319 #endif /* UNITTESTS */
320 
321 }
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1406
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1149
Signature * SigInit(DetectEngineCtx *, const char *)
Parses a signature and adds it to the Detection Engine Context.
uint8_t class
Definition: detect.h:515
int prio
Definition: detect.h:531
Signature * sig_list
Definition: detect.h:729
void SigCleanSignatures(DetectEngineCtx *de_ctx)
#define MAX_SUBSTRINGS
const char * name
Definition: detect.h:1163
Signature container.
Definition: detect.h:495
main detection engine ctx
Definition: detect.h:723
void(* Free)(void *)
Definition: detect.h:1154
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
void DetectSetupParseRegexes(const char *parse_str, pcre **parse_regex, pcre_extra **parse_regex_study)
void SCClassConfLoadClassficationConfigFile(DetectEngineCtx *de_ctx, FILE *fd)
Loads the Classtype info from the classification.config file.
struct Signature_ * next
Definition: detect.h:566
const char * desc
Definition: detect.h:1165
char * class_msg
Definition: detect.h:555
int(* Match)(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1132
const char * url
Definition: detect.h:1166
Container for a Classtype from the Classification.config file.
#define DOC_URL
Definition: suricata.h:86
SCClassConfClasstype * SCClassConfGetClasstype(const char *ct_name, DetectEngineCtx *de_ctx)
Gets the classtype from the corresponding hash table stored in the Detection Engine Context&#39;s class c...
uint8_t len
#define DOC_VERSION
Definition: suricata.h:91
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
#define PARSE_REGEX
FILE * SCClassConfGenerateValidDummyClassConfigFD01(void)
Creates a dummy classification file, with all valid Classtypes, for testing purposes.
void(* RegisterTests)(void)
Definition: detect.h:1155
void DetectClasstypeRegister(void)
Registers the handler functions for the "Classtype" keyword.
DetectEngineCtx * DetectEngineCtxInit(void)