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