suricata
detect-snmp-version.c
Go to the documentation of this file.
1 /* Copyright (C) 2015-2019 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 Pierre Chifflier <chifflier@wzdftpd.net>
22  */
23 
24 #include "suricata-common.h"
25 #include "conf.h"
26 #include "detect.h"
27 #include "detect-parse.h"
28 #include "detect-engine.h"
30 #include "detect-snmp-version.h"
31 #include "app-layer-parser.h"
32 
33 #include "rust-snmp-snmp-gen.h"
34 #include "rust-snmp-detect-gen.h"
35 
36 /**
37  * [snmp.version]:[<|>|<=|>=]<version>;
38  */
39 #define PARSE_REGEX "^\\s*(<=|>=|<|>)?\\s*([0-9]+)\\s*$"
40 static pcre *parse_regex;
41 static pcre_extra *parse_regex_study;
42 
44  PROCEDURE_EQ = 1, /* equal */
45  PROCEDURE_LT, /* less than */
46  PROCEDURE_LE, /* less than */
47  PROCEDURE_GT, /* greater than */
48  PROCEDURE_GE, /* greater than */
49 };
50 
51 typedef struct DetectSNMPVersionData_ {
52  uint32_t version;
55 
56 static DetectSNMPVersionData *DetectSNMPVersionParse (const char *);
57 static int DetectSNMPVersionSetup (DetectEngineCtx *, Signature *s, const char *str);
58 static void DetectSNMPVersionFree(void *);
59 #ifdef UNITTESTS
60 static void DetectSNMPVersionRegisterTests(void);
61 #endif
62 static int g_snmp_version_buffer_id = 0;
63 
64 static int DetectEngineInspectSNMPRequestGeneric(ThreadVars *tv,
65  DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
66  const Signature *s, const SigMatchData *smd,
67  Flow *f, uint8_t flags, void *alstate,
68  void *txv, uint64_t tx_id);
69 
70 static int DetectSNMPVersionMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *,
71  uint8_t, void *, void *, const Signature *,
72  const SigMatchCtx *);
73 
74 /**
75  * \brief Registration function for snmp.procedure keyword.
76  */
78 {
79  sigmatch_table[DETECT_AL_SNMP_VERSION].name = "snmp.version";
80  sigmatch_table[DETECT_AL_SNMP_VERSION].desc = "match SNMP version";
81  sigmatch_table[DETECT_AL_SNMP_VERSION].url = DOC_URL DOC_VERSION "/rules/snmp-keywords.html#snmp.version";
83  sigmatch_table[DETECT_AL_SNMP_VERSION].AppLayerTxMatch = DetectSNMPVersionMatch;
84  sigmatch_table[DETECT_AL_SNMP_VERSION].Setup = DetectSNMPVersionSetup;
85  sigmatch_table[DETECT_AL_SNMP_VERSION].Free = DetectSNMPVersionFree;
86 #ifdef UNITTESTS
87  sigmatch_table[DETECT_AL_SNMP_VERSION].RegisterTests = DetectSNMPVersionRegisterTests;
88 #endif
90 
91  DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study);
92 
95  DetectEngineInspectSNMPRequestGeneric);
96 
99  DetectEngineInspectSNMPRequestGeneric);
100 
101  g_snmp_version_buffer_id = DetectBufferTypeGetByName("snmp.version");
102 }
103 
104 static int DetectEngineInspectSNMPRequestGeneric(ThreadVars *tv,
105  DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
106  const Signature *s, const SigMatchData *smd,
107  Flow *f, uint8_t flags, void *alstate,
108  void *txv, uint64_t tx_id)
109 {
110  return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd,
111  f, flags, alstate, txv, tx_id);
112 }
113 
114 static inline int
115 VersionMatch(const uint32_t version,
116  enum DetectSNMPVersionMode mode, uint32_t ref_version)
117 {
118  switch (mode) {
119  case PROCEDURE_EQ:
120  if (version == ref_version)
121  SCReturnInt(1);
122  break;
123  case PROCEDURE_LT:
124  if (version < ref_version)
125  SCReturnInt(1);
126  break;
127  case PROCEDURE_LE:
128  if (version <= ref_version)
129  SCReturnInt(1);
130  break;
131  case PROCEDURE_GT:
132  if (version > ref_version)
133  SCReturnInt(1);
134  break;
135  case PROCEDURE_GE:
136  if (version >= ref_version)
137  SCReturnInt(1);
138  break;
139  }
140  SCReturnInt(0);
141 }
142 
143 /**
144  * \internal
145  * \brief Function to match version of a TX
146  *
147  * \param t Pointer to thread vars.
148  * \param det_ctx Pointer to the pattern matcher thread.
149  * \param f Pointer to the current flow.
150  * \param flags Flags.
151  * \param state App layer state.
152  * \param s Pointer to the Signature.
153  * \param m Pointer to the sigmatch that we will cast into
154  * DetectSNMPVersionData.
155  *
156  * \retval 0 no match.
157  * \retval 1 match.
158  */
159 static int DetectSNMPVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx,
160  Flow *f, uint8_t flags, void *state,
161  void *txv, const Signature *s,
162  const SigMatchCtx *ctx)
163 {
164  SCEnter();
165 
166  const DetectSNMPVersionData *dd = (const DetectSNMPVersionData *)ctx;
167  uint32_t version;
168  rs_snmp_tx_get_version(txv, &version);
169  SCLogDebug("version %u mode %u ref_version %d",
170  version, dd->mode, dd->version);
171  if (VersionMatch(version, dd->mode, dd->version))
172  SCReturnInt(1);
173  SCReturnInt(0);
174 }
175 
176 /**
177  * \internal
178  * \brief Function to parse options passed via snmp.version keywords.
179  *
180  * \param rawstr Pointer to the user provided options.
181  *
182  * \retval dd pointer to DetectSNMPVersionData on success.
183  * \retval NULL on failure.
184  */
185 static DetectSNMPVersionData *DetectSNMPVersionParse (const char *rawstr)
186 {
187  DetectSNMPVersionData *dd = NULL;
188 #define MAX_SUBSTRINGS 30
189  int ret = 0, res = 0;
190  int ov[MAX_SUBSTRINGS];
191  char mode[2] = "";
192  char value1[20] = "";
193  char *endptr = NULL;
194 
195  ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0,
196  0, ov, MAX_SUBSTRINGS);
197  if (ret < 3 || ret > 5) {
198  SCLogError(SC_ERR_PCRE_MATCH, "Parse error %s", rawstr);
199  goto error;
200  }
201 
202  res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, mode,
203  sizeof(mode));
204  if (res < 0) {
205  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
206  goto error;
207  }
208 
209  res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, value1,
210  sizeof(value1));
211  if (res < 0) {
212  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
213  goto error;
214  }
215 
216  dd = SCCalloc(1, sizeof(DetectSNMPVersionData));
217  if (unlikely(dd == NULL))
218  goto error;
219 
220  if (strlen(mode) == 1) {
221  if (mode[0] == '<')
222  dd->mode = PROCEDURE_LT;
223  else if (mode[0] == '>')
224  dd->mode = PROCEDURE_GT;
225  } else if (strlen(mode) == 2) {
226  if (strcmp(mode, "<=") == 0)
227  dd->mode = PROCEDURE_LE;
228  if (strcmp(mode, ">=") == 0)
229  dd->mode = PROCEDURE_GE;
230  }
231 
232  if (dd->mode == 0) {
233  dd->mode = PROCEDURE_EQ;
234  }
235 
236  /* set the first value */
237  dd->version = strtoul(value1, &endptr, 10);
238  if (endptr == NULL || *endptr != '\0') {
239  SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid character as arg "
240  "to snmp.version keyword");
241  goto error;
242  }
243 
244  return dd;
245 
246 error:
247  if (dd)
248  SCFree(dd);
249  return NULL;
250 }
251 
252 
253 
254 /**
255  * \brief Function to add the parsed snmp version field 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 rawstr Pointer to the user provided flags options.
260  * \param type Defines if this is notBefore or notAfter.
261  *
262  * \retval 0 on Success.
263  * \retval -1 on Failure.
264  */
265 static int DetectSNMPVersionSetup (DetectEngineCtx *de_ctx, Signature *s,
266  const char *rawstr)
267 {
268  DetectSNMPVersionData *dd = NULL;
269  SigMatch *sm = NULL;
270 
272  return -1;
273 
274  dd = DetectSNMPVersionParse(rawstr);
275  if (dd == NULL) {
276  SCLogError(SC_ERR_INVALID_ARGUMENT,"Parsing \'%s\' failed", rawstr);
277  goto error;
278  }
279 
280  /* okay so far so good, lets get this into a SigMatch
281  * and put it in the Signature. */
282  sm = SigMatchAlloc();
283  if (sm == NULL)
284  goto error;
285 
287  sm->ctx = (void *)dd;
288 
289  SCLogDebug("snmp.version %d", dd->version);
290  SigMatchAppendSMToList(s, sm, g_snmp_version_buffer_id);
291  return 0;
292 
293 error:
294  DetectSNMPVersionFree(dd);
295  return -1;
296 }
297 
298 /**
299  * \internal
300  * \brief Function to free memory associated with DetectSNMPVersionData.
301  *
302  * \param de_ptr Pointer to DetectSNMPVersionData.
303  */
304 static void DetectSNMPVersionFree(void *ptr)
305 {
306  SCFree(ptr);
307 }
308 
309 
310 #ifdef UNITTESTS
312 #endif /* UNITTESTS */
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1409
uint16_t flags
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1150
int(* AppLayerTxMatch)(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t flags, void *alstate, void *txv, const Signature *, const SigMatchCtx *)
Definition: detect.h:1136
#define SCLogDebug(...)
Definition: util-debug.h:335
int DetectSignatureSetAppProto(Signature *s, AppProto alproto)
#define unlikely(expr)
Definition: util-optimize.h:35
Data needed for Match()
Definition: detect.h:331
DetectSNMPVersionMode
const char * name
Definition: detect.h:1164
int DetectEngineInspectGenericList(ThreadVars *tv, const DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchData *smd, Flow *f, const uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
Do the content inspection & validation for a signature.
Signature container.
Definition: detect.h:496
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:317
main detection engine ctx
Definition: detect.h:724
int DetectBufferTypeGetByName(const char *name)
#define str(s)
#define SCCalloc(nm, a)
Definition: util-mem.h:197
#define SIG_FLAG_TOCLIENT
Definition: detect.h:242
void(* Free)(void *)
Definition: detect.h:1155
#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)
#define SIG_FLAG_TOSERVER
Definition: detect.h:241
#define SCEnter(...)
Definition: util-debug.h:337
#define PARSE_REGEX
uint8_t type
Definition: detect.h:323
#define SCReturnInt(x)
Definition: util-debug.h:341
const char * desc
Definition: detect.h:1166
void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:288
SigMatchCtx * ctx
Definition: detect.h:325
#define SCFree(a)
Definition: util-mem.h:228
PoolThreadReserved res
uint16_t tx_id
void DetectSNMPVersionRegister(void)
Registration function for snmp.procedure keyword.
#define SIGMATCH_NOOPT
Definition: detect.h:1332
int(* Match)(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1133
const char * url
Definition: detect.h:1167
struct DetectSNMPVersionData_ DetectSNMPVersionData
#define DOC_URL
Definition: suricata.h:86
#define MAX_SUBSTRINGS
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:232
Per thread variable structure.
Definition: threadvars.h:57
#define DOC_VERSION
Definition: suricata.h:91
uint16_t flags
Definition: detect.h:1158
Flow data structure.
Definition: flow.h:325
void DetectAppLayerInspectEngineRegister(const char *name, AppProto alproto, uint32_t dir, int progress, InspectEngineFuncPtr Callback)
register inspect engine at start up time
void(* RegisterTests)(void)
Definition: detect.h:1156
a single match condition for a signature
Definition: detect.h:322
enum DetectSNMPVersionMode mode