1 /* $Id$ */
2 /*
3 ** Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
4 ** Copyright (C) 2002-2013 Sourcefire, Inc.
5 ** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
6 ** Copyright (C) 2000,2001 Andrew R. Baker <andrewb@uab.edu>
7 **
8 ** This program is free software; you can redistribute it and/or modify
9 ** it under the terms of the GNU General Public License Version 2 as
10 ** published by the Free Software Foundation. You may not use, modify or
11 ** distribute this program under any other version of the GNU General
12 ** Public License.
13 **
14 ** This program is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ** GNU General Public License for more details.
18 **
19 ** You should have received a copy of the GNU General Public License
20 ** along with this program; if not, write to the Free Software
21 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 */
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27 #include <sys/resource.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <assert.h>
33 #include <errno.h>
34 #include <ctype.h>
35 #include <unistd.h>
36 #include <stdarg.h>
37 #include <pcap.h>
38 #ifdef HAVE_DUMBNET_H
39 #include <dumbnet.h>
40 #else
41 #include <dnet.h>
42 #endif
43
44 #ifdef HAVE_STRINGS_H
45 # include <strings.h>
46 #endif
47
48 #ifndef WIN32
49 # include <netdb.h>
50 # include <sys/socket.h>
51 # include <netinet/in.h>
52 # include <arpa/inet.h>
53 # include <grp.h>
54 # include <pwd.h>
55 # include <fnmatch.h>
56 #endif /* !WIN32 */
57
58 #include "encode.h"
59 #include "snort_bounds.h"
60 #include "rules.h"
61 #include "treenodes.h"
62 #include "parser.h"
63 #include "plugbase.h"
64 #include "plugin_enum.h"
65 #include "snort_debug.h"
66 #include "util.h"
67 #include "mstring.h"
68 #include "detect.h"
69 #include "fpcreate.h"
70 #include "log.h"
71 #include "generators.h"
72 #include "tag.h"
73 #include "signature.h"
74 #include "strlcatu.h"
75 #include "strlcpyu.h"
76 #include "sfthreshold.h"
77 #include "sfutil/sfthd.h"
78 #include "snort.h"
79 #include "event_queue.h"
80 #include "asn1.h"
81 #include "sfutil/sfghash.h"
82 #include "sp_preprocopt.h"
83 #include "detection-plugins/sp_icmp_type_check.h"
84 #include "detection-plugins/sp_ip_proto.h"
85 #include "detection-plugins/sp_pattern_match.h"
86 #include "detection-plugins/sp_flowbits.h"
87 #include "sf_vartable.h"
88 #include "ipv6_port.h"
89 #include "sfutil/sf_ip.h"
90 #include "sflsq.h"
91 #include "ppm.h"
92 #include "rate_filter.h"
93 #include "detection_filter.h"
94 #include "sfPolicy.h"
95 #include "sfutil/mpse.h"
96 #include "sfutil/sfrim.h"
97 #include "sfutil/sfportobject.h"
98 #include "sfutil/strvec.h"
99 #include "active.h"
100 #include "file_config.h"
101 #include "file_service_config.h"
102 #include "dynamic-plugins/sp_dynamic.h"
103 #include "dynamic-output/plugins/output.h"
104 #include "stream_common.h"
105
106 #ifdef SIDE_CHANNEL
107 # include "sidechannel.h"
108 #endif
109
110 #ifdef TARGET_BASED
111 # include "sftarget_reader.h"
112 #endif
113
114
115 /* Macros *********************************************************************/
116 #define ENABLE_ALL_RULES 1
117 #define ENABLE_RULE 1
118 #define ENABLE_ONE_RULE 0
119 #define MAX_RULE_OPTIONS 256
120 #define MAX_LINE_LENGTH 32768
121 #define MAX_IPLIST_ENTRIES 4096
122 #define DEFAULT_LARGE_RULE_GROUP 9
123 #define SF_IPPROTO_UNKNOWN -1
124 #define MAX_RULE_COUNT (65535 * 2)
125
126 /* Rule list order keywords
127 * This is separate from keywords because activation was used
128 * instead of activate */
129 #define RULE_LIST_TYPE__ALERT "alert"
130 #define RULE_LIST_TYPE__DROP "drop"
131 #define RULE_LIST_TYPE__LOG "log"
132 #define RULE_LIST_TYPE__PASS "pass"
133 #define RULE_LIST_TYPE__REJECT "reject"
134 #define RULE_LIST_TYPE__SDROP "sdrop"
135
136 #define RULE_PROTO_OPT__IP "ip"
137 #define RULE_PROTO_OPT__TCP "tcp"
138 #define RULE_PROTO_OPT__UDP "udp"
139 #define RULE_PROTO_OPT__ICMP "icmp"
140
141 #define RULE_DIR_OPT__DIRECTIONAL "->"
142 #define RULE_DIR_OPT__BIDIRECTIONAL "<>"
143
144 /* For user defined rule type */
145 #define RULE_TYPE_OPT__TYPE "type"
146
147 /* Rule options
148 * Only the basic ones are here. The detection options and preprocessor
149 * detection options define their own */
150 #define RULE_OPT__CLASSTYPE "classtype"
151 #define RULE_OPT__DETECTION_FILTER "detection_filter"
152 #define RULE_OPT__GID "gid"
153 #define RULE_OPT__MSG "msg"
154 #define RULE_OPT__METADATA "metadata"
155 #define RULE_OPT__LOGTO "logto"
156 #define RULE_OPT__PRIORITY "priority"
157 #define RULE_OPT__REFERENCE "reference"
158 #define RULE_OPT__REVISION "rev"
159 #define RULE_OPT__SID "sid"
160 #define RULE_OPT__TAG "tag"
161 #define RULE_OPT__THRESHOLD "threshold"
162
163 /* Metadata rule option keys */
164 #define METADATA_KEY__ENGINE "engine"
165 #define METADATA_KEY__OS "os"
166 #define METADATA_KEY__RULE_FLUSHING "rule-flushing"
167 #define METADATA_KEY__RULE_TYPE "rule-type"
168 #define METADATA_KEY__SOID "soid"
169 #define METADATA_KEY__SERVICE "service"
170
171 /* Metadata rule option values */
172 #define METADATA_VALUE__DECODE "decode"
173 #define METADATA_VALUE__DETECT "detect"
174 #define METADATA_VALUE__DISABLED "disabled"
175 #define METADATA_VALUE__ENABLED "enabled"
176 #define METADATA_VALUE__OFF "off"
177 #define METADATA_VALUE__ON "on"
178 #define METADATA_VALUE__PREPROC "preproc"
179 #define METADATA_VALUE__SHARED "shared"
180
181 /* MPLS payload types */
182 #ifdef MPLS
183 # define MPLS_PAYLOAD_OPT__IPV4 "ipv4"
184 # define MPLS_PAYLOAD_OPT__IPV6 "ipv6"
185 # define MPLS_PAYLOAD_OPT__ETHERNET "ethernet"
186 #endif
187
188 /* Tag options */
189 #define TAG_OPT__BYTES "bytes"
190 #define TAG_OPT__DST "dst"
191 #define TAG_OPT__HOST "host"
192 #define TAG_OPT__PACKETS "packets"
193 #define TAG_OPT__SECONDS "seconds"
194 #define TAG_OPT__SESSION "session"
195 #define TAG_OPT__SRC "src"
196 #define TAG_OPT__EXCLUSIVE "exclusive"
197
198 /* Dynamic library specifier option values */
199 #define DYNAMIC_LIB_OPT__FILE "file"
200 #define DYNAMIC_LIB_OPT__DIRECTORY "directory"
201
202 /* Threshold options */
203 #define THRESHOLD_OPT__COUNT "count"
204 #define THRESHOLD_OPT__GID "gen_id"
205 #define THRESHOLD_OPT__IP "ip"
206 #define THRESHOLD_OPT__SECONDS "seconds"
207 #define THRESHOLD_OPT__SID "sig_id"
208 #define THRESHOLD_OPT__TRACK "track"
209 #define THRESHOLD_OPT__TYPE "type"
210
211 #define THRESHOLD_TYPE__BOTH "both"
212 #define THRESHOLD_TYPE__LIMIT "limit"
213 #define THRESHOLD_TYPE__THRESHOLD "threshold"
214
215 #define THRESHOLD_TRACK__BY_DST "by_dst"
216 #define THRESHOLD_TRACK__BY_SRC "by_src"
217
218 #define RULE_STATE_OPT__DISABLED "disabled"
219 #define RULE_STATE_OPT__ENABLED "enabled"
220
221 #define DETECTION_OPT__BLEEDOVER_PORT_LIMIT "bleedover-port-limit"
222 #define DETECTION_OPT__BLEEDOVER_WARNINGS_ENABLED "bleedover-warnings-enabled"
223 #define DETECTION_OPT__DEBUG "debug"
224 #define DETECTION_OPT__DEBUG_PRINT_NOCONTENT_RULE_TESTS "debug-print-nocontent-rule-tests"
225 #define DETECTION_OPT__DEBUG_PRINT_RULE_GROUP_BUILD_DETAILS "debug-print-rule-group-build-details"
226 #define DETECTION_OPT__DEBUG_PRINT_RULE_GROUPS_UNCOMPILED "debug-print-rule-groups-uncompiled"
227 #define DETECTION_OPT__DEBUG_PRINT_RULE_GROUPS_COMPILED "debug-print-rule-groups-compiled"
228 #define DETECTION_OPT__ENABLE_SINGLE_RULE_GROUP "enable-single-rule-group"
229 #define DETECTION_OPT__MAX_QUEUE_EVENTS "max_queue_events"
230 #define DETECTION_OPT__NO_STREAM_INSERTS "no_stream_inserts"
231 #define DETECTION_OPT__SEARCH_METHOD "search-method"
232 #define DETECTION_OPT__SEARCH_OPTIMIZE "search-optimize"
233 #define DETECTION_OPT__SPLIT_ANY_ANY "split-any-any"
234 #define DETECTION_OPT__MAX_PATTERN_LEN "max-pattern-len"
235 #define DETECTION_OPT__DEBUG_PRINT_FAST_PATTERN "debug-print-fast-pattern"
236
237 /* Protected Content options - there should be a better way instead of declaring the type strings here */
238 #define PROTECTED_CONTENT_OPT__HASH_TYPE "hash"
239 #define EVENT_QUEUE_OPT__LOG "log"
240 #define EVENT_QUEUE_OPT__MAX_QUEUE "max_queue"
241 #define EVENT_QUEUE_OPT__ORDER_EVENTS "order_events"
242 #define EVENT_QUEUE_OPT__PROCESS_ALL_EVENTS "process_all_events"
243
244 #define EVENT_TRACE_OPT__FILE "file"
245 #define EVENT_TRACE_OPT__MAX_DATA "max_data"
246 #define EVENT_TRACE_OPT__FILE_DEFAULT "event_trace.txt"
247 #define EVENT_TRACE_OPT__MAX_DATA_DEFAULT 64
248
249 #define ORDER_EVENTS_OPT__CONTENT_LENGTH "content_length"
250 #define ORDER_EVENTS_OPT__PRIORITY "priority"
251
252 #define THRESHOLD_OPT__MEMCAP "memcap"
253
254 #define CHECKSUM_MODE_OPT__ALL "all"
255 #define CHECKSUM_MODE_OPT__NONE "none"
256 #define CHECKSUM_MODE_OPT__IP "ip"
257 #define CHECKSUM_MODE_OPT__NO_IP "noip"
258 #define CHECKSUM_MODE_OPT__TCP "tcp"
259 #define CHECKSUM_MODE_OPT__NO_TCP "notcp"
260 #define CHECKSUM_MODE_OPT__UDP "udp"
261 #define CHECKSUM_MODE_OPT__NO_UDP "noudp"
262 #define CHECKSUM_MODE_OPT__ICMP "icmp"
263 #define CHECKSUM_MODE_OPT__NO_ICMP "noicmp"
264
265 #define RULE_STATE_OPT__DISABLED "disabled"
266 #define RULE_STATE_OPT__ENABLED "enabled"
267
268 #define POLICY_MODE_PASSIVE "tap"
269 #define POLICY_MODE_INLINE "inline"
270 #define POLICY_MODE_INLINE_TEST "inline_test"
271
272 #ifdef PERF_PROFILING
273 # define PROFILE_OPT__FILENAME "filename"
274 # define PROFILE_OPT__PRINT "print"
275 # define PROFILE_OPT__ALL "all"
276 # define PROFILE_OPT__SORT "sort"
277 # define PROFILE_OPT__CHECKS "checks"
278 # define PROFILE_OPT__AVG_TICKS "avg_ticks"
279 # define PROFILE_OPT__TOTAL_TICKS "total_ticks"
280 # define PROFILE_OPT__MATCHES "matches"
281 # define PROFILE_OPT__NO_MATCHES "nomatches"
282 # define PROFILE_OPT__AVG_TICKS_PER_MATCH "avg_ticks_per_match"
283 # define PROFILE_OPT__AVG_TICKS_PER_NO_MATCH "avg_ticks_per_nomatch"
284 # define PROFILE_OPT__APPEND "append"
285 #endif
286
287 #ifdef PPM_MGR
288 # define PPM_OPT__MAX_PKT_TIME "max-pkt-time"
289 # define PPM_OPT__MAX_RULE_TIME "max-rule-time"
290 # define PPM_OPT__SUSPEND_TIMEOUT "suspend-timeout"
291 # define PPM_OPT__SUSPEND_EXP_RULES "suspend-expensive-rules"
292 # define PPM_OPT__THRESHOLD "threshold"
293 # define PPM_OPT__FAST_PATH_EXP_PKTS "fastpath-expensive-packets"
294 # define PPM_OPT__PKT_LOG "pkt-log"
295 # define PPM_OPT__RULE_LOG "rule-log"
296 # define PPM_OPT__ALERT "alert"
297 # define PPM_OPT__LOG "log"
298 # define PPM_OPT__DEBUG_PKTS "debug-pkts"
299 #endif
300
301 #ifdef ACTIVE_RESPONSE
302 #define RESPONSE_OPT__ATTEMPTS "attempts"
303 #define RESPONSE_OPT__DEVICE "device"
304 #define RESPONSE_OPT__DST_MAC "dst_mac"
305 #endif
306
307 #define ERR_PAIR_COUNT \
308 "%s has incorrect argument count; should be %d pairs.", ERR_KEY
309 #define ERR_NOT_PAIRED \
310 "%s is missing an option or argument to go with: %s.", ERR_KEY, pairs[0]
311 #define ERR_EXTRA_OPTION \
312 "%s has extra option of type: %s.", ERR_KEY, pairs[0]
313 #define ERR_BAD_OPTION \
314 "%s has unknown option: %s.", ERR_KEY, pairs[0]
315 #define ERR_BAD_VALUE \
316 "%s has unknown %s: %s.", ERR_KEY, pairs[0], pairs[1]
317 #define ERR_BAD_ARG_COUNT \
318 "%s has incorrect argument count.", ERR_KEY
319 #define ERR_CREATE \
320 "%s could not be created.", ERR_KEY
321 #define ERR_CREATE_EX \
322 "%s could not be created: %s.", ERR_KEY
323
324 // arbitrary conf file name used to allow initialization w/o conf
325 // (required for packet logging mode)
326 #define NULL_CONF "null"
327
328 /* Data types *****************************************************************/
329 typedef void (*ParseFunc)(SnortConfig *, SnortPolicy *, char *);
330 typedef void (*ParseConfigFunc)(SnortConfig *, char *);
331 typedef void (*ParseRuleOptFunc)(SnortConfig *, RuleTreeNode *, OptTreeNode *, RuleType, char *);
332
333 /* Used to determine whether or not to parse the keyword line based on
334 * whether or not we're parsing rules */
335 typedef enum _KeywordType
336 {
337 KEYWORD_TYPE__MAIN,
338 KEYWORD_TYPE__RULE,
339 KEYWORD_TYPE__ALL
340
341 } KeywordType;
342
343 typedef enum _VarType
344 {
345 VAR_TYPE__DEFAULT,
346 VAR_TYPE__PORTVAR,
347 VAR_TYPE__IPVAR
348
349 } VarType;
350
351 typedef struct _KeywordFunc
352 {
353 char *name;
354 KeywordType type;
355 int expand_vars;
356 int default_policy_only;
357 ParseFunc parse_func;
358
359 } KeywordFunc;
360
361 typedef struct _RuleOptFunc
362 {
363 char *name;
364 int args_required;
365 int only_once;
366 int detection;
367 ParseRuleOptFunc parse_func;
368
369 } RuleOptFunc;
370
371 typedef struct _ConfigFunc
372 {
373 char *name;
374 int args_required;
375 int only_once;
376 int default_policy_only;
377 ParseConfigFunc parse_func;
378
379 } ConfigFunc;
380
381 /* Tracking the port_list_t structure for printing and debugging at
382 * this point...temporarily... */
383 typedef struct
384 {
385 int rule_type;
386 int proto;
387 int icmp_type;
388 int ip_proto;
389 char *protocol;
390 char *src_port;
391 char *dst_port;
392 unsigned int gid;
393 unsigned int sid;
394 int dir;
395 char content;
396 char uricontent;
397
398 } port_entry_t;
399
400 typedef struct
401 {
402 int pl_max;
403 int pl_cnt;
404 port_entry_t pl_array[MAX_RULE_COUNT];
405
406 } port_list_t;
407
408 /* rule counts for port lists */
409 typedef struct
410 {
411 int src;
412 int dst;
413 int aa; /* any-any */
414 int sd; /* src+dst ports specified */
415 int nc; /* no content */
416
417 } rule_count_t;
418
419
420 /* Externs ********************************************************************/
421 extern VarNode *cmd_line_var_list;
422 extern char *snort_conf_file;
423 extern char *snort_conf_dir;
424 extern RuleOptConfigFuncNode *rule_opt_config_funcs;
425
426 /* Globals ********************************************************************/
427
428 char *file_name = NULL; /* current config file being processed */
429 int file_line = 0; /* current line being processed in the file */
430
431 /* Main parsing function uses this to indicate whether or not
432 * rules are to be parsed. */
433 static int parse_rules = 0;
434
435 /* Used when parsing rule options and a threshold is used. Need to add
436 * sid and gid to threshold object and they might not have been
437 * parsed yet. */
438 static THDX_STRUCT *thdx_tmp = NULL;
439
440 int rule_count = 0; /* number of rules generated */
441 int detect_rule_count = 0; /* number of detection rules generated */
442 int decode_rule_count = 0; /* number of decoder rules generated */
443 int preproc_rule_count = 0; /* number of preprocessor rules generated */
444 int head_count = 0; /* number of header blocks (chain heads?) */
445 int otn_count = 0; /* number of chains */
446
447 static port_list_t port_list;
448
449 static rule_count_t tcpCnt;
450 static rule_count_t udpCnt;
451 static rule_count_t icmpCnt;
452 static rule_count_t ipCnt;
453
454 rule_index_map_t *ruleIndexMap = NULL; /* rule index -> sid:gid map */
455
456 static void ParseAlert(SnortConfig *, SnortPolicy *, char *);
457 static void ParseDrop(SnortConfig *, SnortPolicy *, char *);
458 static void ParseLog(SnortConfig *, SnortPolicy *, char *);
459 static void ParsePass(SnortConfig *, SnortPolicy *, char *);
460 static void ParseReject(SnortConfig *, SnortPolicy *, char *);
461 static void ParseSdrop(SnortConfig *, SnortPolicy *, char *);
462
463 #ifdef TARGET_BASED
464 static void ParseAttributeTable(SnortConfig *, SnortPolicy *, char *);
465 #endif /* TARGET_BASED */
466 static void ParseConfig(SnortConfig *, SnortPolicy *, char *);
467 static void ParseDynamicDetectionInfo(SnortConfig *, SnortPolicy *, char *);
468 static void ParseDynamicEngineInfo(SnortConfig *, SnortPolicy *, char *);
469 static void ParseDynamicPreprocessorInfo(SnortConfig *, SnortPolicy *, char *);
470 # ifdef SIDE_CHANNEL
471 static void ParseDynamicSideChannelInfo(SnortConfig *, SnortPolicy *, char *);
472 # endif /* SIDE_CHANNEL */
473 static void ParseDynamicOutputInfo(SnortConfig *, SnortPolicy *, char *);
474 static void ParseEventFilter(SnortConfig *, SnortPolicy *, char *);
475 static void ParseInclude(SnortConfig *, SnortPolicy *, char *);
476 static void ParseIpVar(SnortConfig *, SnortPolicy *, char *);
477 static void ParsePortVar(SnortConfig *, SnortPolicy *, char *);
478 static void ParsePreprocessor(SnortConfig *, SnortPolicy *, char *);
479 static void ParseRateFilter(SnortConfig *, SnortPolicy *, char *);
480 static void ParseRuleState(SnortConfig *, SnortPolicy *, char *);
481 static void ParseRuleTypeDeclaration(SnortConfig *, SnortPolicy *, char *);
482 #ifdef SIDE_CHANNEL
483 static void ParseSideChannelModule(SnortConfig *, SnortPolicy *, char *);
484 static void ConfigSideChannel(SnortConfig *, char *);
485 #endif /* SIDE_CHANNEL */
486 static void ParseSuppress(SnortConfig *, SnortPolicy *, char *);
487 static void ParseThreshold(SnortConfig *, SnortPolicy *, char *);
488 static void ParseVar(SnortConfig *, SnortPolicy *, char *);
489 static void ParseFile(SnortConfig *, SnortPolicy *, char *);
490 static void AddVarToTable(SnortConfig *, char *, char *);
491
492 int ParseBool(char *arg);
493
494 static const KeywordFunc snort_conf_keywords[] =
495 {
496 /* Rule keywords */
497 { SNORT_CONF_KEYWORD__ALERT, KEYWORD_TYPE__RULE, 0, 0, ParseAlert },
498 { SNORT_CONF_KEYWORD__DROP, KEYWORD_TYPE__RULE, 0, 0, ParseDrop },
499 { SNORT_CONF_KEYWORD__BLOCK, KEYWORD_TYPE__RULE, 0, 0, ParseDrop },
500 { SNORT_CONF_KEYWORD__LOG, KEYWORD_TYPE__RULE, 0, 0, ParseLog },
501 { SNORT_CONF_KEYWORD__PASS, KEYWORD_TYPE__RULE, 0, 0, ParsePass },
502 { SNORT_CONF_KEYWORD__REJECT, KEYWORD_TYPE__RULE, 0, 0, ParseReject },
503 { SNORT_CONF_KEYWORD__SDROP, KEYWORD_TYPE__RULE, 0, 0, ParseSdrop },
504 { SNORT_CONF_KEYWORD__SBLOCK, KEYWORD_TYPE__RULE, 0, 0, ParseSdrop },
505
506 /* Non-rule keywords */
507 #ifdef TARGET_BASED
508 /* Need to fatal error if attribute_table is not configured in default
509 * policy. Since we're just skipping configuring non-default
510 * configurations with default only configuration types, set this to
511 * be configured for non-default policies and fatal in function */
512 { SNORT_CONF_KEYWORD__ATTRIBUTE_TABLE, KEYWORD_TYPE__MAIN, 1, 0, ParseAttributeTable },
513 #endif
514 { SNORT_CONF_KEYWORD__CONFIG, KEYWORD_TYPE__MAIN, 1, 0, ParseConfig },
515 { SNORT_CONF_KEYWORD__DYNAMIC_OUTPUT , KEYWORD_TYPE__MAIN, 1, 1, ParseDynamicOutputInfo },
516 { SNORT_CONF_KEYWORD__DYNAMIC_DETECTION, KEYWORD_TYPE__MAIN, 1, 1, ParseDynamicDetectionInfo },
517 { SNORT_CONF_KEYWORD__DYNAMIC_ENGINE, KEYWORD_TYPE__MAIN, 1, 1, ParseDynamicEngineInfo },
518 { SNORT_CONF_KEYWORD__DYNAMIC_PREPROC, KEYWORD_TYPE__MAIN, 1, 1, ParseDynamicPreprocessorInfo },
519 #ifdef SIDE_CHANNEL
520 { SNORT_CONF_KEYWORD__DYNAMIC_SIDE_CHAN, KEYWORD_TYPE__MAIN, 1, 1, ParseDynamicSideChannelInfo },
521 #endif /* SIDE_CHANNEL */
522 { SNORT_CONF_KEYWORD__EVENT_FILTER, KEYWORD_TYPE__MAIN, 1, 0, ParseEventFilter },
523 { SNORT_CONF_KEYWORD__INCLUDE, KEYWORD_TYPE__ALL, 1, 0, ParseInclude },
524 { SNORT_CONF_KEYWORD__IPVAR, KEYWORD_TYPE__MAIN, 0, 0, ParseIpVar },
525 { SNORT_CONF_KEYWORD__OUTPUT, KEYWORD_TYPE__MAIN, 1, 1, ParseOutput },
526 { SNORT_CONF_KEYWORD__PORTVAR, KEYWORD_TYPE__MAIN, 0, 0, ParsePortVar },
527 { SNORT_CONF_KEYWORD__PREPROCESSOR, KEYWORD_TYPE__MAIN, 1, 0, ParsePreprocessor },
528 { SNORT_CONF_KEYWORD__RATE_FILTER, KEYWORD_TYPE__MAIN, 0, 0, ParseRateFilter },
529 { SNORT_CONF_KEYWORD__RULE_STATE, KEYWORD_TYPE__MAIN, 1, 0, ParseRuleState },
530 { SNORT_CONF_KEYWORD__RULE_TYPE, KEYWORD_TYPE__ALL, 1, 0, ParseRuleTypeDeclaration },
531 #ifdef SIDE_CHANNEL
532 { SNORT_CONF_KEYWORD__SIDE_CHANNEL, KEYWORD_TYPE__MAIN, 1, 1, ParseSideChannelModule },
533 #endif /* SIDE_CHANNEL */
534 { SNORT_CONF_KEYWORD__SUPPRESS, KEYWORD_TYPE__MAIN, 0, 0, ParseSuppress },
535 { SNORT_CONF_KEYWORD__THRESHOLD, KEYWORD_TYPE__MAIN, 1, 0, ParseThreshold },
536 { SNORT_CONF_KEYWORD__VAR, KEYWORD_TYPE__MAIN, 0, 0, ParseVar },
537 { SNORT_CONF_KEYWORD__FILE, KEYWORD_TYPE__MAIN, 0, 1, ParseFile },
538 { NULL, KEYWORD_TYPE__ALL, 0, 0, NULL } /* Marks end of array */
539 };
540
541 static void ParseOtnClassType(SnortConfig *, RuleTreeNode *,
542 OptTreeNode *, RuleType, char *);
543 static void ParseOtnDetectionFilter(SnortConfig *, RuleTreeNode *,
544 OptTreeNode *, RuleType, char *);
545 static void ParseOtnGid(SnortConfig *, RuleTreeNode *,
546 OptTreeNode *, RuleType, char *);
547 static void ParseOtnLogTo(SnortConfig *, RuleTreeNode *,
548 OptTreeNode *, RuleType, char *);
549 static void ParseOtnMessage(SnortConfig *, RuleTreeNode *,
550 OptTreeNode *, RuleType, char *);
551 static void ParseOtnMetadata(SnortConfig *, RuleTreeNode *,
552 OptTreeNode *, RuleType, char *);
553 static void ParseOtnPriority(SnortConfig *, RuleTreeNode *,
554 OptTreeNode *, RuleType, char *);
555 static void ParseOtnReference(SnortConfig *, RuleTreeNode *,
556 OptTreeNode *, RuleType, char *);
557 static void ParseOtnRevision(SnortConfig *, RuleTreeNode *,
558 OptTreeNode *, RuleType, char *);
559 static void ParseOtnSid(SnortConfig *, RuleTreeNode *,
560 OptTreeNode *, RuleType, char *);
561 static void ParseOtnTag(SnortConfig *, RuleTreeNode *,
562 OptTreeNode *, RuleType, char *);
563 static void ParseOtnThreshold(SnortConfig *, RuleTreeNode *,
564 OptTreeNode *, RuleType, char *);
565
566 static const RuleOptFunc rule_options[] =
567 {
568 { RULE_OPT__CLASSTYPE, 1, 1, 0, ParseOtnClassType },
569 { RULE_OPT__DETECTION_FILTER, 1, 1, 1, ParseOtnDetectionFilter },
570 { RULE_OPT__GID, 1, 1, 0, ParseOtnGid },
571 { RULE_OPT__LOGTO, 1, 1, 0, ParseOtnLogTo },
572 { RULE_OPT__METADATA, 1, 0, 0, ParseOtnMetadata },
573 { RULE_OPT__MSG, 1, 1, 0, ParseOtnMessage },
574 { RULE_OPT__PRIORITY, 1, 1, 0, ParseOtnPriority },
575 { RULE_OPT__REFERENCE, 1, 0, 0, ParseOtnReference },
576 { RULE_OPT__REVISION, 1, 1, 0, ParseOtnRevision },
577 { RULE_OPT__SID, 1, 1, 0, ParseOtnSid },
578 { RULE_OPT__TAG, 1, 1, 0, ParseOtnTag },
579 { RULE_OPT__THRESHOLD, 1, 1, 1, ParseOtnThreshold },
580
581 { NULL, 0, 0, 0, NULL } /* Marks end of array */
582 };
583
584 #ifdef PERF_PROFILING
585 /* Internal prototypes used in lists below */
586 static void _ConfigProfilePreprocs(SnortConfig *, char *);
587 static void _ConfigProfileRules(SnortConfig *, char *);
588 #endif
589
590 static const ConfigFunc config_opts[] =
591 {
592 { CONFIG_OPT__ALERT_FILE, 1, 1, 1, ConfigAlertFile },
593 { CONFIG_OPT__ALERT_WITH_IFACE_NAME, 0, 1, 1, ConfigAlertWithInterfaceName },
594 { CONFIG_OPT__AUTOGEN_PREPROC_DECODER_RULES, 0, 1, 0, ConfigAutogenPreprocDecoderRules },
595 { CONFIG_OPT__ASN1, 1, 1, 1, ConfigAsn1 },
596 { CONFIG_OPT__BINDING, 1, 0, 1, ConfigBinding },
597 { CONFIG_OPT__BPF_FILE, 1, 1, 1, ConfigBpfFile },
598 { CONFIG_OPT__CHECKSUM_DROP, 0, 0, 0, ConfigChecksumDrop },
599 { CONFIG_OPT__CHECKSUM_MODE, 0, 0, 0, ConfigChecksumMode },
600 { CONFIG_OPT__CHROOT_DIR, 1, 1, 1, ConfigChrootDir },
601 { CONFIG_OPT__CLASSIFICATION, 1, 0, 0, ConfigClassification },
602 { CONFIG_OPT__DAEMON, 0, 1, 1, ConfigDaemon },
603 { CONFIG_OPT__DECODE_DATA_LINK, 0, 1, 1, ConfigDecodeDataLink },
604 { CONFIG_OPT__DECODE_ESP, 0, 1, 1, ConfigEnableEspDecoding },
605 { CONFIG_OPT__DEFAULT_RULE_STATE, 0, 1, 1, ConfigDefaultRuleState },
606 { CONFIG_OPT__DETECTION, 1, 0, 1, ConfigDetection }, /* This is reconfigurable */
607 { CONFIG_OPT__DETECTION_FILTER, 1, 1, 1, ConfigDetectionFilter },
608 { CONFIG_OPT__DISABLE_DECODE_ALERTS, 0, 1, 0, ConfigDisableDecodeAlerts },
609 { CONFIG_OPT__DISABLE_DECODE_DROPS, 0, 1, 0, ConfigDisableDecodeDrops },
610 #ifdef INLINE_FAILOPEN
611 { CONFIG_OPT__DISABLE_INLINE_FAILOPEN, 0, 1, 1, ConfigDisableInlineFailopen },
612 #endif
613 { CONFIG_OPT__DISABLE_IP_OPT_ALERTS, 0, 1, 0, ConfigDisableIpOptAlerts },
614 { CONFIG_OPT__DISABLE_IP_OPT_DROPS, 0, 1, 0, ConfigDisableIpOptDrops },
615 { CONFIG_OPT__DISABLE_TCP_OPT_ALERTS, 0, 1, 0, ConfigDisableTcpOptAlerts },
616 { CONFIG_OPT__DISABLE_TCP_OPT_DROPS, 0, 1, 0, ConfigDisableTcpOptDrops },
617 { CONFIG_OPT__DISABLE_TCP_OPT_EXP_ALERTS, 0, 1, 0, ConfigDisableTcpOptExperimentalAlerts },
618 { CONFIG_OPT__DISABLE_TCP_OPT_EXP_DROPS, 0, 1, 0, ConfigDisableTcpOptExperimentalDrops },
619 { CONFIG_OPT__DISABLE_TCP_OPT_OBS_ALERTS, 0, 1, 0, ConfigDisableTcpOptObsoleteAlerts },
620 { CONFIG_OPT__DISABLE_TCP_OPT_OBS_DROPS, 0, 1, 0, ConfigDisableTcpOptObsoleteDrops },
621 { CONFIG_OPT__DISABLE_TTCP_ALERTS, 0, 1, 0, ConfigDisableTTcpAlerts },
622 { CONFIG_OPT__DISABLE_TCP_OPT_TTCP_ALERTS, 0, 1, 0, ConfigDisableTTcpAlerts },
623 { CONFIG_OPT__DISABLE_TTCP_DROPS, 0, 1, 0, ConfigDisableTTcpDrops },
624 { CONFIG_OPT__DUMP_CHARS_ONLY, 0, 1, 1, ConfigDumpCharsOnly },
625 { CONFIG_OPT__DUMP_PAYLOAD, 0, 1, 1, ConfigDumpPayload },
626 { CONFIG_OPT__DUMP_PAYLOAD_VERBOSE, 0, 1, 1, ConfigDumpPayloadVerbose },
627 { CONFIG_OPT__ENABLE_DECODE_DROPS, 0, 1, 0, ConfigEnableDecodeDrops },
628 { CONFIG_OPT__ENABLE_DECODE_OVERSIZED_ALERTS, 0, 1, 0, ConfigEnableDecodeOversizedAlerts },
629 { CONFIG_OPT__ENABLE_DECODE_OVERSIZED_DROPS, 0, 1, 0, ConfigEnableDecodeOversizedDrops },
630 { CONFIG_OPT__ENABLE_DEEP_TEREDO_INSPECTION, 0, 1, 1, ConfigEnableDeepTeredoInspection },
631 { CONFIG_OPT__ENABLE_GTP_DECODING, 0, 1, 1, ConfigEnableGTPDecoding },
632 { CONFIG_OPT__ENABLE_IP_OPT_DROPS, 0, 1, 1, ConfigEnableIpOptDrops },
633 #ifdef MPLS
634 { CONFIG_OPT__ENABLE_MPLS_MULTICAST, 0, 1, 1, ConfigEnableMplsMulticast },
635 { CONFIG_OPT__ENABLE_MPLS_OVERLAPPING_IP, 0, 1, 1, ConfigEnableMplsOverlappingIp },
636 #endif
637 { CONFIG_OPT__ENABLE_TCP_OPT_DROPS, 0, 1, 0, ConfigEnableTcpOptDrops },
638 { CONFIG_OPT__ENABLE_TCP_OPT_EXP_DROPS, 0, 1, 0, ConfigEnableTcpOptExperimentalDrops },
639 { CONFIG_OPT__ENABLE_TCP_OPT_OBS_DROPS, 0, 1, 0, ConfigEnableTcpOptObsoleteDrops },
640 { CONFIG_OPT__ENABLE_TTCP_DROPS, 0, 1, 0, ConfigEnableTTcpDrops },
641 { CONFIG_OPT__ENABLE_TCP_OPT_TTCP_DROPS, 0, 1, 0, ConfigEnableTTcpDrops },
642 { CONFIG_OPT__EVENT_FILTER, 1, 1, 1, ConfigEventFilter },
643 { CONFIG_OPT__EVENT_QUEUE, 1, 1, 1, ConfigEventQueue },
644 { CONFIG_OPT__EVENT_TRACE, 0, 1, 1, ConfigEventTrace },
645 { CONFIG_OPT__REACT, 1, 1, 1, ConfigReact },
646 #ifdef ENABLE_RESPONSE3
647 { CONFIG_OPT__FLEXRESP2_INTERFACE, 1, 1, 1, ConfigFlexresp2Interface },
648 { CONFIG_OPT__FLEXRESP2_ATTEMPTS, 1, 1, 1, ConfigFlexresp2Attempts },
649 { CONFIG_OPT__FLEXRESP2_MEMCAP, 1, 1, 1, ConfigFlexresp2Memcap },
650 { CONFIG_OPT__FLEXRESP2_ROWS, 1, 1, 1, ConfigFlexresp2Rows },
651 #endif
652 #ifdef ACTIVE_RESPONSE
653 { CONFIG_OPT__RESPONSE, 1, 1, 1, ConfigResponse },
654 #endif
655 { CONFIG_OPT__FLOWBITS_SIZE, 1, 1, 1, ConfigFlowbitsSize },
656 { CONFIG_OPT__IGNORE_PORTS, 1, 0, 1, ConfigIgnorePorts },
657 { CONFIG_OPT__ALERT_VLAN, 0, 1, 1, ConfigIncludeVlanInAlert },
658 { CONFIG_OPT__INTERFACE, 1, 1, 1, ConfigInterface },
659 { CONFIG_OPT__IPV6_FRAG, 1, 1, 1, ConfigIpv6Frag },
660 { CONFIG_OPT__LAYER2RESETS, 1, 1, 1, ConfigLayer2Resets },
661 { CONFIG_OPT__LOG_DIR, 1, 1, 1, ConfigLogDir },
662 { CONFIG_OPT__DAQ_TYPE, 1, 1, 1, ConfigDaqType },
663 { CONFIG_OPT__DAQ_MODE, 1, 1, 1, ConfigDaqMode },
664 { CONFIG_OPT__DAQ_VAR, 1, 0, 1, ConfigDaqVar },
665 { CONFIG_OPT__DAQ_DIR, 1, 0, 1, ConfigDaqDir },
666 { CONFIG_OPT__DIRTY_PIG, 0, 1, 1, ConfigDirtyPig },
667 #ifdef TARGET_BASED
668 { CONFIG_OPT__MAX_ATTRIBUTE_HOSTS, 1, 1, 1, ConfigMaxAttributeHosts },
669 { CONFIG_OPT__MAX_ATTRIBUTE_SERVICES_PER_HOST, 1, 1, 1, ConfigMaxAttributeServicesPerHost },
670 { CONFIG_OPT__MAX_METADATA_SERVICES, 1, 1, 1, ConfigMaxMetadataServices },
671 { CONFIG_OPT__DISABLE_ATTRIBUTE_RELOAD, 0, 1, 1, ConfigDisableAttributeReload },
672 #endif
673 #ifdef MPLS
674 { CONFIG_OPT__MAX_MPLS_LABELCHAIN_LEN, 0, 1, 1, ConfigMaxMplsLabelChain },
675 { CONFIG_OPT__MPLS_PAYLOAD_TYPE, 0, 1, 1, ConfigMplsPayloadType },
676 #endif
677 { CONFIG_OPT__MIN_TTL, 1, 1, 0, ConfigMinTTL },
678 #ifdef NORMALIZER
679 { CONFIG_OPT__NEW_TTL, 1, 1, 0, ConfigNewTTL },
680 #endif
681 { CONFIG_OPT__NO_LOG, 0, 1, 1, ConfigNoLog },
682 { CONFIG_OPT__NO_PCRE, 0, 1, 1, ConfigNoPcre },
683 { CONFIG_OPT__NO_PROMISCUOUS, 0, 1, 1, ConfigNoPromiscuous },
684 { CONFIG_OPT__OBFUSCATE, 0, 1, 1, ConfigObfuscate },
685 { CONFIG_OPT__ORDER, 1, 1, 1, ConfigRuleListOrder },
686 { CONFIG_OPT__PAF_MAX, 1, 1, 0, ConfigPafMax },
687 { CONFIG_OPT__PKT_COUNT, 1, 1, 1, ConfigPacketCount },
688 { CONFIG_OPT__PKT_SNAPLEN, 1, 1, 1, ConfigPacketSnaplen },
689 { CONFIG_OPT__PCRE_MATCH_LIMIT, 1, 1, 1, ConfigPcreMatchLimit },
690 { CONFIG_OPT__PCRE_MATCH_LIMIT_RECURSION, 1, 1, 1, ConfigPcreMatchLimitRecursion },
691 /* XXX We can configure this on the command line - why not in config file ??? */
692 #ifdef NOT_UNTIL_WE_DAEMONIZE_AFTER_READING_CONFFILE
693 { CONFIG_OPT__PID_PATH, 1, 1, 1, ConfigPidPath },
694 #endif
695 { CONFIG_OPT__POLICY, 1, 1, 0, ConfigPolicy },
696 { CONFIG_OPT__IPS_POLICY_MODE, 1, 1, 0, ConfigIpsPolicyMode },
697 { CONFIG_OPT__NAP_POLICY_MODE, 1, 1, 0, ConfigNapPolicyMode },
698 { CONFIG_OPT__POLICY_VERSION , 1, 0, 0, ConfigPolicyVersion },
699 { CONFIG_OPT__PROTECTED_CONTENT , 1, 0, 0, ConfigProtectedContent },
700 #ifdef PPM_MGR
701 { CONFIG_OPT__PPM, 1, 0, 1, ConfigPPM },
702 #endif
703 #ifdef PERF_PROFILING
704 { CONFIG_OPT__PROFILE_PREPROCS, 0, 1, 1, _ConfigProfilePreprocs },
705 { CONFIG_OPT__PROFILE_RULES, 0, 1, 1, _ConfigProfileRules },
706 #endif
707 { CONFIG_OPT__QUIET, 0, 1, 1, ConfigQuiet },
708 { CONFIG_OPT__RATE_FILTER, 1, 1, 1, ConfigRateFilter },
709 { CONFIG_OPT__REFERENCE, 1, 0, 1, ConfigReference },
710 { CONFIG_OPT__REFERENCE_NET, 1, 1, 1, ConfigReferenceNet },
711 { CONFIG_OPT__SET_GID, 1, 1, 1, ConfigSetGid },
712 { CONFIG_OPT__SET_UID, 1, 1, 1, ConfigSetUid },
713 { CONFIG_OPT__SHOW_YEAR, 0, 1, 1, ConfigShowYear },
714 { CONFIG_OPT__SO_RULE_MEMCAP, 1, 1, 1, ConfigSoRuleMemcap },
715 { CONFIG_OPT__STATEFUL, 0, 1, 1, ConfigStateful },
716 { CONFIG_OPT__TAGGED_PACKET_LIMIT, 1, 1, 1, ConfigTaggedPacketLimit },
717 { CONFIG_OPT__THRESHOLD, 1, 1, 1, ConfigThreshold },
718 { CONFIG_OPT__UMASK, 1, 1, 1, ConfigUmask },
719 { CONFIG_OPT__UTC, 0, 1, 1, ConfigUtc },
720 { CONFIG_OPT__VERBOSE, 0, 1, 1, ConfigVerbose },
721 { CONFIG_OPT__VLAN_AGNOSTIC, 0, 1, 1, ConfigVlanAgnostic },
722 { CONFIG_OPT__ADDRESSSPACE_AGNOSTIC, 0, 1, 1, ConfigAddressSpaceAgnostic },
723 { CONFIG_OPT__LOG_IPV6_EXTRA, 0, 1, 1, ConfigLogIPv6Extra },
724 { CONFIG_OPT__DUMP_DYNAMIC_RULES_PATH, 1, 1, 1, ConfigDumpDynamicRulesPath },
725 { CONFIG_OPT__CONTROL_SOCKET_DIR, 1, 1, 1, ConfigControlSocketDirectory },
726 { CONFIG_OPT__FILE, 1, 1, 1, ConfigFile },
727 { CONFIG_OPT__TUNNEL_BYPASS, 1, 1, 1, ConfigTunnelVerdicts },
728 #ifdef SIDE_CHANNEL
729 { CONFIG_OPT__SIDE_CHANNEL, 0, 1, 1, ConfigSideChannel },
730 #endif
731 { CONFIG_OPT__MAX_IP6_EXTENSIONS, 1, 1, 1, ConfigMaxIP6Extensions },
732 { CONFIG_OPT__DISABLE_REPLACE, 0, 1, 0, ConfigDisableReplace },
733 #ifdef DUMP_BUFFER
734 { CONFIG_OPT__BUFFER_DUMP, 1, 1, 1, ConfigBufferDump },
735 { CONFIG_OPT__BUFFER_DUMP_ALERT, 1, 1, 1, ConfigBufferDump },
736 #endif
737 { NULL, 0, 0, 0, NULL } /* Marks end of array */
738 };
739
740 /* Used to determine if a config option has already been configured
741 * Gets zeroed when initially parsing a configuration file, then each
742 * index gets set to 1 as an option is configured. Maps to config_opts */
743 static uint8_t config_opt_configured[sizeof(config_opts) / sizeof(ConfigFunc)];
744
745
746 /* Private function prototypes ************************************************/
747 static void InitVarTables(SnortPolicy *);
748 static void InitPolicyMode(SnortPolicy *);
749 static void InitParser(void);
750 static int VarIsIpAddr(vartable_t *, char *);
751 static RuleType GetRuleType(char *);
752 static void CreateDefaultRules(SnortConfig *);
753 static void ParseConfigFile(SnortConfig *, SnortPolicy *, char *);
754 static int ValidateUserDefinedRuleType(SnortConfig *, char *);
755 static void IntegrityCheckRules(SnortConfig *);
756 static void ParseDynamicLibInfo(DynamicLibInfo *, char *);
757 static int GetRuleProtocol(char *);
758 static RuleTreeNode * ProcessHeadNode(SnortConfig *, RuleTreeNode *, ListHead *);
759 static int ContinuationCheck(char *);
760 static ListHead * CreateRuleType(SnortConfig *, char *, RuleType, int, ListHead *);
761 static int GetChecksumFlags(char *);
762 static int GetPolicyMode(char *,int );
763 static void OtnInit(SnortConfig *);
764 static void _ParseRuleTypeDeclaration(SnortConfig *, FILE *, char *, int);
765 static void printRuleListOrder(RuleListNode *);
766 static RuleListNode * addNodeToOrderedList(RuleListNode *, RuleListNode *, int);
767 static VarEntry * VarDefine(SnortConfig *, char *, char *);
768 static char * VarSearch(SnortConfig *, char *);
769 static char * ExpandVars(SnortConfig *, char *);
770 static VarEntry * VarAlloc(void);
771 static int ParsePort(SnortConfig *, char *, uint16_t *, uint16_t *, char *, int *);
772 static uint16_t ConvPort(char *, char *);
773 static char * ReadLine(FILE *);
774 static void DeleteVars(VarEntry *);
775 static int ValidateIPList(IpAddrSet *, char *);
776 static int PortVarDefine(SnortConfig *, char *, char *);
777 static void port_entry_free(port_entry_t *);
778 static int port_list_add_entry(port_list_t *, port_entry_t *);
779 #if 0
780 static port_entry_t * port_list_get(port_list_t *, int);
781 static void port_list_print(port_list_t *);
782 #endif
783 static void port_list_free(port_list_t *);
784 static void finish_portlist_table(FastPatternConfig *, char *, PortTable *);
785 static void PortTablesFinish(rule_port_tables_t *, FastPatternConfig *);
786 static rule_port_tables_t * PortTablesNew(void);
787 static int FinishPortListRule(rule_port_tables_t *, RuleTreeNode *, OptTreeNode *,
788 int, port_entry_t *, FastPatternConfig *);
789 static PortObject * ParsePortListTcpUdpPort(PortVarTable *, PortTable *, char *);
790 static int ParsePortList(RuleTreeNode *, PortVarTable *, PortTable *, char *, int, int);
791 static void ParseRule(SnortConfig *, SnortPolicy *, char *, RuleType, ListHead *);
792 static void TransferOutputConfigs(OutputConfig *, OutputConfig **);
793 static OutputConfig * DupOutputConfig(OutputConfig *);
794 static void RemoveOutputConfigs(OutputConfig **, int);
795 static void XferHeader(RuleTreeNode *, RuleTreeNode *);
796 static OptTreeNode * ParseRuleOptions(SnortConfig *, RuleTreeNode **,
797 char *, RuleType, int);
798 #ifndef SOURCEFIRE
799 static void DefineAllIfaceVars(SnortConfig *);
800 static void DefineIfaceVar(SnortConfig *, char *, uint8_t *, uint8_t *);
801 #endif
802
803 #ifdef DEBUG_MSGS
804 #if 0
805 static void DumpList(IpAddrNode *, int);
806 #endif
807 static void DumpChain(char *, int, int);
808 static void DumpRuleChains(RuleListNode *);
809 #endif
810 static int ProcessIP(SnortConfig *, char *, RuleTreeNode *, int, int);
811 static int TestHeader(RuleTreeNode *, RuleTreeNode *);
812 static void FreeRuleTreeNode(RuleTreeNode *rtn);
813 static void DestroyRuleTreeNode(RuleTreeNode *rtn);
814 static void AddrToFunc(RuleTreeNode *, int);
815 static void PortToFunc(RuleTreeNode *, int, int, int);
816 static void SetupRTNFuncList(RuleTreeNode *);
817 static void DisallowCrossTableDuplicateVars(SnortConfig *, char *, VarType);
818 static int mergeDuplicateOtn(SnortConfig *, OptTreeNode *, OptTreeNode *, RuleTreeNode *);
819 #if 0
820 #ifdef DEBUG_MSGS
821 static void PrintRtnPorts(RuleTreeNode *);
822 #endif
823 #endif
824
825 static void FreeRuleTreeNodes(SnortConfig *);
826 static void FreeOutputLists(ListHead *list);
827
828 static int ParseNetworkBindingLine(tSfPolicyConfig *, int, char **, char *);
829 static int ParseVlanBindingLine(tSfPolicyConfig *, int, char **, char *);
830 static int ParsePolicyIdBindingLine(tSfPolicyConfig *, int, char **, char *);
831
832 static RuleTreeNode * findHeadNode(SnortConfig *, RuleTreeNode *, tSfPolicyId);
833 static inline RuleTreeNode * createDynamicRuleTypeRtn(SnortConfig *, RuleTreeNode *);
834
835 // only keep drop rules
836 // if we are inline (and can actually drop),
837 // or we are going to just alert instead of drop,
838 // or we are going to ignore session data instead of drop.
839 // the alert case is tested for separately with ScTreatDropAsAlert().
ScKeepDropRules(SnortConfig * sc)840 static inline int ScKeepDropRules (SnortConfig * sc)
841 {
842 return ( ScIpsInlineModeNewConf(sc) || ScAdapterInlineModeNewConf(sc) || ScTreatDropAsIgnoreNewConf(sc) );
843 }
844
ScLoadAsDropRules(SnortConfig * sc)845 static inline int ScLoadAsDropRules (SnortConfig * sc)
846 {
847 return ( ScIpsInlineTestModeNewConf(sc) || ScAdapterInlineTestModeNewConf(sc) );
848 }
849
850 /****************************************************************************
851 * Function: ParseSnortConf()
852 *
853 * Read the rules file a line at a time and send each rule to the rule parser
854 * This is the first pass of the configuration file. It parses everything
855 * except the rules.
856 *
857 * Arguments: None
858 *
859 * Returns:
860 * SnortConfig *
861 * An initialized and configured snort configuration struct.
862 * This struct should be passed on the second pass of the
863 * configuration file to parse the rules.
864 *
865 ***************************************************************************/
ParseSnortConf(void)866 SnortConfig * ParseSnortConf(void)
867 {
868 SnortConfig *sc = SnortConfNew();
869 VarNode *tmp = cmd_line_var_list;
870 tSfPolicyId policy_id;
871
872 file_line = 0;
873 file_name = snort_conf_file ? snort_conf_file : NULL_CONF;
874
875 InitParser();
876
877 /* Setup the default rule action anchor points
878 * Need to do this now in case we get a user defined rule type */
879 CreateDefaultRules(sc);
880
881 sc->port_tables = PortTablesNew();
882
883 mpseInitSummary();
884 OtnInit(sc);
885
886 /* Used to store "config" configurations */
887 sc->config_table = sfghash_new(20, 0, 0, free);
888 if (sc->config_table == NULL)
889 {
890 ParseError("%s(%d) No memory to create config table.\n",
891 __FILE__, __LINE__);
892 }
893
894 sc->fast_pattern_config = FastPatternConfigNew();
895 sc->event_queue_config = EventQueueConfigNew();
896 sc->threshold_config = ThresholdConfigNew();
897 sc->rate_filter_config = RateFilter_ConfigNew();
898 sc->detection_filter_config = DetectionFilterConfigNew();
899 sc->ip_proto_only_lists = (SF_LIST **)SnortAlloc(NUM_IP_PROTOS * sizeof(SF_LIST *));
900
901 /* We're not going to parse rules on the first pass */
902 parse_rules = 0;
903
904 sc->policy_config = sfPolicyInit();
905 if (sc->policy_config == NULL)
906 {
907 ParseError("No memory to create policy configuration.\n");
908 }
909
910 /* Add the default policy */
911 policy_id = sfPolicyAdd(sc->policy_config, file_name);
912 sfSetDefaultPolicy(sc->policy_config, policy_id);
913 sfDynArrayCheckBounds((void **)&sc->targeted_policies, policy_id, &sc->num_policies_allocated);
914 sc->targeted_policies[policy_id] = SnortPolicyNew();
915 InitVarTables(sc->targeted_policies[policy_id]);
916 InitPolicyMode(sc->targeted_policies[policy_id]);
917 setParserPolicy(sc, policy_id);
918
919 #ifndef SOURCEFIRE
920 /* If snort is not run with root privileges, no interfaces will be defined,
921 * so user beware if an iface_ADDRESS variable is used in snort.conf and
922 * snort is not run as root (even if just in read mode) */
923 DefineAllIfaceVars(sc);
924 #endif
925
926 /* Add command line defined variables - duplicates will already
927 * have been resolved */
928 while (tmp != NULL)
929 {
930 AddVarToTable(sc, tmp->name, tmp->value);
931 tmp = tmp->next;
932 }
933
934 /* Initialize storage space for preprocessor defined rule options */
935 sc->preproc_rule_options = PreprocessorRuleOptionsNew();
936 if (sc->preproc_rule_options == NULL)
937 {
938 ParseError("Could not allocate storage for preprocessor rule options.\n");
939 }
940
941 if ( strcmp(file_name, NULL_CONF) )
942 ParseConfigFile(sc, sc->targeted_policies[policy_id], file_name);
943
944 /* We've picked up any targeted policy configs at this point so
945 * it's probably okay to parse them here */
946 for (policy_id = 0;
947 policy_id < sfPolicyNumAllocated(sc->policy_config);
948 policy_id++)
949 {
950 char *fname = sfPolicyGet(sc->policy_config, policy_id);
951
952 /* Already configured default policy */
953 if (policy_id == sfGetDefaultPolicy(sc->policy_config))
954 continue;
955
956 if (fname != NULL)
957 {
958 sfDynArrayCheckBounds(
959 (void **)&sc->targeted_policies, policy_id, &sc->num_policies_allocated);
960 sc->targeted_policies[policy_id] = SnortPolicyNew();
961
962 InitVarTables(sc->targeted_policies[policy_id]);
963 InitPolicyMode(sc->targeted_policies[policy_id]);
964 setParserPolicy(sc, policy_id);
965
966 /* Need to reset this for each targeted policy */
967 memset(config_opt_configured, 0, sizeof(config_opt_configured));
968
969 /* Add command line defined variables - duplicates will already
970 * have been resolved */
971 tmp = cmd_line_var_list;
972 while (tmp != NULL)
973 {
974 AddVarToTable(sc, tmp->name, tmp->value);
975 tmp = tmp->next;
976 }
977
978 /* Parse as include file so if the file is specified relative to
979 * the snort conf directory we'll pick it up */
980 ParseInclude(sc, sc->targeted_policies[policy_id], fname);
981 }
982 }
983
984 /* This can be initialized now since we've picked up any user
985 * defined rules */
986 sc->omd = OtnXMatchDataNew(sc->num_rule_types);
987
988 /* Reset these. The only issue in not reseting would be if we were
989 * parsing a command line again, but do it anyway */
990 file_name = NULL;
991 file_line = 0;
992
993 return sc;
994 }
995
ParsePolicyIdBindingLine(tSfPolicyConfig * config,int num_toks,char ** toks,char * fileName)996 static int ParsePolicyIdBindingLine(
997 tSfPolicyConfig *config,
998 int num_toks,
999 char **toks,
1000 char *fileName
1001 )
1002 {
1003 int i;
1004 int parsedPolicyId;
1005
1006 for (i = 0; i < num_toks; i++)
1007 {
1008 char *endp;
1009 if ( toks[i] )
1010 {
1011 errno = 0;
1012 parsedPolicyId = SnortStrtolRange(toks[i], &endp, 10, 0, USHRT_MAX);
1013 if ((errno == ERANGE) || (*endp != '\0'))
1014 return -1;
1015
1016 if ( sfPolicyIdAddBinding(config, parsedPolicyId, fileName) != 0)
1017 {
1018 return -1;
1019 //FatalError("Unable to add policy: policyId %d, file %s\n", parsedPolicyId, fileName);
1020 }
1021 }
1022 else
1023 {
1024 return -1;
1025 //FatalError("formating error in binding file: %s\n", aLine);
1026 }
1027 }
1028
1029 return 0;
1030 }
1031
ParseVlanBindingLine(tSfPolicyConfig * config,int num_toks,char ** toks,char * fileName)1032 static int ParseVlanBindingLine(
1033 tSfPolicyConfig *config,
1034 int num_toks,
1035 char **toks,
1036 char *fileName
1037 )
1038 {
1039 int i;
1040 int vlanId1=0, vlanId2=0;
1041
1042
1043 for (i = 0; i < num_toks; i++)
1044 {
1045 int num_tok2;
1046 char **toks2;
1047 int vlanId;
1048 unsigned pos;
1049 char *findStr1, *findStr2;
1050 char *endp;
1051 findStr1 = strchr(toks[i], '-');
1052 if ( findStr1 )
1053 {
1054 pos = findStr1 - toks[i];
1055 if ( pos == 0 || pos == (strlen(toks[i]) - 1) )
1056 {
1057 return -1;
1058 }
1059 findStr2 = strchr(findStr1+1, '-');
1060 if ( findStr2 )
1061 {
1062 return -1;
1063 }
1064 toks2 = mSplit(toks[i], "-", 2, &num_tok2, 0);
1065 if (num_tok2 == 2)
1066 {
1067 /* vlanId1 must be < SF_VLAN_BINDING_MAX -1
1068 to allow for an actual range */
1069 vlanId1 = SnortStrtolRange(toks2[0], &endp, 10, 0, SF_VLAN_BINDING_MAX-1);
1070 if( *endp )
1071 {
1072 mSplitFree(&toks2, num_tok2);
1073 return -1;
1074 }
1075 /* vlanId2 must be > vlanId1 */
1076 vlanId2 = SnortStrtolRange(toks2[1], &endp, 10, vlanId1+1, SF_VLAN_BINDING_MAX);
1077 if ( *endp )
1078 {
1079 mSplitFree(&toks2, num_tok2);
1080 return -1;
1081 }
1082 if ( (vlanId1 < 0)
1083 || (vlanId2 >= SF_VLAN_BINDING_MAX)
1084 || (vlanId1 > vlanId2) )
1085 {
1086 mSplitFree(&toks2, num_tok2);
1087 return -1;
1088 //FatalError("Invalid range: %d:%d\n", vlanId1, vlanId2);
1089 }
1090 for (vlanId = vlanId1; vlanId <= vlanId2; vlanId++)
1091 {
1092 if ( sfVlanAddBinding(config, vlanId, fileName) != 0)
1093 {
1094 mSplitFree(&toks2, num_tok2);
1095 return -1;
1096 //FatalError("Unable to add policy: vlan %d, file %s\n", vlanId, fileName);
1097 }
1098 }
1099 }
1100 else
1101 {
1102 mSplitFree(&toks2, num_tok2);
1103 return -1;
1104 }
1105 mSplitFree(&toks2, num_tok2);
1106 }
1107
1108 else if ( toks[i] )
1109 {
1110 vlanId = SnortStrtolRange(toks[i], &endp, 10, 0, SF_VLAN_BINDING_MAX-1);
1111 if( *endp )
1112 return -1;
1113 if ( (vlanId >= SF_VLAN_BINDING_MAX) || sfVlanAddBinding(config, vlanId, fileName) != 0)
1114 {
1115 return -1;
1116 //FatalError("Unable to add policy: vlan %d, file %s\n", vlanId, fileName);
1117 }
1118 }
1119 else
1120 {
1121 return -1;
1122 //FatalError("formating error in binding file: %s\n", aLine);
1123 }
1124 }
1125
1126 return 0;
1127 }
1128
ParseNetworkBindingLine(tSfPolicyConfig * config,int num_toks,char ** toks,char * fileName)1129 static int ParseNetworkBindingLine(
1130 tSfPolicyConfig *config,
1131 int num_toks,
1132 char **toks,
1133 char *fileName
1134 )
1135 {
1136 int i;
1137
1138 for (i = 0; i < num_toks; i++)
1139 {
1140 SFIP_RET status;
1141 sfcidr_t *sfip;
1142
1143 if( (sfip = sfip_alloc(toks[i], &status)) == NULL )
1144 {
1145 return -1;
1146 }
1147 if (sfNetworkAddBinding(config, sfip, fileName) != 0)
1148 {
1149 sfip_free(sfip);
1150 return -1;
1151 // FatalError("Unable to add policy: vlan %d, file %s\n", vlanId, fileName);
1152 }
1153
1154 sfip_free(sfip);
1155 }
1156
1157 return 0;
1158 }
1159
1160 #ifdef DEBUG_MSGS
DumpRuleChains(RuleListNode * rule_lists)1161 static void DumpRuleChains(RuleListNode *rule_lists)
1162 {
1163 RuleListNode *rule = rule_lists;
1164
1165 if (rule_lists == NULL)
1166 return;
1167
1168 while (rule != NULL)
1169 {
1170 DumpChain(rule->name, rule->mode, ETHERNET_TYPE_IP);
1171 DumpChain(rule->name, rule->mode, IPPROTO_TCP);
1172 DumpChain(rule->name, rule->mode, IPPROTO_UDP);
1173 DumpChain(rule->name, rule->mode, IPPROTO_ICMP);
1174
1175 rule = rule->next;
1176 }
1177 }
1178
1179 /****************************************************************************
1180 *
1181 * Function: DumpChain(RuleTreeNode *, char *, char *)
1182 *
1183 * Purpose: Iterate over RTNs calling DumpList on each
1184 *
1185 * Arguments: rtn_idx => the RTN index pointer
1186 * rulename => the name of the rule the list belongs to
1187 * listname => the name of the list being printed out
1188 *
1189 * Returns: void function
1190 *
1191 ***************************************************************************/
DumpChain(char * name,int mode,int proto)1192 static void DumpChain(char *name, int mode, int proto)
1193 {
1194 // XXX Not yet implemented - Rule chain dumping
1195 }
1196
1197 /****************************************************************************
1198 *
1199 * Function: DumpList(IpAddrNode*)
1200 *
1201 * Purpose: print out the chain lists by header block node group
1202 *
1203 * Arguments: node => the head node
1204 *
1205 * Returns: void function
1206 *
1207 ***************************************************************************/
1208 #if 0 // avoid warning: ‘DumpList’ defined but not used
1209 static void DumpList(IpAddrNode *idx, int negated)
1210 {
1211 DEBUG_WRAP(int i=0;);
1212 if(!idx)
1213 return;
1214
1215 while(idx != NULL)
1216 {
1217 DEBUG_WRAP(DebugMessage(DEBUG_RULES,
1218 "[%d] %s",
1219 i++, sfip_ntoa(idx->ip)););
1220
1221 if(negated)
1222 {
1223 DEBUG_WRAP(DebugMessage(DEBUG_RULES,
1224 " (EXCEPTION_FLAG Active)\n"););
1225 }
1226 else
1227 {
1228 DEBUG_WRAP(DebugMessage(DEBUG_RULES, "\n"););
1229 }
1230
1231 idx = idx->next;
1232 }
1233 }
1234 #endif /* 0 */
1235 #endif /* DEBUG */
1236
1237 /*
1238 * Finish adding the rule to the port tables
1239 *
1240 * 1) find the table this rule should belong to (src/dst/any-any tcp,udp,icmp,ip or nocontent)
1241 * 2) find an index for the sid:gid pair
1242 * 3) add all no content rules to a single no content port object, the ports are irrelevant so
1243 * make it a any-any port object.
1244 * 4) if it's an any-any rule with content, add to an any-any port object
1245 * 5) find if we have a port object with these ports defined, if so get it, otherwise create it.
1246 * a)do this for src and dst port
1247 * b)add the rule index/id to the portobject(s)
1248 * c)if the rule is bidir add the rule and port-object to both src and dst tables
1249 *
1250 */
FinishPortListRule(rule_port_tables_t * port_tables,RuleTreeNode * rtn,OptTreeNode * otn,int proto,port_entry_t * pe,FastPatternConfig * fp)1251 static int FinishPortListRule(rule_port_tables_t *port_tables, RuleTreeNode *rtn, OptTreeNode *otn,
1252 int proto, port_entry_t *pe, FastPatternConfig *fp)
1253 {
1254 int large_port_group = 0;
1255 int src_cnt = 0;
1256 int dst_cnt = 0;
1257 int rim_index;
1258 PortTable *dstTable;
1259 PortTable *srcTable;
1260 #ifdef TARGET_BASED
1261 PortTable *dstTable_noservice;
1262 PortTable *srcTable_noservice;
1263 #endif
1264 PortObject *aaObject;
1265 rule_count_t *prc;
1266
1267 #ifdef TARGET_BASED
1268 ServiceOverride service_override = otn->sigInfo.service_override;
1269 int num_services = otn->sigInfo.num_services;
1270
1271 if ( !IsAdaptiveConfigured() )
1272 otn->sigInfo.service_override = ServiceOverride_ElsePorts;
1273 else if ( service_override == ServiceOverride_Nil && num_services )
1274 otn->sigInfo.service_override = ServiceOverride_ElsePorts;
1275 else if ( service_override == ServiceOverride_Nil && !num_services )
1276 otn->sigInfo.service_override = ServiceOverride_OrPorts;
1277 #endif
1278 /* Select the Target PortTable for this rule, based on protocol, src/dst
1279 * dir, and if there is rule content */
1280 if (proto == IPPROTO_TCP)
1281 {
1282 dstTable = port_tables->tcp_dst;
1283 srcTable = port_tables->tcp_src;
1284 aaObject = port_tables->tcp_anyany;
1285 prc = &tcpCnt;
1286 #ifdef TARGET_BASED
1287 dstTable_noservice = port_tables->ns_tcp_dst;
1288 srcTable_noservice = port_tables->ns_tcp_src;
1289 #endif
1290 }
1291 else if (proto == IPPROTO_UDP)
1292 {
1293 dstTable = port_tables->udp_dst;
1294 srcTable = port_tables->udp_src;
1295 aaObject = port_tables->udp_anyany;
1296 prc = &udpCnt;
1297 #ifdef TARGET_BASED
1298 dstTable_noservice = port_tables->ns_udp_dst;
1299 srcTable_noservice = port_tables->ns_udp_src;
1300 #endif
1301 }
1302 else if (proto == IPPROTO_ICMP)
1303 {
1304 dstTable = port_tables->icmp_dst;
1305 srcTable = port_tables->icmp_src;
1306 aaObject = port_tables->icmp_anyany;
1307 prc = &icmpCnt;
1308 #ifdef TARGET_BASED
1309 dstTable_noservice = port_tables->ns_icmp_dst;
1310 srcTable_noservice = port_tables->ns_icmp_src;
1311 #endif
1312 }
1313 else if (proto == ETHERNET_TYPE_IP)
1314 {
1315 dstTable = port_tables->ip_dst;
1316 srcTable = port_tables->ip_src;
1317 aaObject = port_tables->ip_anyany;
1318 prc = &ipCnt;
1319 #ifdef TARGET_BASED
1320 dstTable_noservice = port_tables->ns_ip_dst;
1321 srcTable_noservice = port_tables->ns_ip_src;
1322 #endif
1323 }
1324 else
1325 {
1326 return -1;
1327 }
1328
1329 /* Count rules with both src and dst specific ports */
1330 if (!(rtn->flags & ANY_DST_PORT) && !(rtn->flags & ANY_SRC_PORT))
1331 {
1332 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
1333 "***\n***Info: src & dst ports are both specific"
1334 " >> gid=%u sid=%u src=%s dst=%s\n***\n",
1335 otn->sigInfo.generator, otn->sigInfo.id,
1336 pe->src_port, pe->dst_port););
1337
1338 prc->sd++;
1339 }
1340
1341 /* Create/find an index to store this rules sid and gid at,
1342 * and use as reference in Port Objects */
1343 rim_index = otn->ruleIndex;
1344
1345 /* Add up the nocontent rules */
1346 if (!pe->content && !pe->uricontent)
1347 prc->nc++;
1348
1349 /* If not an any-any rule test for port bleedover, if we are using a
1350 * single rule group, don't bother */
1351 if (!fpDetectGetSingleRuleGroup(fp) &&
1352 (rtn->flags & (ANY_DST_PORT|ANY_SRC_PORT)) != (ANY_DST_PORT|ANY_SRC_PORT))
1353 {
1354 if (!(rtn->flags & ANY_SRC_PORT))
1355 {
1356 src_cnt = PortObjectPortCount(rtn->src_portobject);
1357 if (src_cnt >= fpDetectGetBleedOverPortLimit(fp))
1358 large_port_group = 1;
1359 }
1360
1361 if (!(rtn->flags & ANY_DST_PORT))
1362 {
1363 dst_cnt = PortObjectPortCount(rtn->dst_portobject);
1364 if (dst_cnt >= fpDetectGetBleedOverPortLimit(fp))
1365 large_port_group = 1;
1366 }
1367
1368 if (large_port_group && fpDetectGetBleedOverWarnings(fp))
1369 {
1370
1371 LogMessage("***Bleedover Port Limit(%d) Exceeded for rule %u:%u "
1372 "(%d)ports: ", fpDetectGetBleedOverPortLimit(fp),
1373 otn->sigInfo.generator, otn->sigInfo.id,
1374 (src_cnt > dst_cnt) ? src_cnt : dst_cnt);
1375
1376 /* If logging to syslog, this will be all multiline */
1377 fflush(stdout); fflush(stderr);
1378 PortObjectPrintPortsRaw(rtn->src_portobject);
1379 LogMessage(" -> ");
1380 PortObjectPrintPortsRaw(rtn->dst_portobject);
1381 LogMessage(" adding to any-any group\n");
1382 fflush(stdout);fflush(stderr);
1383 }
1384 }
1385
1386 /* If an any-any rule add rule index to any-any port object
1387 * both content and no-content type rules go here if they are
1388 * any-any port rules...
1389 * If we have an any-any rule or a large port group or
1390 * were using a single rule group we make it an any-any rule. */
1391 if (((rtn->flags & (ANY_DST_PORT|ANY_SRC_PORT)) == (ANY_DST_PORT|ANY_SRC_PORT)) ||
1392 large_port_group || fpDetectGetSingleRuleGroup(fp))
1393 {
1394 if (proto == ETHERNET_TYPE_IP)
1395 {
1396 /* Add the IP rules to the higher level app protocol groups, if they apply
1397 * to those protocols. All IP rules should have any-any port descriptors
1398 * and fall into this test. IP rules that are not tcp/udp/icmp go only into the
1399 * IP table */
1400 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
1401 "Finishing IP any-any rule %u:%u\n",
1402 otn->sigInfo.generator,otn->sigInfo.id););
1403
1404 switch (GetOtnIpProto(otn))
1405 {
1406 case IPPROTO_TCP:
1407 PortObjectAddRule(port_tables->tcp_anyany, rim_index);
1408 tcpCnt.aa++;
1409 break;
1410
1411 case IPPROTO_UDP:
1412 PortObjectAddRule(port_tables->udp_anyany, rim_index);
1413 udpCnt.aa++;
1414 break;
1415
1416 case IPPROTO_ICMP:
1417 PortObjectAddRule(port_tables->icmp_anyany, rim_index);
1418 icmpCnt.aa++;
1419 break;
1420
1421 case -1: /* Add to all ip proto anyany port tables */
1422 PortObjectAddRule(port_tables->tcp_anyany, rim_index);
1423 tcpCnt.aa++;
1424
1425 PortObjectAddRule(port_tables->udp_anyany, rim_index);
1426 udpCnt.aa++;
1427
1428 PortObjectAddRule(port_tables->icmp_anyany, rim_index);
1429 icmpCnt.aa++;
1430
1431 break;
1432
1433 default:
1434 break;
1435 }
1436
1437 /* Add to the IP ANY ANY */
1438 PortObjectAddRule(aaObject, rim_index);
1439 prc->aa++;
1440 }
1441 else
1442 {
1443 /* For other protocols-tcp/udp/icmp add to the any any group */
1444 PortObjectAddRule(aaObject, rim_index);
1445 prc->aa++;
1446 }
1447
1448 return 0; /* done */
1449 }
1450
1451 /* add rule index to dst table if we have a specific dst port or port list */
1452 if (!(rtn->flags & ANY_DST_PORT))
1453 {
1454 PortObject *pox;
1455
1456 prc->dst++;
1457
1458 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
1459 "Finishing rule: dst port rule\n"););
1460
1461 /* find the proper port object */
1462 pox = PortTableFindInputPortObjectPorts(dstTable, rtn->dst_portobject);
1463 if (pox == NULL)
1464 {
1465 /* Create a permanent port object */
1466 pox = PortObjectDupPorts(rtn->dst_portobject);
1467 if (pox == NULL)
1468 {
1469 ParseError("Could not dup a port object - out of memory!\n");
1470 }
1471
1472 /* Add the port object to the table, and add the rule to the port object */
1473 PortTableAddObject(dstTable, pox);
1474 }
1475
1476 PortObjectAddRule(pox, rim_index);
1477
1478 /* if bidir, add this rule and port group to the src table */
1479 if (rtn->flags & BIDIRECTIONAL)
1480 {
1481 pox = PortTableFindInputPortObjectPorts(srcTable, rtn->dst_portobject);
1482 if (pox == NULL)
1483 {
1484 pox = PortObjectDupPorts(rtn->dst_portobject);
1485 if (pox == NULL)
1486 {
1487 ParseError("Could not dup a bidir-port object - out of memory!\n");
1488 }
1489
1490 PortTableAddObject(srcTable, pox);
1491 }
1492
1493 PortObjectAddRule(pox, rim_index);
1494 }
1495 #ifdef TARGET_BASED
1496 // Add to the NOSERVICE group
1497 if (IsAdaptiveConfigured()
1498 && (otn->sigInfo.num_services == 0 || otn->sigInfo.service_override == ServiceOverride_OrPorts))
1499 {
1500
1501 if ( otn->sigInfo.service_override == ServiceOverride_AndPorts )
1502 ParseError("Service override \"and-ports\" specified on a port only rule.");
1503
1504 pox = PortTableFindInputPortObjectPorts(dstTable_noservice, rtn->dst_portobject);
1505 if (pox == NULL)
1506 {
1507 pox = PortObjectDupPorts(rtn->dst_portobject);
1508
1509 if (pox == NULL)
1510 ParseError("Could not dup a port object - out of memory!");
1511
1512 PortTableAddObject(dstTable_noservice, pox);
1513 }
1514
1515 PortObjectAddRule(pox, rim_index);
1516 }
1517 #endif // TARGET_BASED
1518 }
1519
1520 /* add rule index to src table if we have a specific src port or port list */
1521 if (!(rtn->flags & ANY_SRC_PORT))
1522 {
1523 PortObject *pox;
1524
1525 prc->src++;
1526
1527 pox = PortTableFindInputPortObjectPorts(srcTable, rtn->src_portobject);
1528 if (pox == NULL)
1529 {
1530 pox = PortObjectDupPorts(rtn->src_portobject);
1531 if (pox == NULL)
1532 {
1533 ParseError("Could not dup a port object - out of memory!\n");
1534 }
1535
1536 PortTableAddObject(srcTable, pox);
1537 }
1538
1539 PortObjectAddRule(pox, rim_index);
1540
1541 /* if bidir, add this rule and port group to the dst table */
1542 if (rtn->flags & BIDIRECTIONAL)
1543 {
1544 pox = PortTableFindInputPortObjectPorts(dstTable, rtn->src_portobject);
1545 if (pox == NULL)
1546 {
1547 pox = PortObjectDupPorts(rtn->src_portobject);
1548 if (pox == NULL)
1549 {
1550 ParseError("Could not dup a bidir-port object - out "
1551 "of memory!\n");
1552 }
1553
1554 PortTableAddObject(dstTable, pox);
1555 }
1556
1557 PortObjectAddRule(pox, rim_index);
1558 }
1559
1560 #ifdef TARGET_BASED
1561 // Add to the NOSERVICE group
1562 if (IsAdaptiveConfigured()
1563 && (otn->sigInfo.num_services == 0 || otn->sigInfo.service_override == ServiceOverride_OrPorts))
1564 {
1565 if ( otn->sigInfo.service_override == ServiceOverride_AndPorts )
1566 ParseError("Service override \"and-ports\" specified on a port only rule.");
1567
1568 /* find the proper port object */
1569 pox = PortTableFindInputPortObjectPorts(srcTable_noservice, rtn->src_portobject);
1570 if (pox == NULL)
1571 {
1572 pox = PortObjectDupPorts(rtn->src_portobject);
1573
1574 if (pox == NULL)
1575 ParseError("Could not dup a port object - out of memory!\n");
1576
1577 PortTableAddObject(srcTable_noservice, pox);
1578 }
1579
1580 PortObjectAddRule(pox, rim_index);
1581 }
1582 #endif // TARGET_BASED
1583 }
1584
1585 return 0;
1586 }
1587 /*
1588 * Parse a port string as a port var, and create or find a port object for it,
1589 * and add it to the port var table. These are used by the rtn's
1590 * as src and dst port lists for final rtn/otn processing.
1591 *
1592 * These should not be confused with the port objects used to merge ports and rules
1593 * to build PORT_GROUP objects. Those are generated after the otn processing.
1594 *
1595 */
ParsePortListTcpUdpPort(PortVarTable * pvt,PortTable * noname,char * port_str)1596 static PortObject * ParsePortListTcpUdpPort(PortVarTable *pvt,
1597 PortTable *noname, char *port_str)
1598 {
1599 PortObject * portobject;
1600 //PortObject * pox;
1601 char * errstr=0;
1602 POParser poparser;
1603
1604 if ((pvt == NULL) || (noname == NULL) || (port_str == NULL))
1605 return NULL;
1606
1607 /* 1st - check if we have an any port */
1608 if( strcasecmp(port_str,"any")== 0 )
1609 {
1610 portobject = PortVarTableFind(pvt, "any");
1611 if (portobject == NULL)
1612 ParseError("PortVarTable missing an 'any' variable.");
1613
1614 return portobject;
1615 }
1616
1617 /* 2nd - check if we have a PortVar */
1618 else if( port_str[0]=='$' )
1619 {
1620 /*||isalpha(port_str[0])*/ /*TODO: interferes with protocol names for ports*/
1621 char * name = port_str + 1;
1622
1623 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"PortVarTableFind: finding '%s'\n", port_str););
1624
1625 /* look it up in the port var table */
1626 portobject = PortVarTableFind(pvt, name);
1627 if (portobject == NULL)
1628 ParseError("***PortVar Lookup failed on '%s'.", port_str);
1629
1630 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"PortVarTableFind: '%s' found!\n", port_str););
1631 }
1632
1633 /* 3rd - and finally process a raw port list */
1634 else
1635 {
1636 /* port list = [p,p,p:p,p,...] or p or p:p , no embedded spaces due to tokenizer */
1637 PortObject * pox;
1638
1639 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
1640 "parser.c->PortObjectParseString: parsing '%s'\n",port_str););
1641
1642 portobject = PortObjectParseString(pvt, &poparser, 0, port_str, 0);
1643
1644 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
1645 "parser.c->PortObjectParseString: '%s' done.\n",port_str););
1646
1647 if( !portobject )
1648 {
1649 errstr = PortObjectParseError( &poparser );
1650 ParseError("***Rule--PortVar Parse error: (pos=%d,error=%s)\n>>%s\n>>%*s\n",
1651 poparser.pos,errstr,port_str,poparser.pos,"^");
1652 }
1653
1654 /* check if we already have this port object in the un-named port var table ... */
1655 pox = PortTableFindInputPortObjectPorts(noname, portobject);
1656 if( pox )
1657 {
1658 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
1659 "parser.c: already have '%s' as a PortObject - "
1660 "calling PortObjectFree(portbject) line=%d\n",port_str,__LINE__ ););
1661 PortObjectFree( portobject );
1662 portobject = pox;
1663 }
1664 else
1665 {
1666 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
1667 "parser.c: adding '%s' as a PortObject line=%d\n",port_str,__LINE__ ););
1668 /* Add to the un-named port var table */
1669 if (PortTableAddObject(noname, portobject))
1670 {
1671 ParseError("Unable to add raw port object to unnamed "
1672 "port var table, out of memory!\n");
1673 }
1674 }
1675 }
1676
1677 return portobject;
1678 }
1679 #ifdef XXXXX
1680 /*
1681 * Extract the Icmp Type field to determine the PortGroup.
1682 */
GetPortListIcmpPortObject(OptTreeNode * otn,PortTable * rulesPortTable,PortObject * anyAnyPortObject)1683 PortObject * GetPortListIcmpPortObject( OptTreeNode * otn, PortTable * rulesPortTable, PortObject * anyAnyPortObject )
1684 {
1685 PortObject * portobject=0;
1686 int type;
1687 IcmpTypeCheckData * IcmpType;
1688
1689 IcmpType = (IcmpTypeCheckData *)otn->ds_list[PLUGIN_ICMP_TYPE];
1690
1691 if( IcmpType && (IcmpType->operator == ICMP_TYPE_TEST_EQ) )
1692 {
1693 type = IcmpType->icmp_type;
1694 }
1695 else
1696 {
1697 return anyAnyPortObject;
1698 }
1699
1700 /* TODO: optimize */
1701 return anyAnyPortObject;
1702 }
1703 /*
1704 * Extract the IP Protocol field to determine the PortGroup.
1705 */
GetPortListIPPortObject(OptTreeNode * otn,PortTable * rulesPortTable,PortObject * anyAnyPortObject)1706 PortObject * GetPortListIPPortObject( OptTreeNode * otn,PortTable * rulesPortTable, PortObject * anyAnyPortObject )
1707 {
1708 if (GetOtnIpProto(otn) == -1)
1709 return anyAnyPortObject;
1710
1711 /* TODO: optimize */
1712 return anyAnyPortObject;
1713 }
1714
1715 #if 0
1716 Not currently used
1717 /*
1718 * Extract the Icmp Type field to determine the PortGroup.
1719 */
1720 static
1721 int GetOtnIcmpType(OptTreeNode * otn )
1722 {
1723 int type;
1724 IcmpTypeCheckData * IcmpType;
1725
1726 IcmpType = (IcmpTypeCheckData *)otn->ds_list[PLUGIN_ICMP_TYPE];
1727
1728 if( IcmpType && (IcmpType->operator == ICMP_TYPE_TEST_EQ) )
1729 {
1730 type = IcmpType->icmp_type;
1731 }
1732 else
1733 {
1734 return -1;
1735 }
1736
1737 return -1;
1738 }
1739 #endif
1740
1741 #endif /* XXXX - PORTLISTS */
1742 /*
1743 * Process the rule, add it to the appropriate PortObject
1744 * and add the PortObject to the rtn.
1745 *
1746 * TCP/UDP rules use ports/portlists, icmp uses the icmp type field and ip uses the protocol
1747 * field as a dst port for the purposes of looking up a rule group as packets are being
1748 * processed.
1749 *
1750 * TCP/UDP- use src/dst ports
1751 * ICMP - use icmp type as dst port,src=-1
1752 * IP - use protocol as dst port,src=-1
1753 *
1754 * rtn - proto_node
1755 * port_str - port list string or port var name
1756 * proto - protocol
1757 * dst_flag - dst or src port flag, true = dst, false = src
1758 *
1759 */
ParsePortList(RuleTreeNode * rtn,PortVarTable * pvt,PortTable * noname,char * port_str,int proto,int dst_flag)1760 static int ParsePortList(RuleTreeNode *rtn, PortVarTable *pvt, PortTable *noname,
1761 char *port_str, int proto, int dst_flag)
1762 {
1763 PortObject *portobject = NULL; /* src or dst */
1764
1765 /* Get the protocol specific port object */
1766 if( proto == IPPROTO_TCP || proto == IPPROTO_UDP )
1767 {
1768 portobject = ParsePortListTcpUdpPort(pvt, noname, port_str);
1769 }
1770 else /* ICMP, IP - no real ports just Type and Protocol */
1771 {
1772 portobject = PortVarTableFind(pvt, "any");
1773 if (portobject == NULL)
1774 {
1775 ParseError("PortVarTable missing an 'any' variable\n");
1776 }
1777 }
1778
1779 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"Rule-PortVar Parsed: %s \n",port_str););
1780
1781 /* !ports - port lists can be mixed 80:90,!82,
1782 * so the old NOT flag is depracated for port lists
1783 */
1784
1785 /* set up any any flags */
1786 if( PortObjectHasAny(portobject) )
1787 {
1788 if( dst_flag )
1789 rtn->flags |= ANY_DST_PORT;
1790 else
1791 rtn->flags |= ANY_SRC_PORT;
1792 }
1793
1794 /* check for a pure not rule - fatal if we find one */
1795 if( PortObjectIsPureNot( portobject ) )
1796 {
1797 ParseError("Pure NOT ports are not allowed!");
1798 /*
1799 if( dst_flag )
1800 rtn->flags |= EXCEPT_DST_PORT;
1801 else
1802 rtn->flags |= EXCEPT_SRC_PORT;
1803 */
1804 }
1805
1806 /*
1807 * set to the port object for this rules src/dst port,
1808 * these are used during rtn/otn port verification of the rule.
1809 */
1810
1811 if (dst_flag)
1812 rtn->dst_portobject = portobject;
1813 else
1814 rtn->src_portobject = portobject;
1815
1816 return 0;
1817 }
1818
1819 /*
1820 * ParseIpsPortList() will create portlist for portocol specific and only for IPS policy at the snort
1821 * process bringup, it will be used to enable/disable detection on packet.
1822 */
ParseIpsPortList(SnortConfig * sc,IpProto protocol)1823 IpsPortFilter** ParseIpsPortList (SnortConfig *sc, IpProto protocol)
1824 {
1825 tSfPolicyId policyId;
1826 IpsPortFilter *ips_portfilter;
1827 bool ignore_any = false;
1828
1829 // Allocate memory for each policy to hold port filter list
1830 IpsPortFilter **ips_port_filter_list = ( IpsPortFilter** ) SnortAlloc( sizeof(IpsPortFilter*) * sfPolicyNumAllocated(sc->policy_config) );
1831
1832 if ( !ips_port_filter_list )
1833 {
1834 ParseError("IPS portlist memory allocation failed\n");
1835 return NULL;
1836 }
1837
1838 ignore_any = getStreamIgnoreAnyConfig(sc, protocol);
1839 for (policyId = 0; policyId < sfPolicyNumAllocated(sc->policy_config); policyId++)
1840 {
1841 ips_portfilter = NULL;
1842 // Create port filter list for default and IPS policy
1843 if ( (policyId == 0) || (!getStreamPolicyConfig(policyId, 0)) )
1844 {
1845 ips_portfilter = ( IpsPortFilter* ) SnortAlloc( sizeof(IpsPortFilter) );
1846 if ( ips_portfilter )
1847 {
1848 ips_portfilter->parserPolicyId = policyId;
1849 setPortFilterList(sc, ips_portfilter->port_filter, IPPROTO_UDP, ignore_any, policyId);
1850 ips_port_filter_list[ policyId ] = ips_portfilter;
1851 } else
1852 {
1853 ParseError("Failed to allocate memory for port filter list policy id :%d \n",policyId);
1854 return NULL;
1855 }
1856 } else
1857 {
1858 // NAP policy port filter list is created in pre-processor check
1859 ips_port_filter_list[ policyId ] = NULL;
1860 }
1861 }
1862 return ips_port_filter_list;
1863 }
1864
1865 /****************************************************************************
1866 *
1867 * Function: CheckForIPListConflicts
1868 *
1869 * Purpose: Checks For IP List Conflicts in a RuleTreeNode. Such as
1870 * negations that are overlapping and more general are not allowed.
1871 *
1872 * For example, the following is not allowed:
1873 *
1874 * [1.1.0.0/16,!1.0.0.0/8]
1875 *
1876 * The following is allowed though (not overlapping):
1877 *
1878 * [1.1.0.0/16,!2.0.0.0/8]
1879 *
1880 * Arguments: addrset -- IpAddrSet pointer.
1881 *
1882 * Returns: -1 if IP is empty, 1 if a conflict exists and 0 otherwise.
1883 *
1884 ***************************************************************************/
CheckForIPListConflicts(IpAddrSet * addrset)1885 int CheckForIPListConflicts(IpAddrSet *addrset)
1886 {
1887 /* Conflict checking takes place inside the SFIP library */
1888 return 0;
1889 }
1890
1891 /****************************************************************************
1892 *
1893 * Function: AddRuleFuncToList(int (*func)(), RuleTreeNode *)
1894 *
1895 * Purpose: Adds RuleTreeNode associated detection functions to the
1896 * current rule's function list
1897 *
1898 * Arguments: *func => function pointer to the detection function
1899 * rtn => pointer to the current rule
1900 *
1901 * Returns: void function
1902 *
1903 ***************************************************************************/
AddRuleFuncToList(int (* rfunc)(Packet *,struct _RuleTreeNode *,struct _RuleFpList *,int),RuleTreeNode * rtn)1904 void AddRuleFuncToList(int (*rfunc) (Packet *, struct _RuleTreeNode *, struct _RuleFpList *, int), RuleTreeNode * rtn)
1905 {
1906 RuleFpList *idx;
1907
1908 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Adding new rule to list\n"););
1909
1910 idx = rtn->rule_func;
1911 if(idx == NULL)
1912 {
1913 rtn->rule_func = (RuleFpList *)SnortAlloc(sizeof(RuleFpList));
1914
1915 rtn->rule_func->RuleHeadFunc = rfunc;
1916 }
1917 else
1918 {
1919 while(idx->next != NULL)
1920 idx = idx->next;
1921
1922 idx->next = (RuleFpList *)SnortAlloc(sizeof(RuleFpList));
1923 idx = idx->next;
1924 idx->RuleHeadFunc = rfunc;
1925 }
1926 }
1927
1928
1929 /****************************************************************************
1930 *
1931 * Function: SetupRTNFuncList(RuleTreeNode *)
1932 *
1933 * Purpose: Configures the function list for the rule header detection
1934 * functions (addrs and ports)
1935 *
1936 * Arguments: rtn => the pointer to the current rules list entry to attach to
1937 *
1938 * Returns: void function
1939 *
1940 ***************************************************************************/
SetupRTNFuncList(RuleTreeNode * rtn)1941 static void SetupRTNFuncList(RuleTreeNode * rtn)
1942 {
1943 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Initializing RTN function list!\n"););
1944 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Functions: "););
1945
1946 if(rtn->flags & BIDIRECTIONAL)
1947 {
1948 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"CheckBidirectional->\n"););
1949 AddRuleFuncToList(CheckBidirectional, rtn);
1950 }
1951 else
1952 {
1953 /* Attach the proper port checking function to the function list */
1954 /*
1955 * the in-line "if's" check to see if the "any" or "not" flags have
1956 * been set so the PortToFunc call can determine which port testing
1957 * function to attach to the list
1958 */
1959 PortToFunc(rtn, (rtn->flags & ANY_DST_PORT ? 1 : 0),
1960 (rtn->flags & EXCEPT_DST_PORT ? 1 : 0), DST);
1961
1962 /* as above */
1963 PortToFunc(rtn, (rtn->flags & ANY_SRC_PORT ? 1 : 0),
1964 (rtn->flags & EXCEPT_SRC_PORT ? 1 : 0), SRC);
1965
1966 /* link in the proper IP address detection function */
1967 AddrToFunc(rtn, SRC);
1968
1969 /* last verse, same as the first (but for dest IP) ;) */
1970 AddrToFunc(rtn, DST);
1971 }
1972
1973 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"RuleListEnd\n"););
1974
1975 /* tack the end (success) function to the list */
1976 AddRuleFuncToList(RuleListEnd, rtn);
1977 }
1978
1979 /****************************************************************************
1980 *
1981 * Function: AddrToFunc(RuleTreeNode *, u_long, u_long, int, int)
1982 *
1983 * Purpose: Links the proper IP address testing function to the current RTN
1984 * based on the address, netmask, and addr flags
1985 *
1986 * Arguments: rtn => the pointer to the current rules list entry to attach to
1987 * ip => IP address of the current rule
1988 * mask => netmask of the current rule
1989 * exception_flag => indicates that a "!" has been set for this
1990 * address
1991 * mode => indicates whether this is a rule for the source
1992 * or destination IP for the rule
1993 *
1994 * Returns: void function
1995 *
1996 ***************************************************************************/
AddrToFunc(RuleTreeNode * rtn,int mode)1997 static void AddrToFunc(RuleTreeNode * rtn, int mode)
1998 {
1999 /*
2000 * if IP and mask are both 0, this is a "any" IP and we don't need to
2001 * check it
2002 */
2003 switch(mode)
2004 {
2005 case SRC:
2006 if((rtn->flags & ANY_SRC_IP) == 0)
2007 {
2008 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"CheckSrcIP -> "););
2009 AddRuleFuncToList(CheckSrcIP, rtn);
2010 }
2011
2012 break;
2013
2014 case DST:
2015 if((rtn->flags & ANY_DST_IP) == 0)
2016 {
2017 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"CheckDstIP -> "););
2018 AddRuleFuncToList(CheckDstIP, rtn);
2019 }
2020
2021 break;
2022 }
2023 }
2024
2025 /****************************************************************************
2026 *
2027 * Function: PortToFunc(RuleTreeNode *, int, int, int)
2028 *
2029 * Purpose: Links in the port analysis function for the current rule
2030 *
2031 * Arguments: rtn => the pointer to the current rules list entry to attach to
2032 * any_flag => accept any port if set
2033 * except_flag => indicates negation (logical NOT) of the test
2034 * mode => indicates whether this is a rule for the source
2035 * or destination port for the rule
2036 *
2037 * Returns: void function
2038 *
2039 ***************************************************************************/
PortToFunc(RuleTreeNode * rtn,int any_flag,int except_flag,int mode)2040 static void PortToFunc(RuleTreeNode * rtn, int any_flag, int except_flag, int mode)
2041 {
2042 /*
2043 * if the any flag is set we don't need to perform any test to match on
2044 * this port
2045 */
2046 if(any_flag)
2047 return;
2048
2049 /* if the except_flag is up, test with the "NotEq" funcs */
2050 if(except_flag)
2051 {
2052 switch(mode)
2053 {
2054 case SRC:
2055 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"CheckSrcPortNotEq -> "););
2056 AddRuleFuncToList(CheckSrcPortNotEq, rtn);
2057 break;
2058
2059
2060 case DST:
2061 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"CheckDstPortNotEq -> "););
2062 AddRuleFuncToList(CheckDstPortNotEq, rtn);
2063 break;
2064 }
2065
2066 return;
2067 }
2068 /* default to setting the straight test function */
2069 switch(mode)
2070 {
2071 case SRC:
2072 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"CheckSrcPortEqual -> "););
2073 AddRuleFuncToList(CheckSrcPortEqual, rtn);
2074 break;
2075
2076 case DST:
2077 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"CheckDstPortEqual -> "););
2078 AddRuleFuncToList(CheckDstPortEqual, rtn);
2079 break;
2080 }
2081
2082 return;
2083 }
2084
2085 /****************************************************************************
2086 * Function: ParsePreprocessor()
2087 *
2088 * Saves the preprocessor configuration for loading later after dynamic
2089 * preprocessor keywords and configuration functions have been registered.
2090 * Configuration is also used later for configuration reload to check if
2091 * configuration has changed.
2092 *
2093 * Arguments:
2094 * SnortConfig *
2095 * Snort configuration to attach preprocessor configuration to.
2096 * char *
2097 * The preprocessor arguments.
2098 *
2099 * Returns: void function
2100 *
2101 ***************************************************************************/
ParsePreprocessor(SnortConfig * sc,SnortPolicy * p,char * args)2102 static void ParsePreprocessor(SnortConfig *sc, SnortPolicy *p, char *args)
2103 {
2104 char **toks;
2105 int num_toks;
2106 char *keyword;
2107 char *opts = NULL;
2108 PreprocConfig *config;
2109
2110 if ((sc == NULL) || (p == NULL) || (args == NULL))
2111 return;
2112
2113 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Preprocessor\n"););
2114
2115 /* break out the arguments from the keywords */
2116 toks = mSplit(args, ":", 2, &num_toks, '\\');
2117 keyword = toks[0];
2118
2119 if (num_toks > 1)
2120 opts = toks[1];
2121
2122 /* Save the configuration and load later */
2123 config = (PreprocConfig *)SnortAlloc(sizeof(PreprocConfig));
2124
2125 if (p->preproc_configs == NULL)
2126 {
2127 p->preproc_configs = config;
2128 }
2129 else
2130 {
2131 PreprocConfig *tmp = p->preproc_configs;
2132
2133 while (tmp->next != NULL)
2134 tmp = tmp->next;
2135
2136 tmp->next = config;
2137 }
2138
2139 config->keyword = SnortStrdup(keyword);
2140 config->file_name = SnortStrdup(file_name);
2141 config->file_line = file_line;
2142
2143 if (opts != NULL)
2144 config->opts = SnortStrdup(opts);
2145 else
2146 config->opts = NULL;
2147
2148 mSplitFree(&toks, num_toks);
2149 }
2150
ConfigurePreprocessors(SnortConfig * sc,int configure_dynamic)2151 void ConfigurePreprocessors(SnortConfig *sc, int configure_dynamic)
2152 {
2153 char *stored_file_name = file_name;
2154 int stored_file_line = file_line;
2155 tSfPolicyId i;
2156 #ifndef REG_TEST
2157 struct rusage ru;
2158 #endif
2159
2160 if (sc == NULL)
2161 return;
2162
2163 for (i = 0; i < sc->num_policies_allocated; i++)
2164 {
2165 PreprocConfig *config;
2166
2167 setParserPolicy(sc, i);
2168
2169 if (sc->targeted_policies[i] == NULL)
2170 continue;
2171
2172 config = sc->targeted_policies[i]->preproc_configs;
2173
2174 for (; config != NULL; config = config->next)
2175 {
2176 PreprocConfigFuncNode *node;
2177
2178 if (config->configured)
2179 continue;
2180
2181 file_name = config->file_name;
2182 file_line = config->file_line;
2183
2184 node = GetPreprocConfig(config->keyword);
2185 if ((node == NULL) && configure_dynamic)
2186 ParseError("Unknown preprocessor: \"%s\".", config->keyword);
2187
2188 if (node != NULL)
2189 {
2190 #ifdef SNORT_RELOAD
2191 if (node->initialized)
2192 {
2193 if (node->reload_func != NULL)
2194 {
2195 PreprocessorSwapData *swapData;
2196 PreprocessorSwapData **swapDataNode;
2197
2198 for (swapData = sc->preprocSwapData;
2199 swapData && swapData->preprocNode != node;
2200 swapData = swapData->next);
2201 if (!swapData)
2202 {
2203 swapData = (PreprocessorSwapData *)SnortAlloc(sizeof(*swapData));
2204 swapData->preprocNode = node;
2205 for (swapDataNode = &sc->preprocSwapData; *swapDataNode; swapDataNode = &(*swapDataNode)->next);
2206 *swapDataNode = swapData;
2207 }
2208 node->reload_func(sc, config->opts, &swapData->data);
2209 if (!sc->streamReloadConfig && node->keyword && strcmp(node->keyword, "stream5_global") == 0)
2210 sc->streamReloadConfig = swapData->data;
2211 }
2212 }
2213 else
2214 #endif
2215 {
2216 if (node->config_func != NULL)
2217 node->config_func(sc, config->opts);
2218 }
2219
2220 config->configured = 1;
2221 }
2222 }
2223 }
2224
2225 #ifdef SNORT_RELOAD
2226 for (i = 0; i < sc->num_policies_allocated; i++)
2227 {
2228 PreprocConfig *config;
2229
2230 setParserPolicy(sc, i);
2231
2232 if (sc->targeted_policies[i] == NULL)
2233 continue;
2234
2235 setParserPolicy(sc, i);
2236
2237 config = sc->targeted_policies[i]->preproc_configs;
2238
2239 /* Set all configured preprocessors to intialized */
2240 for (; config != NULL; config = config->next)
2241 {
2242 if (config->configured)
2243 {
2244 PreprocConfigFuncNode *node = GetPreprocConfig(config->keyword);
2245
2246 if (node != NULL)
2247 node->initialized = 1;
2248 }
2249 }
2250 }
2251 #endif
2252
2253 /* Reset these since we're done with configuring dynamic preprocessors */
2254 file_name = stored_file_name;
2255 file_line = stored_file_line;
2256 #ifndef REG_TEST
2257 if (ScTestMode())
2258 {
2259 if (configure_dynamic)
2260 {
2261 getrusage(RUSAGE_SELF, &ru);
2262 LogMessage("MaxRss at the end of dynamic preproc config:%li\n", ru.ru_maxrss);
2263 }
2264 else
2265 {
2266 getrusage(RUSAGE_SELF, &ru);
2267 LogMessage("MaxRss at the end of static preproc config:%li\n", ru.ru_maxrss);
2268 }
2269 }
2270 #endif
2271
2272 }
2273
2274 #ifdef SIDE_CHANNEL
2275
ParseSideChannelModule(SnortConfig * sc,SnortPolicy * p,char * args)2276 static void ParseSideChannelModule(SnortConfig *sc, SnortPolicy *p, char *args)
2277 {
2278 char **toks;
2279 int num_toks;
2280 char *opts = NULL;
2281 SideChannelModuleConfig *config;
2282
2283 toks = mSplit(args, ":", 2, &num_toks, '\\');
2284
2285 if (num_toks > 1)
2286 opts = toks[1];
2287
2288 config = (SideChannelModuleConfig *) SnortAlloc(sizeof(SideChannelModuleConfig));
2289
2290 if (sc->side_channel_config.module_configs == NULL)
2291 {
2292 sc->side_channel_config.module_configs = config;
2293 }
2294 else
2295 {
2296 SideChannelModuleConfig *tmp = sc->side_channel_config.module_configs;
2297
2298 while (tmp->next != NULL)
2299 tmp = tmp->next;
2300
2301 tmp->next = config;
2302 }
2303
2304 config->keyword = SnortStrdup(toks[0]);
2305 if (opts != NULL)
2306 config->opts = SnortStrdup(opts);
2307
2308 /* This could come from parsing the command line (No, actually, I don't think that it could...) */
2309 if (file_name != NULL)
2310 {
2311 config->file_name = SnortStrdup(file_name);
2312 config->file_line = file_line;
2313 }
2314
2315 mSplitFree(&toks, num_toks);
2316 }
2317
ConfigureSideChannelModules(SnortConfig * sc)2318 void ConfigureSideChannelModules(SnortConfig *sc)
2319 {
2320 SideChannelModuleConfig *config;
2321 char *stored_file_name = file_name;
2322 int stored_file_line = file_line;
2323 int rval;
2324
2325 for (config = sc->side_channel_config.module_configs; config != NULL; config = config->next)
2326 {
2327 file_name = config->file_name;
2328 file_line = config->file_line;
2329
2330 rval = ConfigureSideChannelModule(config->keyword, config->opts);
2331 if (rval == -ENOENT)
2332 ParseError("Unknown side channel plugin: \"%s\"", config->keyword);
2333 }
2334
2335 /* Reset these since we're done with configuring side channels */
2336 file_name = stored_file_name;
2337 file_line = stored_file_line;
2338 }
2339
2340 #endif /* SIDE_CHANNEL */
2341
2342 /* Parses standalone rate_filter configuration.
2343 *
2344 * Parses rate_filter configuration in the following format and populates internal
2345 * structures:
2346 * @code
2347 * rate_filter gid <gen-id>, sid <sig-id>,
2348 * track <by_src|by_dst|by_rule>,
2349 * count <c> , seconds <s>,
2350 * new_action <alert|drop|pass|drop|reject|sdrop>,
2351 * timeout <t> [, apply_to <cidr>];
2352 * @endcode
2353 * And then adds it into pContext.
2354 *
2355 * @param rule - string containing rate_filter configuration from snort.conf file.
2356 *
2357 * @returns void
2358 */
ParseRateFilter(SnortConfig * sc,SnortPolicy * p,char * args)2359 static void ParseRateFilter(SnortConfig *sc, SnortPolicy *p, char *args)
2360 {
2361 char **toks;
2362 int num_toks;
2363 int count_flag = 0;
2364 int new_action_flag = 0;
2365 int timeout_flag = 0;
2366 int seconds_flag = 0;
2367 int tracking_flag = 0;
2368 int genid_flag = 0;
2369 int sigid_flag = 0;
2370 int apply_flag = 0;
2371 int i;
2372 const char* ERR_KEY = "rate_filter";
2373
2374 tSFRFConfigNode thdx;
2375
2376 memset( &thdx, 0, sizeof(thdx) );
2377
2378 /* Potential IP list might be present so we can't split on commas
2379 * Change commas to semi-colons */
2380 args = FixSeparators(args, ';', "rate_filter");
2381 toks = mSplit(args, ";", 0, &num_toks, 0); /* get rule option pairs */
2382
2383 for (i = 0; i < num_toks; i++)
2384 {
2385 char **pairs;
2386 int num_pairs;
2387
2388 pairs = mSplit(toks[i], " \t", 2, &num_pairs, 0); /* get rule option pairs */
2389
2390 if (num_pairs != 2)
2391 {
2392 ParseError(ERR_NOT_PAIRED);
2393 }
2394
2395 if (!strcasecmp(pairs[0], "gen_id"))
2396 {
2397 if ( genid_flag++ )
2398 {
2399 ParseError(ERR_EXTRA_OPTION);
2400 }
2401
2402 thdx.gid = xatou(pairs[1], "rate_filter: gen_id");
2403 }
2404 else if (!strcasecmp(pairs[0], "sig_id"))
2405 {
2406 if ( sigid_flag++ )
2407 {
2408 ParseError(ERR_EXTRA_OPTION);
2409 }
2410
2411 thdx.sid = xatou(pairs[1], "rate_filter: sig_id");
2412 }
2413 else if (!strcasecmp(pairs[0], "track"))
2414 {
2415 if ( tracking_flag++ )
2416 {
2417 ParseError(ERR_EXTRA_OPTION);
2418 }
2419
2420 if (!strcasecmp(pairs[1], "by_src"))
2421 {
2422 thdx.tracking = SFRF_TRACK_BY_SRC;
2423 }
2424 else if (!strcasecmp(pairs[1], "by_dst"))
2425 {
2426 thdx.tracking = SFRF_TRACK_BY_DST;
2427 }
2428 else if (!strcasecmp(pairs[1], "by_rule"))
2429 {
2430 thdx.tracking = SFRF_TRACK_BY_RULE;
2431 }
2432 else
2433 {
2434 ParseError(ERR_BAD_VALUE);
2435 }
2436 }
2437 else if (!strcasecmp(pairs[0], "count"))
2438 {
2439 if ( count_flag++ )
2440 {
2441 ParseError(ERR_EXTRA_OPTION);
2442 }
2443
2444 thdx.count = xatoup(pairs[1], "rate_filter: count");
2445 }
2446 else if (!strcasecmp(pairs[0], "seconds"))
2447 {
2448 if ( seconds_flag++ )
2449 {
2450 ParseError(ERR_EXTRA_OPTION);
2451 }
2452
2453 thdx.seconds = xatou(pairs[1], "rate_filter: seconds");
2454 }
2455 else if (!strcasecmp(pairs[0], "new_action"))
2456 {
2457 if ( new_action_flag++ )
2458 {
2459 ParseError(ERR_EXTRA_OPTION);
2460 }
2461
2462 if (!strcasecmp(pairs[1], "alert"))
2463 {
2464 thdx.newAction = RULE_TYPE__ALERT;
2465 }
2466 else if (!strcasecmp(pairs[1], "drop"))
2467 {
2468 thdx.newAction = RULE_TYPE__DROP;
2469 }
2470 else if (!strcasecmp(pairs[1], "pass"))
2471 {
2472 thdx.newAction = RULE_TYPE__PASS;
2473 }
2474 else if (!strcasecmp(pairs[1], "log"))
2475 {
2476 thdx.newAction = RULE_TYPE__LOG;
2477 }
2478 else if (!strcasecmp(pairs[1], "reject"))
2479 {
2480 thdx.newAction = RULE_TYPE__REJECT;
2481 }
2482 else if (!strcasecmp(pairs[1], "sdrop"))
2483 {
2484 thdx.newAction = RULE_TYPE__SDROP;
2485 }
2486 else
2487 {
2488 ParseError(ERR_BAD_VALUE);
2489 }
2490 }
2491 else if (!strcasecmp(pairs[0], "timeout"))
2492 {
2493 if ( timeout_flag++ )
2494 {
2495 ParseError(ERR_EXTRA_OPTION);
2496 }
2497
2498 thdx.timeout = xatou(pairs[1],"rate_filter: timeout");
2499 }
2500 else if (!strcasecmp(pairs[0], "apply_to"))
2501 {
2502 char *ip_list = pairs[1];
2503
2504 if ( apply_flag++ )
2505 {
2506 ParseError(ERR_EXTRA_OPTION);
2507 }
2508
2509 thdx.applyTo = IpAddrSetParse(sc, ip_list);
2510 }
2511 else
2512 {
2513 ParseError(ERR_BAD_OPTION);
2514 }
2515
2516 mSplitFree(&pairs, num_pairs);
2517 }
2518
2519 if ( (genid_flag != 1) || (sigid_flag != 1) || (tracking_flag != 1)
2520 || (count_flag != 1) || (seconds_flag != 1) || (new_action_flag != 1)
2521 || (timeout_flag != 1) || (apply_flag > 1) )
2522 {
2523 ParseError(ERR_BAD_ARG_COUNT);
2524 }
2525 if ( !thdx.seconds
2526 && (thdx.gid != GENERATOR_INTERNAL
2527 || thdx.sid != INTERNAL_EVENT_SESSION_ADD) )
2528 {
2529 ParseError("rate_filter: seconds must be > 0");
2530 }
2531
2532 if (RateFilter_Create(sc, sc->rate_filter_config, &thdx))
2533 {
2534 ParseError(ERR_CREATE);
2535 }
2536
2537 mSplitFree(&toks, num_toks);
2538 }
2539
ParseRuleTypeOutput(SnortConfig * sc,char * args,ListHead * list)2540 static void ParseRuleTypeOutput(SnortConfig *sc, char *args, ListHead *list)
2541 {
2542 char **toks;
2543 int num_toks;
2544 char *opts = NULL;
2545 OutputConfig *config;
2546
2547 toks = mSplit(args, ":", 2, &num_toks, '\\');
2548
2549 if (num_toks > 1)
2550 opts = toks[1];
2551
2552 config = (OutputConfig *)SnortAlloc(sizeof(OutputConfig));
2553
2554 if (sc->rule_type_output_configs == NULL)
2555 {
2556 sc->rule_type_output_configs = config;
2557 }
2558 else
2559 {
2560 OutputConfig *tmp = sc->rule_type_output_configs;
2561
2562 while (tmp->next != NULL)
2563 tmp = tmp->next;
2564
2565 tmp->next = config;
2566 }
2567
2568 config->keyword = SnortStrdup(toks[0]);
2569 if (opts != NULL)
2570 config->opts = SnortStrdup(opts);
2571 config->rule_list = list;
2572
2573 if (file_name != NULL)
2574 {
2575 config->file_name = SnortStrdup(file_name);
2576 config->file_line = file_line;
2577 }
2578
2579 mSplitFree(&toks, num_toks);
2580 }
2581
ParseOutput(SnortConfig * sc,SnortPolicy * p,char * args)2582 void ParseOutput(SnortConfig *sc, SnortPolicy *p, char *args)
2583 {
2584 char **toks;
2585 int num_toks;
2586 char *opts = NULL;
2587 OutputConfig *config;
2588
2589 toks = mSplit(args, ":", 2, &num_toks, '\\');
2590
2591 if (num_toks > 1)
2592 opts = toks[1];
2593
2594 config = (OutputConfig *)SnortAlloc(sizeof(OutputConfig));
2595
2596 if (sc->output_configs == NULL)
2597 {
2598 sc->output_configs = config;
2599 }
2600 else
2601 {
2602 OutputConfig *tmp = sc->output_configs;
2603
2604 while (tmp->next != NULL)
2605 tmp = tmp->next;
2606
2607 tmp->next = config;
2608 }
2609
2610 config->keyword = SnortStrdup(toks[0]);
2611 if (opts != NULL)
2612 config->opts = SnortStrdup(opts);
2613
2614 /* This could come from parsing the command line */
2615 if (file_name != NULL)
2616 {
2617 config->file_name = SnortStrdup(file_name);
2618 config->file_line = file_line;
2619 }
2620
2621 mSplitFree(&toks, num_toks);
2622 }
2623
TransferOutputConfigs(OutputConfig * from_list,OutputConfig ** to_list)2624 static void TransferOutputConfigs(OutputConfig *from_list, OutputConfig **to_list)
2625 {
2626 if ((from_list == NULL) || (to_list == NULL))
2627 return;
2628
2629 for (; from_list != NULL; from_list = from_list->next)
2630 {
2631 if (*to_list == NULL)
2632 {
2633 *to_list = DupOutputConfig(from_list);
2634 }
2635 else
2636 {
2637 OutputConfig *tmp = DupOutputConfig(from_list);
2638
2639 if (tmp != NULL)
2640 {
2641 tmp->next = *to_list;
2642 *to_list = tmp;
2643 }
2644 }
2645 }
2646 }
2647
DupOutputConfig(OutputConfig * dupme)2648 static OutputConfig * DupOutputConfig(OutputConfig *dupme)
2649 {
2650 OutputConfig *medup;
2651
2652 if (dupme == NULL)
2653 return NULL;
2654
2655 medup = (OutputConfig *)SnortAlloc(sizeof(OutputConfig));
2656
2657 if (dupme->keyword != NULL)
2658 medup->keyword = SnortStrdup(dupme->keyword);
2659
2660 if (dupme->opts != NULL)
2661 medup->opts = SnortStrdup(dupme->opts);
2662
2663 if (dupme->file_name != NULL)
2664 medup->file_name = SnortStrdup(dupme->file_name);
2665
2666 medup->file_line = dupme->file_line;
2667 medup->rule_list = dupme->rule_list;
2668
2669 return medup;
2670 }
2671
RemoveOutputConfigs(OutputConfig ** head,int remove_flags)2672 static void RemoveOutputConfigs(OutputConfig **head, int remove_flags)
2673 {
2674 OutputConfig *config;
2675 OutputConfig *last = NULL;
2676
2677 if (head == NULL)
2678 return;
2679
2680 config = *head;
2681
2682 while (config != NULL)
2683 {
2684 int type_flags = GetOutputTypeFlags(config->keyword);
2685
2686 if (type_flags & remove_flags)
2687 {
2688 OutputConfig *tmp = config;
2689
2690 config = config->next;
2691
2692 if (last == NULL)
2693 *head = config;
2694 else
2695 last->next = config;
2696
2697 free(tmp->keyword);
2698
2699 if (tmp->opts != NULL)
2700 free(tmp->opts);
2701
2702 if (tmp->file_name != NULL)
2703 free(tmp->file_name);
2704
2705 free(tmp);
2706 }
2707 else
2708 {
2709 last = config;
2710 config = config->next;
2711 }
2712 }
2713 }
2714
ResolveOutputPlugins(SnortConfig * cmd_line,SnortConfig * config_file)2715 void ResolveOutputPlugins(SnortConfig *cmd_line, SnortConfig *config_file)
2716 {
2717 int cmd_line_type_flags = 0;
2718
2719 if (cmd_line == NULL)
2720 return;
2721
2722 if (cmd_line->no_log)
2723 {
2724 /* Free any log output plugins in both lists */
2725 RemoveOutputConfigs(&cmd_line->output_configs, OUTPUT_TYPE__LOG);
2726
2727 if (config_file != NULL)
2728 {
2729 RemoveOutputConfigs(&config_file->output_configs, OUTPUT_TYPE__LOG);
2730 RemoveOutputConfigs(&config_file->rule_type_output_configs, OUTPUT_TYPE__LOG);
2731 }
2732 }
2733 else if ((config_file != NULL) && config_file->no_log)
2734 {
2735 /* Free any log output plugins in config list */
2736 RemoveOutputConfigs(&config_file->output_configs, OUTPUT_TYPE__LOG);
2737 RemoveOutputConfigs(&config_file->rule_type_output_configs, OUTPUT_TYPE__LOG);
2738 }
2739
2740 if (cmd_line->no_alert)
2741 {
2742 /* Free any alert output plugins in both lists */
2743 RemoveOutputConfigs(&cmd_line->output_configs, OUTPUT_TYPE__ALERT);
2744
2745 if (config_file != NULL)
2746 {
2747 RemoveOutputConfigs(&config_file->output_configs, OUTPUT_TYPE__ALERT);
2748 RemoveOutputConfigs(&config_file->rule_type_output_configs, OUTPUT_TYPE__ALERT);
2749 }
2750 }
2751 else if ((config_file != NULL) && config_file->no_alert)
2752 {
2753 /* Free any alert output plugins in config list */
2754 RemoveOutputConfigs(&config_file->output_configs, OUTPUT_TYPE__ALERT);
2755 RemoveOutputConfigs(&config_file->rule_type_output_configs, OUTPUT_TYPE__ALERT);
2756 }
2757
2758 /* Command line overrides configuration file output */
2759 if (cmd_line->output_configs != NULL)
2760 {
2761 OutputConfig *config = cmd_line->output_configs;
2762
2763 for (; config != NULL; config = config->next)
2764 {
2765 int type_flags = GetOutputTypeFlags(config->keyword);
2766
2767 cmd_line_type_flags |= type_flags;
2768
2769 if (config_file != NULL)
2770 {
2771 RemoveOutputConfigs(&config_file->output_configs, type_flags);
2772 RemoveOutputConfigs(&config_file->rule_type_output_configs, type_flags);
2773 }
2774 }
2775
2776 /* Put what's in the command line output into the config file output */
2777 if (config_file != NULL)
2778 TransferOutputConfigs(cmd_line->output_configs, &config_file->output_configs);
2779 }
2780
2781 if (config_file != NULL)
2782 {
2783 if (cmd_line->no_log)
2784 config_file->no_log = cmd_line->no_log;
2785
2786 if (cmd_line->no_alert)
2787 config_file->no_alert = cmd_line->no_alert;
2788 }
2789
2790 /* Don't try to configure defaults if running in test mode */
2791 if (!ScTestModeNewConf(cmd_line))
2792 {
2793 if (config_file == NULL)
2794 {
2795 if (!cmd_line->no_log && !(cmd_line_type_flags & OUTPUT_TYPE__LOG))
2796 ParseOutput(cmd_line, NULL, "log_tcpdump");
2797
2798 if (!cmd_line->no_alert && !(cmd_line_type_flags & OUTPUT_TYPE__ALERT))
2799 ParseOutput(cmd_line, NULL, "alert_full");
2800 }
2801 else
2802 {
2803 int config_file_type_flags = 0;
2804 OutputConfig *config = config_file->output_configs;
2805
2806 for (; config != NULL; config = config->next)
2807 config_file_type_flags |= GetOutputTypeFlags(config->keyword);
2808
2809 if (!config_file->no_log && !(config_file_type_flags & OUTPUT_TYPE__LOG))
2810 ParseOutput(config_file, NULL, "log_tcpdump");
2811
2812 if (!config_file->no_alert && !(config_file_type_flags & OUTPUT_TYPE__ALERT))
2813 ParseOutput(config_file, NULL, "alert_full");
2814 }
2815 }
2816 }
2817
ConfigureOutputPlugins(SnortConfig * sc)2818 void ConfigureOutputPlugins(SnortConfig *sc)
2819 {
2820 OutputConfig *config;
2821 char *stored_file_name = file_name;
2822 int stored_file_line = file_line;
2823
2824 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Output Plugin\n"););
2825
2826 for (config = sc->output_configs; config != NULL; config = config->next)
2827 {
2828 OutputConfigFunc oc_func;
2829
2830 file_name = config->file_name;
2831 file_line = config->file_line;
2832
2833 oc_func = GetOutputConfigFunc(config->keyword);
2834 if (oc_func == NULL)
2835 ParseError("Unknown output plugin: \"%s\"", config->keyword);
2836
2837 oc_func(sc, config->opts);
2838 }
2839
2840 /* Configure output plugins for user defined rule types */
2841 for (config = sc->rule_type_output_configs; config != NULL; config = config->next)
2842 {
2843 OutputConfigFunc oc_func;
2844
2845 file_name = config->file_name;
2846 file_line = config->file_line;
2847
2848 oc_func = GetOutputConfigFunc(config->keyword);
2849 if (oc_func == NULL)
2850 ParseError("Unknown output plugin \"%s\"", config->keyword);
2851
2852 /* Each user defined rule type has it's own rule list and output plugin is
2853 * attached to it's Alert and/or Log lists */
2854 sc->head_tmp = config->rule_list;
2855 oc_func(sc, config->opts);
2856 sc->head_tmp = NULL;
2857 }
2858
2859 /* Reset these since we're done with configuring dynamic preprocessors */
2860 file_name = stored_file_name;
2861 file_line = stored_file_line;
2862 }
2863
FreeRuleTreeNode(RuleTreeNode * rtn)2864 static void FreeRuleTreeNode(RuleTreeNode *rtn)
2865 {
2866 RuleFpList *idx, *tmp;
2867 if (!rtn)
2868 return;
2869
2870 if (rtn->sip)
2871 {
2872 sfvar_free(rtn->sip);
2873 }
2874
2875 if (rtn->dip)
2876 {
2877 sfvar_free(rtn->dip);
2878 }
2879
2880 idx = rtn->rule_func;
2881 while (idx)
2882 {
2883 tmp = idx;
2884 idx = idx->next;
2885 free(tmp);
2886 }
2887 }
2888
DestroyRuleTreeNode(RuleTreeNode * rtn)2889 static void DestroyRuleTreeNode(RuleTreeNode *rtn)
2890 {
2891 if (!rtn)
2892 return;
2893
2894 rtn->otnRefCount--;
2895 if (rtn->otnRefCount != 0)
2896 return;
2897
2898 FreeRuleTreeNode(rtn);
2899
2900 free(rtn);
2901 }
2902
2903 /****************************************************************************
2904 *
2905 * Function: mergeDuplicateOtn()
2906 *
2907 * Purpose: Conditionally removes duplicate SID/GIDs. Keeps duplicate with
2908 * higher revision. If revision is the same, keeps newest rule.
2909 *
2910 * Arguments: otn_dup => The existing duplicate
2911 * rtn => the RTN chain to check
2912 * char => String describing the rule
2913 * rule_type => enumerated rule type (alert, pass, log)
2914 *
2915 * Returns: 0 if original rule stays, 1 if new rule stays
2916 *
2917 ***************************************************************************/
mergeDuplicateOtn(SnortConfig * sc,OptTreeNode * otn_dup,OptTreeNode * otn_new,RuleTreeNode * rtn_new)2918 static int mergeDuplicateOtn(SnortConfig *sc, OptTreeNode *otn_dup,
2919 OptTreeNode *otn_new, RuleTreeNode *rtn_new)
2920 {
2921 RuleTreeNode *rtn_dup = NULL;
2922 RuleTreeNode *rtnTmp2 = NULL;
2923 unsigned i;
2924
2925 if (otn_dup->proto != otn_new->proto)
2926 {
2927 ParseError("GID %d SID %d in rule duplicates previous rule, with "
2928 "different protocol.",
2929 otn_new->sigInfo.generator, otn_new->sigInfo.id);
2930 }
2931
2932 rtn_dup = getParserRtnFromOtn(sc, otn_dup);
2933
2934 if((rtn_dup != NULL) && (rtn_dup->type != rtn_new->type))
2935 {
2936 ParseError("GID %d SID %d in rule duplicates previous rule, with "
2937 "different type.",
2938 otn_new->sigInfo.generator, otn_new->sigInfo.id);
2939 }
2940
2941 if((otn_new->sigInfo.shared < otn_dup->sigInfo.shared)
2942 || ((otn_new->sigInfo.shared == otn_dup->sigInfo.shared)
2943 && (otn_new->sigInfo.rev < otn_dup->sigInfo.rev)))
2944 {
2945 //existing OTN is newer version. Keep existing and discard the new one.
2946 //OTN is for new policy group, salvage RTN
2947 deleteRtnFromOtn(sc, otn_new, getParserPolicy(sc));
2948
2949 ParseMessage("GID %d SID %d duplicates previous rule. Using %s.",
2950 otn_new->sigInfo.generator, otn_new->sigInfo.id,
2951 otn_dup->sigInfo.shared ? "SO rule.":"higher revision");
2952
2953 /* delete the data for each rule option in this OTN */
2954 OtnDeleteData(otn_new);
2955
2956 /* Now free the OTN itself -- this function is also used
2957 * by the hash-table calls out of OtnRemove, so it cannot
2958 * be modified to delete data for rule options */
2959 OtnFree(otn_new);
2960
2961 //Add rtn to existing otn for the first rule instance in a policy,
2962 //otherwise ignore it
2963 if (rtn_dup == NULL)
2964 {
2965 addRtnToOtn(sc, otn_dup, getParserPolicy(sc), rtn_new);
2966 }
2967 else
2968 {
2969 DestroyRuleTreeNode(rtn_new);
2970 }
2971
2972 return 0;
2973 }
2974
2975 //delete existing rule instance and keep the new one
2976
2977 for (i = 0; i < otn_dup->proto_node_num; i++)
2978 {
2979 rtnTmp2 = deleteRtnFromOtn(sc, otn_dup, i);
2980
2981 if ((rtnTmp2 && (i != getParserPolicy(sc))))
2982 {
2983 addRtnToOtn(sc, otn_new, i, rtnTmp2);
2984 }
2985 }
2986
2987 if (rtn_dup)
2988 {
2989 if (ScConfErrorOutNewConf(sc))
2990 {
2991 ParseError("GID %d SID %d in rule duplicates previous rule.",
2992 otn_new->sigInfo.generator, otn_new->sigInfo.id);
2993 }
2994 else
2995 {
2996 ParseWarning("GID %d SID %d in rule duplicates previous "
2997 "rule. Ignoring old rule.\n",
2998 otn_new->sigInfo.generator, otn_new->sigInfo.id);
2999 }
3000
3001 switch (otn_new->sigInfo.rule_type)
3002 {
3003 case SI_RULE_TYPE_DETECT:
3004 detect_rule_count--;
3005 break;
3006 case SI_RULE_TYPE_DECODE:
3007 decode_rule_count--;
3008 break;
3009 case SI_RULE_TYPE_PREPROC:
3010 preproc_rule_count--;
3011 break;
3012 default:
3013 break;
3014 }
3015 }
3016
3017 otn_count--;
3018
3019 OtnRemove(sc->otn_map, sc->so_rule_otn_map, otn_dup);
3020 DestroyRuleTreeNode(rtn_dup);
3021
3022 return 1;
3023 }
3024
3025 /* createDynamicRuleTypeRtn
3026 *
3027 * This api is only getting called whenever will see those
3028 * GID/SID pairs whose rule action type is getting modulated
3029 * from code depending upon few runtime parameters.
3030 *
3031 * In present scenario for
3032 * GID - GENERATOR_FILE_SIGNATURE/GENERATOR_FILE_TYPE, rule action
3033 * type is getting modified depending upon file verdict.
3034 *
3035 * I/P - SnortConfig -
3036 * old_rtn - This is the old RTN which has been created
3037 * irrespective of above mentioned scenario.
3038 * As a new RTN will be created with type NONE,
3039 * will destroy this old RTN.
3040 *
3041 * O/P - rtn - This is RTN which has been created with
3042 * RULE_TYPE_NONE specify that rule type will
3043 * be decided at the run time.
3044 */
createDynamicRuleTypeRtn(SnortConfig * sc,RuleTreeNode * old_rtn)3045 static inline RuleTreeNode * createDynamicRuleTypeRtn(SnortConfig *sc, RuleTreeNode *old_rtn)
3046 {
3047 RuleTreeNode test_rtn;
3048 RuleTreeNode *rtn;
3049 ListHead *list = old_rtn->listhead;
3050
3051 memset(&test_rtn, 0, sizeof(RuleTreeNode));
3052
3053 /* Making own key by changing the type to NONE */
3054 test_rtn.flags |= ANY_DST_PORT;
3055 test_rtn.flags |= ANY_SRC_PORT;
3056 test_rtn.flags |= ANY_DST_IP;
3057 test_rtn.flags |= ANY_SRC_IP;
3058 test_rtn.flags |= BIDIRECTIONAL;
3059
3060 /*
3061 * Initialising the rule type as NONE since type value will be
3062 * dynamic for GENERATOR_FILE_SIGNATURE/GENERATOR_FILE_TYPE
3063 */
3064 test_rtn.type = RULE_TYPE__NONE;
3065 test_rtn.listhead = list;
3066
3067 DestroyRuleTreeNode(old_rtn);
3068
3069 /* Creating the RTN node for File policy internal IPS rules(147:1/146)*/
3070 rtn = ProcessHeadNode(sc, &test_rtn, list);
3071 return rtn;
3072 }
3073
3074 /****************************************************************************
3075 *
3076 * Function: ParseRuleOptions(char *, int)
3077 *
3078 * Purpose: Process an individual rule's options and add it to the
3079 * appropriate rule chain
3080 *
3081 * Arguments: rule => rule string
3082 * rule_type => enumerated rule type (alert, pass, log)
3083 * *conflicts => Identifies whether there was a conflict due to duplicate
3084 * rule and whether existing otn was newer or not.
3085 * 0 - no conflict
3086 * 1 - existing otn is newer.
3087 * -1 - existing otn is older.
3088 *
3089 * Returns:
3090 * OptTreeNode *
3091 * The new OptTreeNode on success or NULL on error.
3092 *
3093 ***************************************************************************/
ParseRuleOptions(SnortConfig * sc,RuleTreeNode ** rtn_addr,char * rule_opts,RuleType rule_type,int protocol)3094 OptTreeNode * ParseRuleOptions(SnortConfig *sc, RuleTreeNode **rtn_addr,
3095 char *rule_opts, RuleType rule_type, int protocol)
3096 {
3097 OptTreeNode *otn;
3098 RuleOptOtnHandler otn_handler = NULL;
3099 int num_detection_opts = 0;
3100 char *dopt_keyword = NULL;
3101 OptFpList *fpl = NULL;
3102 int got_sid = 0;
3103 RuleTreeNode *rtn = *rtn_addr;
3104
3105 otn = (OptTreeNode *)SnortAlloc(sizeof(OptTreeNode));
3106
3107 otn->chain_node_number = otn_count;
3108 otn->proto = protocol;
3109 otn->event_data.sig_generator = GENERATOR_SNORT_ENGINE;
3110 otn->sigInfo.generator = GENERATOR_SNORT_ENGINE;
3111 otn->sigInfo.rule_type = SI_RULE_TYPE_DETECT; /* standard rule */
3112 otn->sigInfo.rule_flushing = SI_RULE_FLUSHING_ON; /* usually just standard rules cause a flush*/
3113 #ifdef TARGET_BASED
3114 otn->sigInfo.service_override = ServiceOverride_Nil;
3115 #endif
3116
3117 /* Set the default rule state */
3118 otn->rule_state = ScDefaultRuleStateNewConf(sc);
3119
3120 if (rule_opts == NULL)
3121 {
3122 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "No rule options.\n"););
3123
3124 if (ScRequireRuleSidNewConf(sc))
3125 ParseError("Each rule must contain a Rule-sid.");
3126
3127 addRtnToOtn(sc, otn, getParserPolicy(sc), rtn);
3128
3129 otn->ruleIndex = RuleIndexMapAdd(ruleIndexMap,
3130 otn->sigInfo.generator,
3131 otn->sigInfo.id);
3132 }
3133 else
3134 {
3135 char **toks;
3136 int num_toks;
3137 char configured[sizeof(rule_options) / sizeof(RuleOptFunc)];
3138 int i;
3139 OptTreeNode *otn_dup;
3140
3141 if ((rule_opts[0] != '(') || (rule_opts[strlen(rule_opts) - 1] != ')'))
3142 {
3143 ParseError("Rule options must be enclosed in '(' and ')'.");
3144 }
3145
3146 /* Move past '(' and zero out ')' */
3147 rule_opts++;
3148 rule_opts[strlen(rule_opts) - 1] = '\0';
3149
3150 /* Used to determine if a rule option has already been configured
3151 * in the rule. Some can only be configured once */
3152 memset(configured, 0, sizeof(configured));
3153
3154 toks = mSplit(rule_opts, ";", 0, &num_toks, '\\');
3155
3156 for (i = 0; i < num_toks; i++)
3157 {
3158 char **opts;
3159 int num_opts;
3160 char *option_args = NULL;
3161 int j;
3162
3163 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES," option: %s\n", toks[i]););
3164
3165 /* break out the option name from its data */
3166 opts = mSplit(toks[i], ":", 2, &num_opts, '\\');
3167
3168 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES," option name: %s\n", opts[0]););
3169
3170 if (num_opts == 2)
3171 {
3172 option_args = opts[1];
3173 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES," option args: %s\n", option_args););
3174 }
3175
3176 for (j = 0; rule_options[j].name != NULL; j++)
3177 {
3178 if (strcasecmp(opts[0], rule_options[j].name) == 0)
3179 {
3180 if (configured[j] && rule_options[j].only_once)
3181 {
3182 ParseError("Only one '%s' rule option per rule.",
3183 opts[0]);
3184 }
3185
3186 if ((option_args == NULL) && rule_options[j].args_required)
3187 {
3188 ParseError("No argument passed to keyword \"%s\". "
3189 "Make sure you didn't forget a ':' or the "
3190 "argument to this keyword.\n", opts[0]);
3191 }
3192
3193 rule_options[j].parse_func(sc, rtn, otn, rule_type, option_args);
3194 configured[j] = 1;
3195
3196 if ( !dopt_keyword && rule_options[j].detection )
3197 dopt_keyword = SnortStrdup(opts[0]);
3198 break;
3199 }
3200 }
3201
3202 /* Because we actually allow an sid of 0 */
3203 if ((rule_options[j].name != NULL) &&
3204 (strcasecmp(rule_options[j].name, RULE_OPT__SID) == 0))
3205 {
3206 got_sid = 1;
3207 }
3208
3209 /* It's possibly a detection option plugin */
3210 if (rule_options[j].name == NULL)
3211 {
3212 RuleOptConfigFuncNode *dopt = rule_opt_config_funcs;
3213
3214 for (; dopt != NULL; dopt = dopt->next)
3215 {
3216 if (strcasecmp(opts[0], dopt->keyword) == 0)
3217 {
3218 dopt->func(sc, option_args, otn, protocol);
3219
3220 /* If this option contains an OTN handler, save it for
3221 use after the rule is done parsing. */
3222 if (dopt->otn_handler != NULL)
3223 otn_handler = dopt->otn_handler;
3224
3225 /* This is done so if we have a preprocessor/decoder
3226 * rule, we can tell the user that detection options
3227 * are not supported with those types of rules, and
3228 * what the detection option is */
3229 if ((dopt_keyword == NULL) &&
3230 (dopt->type == OPT_TYPE_DETECTION))
3231 {
3232 dopt_keyword = SnortStrdup(opts[0]);
3233 }
3234
3235 break;
3236 }
3237 }
3238
3239 if (dopt == NULL)
3240 {
3241 /* Maybe it's a preprocessor rule option */
3242 PreprocOptionInit initFunc = NULL;
3243 PreprocOptionEval evalFunc = NULL;
3244 PreprocOptionFastPatternFunc fpFunc = NULL;
3245 PreprocOptionOtnHandler preprocOtnHandler = NULL;
3246 PreprocOptionCleanup cleanupFunc = NULL;
3247 void *opt_data = NULL;
3248
3249 int ret = GetPreprocessorRuleOptionFuncs
3250 (sc, opts[0], &initFunc, &evalFunc,
3251 &preprocOtnHandler, &fpFunc, &cleanupFunc);
3252
3253 if (ret && (initFunc != NULL))
3254 {
3255 initFunc(sc, opts[0], option_args, &opt_data);
3256 AddPreprocessorRuleOption(sc, opts[0], otn, opt_data, evalFunc);
3257 if (preprocOtnHandler != NULL)
3258 otn_handler = (RuleOptOtnHandler)preprocOtnHandler;
3259
3260 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "%s->", opts[0]););
3261 }
3262 else
3263 {
3264 /* Unrecognized rule option */
3265 ParseError("Unknown rule option: '%s'.", opts[0]);
3266 }
3267 }
3268
3269 if (dopt_keyword == NULL)
3270 dopt_keyword = SnortStrdup(opts[0]);
3271
3272 num_detection_opts++;
3273 }
3274
3275 mSplitFree(&opts, num_opts);
3276 }
3277
3278 if ((dopt_keyword != NULL) &&
3279 (otn->sigInfo.rule_type != SI_RULE_TYPE_DETECT))
3280 {
3281 /* Preprocessor and decoder rules can not have
3282 * detection options */
3283 ParseError("Preprocessor and decoder rules do not support "
3284 "detection options: %s.", dopt_keyword);
3285 }
3286
3287 if (dopt_keyword != NULL)
3288 free(dopt_keyword);
3289
3290 /* Each rule must have a sid irrespective of snort
3291 * in test mode or IPS/IDS mode.*/
3292 if (!got_sid)
3293 ParseError("Each rule must contain a rule sid.");
3294
3295 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"OptListEnd\n"););
3296
3297 if ((otn->sigInfo.generator == GENERATOR_FILE_SIGNATURE &&
3298 otn->sigInfo.id == FILE_SIGNATURE_SHA256) ||
3299 otn->sigInfo.generator == GENERATOR_FILE_TYPE)
3300 {
3301 rtn = createDynamicRuleTypeRtn(sc, rtn);
3302 *rtn_addr = rtn;
3303 }
3304 addRtnToOtn(sc, otn, getParserPolicy(sc), rtn);
3305
3306 /* Check for duplicate SID */
3307 otn_dup = OtnLookup(sc->otn_map, otn->sigInfo.generator, otn->sigInfo.id);
3308 if (otn_dup != NULL)
3309 {
3310 otn->ruleIndex = otn_dup->ruleIndex;
3311
3312 if (mergeDuplicateOtn(sc, otn_dup, otn, rtn) == 0)
3313 {
3314 /* We are keeping the old/dup OTN and trashing the new one
3315 * we just created - it's free'd in the remove dup function */
3316 mSplitFree(&toks, num_toks);
3317 return NULL;
3318 }
3319 }
3320 else
3321 {
3322 otn->ruleIndex = RuleIndexMapAdd(ruleIndexMap,
3323 otn->sigInfo.generator,
3324 otn->sigInfo.id);
3325 }
3326
3327 mSplitFree(&toks, num_toks);
3328 }
3329
3330 otn->num_detection_opts += num_detection_opts;
3331 otn_count++;
3332
3333 if (otn->sigInfo.rule_type == SI_RULE_TYPE_DETECT)
3334 {
3335 detect_rule_count++;
3336 }
3337 else if (otn->sigInfo.rule_type == SI_RULE_TYPE_DECODE)
3338 {
3339 //Set the bit if the decoder rule is enabled in the policies
3340 UpdateDecodeRulesArray(otn->sigInfo.id, ENABLE_RULE, ENABLE_ONE_RULE);
3341 decode_rule_count++;
3342 }
3343 else if (otn->sigInfo.rule_type == SI_RULE_TYPE_PREPROC)
3344 {
3345 preproc_rule_count++;
3346 }
3347
3348 fpl = AddOptFuncToList(OptListEnd, otn);
3349 fpl->type = RULE_OPTION_TYPE_LEAF_NODE;
3350
3351 if (otn_handler != NULL)
3352 {
3353 otn_handler(sc, otn);
3354 }
3355
3356 FinalizeContentUniqueness(sc, otn);
3357 ValidateFastPattern(otn);
3358
3359 if ((thdx_tmp != NULL) && (otn->detection_filter != NULL))
3360 {
3361 ParseError("The \"detection_filter\" rule option and the \"threshold\" "
3362 "rule option cannot be used in the same rule.\n");
3363 }
3364
3365 if (thdx_tmp != NULL)
3366 {
3367 int rstat;
3368
3369 thdx_tmp->sig_id = otn->sigInfo.id;
3370 thdx_tmp->gen_id = otn->sigInfo.generator;
3371 rstat = sfthreshold_create(sc, sc->threshold_config, thdx_tmp);
3372
3373 if (rstat)
3374 {
3375 if (rstat == THD_TOO_MANY_THDOBJ)
3376 {
3377 ParseError("threshold (in rule): could not create threshold - "
3378 "only one per sig_id=%u.", thdx_tmp->sig_id);
3379 }
3380 else
3381 {
3382 ParseError("threshold (in rule): could not add threshold "
3383 "for sig_id=%u!\n", thdx_tmp->sig_id);
3384 }
3385 }
3386
3387 thdx_tmp = NULL;
3388 }
3389
3390 /* setup gid,sid->otn mapping */
3391 SoRuleOtnLookupAdd(sc->so_rule_otn_map, otn);
3392 OtnLookupAdd(sc->otn_map, otn);
3393
3394 return otn;
3395 }
3396
3397 /****************************************************************************
3398 *
3399 * Function: GetRuleProtocol(char *)
3400 *
3401 * Purpose: Figure out which protocol the current rule is talking about
3402 *
3403 * Arguments: proto_str => the protocol string
3404 *
3405 * Returns: The integer value of the protocol
3406 *
3407 ***************************************************************************/
GetRuleProtocol(char * proto_str)3408 static int GetRuleProtocol(char *proto_str)
3409 {
3410 if (strcasecmp(proto_str, RULE_PROTO_OPT__TCP) == 0)
3411 {
3412 return IPPROTO_TCP;
3413 }
3414 else if (strcasecmp(proto_str, RULE_PROTO_OPT__UDP) == 0)
3415 {
3416 return IPPROTO_UDP;
3417 }
3418 else if (strcasecmp(proto_str, RULE_PROTO_OPT__ICMP) == 0)
3419 {
3420 return IPPROTO_ICMP;
3421 }
3422 else if (strcasecmp(proto_str, RULE_PROTO_OPT__IP) == 0)
3423 {
3424 return ETHERNET_TYPE_IP;
3425 }
3426 else
3427 {
3428 /* If we've gotten here, we have a protocol string we didn't recognize
3429 * and should exit */
3430 ParseError("Bad protocol: %s.", proto_str);
3431 }
3432
3433 return -1;
3434 }
3435
3436
ProcessIP(SnortConfig * sc,char * addr,RuleTreeNode * rtn,int mode,int neg_list)3437 static int ProcessIP(SnortConfig *sc, char *addr, RuleTreeNode *rtn, int mode, int neg_list)
3438 {
3439 vartable_t *ip_vartable = sc->targeted_policies[getParserPolicy(sc)]->ip_vartable;
3440
3441 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Got address string: %s\n",
3442 addr););
3443 assert(rtn);
3444 /* If a rule has a variable in it, we want to copy that variable's
3445 * contents to the IP variable (IP list) stored with the rtn.
3446 * This code tries to look up the variable, and if found, will copy it
3447 * to the rtn->{sip,dip} */
3448 if(mode == SRC)
3449 {
3450 int ret;
3451
3452 if (rtn->sip == NULL)
3453 {
3454 sfip_var_t *tmp = sfvt_lookup_var(ip_vartable, addr);
3455 if (tmp != NULL)
3456 {
3457 rtn->sip = sfvar_create_alias(tmp, tmp->name);
3458 if (rtn->sip == NULL)
3459 ret = SFIP_FAILURE;
3460 else
3461 ret = SFIP_SUCCESS;
3462 }
3463 else
3464 {
3465 rtn->sip = (sfip_var_t *)SnortAlloc(sizeof(sfip_var_t));
3466 ret = sfvt_add_to_var(ip_vartable, rtn->sip, addr);
3467 }
3468 }
3469 else
3470 {
3471 ret = sfvt_add_to_var(ip_vartable, rtn->sip, addr);
3472 }
3473
3474 /* The function sfvt_add_to_var adds 'addr' to the variable 'rtn->sip' */
3475 if (ret != SFIP_SUCCESS)
3476 {
3477 if(ret == SFIP_LOOKUP_FAILURE)
3478 {
3479 ParseError("Undefined variable in the string: %s.", addr);
3480 }
3481 else if(ret == SFIP_CONFLICT)
3482 {
3483 ParseError("Negated IP ranges that are more general than "
3484 "non-negated ranges are not allowed. Consider "
3485 "inverting the logic: %s.", addr);
3486 }
3487 else if(ret == SFIP_NOT_ANY)
3488 {
3489 ParseError("!any is not allowed: %s.", addr);
3490 }
3491 else
3492 {
3493 ParseError("Unable to process the IP address: %s.", addr);
3494 }
3495 }
3496
3497 if(rtn->sip->head && rtn->sip->head->flags & SFIP_ANY)
3498 {
3499 rtn->flags |= ANY_SRC_IP;
3500 }
3501 }
3502 /* mode == DST */
3503 else
3504 {
3505 int ret;
3506
3507 if (rtn->dip == NULL)
3508 {
3509 sfip_var_t *tmp = sfvt_lookup_var(ip_vartable, addr);
3510 if (tmp != NULL)
3511 {
3512 rtn->dip = sfvar_create_alias(tmp, tmp->name);
3513 if (rtn->dip == NULL)
3514 ret = SFIP_FAILURE;
3515 else
3516 ret = SFIP_SUCCESS;
3517 }
3518 else
3519 {
3520 rtn->dip = (sfip_var_t *)SnortAlloc(sizeof(sfip_var_t));
3521 ret = sfvt_add_to_var(ip_vartable, rtn->dip, addr);
3522 }
3523 }
3524 else
3525 {
3526 ret = sfvt_add_to_var(ip_vartable, rtn->dip, addr);
3527 }
3528
3529 if (ret != SFIP_SUCCESS)
3530 {
3531 if(ret == SFIP_LOOKUP_FAILURE)
3532 {
3533 ParseError("Undefined variable in the string: %s.", addr);
3534 }
3535 else if(ret == SFIP_CONFLICT)
3536 {
3537 ParseError("Negated IP ranges that are more general than "
3538 "non-negated ranges are not allowed. Consider "
3539 "inverting the logic: %s.", addr);
3540 }
3541 else if(ret == SFIP_NOT_ANY)
3542 {
3543 ParseError("!any is not allowed: %s.", addr);
3544 }
3545 else
3546 {
3547 ParseError("Unable to process the IP address: %s.", addr);
3548 }
3549 }
3550
3551 if(rtn->dip->head && rtn->dip->head->flags & SFIP_ANY)
3552 {
3553 rtn->flags |= ANY_DST_IP;
3554 }
3555 }
3556
3557 /* Make sure the IP lists provided by the user are valid */
3558 if (mode == SRC)
3559 ValidateIPList(rtn->sip, addr);
3560 else
3561 ValidateIPList(rtn->dip, addr);
3562
3563 return 0;
3564 }
3565
3566
3567 /****************************************************************************
3568 *
3569 * Function: ParsePort(SnortConfig *, char *, u_short *)
3570 *
3571 * Purpose: Convert the port string over to an integer value
3572 *
3573 * Arguments: prule_port => port rule string
3574 * port => converted integer value of the port
3575 *
3576 * Returns: 0 for a normal port number, 1 for an "any" port
3577 *
3578 ***************************************************************************/
ParsePort(SnortConfig * sc,char * prule_port,uint16_t * hi_port,uint16_t * lo_port,char * proto,int * not_flag)3579 int ParsePort(SnortConfig *sc, char *prule_port, uint16_t *hi_port, uint16_t *lo_port, char *proto, int *not_flag)
3580 {
3581 char **toks; /* token dbl buffer */
3582 int num_toks; /* number of tokens found by mSplit() */
3583 char *rule_port; /* port string */
3584
3585 *not_flag = 0;
3586
3587 /* check for variable */
3588 if(!strncmp(prule_port, "$", 1))
3589 {
3590 if((rule_port = VarGet(sc, prule_port + 1)) == NULL)
3591 {
3592 ParseError("Undefined variable %s.", prule_port);
3593 }
3594 }
3595 else
3596 rule_port = prule_port;
3597
3598 if(rule_port[0] == '(')
3599 {
3600 /* user forgot to put a port number in for this rule */
3601 ParseError("Bad port number: \"%s\".", rule_port);
3602 }
3603
3604
3605 /* check for wildcards */
3606 if(!strcasecmp(rule_port, "any"))
3607 {
3608 *hi_port = 0;
3609 *lo_port = 0;
3610 return 1;
3611 }
3612
3613 if(rule_port[0] == '!')
3614 {
3615 if(!strcasecmp(&rule_port[1], "any"))
3616 {
3617 ParseWarning("Negating \"any\" is invalid. Rule "
3618 "will be ignored.");
3619 return -1;
3620 }
3621
3622 *not_flag = 1;
3623 rule_port++;
3624 }
3625
3626 if(rule_port[0] == ':')
3627 {
3628 *lo_port = 0;
3629 }
3630
3631 toks = mSplit(rule_port, ":", 2, &num_toks, 0);
3632
3633 switch(num_toks)
3634 {
3635 case 1:
3636 *hi_port = (u_short)ConvPort(toks[0], proto);
3637
3638 if(rule_port[0] == ':')
3639 {
3640 *lo_port = 0;
3641 }
3642 else
3643 {
3644 *lo_port = *hi_port;
3645
3646 if(strchr(rule_port, ':') != NULL)
3647 {
3648 *hi_port = MAXPORTS-1;
3649 }
3650 }
3651
3652 break;
3653
3654 case 2:
3655 *lo_port = (u_short)ConvPort(toks[0], proto);
3656
3657 if(toks[1][0] == 0)
3658 *hi_port = MAXPORTS-1;
3659 else
3660 *hi_port = (u_short)ConvPort(toks[1], proto);
3661
3662 break;
3663
3664 default:
3665 ParseError("Port conversion failed on \"%s\".", rule_port);
3666 }
3667
3668 mSplitFree(&toks, num_toks);
3669
3670 return 0;
3671 }
3672
3673 /****************************************************************************
3674 *
3675 * Function: ConvPort(char *, char *)
3676 *
3677 * Purpose: Convert the port string over to an integer value
3678 *
3679 * Arguments: port => port string
3680 * proto => converted integer value of the port
3681 *
3682 * Returns: the port number
3683 *
3684 ***************************************************************************/
ConvPort(char * port,char * proto)3685 uint16_t ConvPort(char *port, char *proto)
3686 {
3687 int conv; /* storage for the converted number */
3688 char *digit; /* used to check for a number */
3689 struct servent *service_info;
3690
3691 /*
3692 * convert a "word port" (http, ftp, imap, whatever) to its corresponding
3693 * numeric port value
3694 */
3695 if(isalpha((int) port[0]) != 0)
3696 {
3697 service_info = getservbyname(port, proto);
3698
3699 if(service_info != NULL)
3700 {
3701 conv = ntohs(service_info->s_port);
3702 return conv;
3703 }
3704 else
3705 {
3706 ParseError("getservbyname() failed on \"%s\".", port);
3707 }
3708 }
3709 digit = port;
3710 while (*digit) {
3711
3712 if(!isdigit((int) *digit))
3713 {
3714 ParseError("Invalid port: %s.", port);
3715 }
3716 digit++;
3717 }
3718 /* convert the value */
3719 conv = atoi(port);
3720
3721 /* make sure it's in bounds */
3722 if ((conv < 0) || (conv > MAXPORTS-1))
3723 {
3724 ParseError("Bad port number: %s.", port);
3725 }
3726
3727 return (uint16_t)conv;
3728 }
3729
3730 /****************************************************************************
3731 *
3732 * Function: XferHeader(RuleTreeNode *, RuleTreeNode *)
3733 *
3734 * Purpose: Transfer the rule block header data from point A to point B
3735 *
3736 * Arguments: rule => the place to xfer from
3737 * rtn => the place to xfer to
3738 *
3739 * Returns: void function
3740 *
3741 ***************************************************************************/
XferHeader(RuleTreeNode * test_node,RuleTreeNode * rtn)3742 static void XferHeader(RuleTreeNode *test_node, RuleTreeNode *rtn)
3743 {
3744 rtn->flags = test_node->flags;
3745 rtn->type = test_node->type;
3746 rtn->sip = test_node->sip;
3747 rtn->dip = test_node->dip;
3748
3749 rtn->proto = test_node->proto;
3750
3751 rtn->src_portobject = test_node->src_portobject;
3752 rtn->dst_portobject = test_node->dst_portobject;
3753 }
3754
3755 /****************************************************************************
3756 *
3757 * Function: CompareIPNodes(RuleTreeNode *, RuleTreeNode *). Support function
3758 * for CompareIPLists.
3759 *
3760 * Purpose: Checks if the node's contents equal.
3761 *
3762 * Returns: 1 if they match, 0 if they don't
3763 *
3764 ***************************************************************************/
CompareIPNodes(IpAddrNode * one,IpAddrNode * two)3765 int CompareIPNodes(IpAddrNode *one, IpAddrNode *two)
3766 {
3767 if( (sfip_compare(&one->ip->addr, &two->ip->addr) != SFIP_EQUAL) ||
3768 (sfip_bits(one->ip) != sfip_bits(two->ip)) ||
3769 (sfvar_flags(one) != sfvar_flags(two)) )
3770 return 0;
3771 return 1;
3772 }
3773
3774
3775 /****************************************************************************
3776 *
3777 * Function: TestHeader(RuleTreeNode *, RuleTreeNode *)
3778 *
3779 * Purpose: Check to see if the two header blocks are identical
3780 *
3781 * Arguments: rule => uh
3782 * rtn => uuuuhhhhh....
3783 *
3784 * Returns: 1 if they match, 0 if they don't
3785 *
3786 ***************************************************************************/
TestHeader(RuleTreeNode * rule,RuleTreeNode * rtn)3787 static int TestHeader(RuleTreeNode * rule, RuleTreeNode * rtn)
3788 {
3789 if ((rule == NULL) || (rtn == NULL))
3790 return 0;
3791
3792 if (rule->type != rtn->type)
3793 return 0;
3794
3795 if (rule->proto != rtn->proto)
3796 return 0;
3797
3798 /* For custom rule type declarations */
3799 if (rule->listhead != rtn->listhead)
3800 return 0;
3801
3802 if (rule->flags != rtn->flags)
3803 return 0;
3804
3805 if ((rule->sip != NULL) && (rtn->sip != NULL) &&
3806 (sfvar_compare(rule->sip, rtn->sip) != SFIP_EQUAL))
3807 {
3808 return 0;
3809 }
3810
3811 if ((rule->dip != NULL) && (rtn->dip != NULL) &&
3812 (sfvar_compare(rule->dip, rtn->dip) != SFIP_EQUAL))
3813 {
3814 return 0;
3815 }
3816
3817 /* compare the port group pointers - this prevents confusing src/dst port objects
3818 * with the same port set, and it's quicker. It does assume that we only have
3819 * one port object and pointer for each unique port set...this is handled by the
3820 * parsing and initial port object storage and lookup. This must be consistent during
3821 * the rule parsing phase. - man */
3822 if ((rule->src_portobject != rtn->src_portobject)
3823 || (rule->dst_portobject != rtn->dst_portobject))
3824 {
3825 return 0;
3826 }
3827
3828 return 1;
3829 }
3830
3831 /*
3832 * PortVarDefine
3833 *
3834 * name - portlist name, i.e. http, smtp, ...
3835 * s - port number, port range, or a list of numbers/ranges in brackets
3836 *
3837 * examples:
3838 * portvar http [80,8080,8138,8700:8800,!8711]
3839 * portvar http $http_basic
3840 */
PortVarDefine(SnortConfig * sc,char * name,char * s)3841 static int PortVarDefine(SnortConfig *sc, char *name, char *s)
3842 {
3843 PortObject *po;
3844 POParser pop;
3845 char *errstr="unknown";
3846 int rstat;
3847 PortVarTable *portVarTable = sc->targeted_policies[getParserPolicy(sc)]->portVarTable;
3848 char *end;
3849 bool invalidvar = true;
3850
3851 DisallowCrossTableDuplicateVars(sc, name, VAR_TYPE__PORTVAR);
3852
3853 for(end = name; *end && !isspace((int)*end) && *end != '\\'; end++)
3854 {
3855 if(isalpha((int)*end))
3856 invalidvar = false;
3857 }
3858
3859 if(invalidvar)
3860 ParseError("Can not define variable name - %s. Use different name", name);
3861
3862 if( SnortStrcasestr(s,strlen(s),"any") ) /* this allows 'any' or '[any]' */
3863 {
3864 if(strstr(s,"!"))
3865 {
3866 ParseError("Illegal use of negation and 'any': %s.", s);
3867 }
3868
3869 po = PortObjectNew();
3870 if( !po )
3871 {
3872 ParseError("PortVarTable missing an 'any' variable.\n");
3873 }
3874 PortObjectSetName( po, name );
3875 PortObjectAddPortAny( po );
3876 }
3877 else
3878 {
3879 /* Parse the Port List info into a PortObject */
3880 po = PortObjectParseString(portVarTable, &pop, name, s, 0);
3881 if(!po)
3882 {
3883 errstr = PortObjectParseError( &pop );
3884 ParseError("*** PortVar Parse error: (pos=%d,error=%s)\n>>%s\n>>%*s.",
3885 pop.pos,errstr,s,pop.pos,"^");
3886 }
3887 }
3888
3889 /* Add The PortObject to the PortList Table */
3890 rstat = PortVarTableAdd(portVarTable, po);
3891 if( rstat < 0 )
3892 {
3893 ParseError("***PortVarTableAdd failed with '%s', exiting.", po->name);
3894 }
3895 else if( rstat > 0 )
3896 {
3897 ParseMessage("PortVar '%s', already defined.", po->name);
3898 }
3899
3900 /* Print the PortList - PortObjects */
3901 LogMessage("PortVar '%s' defined : ",po->name);
3902 PortObjectPrintPortsRaw(po);
3903 LogMessage("\n");
3904
3905 return 0;
3906 }
3907
3908 /****************************************************************************
3909 *
3910 * Function: VarAlloc()
3911 *
3912 * Purpose: allocates memory for a variable
3913 *
3914 * Arguments: none
3915 *
3916 * Returns: pointer to new VarEntry
3917 *
3918 ***************************************************************************/
VarAlloc()3919 VarEntry *VarAlloc()
3920 {
3921 VarEntry *new;
3922
3923 new = (VarEntry *)SnortAlloc(sizeof(VarEntry));
3924
3925 return(new);
3926 }
3927
3928 /****************************************************************************
3929 *
3930 * Function: VarIsIpAddr(char *, char *)
3931 *
3932 * Purpose: Checks if a var is an IP address. Necessary since moving forward
3933 * we want all IP addresses handled by the IP variable table.
3934 * If a list is given, this checks each value.
3935 *
3936 * Arguments: value => the string to check
3937 *
3938 * Returns: 1 if IP address, 0 otherwise
3939 *
3940 ***************************************************************************/
VarIsIpAddr(vartable_t * ip_vartable,char * value)3941 static int VarIsIpAddr(vartable_t *ip_vartable, char *value)
3942 {
3943 char *tmp;
3944
3945 /* empty list, consider this an IP address */
3946 if ((*value == '[') && (*(value+1) == ']'))
3947 return 1;
3948
3949 while(*value == '!' || *value == '[') value++;
3950
3951 /* Check for dotted-quad */
3952 if( isdigit((int)*value) &&
3953 ((tmp = strchr(value, (int)'.')) != NULL) &&
3954 ((tmp = strchr(tmp+1, (int)'.')) != NULL) &&
3955 (strchr(tmp+1, (int)'.') != NULL))
3956 return 1;
3957
3958 /* IPv4 with a mask, and fewer than 4 fields */
3959 else if( isdigit((int)*value) &&
3960 (strchr(value+1, (int)':') == NULL) &&
3961 ((tmp = strchr(value+1, (int)'/')) != NULL) &&
3962 isdigit((int)(*(tmp+1))) )
3963 return 1;
3964
3965 /* IPv6 */
3966 else if((tmp = strchr(value, (int)':')) != NULL)
3967 {
3968 char *tmp2;
3969
3970 if((tmp2 = strchr(tmp+1, (int)':')) == NULL)
3971 return 0;
3972
3973 for(tmp++; tmp < tmp2; tmp++)
3974 if(!isxdigit((int)*tmp))
3975 return 0;
3976
3977 return 1;
3978 }
3979
3980 /* Any */
3981 else if(!strncmp(value, "any", 3))
3982 return 1;
3983
3984 /* Check if it's a variable containing an IP */
3985 else if(sfvt_lookup_var(ip_vartable, value+1) || sfvt_lookup_var(ip_vartable, value))
3986 return 1;
3987
3988 return 0;
3989 }
3990
3991 /****************************************************************************
3992 *
3993 * Function: CheckBrackets(char *)
3994 *
3995 * Purpose: Check that the brackets match up in a string that
3996 * represents a list.
3997 *
3998 * Arguments: value => the string to check
3999 *
4000 * Returns: 1 if the brackets match correctly, 0 otherwise
4001 *
4002 ***************************************************************************/
CheckBrackets(char * value)4003 static int CheckBrackets(char *value)
4004 {
4005 int num_brackets = 0;
4006
4007 while (*value == '!')
4008 value++;
4009
4010 if ((value[0] != '[') || value[strlen(value)-1] != ']')
4011 {
4012 /* List does not begin or end with a bracket. */
4013 return 0;
4014 }
4015
4016 while ((*value != '\0') && (num_brackets >= 0))
4017 {
4018 if (*value == '[')
4019 num_brackets++;
4020 else if (*value == ']')
4021 num_brackets--;
4022 value++;
4023 }
4024 if (num_brackets != 0)
4025 {
4026 /* Mismatched brackets */
4027 return 0;
4028 }
4029
4030 return 1;
4031 }
4032
4033 /****************************************************************************
4034 *
4035 * Function: VarIsIpList(vartable_t *, char*)
4036 *
4037 * Purpose: Checks if a var is a list of IP addresses.
4038 *
4039 * Arguments: value => the string to check
4040 *
4041 * Returns: 1 if each item is an IP address, 0 otherwise
4042 *
4043 ***************************************************************************/
VarIsIpList(vartable_t * ip_vartable,char * value)4044 static int VarIsIpList(vartable_t *ip_vartable, char *value)
4045 {
4046 char *copy, *item;
4047 int item_is_ip = 1;
4048
4049 copy = SnortStrdup((const char*)value);
4050
4051 /* Ensure that the brackets are correct. */
4052 if (strchr((const char*)copy, ','))
4053 {
4054 /* This is a list! */
4055 if (CheckBrackets(copy) == 0)
4056 {
4057 free(copy);
4058 return 0;
4059 }
4060 }
4061
4062 /* There's no need to worry about the list structure here.
4063 * We just strip out the IP delimiters and process each one. */
4064 item = strtok(copy, "[],!");
4065 while ((item != NULL) && item_is_ip)
4066 {
4067 item_is_ip = VarIsIpAddr(ip_vartable, item);
4068 item = strtok(NULL, "[],!");
4069 }
4070
4071 free(copy);
4072 return item_is_ip;
4073 }
4074
4075 /****************************************************************************
4076 *
4077 * Function: DisallowCrossTableDuplicateVars(char *, int)
4078 *
4079 * Purpose: FatalErrors if the a variable name is redefined across variable
4080 * types. Enforcing this mutual exclusion prevents the
4081 * catatrophe where the variable lookup fall-through (see VarSearch)
4082 * finds an unintended variable from the wrong table. Note: VarSearch
4083 * is only necessary for ExpandVars.
4084 *
4085 * Arguments: name => The name of the variable
4086 * var_type => The type of the variable that is about to be defined.
4087 * The corresponding variable table will not be searched.
4088 *
4089 * Returns: void function
4090 *
4091 ***************************************************************************/
DisallowCrossTableDuplicateVars(SnortConfig * sc,char * name,VarType var_type)4092 static void DisallowCrossTableDuplicateVars(SnortConfig *sc, char *name, VarType var_type)
4093 {
4094 VarEntry *var_table = sc->targeted_policies[getParserPolicy(sc)]->var_table;
4095 PortVarTable *portVarTable = sc->targeted_policies[getParserPolicy(sc)]->portVarTable;
4096 VarEntry *p = var_table;
4097 vartable_t *ip_vartable = sc->targeted_policies[getParserPolicy(sc)]->ip_vartable;
4098
4099 /* If this is a faked Portvar, treat as a portvar */
4100 if ((var_type == VAR_TYPE__DEFAULT) &&
4101 (strstr(name, "_PORT") || strstr(name, "PORT_")))
4102 {
4103 var_type = VAR_TYPE__PORTVAR;
4104 }
4105
4106 switch (var_type)
4107 {
4108 case VAR_TYPE__DEFAULT:
4109 if (PortVarTableFind(portVarTable, name)
4110 || sfvt_lookup_var(ip_vartable, name)
4111 )
4112 {
4113 ParseError("Can not redefine variable name %s to be of type "
4114 "'var'. Use a different name.", name);
4115 }
4116 break;
4117
4118 case VAR_TYPE__PORTVAR:
4119 if (var_table != NULL)
4120 {
4121 do
4122 {
4123 if(strcasecmp(p->name, name) == 0)
4124 {
4125 ParseError("Can not redefine variable name %s to be of "
4126 "type 'portvar'. Use a different name.", name);
4127 }
4128 p = p->next;
4129 } while(p != var_table);
4130 }
4131
4132 if(sfvt_lookup_var(ip_vartable, name))
4133 {
4134 ParseError("Can not redefine variable name %s to be of type "
4135 "'portvar'. Use a different name.", name);
4136 }
4137
4138 break;
4139
4140 case VAR_TYPE__IPVAR:
4141 if (var_table != NULL)
4142 {
4143 do
4144 {
4145 if(strcasecmp(p->name, name) == 0)
4146 {
4147 ParseError("Can not redefine variable name %s to be of "
4148 "type 'ipvar'. Use a different name.", name);
4149 }
4150
4151 p = p->next;
4152 } while(p != var_table);
4153 }
4154
4155 if(PortVarTableFind(portVarTable, name))
4156 {
4157 ParseError("Can not redefine variable name %s to be of type "
4158 "'ipvar'. Use a different name.", name);
4159 }
4160
4161 default:
4162 /* Invalid function usage */
4163 break;
4164 }
4165 }
4166
4167 /****************************************************************************
4168 *
4169 * Function: VarDefine(char *, char *)
4170 *
4171 * Purpose: define the contents of a variable
4172 *
4173 * Arguments: name => the name of the variable
4174 * value => the contents of the variable
4175 *
4176 * Returns: void function
4177 *
4178 ***************************************************************************/
VarDefine(SnortConfig * sc,char * name,char * value)4179 VarEntry * VarDefine(SnortConfig *sc, char *name, char *value)
4180 {
4181 VarEntry *var_table = sc->targeted_policies[getParserPolicy(sc)]->var_table;
4182 vartable_t *ip_vartable = sc->targeted_policies[getParserPolicy(sc)]->ip_vartable;
4183 VarEntry *p;
4184 uint32_t var_id = 0;
4185
4186 if(value == NULL)
4187 {
4188 ParseError("Bad value in variable definition! Make sure you don't "
4189 "have a \"$\" in the var name.");
4190 }
4191
4192 if(VarIsIpList(ip_vartable, value))
4193 {
4194 SFIP_RET ret;
4195
4196 if (ip_vartable == NULL)
4197 return NULL;
4198
4199 /* Verify a variable by this name is not already used as either a
4200 * portvar or regular var. Enforcing this mutual exclusion prevents the
4201 * catatrophe where the variable lookup fall-through (see VarSearch)
4202 * finds an unintended variable from the wrong table. Note: VarSearch
4203 * is only necessary for ExpandVars. */
4204 DisallowCrossTableDuplicateVars(sc, name, VAR_TYPE__IPVAR);
4205
4206 if((ret = sfvt_define(ip_vartable, name, value)) != SFIP_SUCCESS)
4207 {
4208 switch(ret) {
4209 case SFIP_ARG_ERR:
4210 ParseError("The following is not allowed: %s.", value);
4211 break;
4212
4213 case SFIP_DUPLICATE:
4214 ParseMessage("Var '%s' redefined.", name);
4215 break;
4216
4217 case SFIP_CONFLICT:
4218 ParseError("Negated IP ranges that are more general than "
4219 "non-negated ranges are not allowed. Consider "
4220 "inverting the logic in %s.", name);
4221 break;
4222
4223 case SFIP_NOT_ANY:
4224 ParseError("!any is not allowed in %s.", name);
4225 break;
4226
4227 default:
4228 ParseError("Failed to parse the IP address: %s.", value);
4229 }
4230 }
4231 return NULL;
4232 }
4233 /* Check if this is a variable that stores an IP */
4234 else if(*value == '$')
4235 {
4236 sfip_var_t *var;
4237 if((var = sfvt_lookup_var(ip_vartable, value)) != NULL)
4238 {
4239 sfvt_define(ip_vartable, name, value);
4240 return NULL;
4241 }
4242 }
4243
4244
4245 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
4246 "VarDefine: name=%s value=%s\n",name,value););
4247
4248 /* Check to see if this variable is just being aliased */
4249 if (var_table != NULL)
4250 {
4251 VarEntry *tmp = var_table;
4252
4253 do
4254 {
4255 /* value+1 to move past $ */
4256 if (strcmp(tmp->name, value+1) == 0)
4257 {
4258 var_id = tmp->id;
4259 break;
4260 }
4261
4262 tmp = tmp->next;
4263
4264 } while (tmp != var_table);
4265 }
4266
4267 value = ExpandVars(sc, value);
4268 if(!value)
4269 {
4270 ParseError("Could not expand var('%s').", name);
4271 }
4272
4273 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
4274 "VarDefine: name=%s value=%s (expanded)\n",name,value););
4275
4276 DisallowCrossTableDuplicateVars(sc, name, VAR_TYPE__DEFAULT);
4277
4278 if (var_table == NULL)
4279 {
4280 p = VarAlloc();
4281 p->name = SnortStrdup(name);
4282 p->value = SnortStrdup(value);
4283
4284 p->prev = p;
4285 p->next = p;
4286
4287 sc->targeted_policies[getParserPolicy(sc)]->var_table = p;
4288
4289 p->id = sc->targeted_policies[getParserPolicy(sc)]->var_id++;
4290
4291 return p;
4292 }
4293
4294 /* See if an existing variable is being redefined */
4295 p = var_table;
4296
4297 do
4298 {
4299 if (strcasecmp(p->name, name) == 0)
4300 {
4301 if (p->value != NULL)
4302 free(p->value);
4303
4304 p->value = SnortStrdup(value);
4305 ParseWarning("Var '%s' redefined\n", p->name);
4306 return p;
4307 }
4308
4309 p = p->next;
4310
4311 } while (p != var_table); /* List is circular */
4312
4313 p = VarAlloc();
4314 p->name = SnortStrdup(name);
4315 p->value = SnortStrdup(value);
4316 p->prev = var_table;
4317 p->next = var_table->next;
4318 p->next->prev = p;
4319 var_table->next = p;
4320
4321 if (!var_id)
4322 p->id = sc->targeted_policies[getParserPolicy(sc)]->var_id++;
4323 else
4324 p->id = var_id;
4325
4326 #ifdef XXXXXXX
4327 vlen = strlen(value);
4328 LogMessage("Var '%s' defined, value len = %d chars", p->name, vlen );
4329
4330 if( vlen < 64 )
4331 {
4332 LogMessage(", value = %s\n", value );
4333 }
4334 else
4335 {
4336 LogMessage("\n");
4337 n = 128;
4338 s = value;
4339 while(vlen)
4340 {
4341 if( n > vlen ) n = vlen;
4342 LogMessage(" %.*s\n", n, s );
4343 s += n;
4344 vlen -= n;
4345 }
4346 }
4347 #endif
4348
4349 return p;
4350 }
4351
DeleteVars(VarEntry * var_table)4352 static void DeleteVars(VarEntry *var_table)
4353 {
4354 VarEntry *q, *p = var_table;
4355
4356 while (p)
4357 {
4358 q = p->next;
4359 if (p->name)
4360 free(p->name);
4361 if (p->value)
4362 free(p->value);
4363 if (p->addrset)
4364 {
4365 IpAddrSetDestroy(p->addrset);
4366 }
4367 free(p);
4368 p = q;
4369 if (p == var_table)
4370 break; /* Grumble, it's a friggin circular list */
4371 }
4372 }
4373
4374 /****************************************************************************
4375 *
4376 * Function: VarGet(SnortConfig *, char *)
4377 *
4378 * Purpose: get the contents of a variable
4379 *
4380 * Arguments: name => the name of the variable
4381 *
4382 * Returns: char * to contents of variable or FatalErrors on an
4383 * undefined variable name
4384 *
4385 ***************************************************************************/
VarGet(SnortConfig * sc,char * name)4386 char *VarGet(SnortConfig *sc, char *name)
4387 {
4388 SnortPolicy *policy;
4389 VarEntry *var_table;
4390 vartable_t *ip_vartable;
4391 sfip_var_t *var;
4392
4393 if (sc == NULL)
4394 return NULL;
4395
4396 policy = sc->targeted_policies[getParserPolicy(sc)];
4397 if (policy == NULL)
4398 return NULL;
4399
4400 var_table = sc->targeted_policies[getParserPolicy(sc)]->var_table;
4401
4402 // XXX-IPv6 This function should never be used if IP6 support is enabled!
4403 // Infact it won't presently even work for IP variables since the raw ASCII
4404 // value is never stored, and is never meant to be used.
4405 ip_vartable = sc->targeted_policies[getParserPolicy(sc)]->ip_vartable;
4406
4407 if((var = sfvt_lookup_var(ip_vartable, name)) == NULL) {
4408 /* Do the old style lookup since it wasn't found in
4409 * the variable table */
4410 if(var_table != NULL)
4411 {
4412 VarEntry *p = var_table;
4413 do
4414 {
4415 if(strcasecmp(p->name, name) == 0)
4416 return p->value;
4417 p = p->next;
4418 } while(p != var_table);
4419 }
4420
4421 ParseError("Undefined variable name: %s.", name);
4422 }
4423
4424 return name;
4425
4426 }
4427
4428 /****************************************************************************
4429 *
4430 * Function: ExpandVars()
4431 *
4432 * Purpose: expand all variables in a string
4433 *
4434 * Arguments:
4435 * SnortConfig *
4436 * The snort config that has the vartables.
4437 * char *
4438 * The name of the variable.
4439 *
4440 * Returns:
4441 * char *
4442 * The expanded string. Note that the string is returned in a
4443 * static variable and most likely needs to be string dup'ed.
4444 *
4445 ***************************************************************************/
ExpandVars(SnortConfig * sc,char * string)4446 static char * ExpandVars(SnortConfig *sc, char *string)
4447 {
4448 static char estring[ PARSERULE_SIZE ];
4449
4450 char rawvarname[128], varname[128], varaux[128], varbuffer[128];
4451 char varmodifier, *varcontents;
4452 int varname_completed, c, i, j, iv, jv, l_string, name_only;
4453 int quote_toggle = 0;
4454
4455 if(!string || !*string || !strchr(string, '$'))
4456 return(string);
4457
4458 memset((char *) estring, 0, PARSERULE_SIZE);
4459
4460 i = j = 0;
4461 l_string = strlen(string);
4462 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "ExpandVars, Before: %s\n", string););
4463
4464 while(i < l_string && j < (int)sizeof(estring) - 1)
4465 {
4466 c = string[i++];
4467
4468 if(c == '"')
4469 {
4470 /* added checks to make sure that we are inside a quoted string
4471 */
4472 quote_toggle ^= 1;
4473 }
4474
4475 if(c == '$' && !quote_toggle)
4476 {
4477 memset((char *) rawvarname, 0, sizeof(rawvarname));
4478 varname_completed = 0;
4479 name_only = 1;
4480 iv = i;
4481 jv = 0;
4482
4483 if(string[i] == '(')
4484 {
4485 name_only = 0;
4486 iv = i + 1;
4487 }
4488
4489 while(!varname_completed
4490 && iv < l_string
4491 && jv < (int)sizeof(rawvarname) - 1)
4492 {
4493 c = string[iv++];
4494
4495 if((name_only && !(isalnum(c) || c == '_'))
4496 || (!name_only && c == ')'))
4497 {
4498 varname_completed = 1;
4499
4500 if(name_only)
4501 iv--;
4502 }
4503 else
4504 {
4505 rawvarname[jv++] = (char)c;
4506 }
4507 }
4508
4509 if(varname_completed || iv == l_string)
4510 {
4511 char *p;
4512
4513 i = iv;
4514
4515 varcontents = NULL;
4516
4517 memset((char *) varname, 0, sizeof(varname));
4518 memset((char *) varaux, 0, sizeof(varaux));
4519 varmodifier = ' ';
4520
4521 p = strchr(rawvarname, ':');
4522 if (p)
4523 {
4524 SnortStrncpy(varname, rawvarname, p - rawvarname);
4525
4526 if(strlen(p) >= 2)
4527 {
4528 varmodifier = *(p + 1);
4529 SnortStrncpy(varaux, p + 2, sizeof(varaux));
4530 }
4531 }
4532 else
4533 SnortStrncpy(varname, rawvarname, sizeof(varname));
4534
4535 memset((char *) varbuffer, 0, sizeof(varbuffer));
4536
4537 varcontents = VarSearch(sc, varname);
4538
4539 switch(varmodifier)
4540 {
4541 case '-':
4542 if(!varcontents || !strlen(varcontents))
4543 varcontents = varaux;
4544 break;
4545
4546 case '?':
4547 if(!varcontents || !strlen(varcontents))
4548 {
4549 ErrorMessage("%s(%d): ", file_name, file_line);
4550
4551 if(strlen(varaux))
4552 ParseError("%s", varaux);
4553 else
4554 ParseError("Undefined variable \"%s\".", varname);
4555 }
4556 break;
4557 }
4558
4559 /* If variable not defined now, we're toast */
4560 if(!varcontents || !strlen(varcontents))
4561 ParseError("Undefined variable name: %s.", varname);
4562
4563 if(varcontents)
4564 {
4565 int l_varcontents = strlen(varcontents);
4566
4567 iv = 0;
4568
4569 while(iv < l_varcontents && j < (int)sizeof(estring) - 1)
4570 estring[j++] = varcontents[iv++];
4571 }
4572 }
4573 else
4574 {
4575 estring[j++] = '$';
4576 }
4577 }
4578 else
4579 {
4580 estring[j++] = (char)c;
4581 }
4582 }
4583
4584 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "ExpandVars, After: %s\n", estring););
4585
4586 return estring;
4587 }
4588
ProcessFileOption(SnortConfig * sc,const char * filespec)4589 char * ProcessFileOption(SnortConfig *sc, const char *filespec)
4590 {
4591 char *filename = NULL;
4592 char buffer[STD_BUF];
4593
4594 if (sc == NULL)
4595 sc = snort_conf;
4596
4597 if(filespec == NULL)
4598 {
4599 ParseError("no argument in this file option, remove extra ':' at the end of the alert option\n");
4600 }
4601
4602 /* look for ".." in the string and complain and exit if it is found */
4603 if(strstr(filespec, "..") != NULL)
4604 {
4605 ParseError("file definition contains \"..\". Do not do that!\n");
4606 }
4607
4608 if(filespec[0] == '/')
4609 {
4610 /* absolute filespecs are saved as is */
4611 filename = SnortStrdup(filespec);
4612 }
4613 else
4614 {
4615 /* relative filespec is considered relative to the log directory */
4616 /* or /var/log if the log directory has not been set */
4617 /* Make sure this function isn't called before log dir is set */
4618 if ((sc != NULL) && (sc->log_dir != NULL))
4619 {
4620 strlcpy(buffer, snort_conf->log_dir, STD_BUF);
4621 }
4622 else
4623 {
4624 strlcpy(buffer, "/var/log/snort", STD_BUF);
4625 }
4626
4627 strlcat(buffer, "/", STD_BUF - strlen(buffer));
4628 strlcat(buffer, filespec, STD_BUF - strlen(buffer));
4629 buffer[sizeof(buffer) - 1] = '\0';
4630 filename = SnortStrdup(buffer);
4631 }
4632
4633 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"ProcessFileOption: %s\n", filename););
4634
4635 return filename;
4636 }
4637
4638
4639 #ifdef TARGET_BASED
ParseAttributeTable(SnortConfig * sc,SnortPolicy * p,char * args)4640 static void ParseAttributeTable(SnortConfig *sc, SnortPolicy *p, char *args)
4641 {
4642 tSfPolicyId currentPolicyId = getParserPolicy(sc);
4643 tSfPolicyId defaultPolicyId = sfGetDefaultPolicy(sc->policy_config);
4644 TargetBasedConfig *defTbc = &sc->targeted_policies[defaultPolicyId]->target_based_config;
4645
4646 /* Save for configuring after configuration is parsed in case
4647 * config max_attribute_hosts is configured after this */
4648 if ((currentPolicyId != defaultPolicyId)
4649 && ((defTbc->args == NULL) || (strcmp(args, defTbc->args) != 0)))
4650 {
4651 //arguments should be same as in default policy. Ignoring the arguments
4652 ParseError("Attribute table must be configured in default policy if "
4653 "it is to be used in other policies and attribute table "
4654 "filename must be the same across policies.");
4655 }
4656
4657 if(p->target_based_config.args)
4658 free(p->target_based_config.args);
4659 p->target_based_config.args = SnortStrdup(args);
4660
4661 if (file_name != NULL)
4662 {
4663 if(p->target_based_config.file_name)
4664 free(p->target_based_config.file_name);
4665 p->target_based_config.file_name = SnortStrdup(file_name);
4666 p->target_based_config.file_line = file_line;
4667 }
4668 }
4669 #endif
4670
ParseConfig(SnortConfig * sc,SnortPolicy * p,char * args)4671 static void ParseConfig(SnortConfig *sc, SnortPolicy *p, char *args)
4672 {
4673 char **toks;
4674 int num_toks;
4675 char *opts = NULL;
4676 int i;
4677
4678 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Rule file config\n"););
4679
4680 toks = mSplit(args, ":", 2, &num_toks, 0);
4681
4682 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Opt: %s\n", toks[0]););
4683
4684 if (num_toks > 1)
4685 {
4686 /* Dup the opts because we're putting into hash table */
4687 opts = SnortStrdup(toks[1]);
4688 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Args: %s\n", opts););
4689 }
4690
4691 switch (sfghash_add(sc->config_table, toks[0], opts))
4692 {
4693 case SFGHASH_NOMEM:
4694 ParseError("%s(%d) No memory to add entry to config table.\n",
4695 __FILE__, __LINE__);
4696 break;
4697
4698 case SFGHASH_INTABLE:
4699 /* Only reference and classifications are likely dup candidates
4700 * right now and we're not too worried about keeping track of
4701 * all of them */
4702 if (opts != NULL)
4703 {
4704 free(opts);
4705 opts = toks[1];
4706 }
4707
4708 break;
4709
4710 default:
4711 break;
4712 }
4713
4714 for (i = 0; config_opts[i].name != NULL; i++)
4715 {
4716 if (strcasecmp(toks[0], config_opts[i].name) == 0)
4717 {
4718 if ((getParserPolicy(sc) != getDefaultPolicy()) &&
4719 config_opts[i].default_policy_only)
4720 {
4721 /* Config option configurable on by the default policy*/
4722 /**Dont raise parse error, ignore any config that is not allowed in non-default
4723 * policy.
4724 */
4725 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Config option \"%s\" "
4726 "configurable only by default policy. Ignoring it\n", toks[0]));
4727 break;
4728 }
4729
4730 if (config_opts[i].only_once && config_opt_configured[i])
4731 {
4732 /* Configured already and set to only configure once
4733 * This array is reset for each policy read in so this is
4734 * on a per policy basis */
4735 ParseError("Config option \"%s\" can only be "
4736 "configured once.", toks[0]);
4737 }
4738
4739 if (config_opts[i].args_required && (opts == NULL))
4740 {
4741 /* Need arguments and there are none */
4742 ParseError("Config option \"%s\" requires arguments.", toks[0]);
4743 }
4744
4745 config_opts[i].parse_func(sc, opts);
4746 config_opt_configured[i] = 1;
4747 break;
4748 }
4749 }
4750
4751 if (config_opts[i].name == NULL)
4752 {
4753 /* Didn't find a matching config option */
4754 ParseError("Unknown config directive: %s.", toks[0]);
4755 }
4756
4757 mSplitFree(&toks, num_toks);
4758 }
4759
4760 /****************************************************************************
4761 *
4762 * Purpose: Check that special rules have an OTN.
4763 * TODO: Free up memory associated with disabled rules.
4764 *
4765 * Arguments: list => Pointer for a list of rules
4766 *
4767 * Returns: void function
4768 *
4769 * Notes: man - modified to used .shared flag in otn sigInfo instead of specialGID
4770 * sas - removed specialGID
4771 *
4772 *****************************************************************************/
CheckRuleStates(SnortConfig * sc)4773 int CheckRuleStates(SnortConfig *sc)
4774 {
4775 RuleTreeNode *rtn;
4776 OptTreeNode *otn;
4777 SFGHASH_NODE *hashNode;
4778 int oneErr = 0;
4779 tSfPolicyId policyId = 0;
4780
4781 if (sc == NULL)
4782 return 0;
4783
4784 for (hashNode = sfghash_findfirst(sc->otn_map);
4785 hashNode;
4786 hashNode = sfghash_findnext(sc->otn_map))
4787 {
4788 otn = (OptTreeNode *)hashNode->data;
4789 for (policyId = 0;
4790 policyId < otn->proto_node_num;
4791 policyId++)
4792 {
4793 rtn = otn->proto_nodes[policyId];
4794
4795 if (!rtn)
4796 {
4797 continue;
4798 }
4799
4800 if ((rtn->proto == IPPROTO_TCP) || (rtn->proto == IPPROTO_UDP) ||
4801 (rtn->proto == IPPROTO_ICMP) || (rtn->proto == ETHERNET_TYPE_IP))
4802 {
4803 //do operation
4804 if ( otn->sigInfo.shared )
4805 {
4806 if (otn->ds_list[PLUGIN_DYNAMIC] == NULL)
4807 {
4808 // Have a dynamic rule but no dynamic plugin
4809 if (otn->sigInfo.id != otn->sigInfo.otnKey.sid)
4810 {
4811 // If its a different SID, but same soid metadata as something
4812 // else, try to find it
4813 OptTreeNode *otn_original;
4814 otn_original = SoRuleOtnLookup(sc->so_rule_otn_map,
4815 otn->sigInfo.otnKey.gid, otn->sigInfo.otnKey.sid);
4816
4817 if ( otn_original && (otn != otn_original) &&
4818 !otn->sigInfo.dup_opt_func )
4819 {
4820 OptFpList *opt_func = otn->opt_func;
4821 while (opt_func != NULL)
4822 {
4823 /* Delete the option functions that came from the
4824 * parsing -- this rule will be identical to its
4825 * "cloned" brother. */
4826 OptFpList *tmp = opt_func;
4827 opt_func = opt_func->next;
4828 free(tmp);
4829 }
4830 if (otn_original->sigInfo.shared)
4831 {
4832 /* Its still a shared object -- has its own detection function. */
4833 otn->ds_list[PLUGIN_DYNAMIC] = otn_original->ds_list[PLUGIN_DYNAMIC];
4834 }
4835 else
4836 {
4837 /* It was back-converted from a shared object */
4838 int i;
4839 for (i=PLUGIN_CLIENTSERVER; i<PLUGIN_MAX; i++)
4840 {
4841 otn->ds_list[i] = otn_original->ds_list[i];
4842 }
4843 otn->sigInfo.shared = 0; /* no longer shared */
4844 }
4845 otn->opt_func = otn_original->opt_func;
4846 otn->sigInfo.dup_opt_func = 1;
4847 }
4848 }
4849 }
4850
4851 if (otn->sigInfo.shared && (otn->ds_list[PLUGIN_DYNAMIC] == NULL))
4852 {
4853 /* If still shared... */
4854 ErrorMessage("Encoded Rule Plugin SID: %d, GID: %d not "
4855 "registered properly. Disabling this rule.\n",
4856 otn->sigInfo.id, otn->sigInfo.generator);
4857 oneErr = 1;
4858 otn->rule_state = RULE_STATE_DISABLED;
4859 }
4860 }
4861 }
4862 }
4863 }
4864
4865 return oneErr;
4866 }
4867
4868 /****************************************************************************
4869 *
4870 * Purpose: Adjust the information for a given rule
4871 * relative to the Rule State list
4872 *
4873 * Arguments: None
4874 *
4875 * Returns: void function
4876 *
4877 * Notes: specialGID is depracated, uses sigInfo.shared flag
4878 *
4879 *****************************************************************************/
SetRuleStates(SnortConfig * sc)4880 void SetRuleStates(SnortConfig *sc)
4881 {
4882 RuleState *rule_state;
4883 #if 0
4884 int oneErr = 0, err;
4885 #endif
4886
4887 if (sc == NULL)
4888 return;
4889
4890 /* First, cycle through the rule state list and update the
4891 * rule state for each one we find. */
4892 for (rule_state = sc->rule_state_list; rule_state != NULL; rule_state = rule_state->next)
4893 {
4894 /* Lookup the OTN by ruleState->sid, ruleState->gid */
4895 OptTreeNode *otn = OtnLookup(sc->otn_map, rule_state->gid, rule_state->sid);
4896
4897 if (otn == NULL)
4898 {
4899 ParseError("Rule state specified for invalid SID: %d GID: %d\n",
4900 rule_state->sid, rule_state->gid);
4901 }
4902
4903 otn->rule_state = rule_state->state;
4904 }
4905
4906 /* Check TCP/UDP/ICMP/IP in one iteration for all rulelists and for all policies*/
4907 #if 1
4908 CheckRuleStates(sc);
4909 #else
4910 err = CheckRuleStates(sc);
4911 if (err)
4912 oneErr = 1;
4913
4914 if (oneErr)
4915 {
4916 FatalError("Misconfigured or unregistered encoded rule plugins\n");
4917 }
4918 #endif
4919 }
4920
4921 /****************************************************************************
4922 *
4923 * Purpose: Parses a rule state line.
4924 * Format is sid, gid, state, action.
4925 * state should be "enabled" or "disabled"
4926 * action should be "alert", "drop", "sdrop", "log", etc.
4927 *
4928 * Arguments: args => string containing a single rule state entry
4929 *
4930 * Returns: void function
4931 *
4932 *****************************************************************************/
ParseRuleState(SnortConfig * sc,SnortPolicy * p,char * args)4933 static void ParseRuleState(SnortConfig *sc, SnortPolicy *p, char *args)
4934 {
4935 char **toks;
4936 int num_toks;
4937 RuleState *state;
4938 char *endptr;
4939
4940 if (sc == NULL)
4941 return;
4942
4943 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"RuleState\n"););
4944
4945 toks = mSplit(args, ", ", 0, &num_toks, 0);
4946
4947 if (num_toks != 4)
4948 ParseError("Config rule_state: Empty state info.");
4949
4950 state = (RuleState *)SnortAlloc(sizeof(RuleState));
4951
4952 state->sid = SnortStrtoul(toks[0], &endptr, 0);
4953 if ((errno == ERANGE) || (*endptr != '\0'))
4954 {
4955 ParseError("Invalid sid for rule state: %s. Sid must be between 0 and "
4956 "%u inclusive.", args, UINT32_MAX);
4957 }
4958
4959 state->gid = SnortStrtoul(toks[1], &endptr, 0);
4960 if ((errno == ERANGE) || (*endptr != '\0'))
4961 {
4962 ParseError("Invalid gid for rule state: %s. Gid must be between 0 and "
4963 "%u inclusive.", args, UINT32_MAX);
4964 }
4965
4966 if (strcasecmp(toks[2], RULE_STATE_OPT__DISABLED) == 0)
4967 {
4968 state->state = RULE_STATE_DISABLED;
4969 }
4970 else if (strcasecmp(toks[2], RULE_STATE_OPT__ENABLED) == 0)
4971 {
4972 state->state = RULE_STATE_ENABLED;
4973 }
4974 else
4975 {
4976 ParseError("Rule_state: Invalid state - must be either "
4977 "'enabled' or 'disabled'.");
4978 }
4979
4980 state->action = GetRuleType(toks[3]);
4981 if (state->action == RULE_TYPE__NONE)
4982 {
4983 ParseError("Rule_state: Invalid action - must be a valid "
4984 "rule type.");
4985 }
4986
4987 mSplitFree(&toks, num_toks);
4988
4989 if (sc->rule_state_list == NULL)
4990 {
4991 sc->rule_state_list = state;
4992 }
4993 else
4994 {
4995 state->next = sc->rule_state_list;
4996 sc->rule_state_list = state;
4997 }
4998 }
4999
ParseDynamicLibInfo(DynamicLibInfo * dylib_info,char * args)5000 static void ParseDynamicLibInfo(DynamicLibInfo *dylib_info, char *args)
5001 {
5002 char getcwd_path[PATH_MAX];
5003 char **toks = NULL;
5004 int num_toks = 0;
5005 char *path = NULL;
5006 PathType ptype = PATH_TYPE__FILE;
5007 DynamicLibPath *dylib_path;
5008 struct stat buf;
5009
5010 if (dylib_info == NULL)
5011 return;
5012
5013 if (dylib_info->count >= MAX_DYNAMIC_LIBS)
5014 {
5015 ParseError("Maximum number of loaded libriaries of this dynamic "
5016 "library type exceeded: %d.", MAX_DYNAMIC_LIBS);
5017 }
5018
5019 if (args == NULL)
5020 {
5021 if (getcwd(getcwd_path, sizeof(getcwd_path)) == NULL)
5022 {
5023 ParseError("Dynamic library path too long. If you really "
5024 "think your path needs to be as long as it is, please "
5025 "submit a bug to bugs@snort.org.");
5026 }
5027
5028 path = getcwd_path;
5029 ptype = PATH_TYPE__DIRECTORY;
5030 }
5031 else
5032 {
5033 toks = mSplit(args, " \t", 0, &num_toks, 0);
5034
5035 if (num_toks == 1)
5036 {
5037 path = toks[0];
5038 ptype = PATH_TYPE__FILE;
5039 }
5040 else if (num_toks == 2)
5041 {
5042 if (strcasecmp(toks[0], DYNAMIC_LIB_OPT__FILE) == 0)
5043 {
5044 ptype = PATH_TYPE__FILE;
5045 }
5046 else if (strcasecmp(toks[0], DYNAMIC_LIB_OPT__DIRECTORY) == 0)
5047 {
5048 ptype = PATH_TYPE__DIRECTORY;
5049 }
5050 else
5051 {
5052 ParseError("Invalid specifier for Dynamic library specifier. "
5053 "Should be file|directory pathname.");
5054 }
5055
5056 path = toks[1];
5057 }
5058 else
5059 {
5060 ParseError("Missing/incorrect dynamic engine lib specifier.");
5061 }
5062 }
5063
5064 dylib_path = (DynamicLibPath *)SnortAlloc(sizeof(DynamicLibPath));
5065 dylib_path->ptype = ptype;
5066 dylib_path->path = SnortStrdup(path);
5067
5068 dylib_info->lib_paths[dylib_info->count] = dylib_path;
5069 dylib_info->count++;
5070
5071 if (toks != NULL)
5072 mSplitFree(&toks, num_toks);
5073
5074 if (stat(dylib_path->path, &buf) == -1)
5075 {
5076 ParseError("Could not stat dynamic module path \"%s\": %s.\n",
5077 dylib_path->path, strerror(errno));
5078 }
5079
5080 dylib_path->last_mod_time = buf.st_mtime;
5081 }
5082
5083 /****************************************************************************
5084 *
5085 * Purpose: Parses a dynamic engine line
5086 * Format is full path of dynamic engine
5087 *
5088 * Arguments: args => string containing a single dynamic engine
5089 *
5090 * Returns: void function
5091 *
5092 *****************************************************************************/
ParseDynamicEngineInfo(SnortConfig * sc,SnortPolicy * p,char * args)5093 static void ParseDynamicEngineInfo(SnortConfig *sc, SnortPolicy *p, char *args)
5094 {
5095 if (sc == NULL)
5096 return;
5097
5098 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"DynamicEngine\n"););
5099
5100 if (sc->dyn_engines == NULL)
5101 {
5102 sc->dyn_engines = (DynamicLibInfo *)SnortAlloc(sizeof(DynamicLibInfo));
5103 sc->dyn_engines->type = DYNAMIC_TYPE__ENGINE;
5104 }
5105
5106 ParseDynamicLibInfo(sc->dyn_engines, args);
5107 }
5108
5109 /****************************************************************************
5110 *
5111 * Purpose: Parses a dynamic detection lib line
5112 * Format is full path of dynamic engine
5113 *
5114 * Arguments: args => string containing a single dynamic engine
5115 *
5116 * Returns: void function
5117 *
5118 *****************************************************************************/
ParseDynamicDetectionInfo(SnortConfig * sc,SnortPolicy * p,char * args)5119 static void ParseDynamicDetectionInfo(SnortConfig *sc, SnortPolicy *p, char *args)
5120 {
5121 if (sc == NULL)
5122 return;
5123
5124 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"DynamicDetection\n"););
5125
5126 if (sc->dyn_rules == NULL)
5127 {
5128 sc->dyn_rules = (DynamicLibInfo *)SnortAlloc(sizeof(DynamicLibInfo));
5129 sc->dyn_rules->type = DYNAMIC_TYPE__DETECTION;
5130 }
5131
5132 ParseDynamicLibInfo(sc->dyn_rules, args);
5133 }
5134
5135 /****************************************************************************
5136 *
5137 * Purpose: Parses a dynamic preprocessor lib line
5138 * Format is full path of dynamic engine
5139 *
5140 * Arguments: args => string containing a single dynamic engine
5141 *
5142 * Returns: void function
5143 *
5144 *****************************************************************************/
ParseDynamicPreprocessorInfo(SnortConfig * sc,SnortPolicy * p,char * args)5145 static void ParseDynamicPreprocessorInfo(SnortConfig *sc, SnortPolicy *p, char *args)
5146 {
5147 if (sc == NULL)
5148 return;
5149
5150 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"DynamicPreprocessor\n"););
5151
5152 if (sc->dyn_preprocs == NULL)
5153 {
5154 sc->dyn_preprocs = (DynamicLibInfo *)SnortAlloc(sizeof(DynamicLibInfo));
5155 sc->dyn_preprocs->type = DYNAMIC_TYPE__PREPROCESSOR;
5156 }
5157
5158 ParseDynamicLibInfo(sc->dyn_preprocs, args);
5159 }
5160
5161 # ifdef SIDE_CHANNEL
5162
5163 /****************************************************************************
5164 *
5165 * Purpose: Parses a dynamic side channel lib line
5166 * Format is full path of dynamic side channel
5167 *
5168 * Arguments: args => string containing a single dynamic side channel
5169 *
5170 * Returns: void function
5171 *
5172 *****************************************************************************/
ParseDynamicSideChannelInfo(SnortConfig * sc,SnortPolicy * p,char * args)5173 static void ParseDynamicSideChannelInfo(SnortConfig *sc, SnortPolicy *p, char *args)
5174 {
5175 if (sc == NULL)
5176 return;
5177
5178 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"DynamicSideChannel\n"););
5179
5180 if (sc->dyn_side_channels == NULL)
5181 {
5182 sc->dyn_side_channels = (DynamicLibInfo *)SnortAlloc(sizeof(DynamicLibInfo));
5183 sc->dyn_side_channels->type = DYNAMIC_TYPE__SIDE_CHANNEL;
5184 }
5185
5186 ParseDynamicLibInfo(sc->dyn_side_channels, args);
5187 }
5188
5189 # endif /* SIDE_CHANNEL */
5190
5191 /****************************************************************************
5192 *
5193 * Purpose: Parses a dynamic output lib line
5194 * Format is full path of dynamic output
5195 *
5196 * Arguments: args => string containing a single dynamic output
5197 *
5198 * Returns: void function
5199 *
5200 *****************************************************************************/
ParseDynamicOutputInfo(SnortConfig * sc,SnortPolicy * p,char * args)5201 static void ParseDynamicOutputInfo(SnortConfig *sc, SnortPolicy *p, char *args)
5202 {
5203 char **toks = NULL;
5204 int num_toks = 0;
5205 char *path = NULL;
5206 PathType ptype = PATH_TYPE__FILE;
5207 if (sc == NULL)
5208 return;
5209
5210 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"DynamicOutput\n"););
5211
5212 if (args == NULL)
5213 {
5214 char *getcwd_path = SnortAlloc(PATH_MAX);
5215
5216 if (getcwd(getcwd_path, PATH_MAX) == NULL)
5217 {
5218 ParseError("Dynamic library path too long. If you really "
5219 "think your path needs to be as long as it is, please "
5220 "submit a bug to bugs@snort.org.");
5221 }
5222
5223 path = getcwd_path;
5224 ptype = PATH_TYPE__DIRECTORY;
5225 }
5226 else
5227 {
5228 toks = mSplit(args, " \t", 0, &num_toks, 0);
5229
5230 if (num_toks == 1)
5231 {
5232 path = SnortStrdup(toks[0]);
5233 ptype = PATH_TYPE__FILE;
5234 }
5235 else if (num_toks == 2)
5236 {
5237 if (strcasecmp(toks[0], DYNAMIC_LIB_OPT__FILE) == 0)
5238 {
5239 ptype = PATH_TYPE__FILE;
5240 }
5241 else if (strcasecmp(toks[0], DYNAMIC_LIB_OPT__DIRECTORY) == 0)
5242 {
5243 ptype = PATH_TYPE__DIRECTORY;
5244 }
5245 else
5246 {
5247 ParseError("Invalid specifier for Dynamic library specifier. "
5248 "Should be file|directory pathname.");
5249 }
5250
5251 path = SnortStrdup(toks[1]);
5252 }
5253 else
5254 {
5255 ParseError("Missing/incorrect dynamic engine lib specifier.");
5256 }
5257 mSplitFree(&toks, num_toks);
5258 }
5259 if (ptype == PATH_TYPE__DIRECTORY)
5260 output_load(path);
5261 else if (ptype == PATH_TYPE__FILE)
5262 output_load_module(path);
5263 if (path)
5264 free(path);
5265
5266 }
5267
5268 /* verify that we are not reusing some other keyword */
ValidateUserDefinedRuleType(SnortConfig * sc,char * keyword)5269 static int ValidateUserDefinedRuleType(SnortConfig *sc, char *keyword)
5270 {
5271 RuleListNode *node;
5272
5273 if ((sc == NULL) || (sc->rule_lists == NULL))
5274 return 0;
5275
5276 node = sc->rule_lists;
5277
5278 /* This keyword cannot match any of our predefined rule types */
5279 if (GetRuleType(keyword) != RULE_TYPE__NONE)
5280 return 0;
5281
5282 /* Walk through the rule list to make sure the user didn't already
5283 * define this one */
5284 while (node != NULL)
5285 {
5286 if (strcasecmp(node->name, keyword) == 0)
5287 return 0;
5288
5289 node = node->next;
5290 }
5291
5292 return 1;
5293 }
5294
5295 /* This function does nothing. It is just a place holder in the snort conf
5296 * keyword array so the keyword can be matched. Its's a special configuration
5297 * case in that multiple non-escaped lines need to be read and the current
5298 * file pointer needs to be passed in. */
ParseRuleTypeDeclaration(SnortConfig * sc,SnortPolicy * p,char * arg)5299 static void ParseRuleTypeDeclaration(SnortConfig *sc, SnortPolicy *p, char *arg)
5300 {
5301 return;
5302 }
5303
_ParseRuleTypeDeclaration(SnortConfig * sc,FILE * fp,char * arg,int prules)5304 static void _ParseRuleTypeDeclaration(SnortConfig *sc, FILE *fp, char *arg, int prules)
5305 {
5306 char **toks;
5307 int num_toks;
5308 char *input;
5309 char *rule_type_name;
5310 RuleType type;
5311 int rval = 1;
5312 ListHead *listhead = NULL;
5313 int got_output = 0;
5314
5315 if ((sc == NULL) || (fp == NULL) || (arg == NULL))
5316 return;
5317
5318 /* Already parsed this or ignoring for any non-default policy, but need to move past
5319 * the rule declaration because it doesn't have continuation characters
5320 */
5321 if (prules /* parsing rules */
5322 || (getParserPolicy(sc) != getDefaultPolicy()))
5323 {
5324 while (1)
5325 {
5326 input = ReadLine(fp);
5327 if (input == NULL)
5328 ParseError("Rule type declaration syntax error: %s.", arg);
5329
5330 toks = mSplit(input, " \t", 2, &num_toks, 0);
5331
5332 /* Just continue for blank line */
5333 if (toks == NULL)
5334 {
5335 free (input);
5336 continue;
5337 }
5338
5339 /* Got end of rule type */
5340 if ((num_toks == 1) && (strcmp(toks[0], "}") == 0))
5341 {
5342 free(input);
5343 mSplitFree(&toks, num_toks);
5344 break;
5345 }
5346
5347 free(input);
5348 mSplitFree(&toks, num_toks);
5349 }
5350
5351 return;
5352 }
5353
5354
5355 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Rule type declaration\n"););
5356
5357 toks = mSplit(arg, " \t", 2, &num_toks, 0);
5358
5359 /* Need rule type name for creating new node in rule list */
5360 rule_type_name = SnortStrdup(ExpandVars(sc, toks[0]));
5361
5362 /* Verify keyword is unique */
5363 if (!ValidateUserDefinedRuleType(sc, rule_type_name))
5364 {
5365 ParseError("Duplicate rule type declaration found: %s.", rule_type_name);
5366 }
5367
5368 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Declaring new rule type: %s\n",
5369 rule_type_name););
5370
5371 if (num_toks == 2)
5372 {
5373 /* User put '{' on the same line, which is okay */
5374 if ((toks[1] != NULL) && (strcmp(toks[1], "{") != 0))
5375 {
5376 ParseError("Rule type declaration syntax error: %s.", arg);
5377 }
5378 }
5379 else
5380 {
5381 /* Get next line. It should only be '{' */
5382 input = ReadLine(fp);
5383 if ((input == NULL) || (strcmp(input, "{") != 0))
5384 {
5385 ParseError("Rule type declaration syntax error: %s.", arg);
5386 }
5387
5388 free(input);
5389 }
5390
5391 mSplitFree(&toks, num_toks);
5392
5393 input = ReadLine(fp);
5394 if (input == NULL)
5395 ParseError("Rule type declaration syntax error: %s.", arg);
5396
5397 toks = mSplit(input, " \t", 2, &num_toks, 0);
5398 if ((num_toks != 2) ||
5399 (strcasecmp(toks[0], RULE_TYPE_OPT__TYPE) != 0))
5400 {
5401 ParseError("Rule type declaration syntax error: %s.", arg);
5402 }
5403
5404 type = GetRuleType(toks[1]);
5405 if (type == RULE_TYPE__NONE)
5406 ParseError("Invalid type for rule type declaration: %s.", toks[1]);
5407
5408 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"\ttype(%i): %s\n", type, toks[1]););
5409
5410 if (type == RULE_TYPE__PASS)
5411 rval = 0;
5412
5413 listhead = CreateRuleType(sc, rule_type_name, type, rval, NULL);
5414
5415 free(rule_type_name);
5416 free(input);
5417 mSplitFree(&toks, num_toks);
5418
5419 /* Get output plugin declarations
5420 * This will break if '}' is found on the line and fatal error if not and
5421 * the line isn't an output configuration */
5422 while (1)
5423 {
5424 input = ReadLine(fp);
5425 if (input == NULL)
5426 ParseError("Rule type declaration syntax error: %s.", arg);
5427
5428 toks = mSplit(input, " \t", 2, &num_toks, 0);
5429
5430 /* Just continue for blank line */
5431 if (toks == NULL)
5432 {
5433 free(input);
5434 continue;
5435 }
5436
5437 /* Got end of rule type */
5438 if ((num_toks == 1) && (strcmp(toks[0], "}") == 0))
5439 {
5440 free(input);
5441 mSplitFree(&toks, num_toks);
5442 break;
5443 }
5444
5445 if ((num_toks != 2) ||
5446 (strcasecmp(toks[0], SNORT_CONF_KEYWORD__OUTPUT) != 0))
5447 {
5448 ParseError("Rule type declaration syntax error: %s. This line "
5449 "should contain an output declaration.", toks[0]);
5450 }
5451
5452 ParseRuleTypeOutput(sc, toks[1], listhead);
5453
5454 free(input);
5455 mSplitFree(&toks, num_toks);
5456
5457 got_output = 1;
5458 }
5459
5460 if (!got_output)
5461 ParseError("Rule type declaration requires an output configuration.");
5462
5463 sc->num_rule_types++;
5464 }
5465
5466 /* adapted from ParseRuleFile in rules.c
5467 * Returns NULL if the end of file is reached or some other strange file
5468 * reading error should occur
5469 * Will read lines until it finds one that isn't empty or commented
5470 * Returned string, if not NULL, needs to be freed */
ReadLine(FILE * file)5471 char * ReadLine(FILE * file)
5472 {
5473 char *buf = (char *)SnortAlloc(MAX_LINE_LENGTH + 1);
5474
5475 /* Read a line from file and return it. Return NULL for lines that
5476 * are comment characters or empty */
5477 while ((fgets(buf, MAX_LINE_LENGTH, file)) != NULL)
5478 {
5479 int i;
5480 char *index;
5481 char *ret_line;
5482
5483 file_line++;
5484 index = buf;
5485
5486 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Got line %s (%d): %s\n",
5487 file_name, file_line, buf););
5488
5489 /* advance through any whitespace at the beginning of the line */
5490 while (isspace((int)*index))
5491 index++;
5492
5493 /* If it's an empty line or starts with a comment character */
5494 if ((strlen(index) == 0) || (*index == '#') || (*index == ';'))
5495 continue;
5496
5497 /* Trim off any whitespace at the end of the line */
5498 for (i = strlen(index); i > 0; i--)
5499 {
5500 if (!isspace((int)index[i - 1]))
5501 break;
5502 }
5503
5504 index[i] = '\0';
5505
5506 /* return a copy of the line */
5507 ret_line = SnortStrdup(index);
5508 free(buf);
5509 return ret_line;
5510 }
5511
5512 free(buf);
5513 return NULL;
5514 }
5515
5516 /*
5517 * Same as VarGet - but this does not Fatal out if a var is not found
5518 */
VarSearch(SnortConfig * sc,char * name)5519 static char * VarSearch(SnortConfig *sc, char *name)
5520 {
5521 VarEntry *var_table = sc->targeted_policies[getParserPolicy(sc)]->var_table;
5522 PortVarTable *portVarTable = sc->targeted_policies[getParserPolicy(sc)]->portVarTable;
5523 vartable_t *ip_vartable = sc->targeted_policies[getParserPolicy(sc)]->ip_vartable;
5524 sfip_var_t *ipvar;
5525
5526 if ((ipvar = sfvt_lookup_var(ip_vartable, name)) != NULL)
5527 return ExpandVars(sc, ipvar->value);
5528
5529 /* XXX Return a string value */
5530 if (PortVarTableFind(portVarTable, name))
5531 return name;
5532
5533 if (var_table != NULL)
5534 {
5535 VarEntry *p = var_table;
5536 do
5537 {
5538 if(strcasecmp(p->name, name) == 0)
5539 return p->value;
5540 p = p->next;
5541
5542 } while(p != var_table);
5543 }
5544
5545 return NULL;
5546 }
5547
5548 /*****************************************************************
5549 * Function: GetPcaps()
5550 *
5551 * This function takes a list of pcap types and arguments from
5552 * the command line, parses them depending on type and puts them
5553 * in a user supplied queue. The pcap object list will contain
5554 * PcapReadObject structures. The returned queue contains
5555 * strings representing paths to pcaps.
5556 *
5557 * returns -1 on error and 0 on success
5558 *
5559 ****************************************************************/
GetPcaps(SF_LIST * pol,SF_QUEUE * pcap_queue)5560 int GetPcaps(SF_LIST *pol, SF_QUEUE *pcap_queue)
5561 {
5562 PcapReadObject *pro = NULL;
5563 int type = 0;
5564 char *arg = NULL;
5565 char *filter = NULL;
5566 int ret = 0;
5567
5568 if ((pol == NULL) || (pcap_queue == NULL))
5569 return -1;
5570
5571 for (pro = (PcapReadObject *)sflist_first(pol);
5572 pro != NULL;
5573 pro = (PcapReadObject *)sflist_next(pol))
5574 {
5575 type = pro->type;
5576 arg = pro->arg;
5577 filter = pro->filter;
5578
5579 switch (type)
5580 {
5581 case PCAP_SINGLE:
5582 {
5583 char *pcap = NULL;
5584 struct stat stat_buf;
5585
5586 /* Don't check file if reading from stdin */
5587 if (strcmp(arg, "-") != 0)
5588 {
5589 /* do a quick check to make sure file exists */
5590 if (stat(arg, &stat_buf) == -1)
5591 {
5592 ErrorMessage("Error getting stat on pcap file: %s: %s\n",
5593 arg, strerror(errno));
5594 return -1;
5595 }
5596 else if (!(stat_buf.st_mode & (S_IFREG|S_IFIFO)))
5597 {
5598 ErrorMessage("Specified pcap is not a regular file: %s\n", arg);
5599 return -1;
5600 }
5601 }
5602
5603 pcap = SnortStrdup(arg);
5604 ret = sfqueue_add(pcap_queue, (NODE_DATA)pcap);
5605 if (ret == -1)
5606 {
5607 ErrorMessage("Could not add pcap to pcap list\n");
5608 free(pcap);
5609 return -1;
5610 }
5611 }
5612
5613 break;
5614
5615 case PCAP_FILE_LIST:
5616 /* arg should be a file with a list of pcaps in it */
5617 {
5618 FILE *pcap_file = NULL;
5619 char *pcap = NULL;
5620 char path_buf[4096]; /* max chars we'll accept for a path */
5621
5622 pcap_file = fopen(arg, "r");
5623 if (pcap_file == NULL)
5624 {
5625 ErrorMessage("Could not open pcap list file: %s: %s\n",
5626 arg, strerror(errno));
5627 return -1;
5628 }
5629
5630 while (fgets(path_buf, sizeof(path_buf), pcap_file) != NULL)
5631 {
5632 char *path_buf_ptr, *path_buf_end;
5633 struct stat stat_buf;
5634
5635 path_buf[sizeof(path_buf) - 1] = '\0';
5636 path_buf_ptr = &path_buf[0];
5637 path_buf_end = path_buf_ptr + strlen(path_buf_ptr);
5638
5639 /* move past spaces if any */
5640 while (isspace((int)*path_buf_ptr))
5641 path_buf_ptr++;
5642
5643 /* if nothing but spaces on line, continue */
5644 if (*path_buf_ptr == '\0')
5645 continue;
5646
5647 /* get rid of trailing spaces */
5648 while ((path_buf_end > path_buf_ptr) &&
5649 (isspace((int)*(path_buf_end - 1))))
5650 path_buf_end--;
5651
5652 *path_buf_end = '\0';
5653
5654 /* do a quick check to make sure file exists */
5655 if (stat(path_buf_ptr, &stat_buf) == -1)
5656 {
5657 ErrorMessage("Error getting stat on pcap file: %s: %s\n",
5658 path_buf_ptr, strerror(errno));
5659 fclose(pcap_file);
5660 return -1;
5661 }
5662 #ifndef WIN32
5663 else if (stat_buf.st_mode & S_IFDIR)
5664 {
5665 ret = GetFilesUnderDir(path_buf_ptr, pcap_queue, filter);
5666 if (ret == -1)
5667 {
5668 ErrorMessage("Error getting pcaps under dir: %s\n", path_buf_ptr);
5669 fclose(pcap_file);
5670 return -1;
5671 }
5672 }
5673 #endif
5674 else if (stat_buf.st_mode & S_IFREG)
5675 {
5676 #ifndef WIN32
5677 if ((filter == NULL) || (fnmatch(filter, path_buf_ptr, 0) == 0))
5678 {
5679 #endif
5680 pcap = SnortStrdup(path_buf_ptr);
5681 ret = sfqueue_add(pcap_queue, (NODE_DATA)pcap);
5682 if (ret == -1)
5683 {
5684 ErrorMessage("Could not insert pcap into list: %s\n", pcap);
5685 free(pcap);
5686 fclose(pcap_file);
5687 return -1;
5688 }
5689 #ifndef WIN32
5690 }
5691 #endif
5692 }
5693 else
5694 {
5695 #ifdef WIN32
5696 ErrorMessage("Specified entry in \'%s\' is not a regular file: %s\n",
5697 arg, path_buf_ptr);
5698 #else
5699 ErrorMessage("Specified entry in \'%s\' is not a regular file or directory: %s\n",
5700 arg, path_buf_ptr);
5701 #endif
5702 fclose(pcap_file);
5703 return -1;
5704 }
5705 }
5706
5707 fclose(pcap_file);
5708 }
5709
5710 break;
5711
5712 case PCAP_LIST:
5713 /* arg should be a space separated list of pcaps */
5714 {
5715 char *tmp = NULL;
5716 char *pcap = NULL;
5717 struct stat stat_buf;
5718
5719 tmp = strtok_r(arg, " ", &arg);
5720 if (tmp == NULL)
5721 {
5722 ErrorMessage("No pcaps specified in pcap list\n");
5723 return -1;
5724 }
5725
5726 do
5727 {
5728 /* do a quick check to make sure file exists */
5729 if (stat(tmp, &stat_buf) == -1)
5730 {
5731 ErrorMessage("Error getting stat on file: %s: %s\n",
5732 tmp, strerror(errno));
5733 return -1;
5734 }
5735 else if (!(stat_buf.st_mode & (S_IFREG|S_IFIFO)))
5736 {
5737 ErrorMessage("Specified pcap is not a regular file: %s\n", tmp);
5738 return -1;
5739 }
5740
5741 pcap = SnortStrdup(tmp);
5742 ret = sfqueue_add(pcap_queue, (NODE_DATA)pcap);
5743 if (ret == -1)
5744 {
5745 ErrorMessage("Could not insert pcap into list: %s\n", pcap);
5746 free(pcap);
5747 return -1;
5748 }
5749
5750 } while ((tmp = strtok_r(NULL, " ", &arg)) != NULL);
5751 }
5752
5753 break;
5754
5755 #ifndef WIN32
5756 case PCAP_DIR:
5757 /* arg should be a directory name */
5758 ret = GetFilesUnderDir(arg, pcap_queue, filter);
5759 if (ret == -1)
5760 {
5761 ErrorMessage("Error getting pcaps under dir: %s\n", arg);
5762 return -1;
5763 }
5764
5765 break;
5766 #endif
5767
5768 default:
5769 ParseError("Bad read multiple pcaps type\n");
5770 break;
5771 }
5772 }
5773
5774 return 0;
5775 }
5776
ValidateIPList(IpAddrSet * addrset,char * token)5777 int ValidateIPList(IpAddrSet *addrset, char *token)
5778 {
5779 if(!addrset || !(addrset->head||addrset->neg_head))
5780 {
5781 ParseError("Empty IP used either as source IP or as "
5782 "destination IP in a rule. IP list: %s.", token);
5783 }
5784
5785 return 0;
5786 }
5787
ParserCleanup(void)5788 void ParserCleanup(void)
5789 {
5790 port_list_free(&port_list);
5791
5792 if (ruleIndexMap != NULL)
5793 {
5794 RuleIndexMapFree(&ruleIndexMap);
5795 ruleIndexMap = NULL;
5796 }
5797 }
5798
InitVarTables(SnortPolicy * p)5799 static void InitVarTables(SnortPolicy *p)
5800 {
5801 if (p == NULL)
5802 return;
5803
5804 if (p->var_table != NULL)
5805 DeleteVars(p->var_table);
5806 p->var_id = 1;
5807
5808 if (p->ip_vartable != NULL)
5809 sfvt_free_table(p->ip_vartable);
5810 p->ip_vartable = sfvt_alloc_table();
5811
5812 if (p->portVarTable != NULL)
5813 PortVarTableFree(p->portVarTable);
5814 p->portVarTable = PortVarTableCreate();
5815
5816 if (p->nonamePortVarTable != NULL)
5817 PortTableFree(p->nonamePortVarTable);
5818 p->nonamePortVarTable = PortTableNew();
5819
5820 if ((p->portVarTable == NULL) || (p->nonamePortVarTable == NULL))
5821 {
5822 ParseError("Failed to create port variable tables.\n");
5823 }
5824 }
5825
InitPolicyMode(SnortPolicy * p)5826 static void InitPolicyMode(SnortPolicy *p)
5827 {
5828 if (!ScAdapterInlineMode() && !ScAdapterInlineTestMode())
5829 {
5830 p->ips_policy_mode = POLICY_MODE__PASSIVE;
5831 p->nap_policy_mode = POLICY_MODE__PASSIVE;
5832 }
5833 else if (ScAdapterInlineTestMode())
5834 {
5835 p->ips_policy_mode = POLICY_MODE__INLINE_TEST;
5836 p->nap_policy_mode = POLICY_MODE__INLINE_TEST;
5837 }
5838 else
5839 {
5840 p->ips_policy_mode = POLICY_MODE__INLINE;
5841 p->nap_policy_mode = POLICY_MODE__INLINE;
5842 }
5843 }
5844
InitParser(void)5845 static void InitParser(void)
5846 {
5847 rule_count = 0;
5848 detect_rule_count = 0;
5849 decode_rule_count = 0;
5850 preproc_rule_count = 0;
5851 head_count = 0;
5852 otn_count = 0;
5853
5854 memset(&tcpCnt, 0, sizeof(tcpCnt));
5855 memset(&udpCnt, 0, sizeof(udpCnt));
5856 memset(&ipCnt, 0, sizeof(ipCnt));
5857 memset(&icmpCnt, 0, sizeof(icmpCnt));
5858
5859 port_list_free(&port_list);
5860 memset(&port_list, 0, sizeof(port_list));
5861 port_list.pl_max = MAX_RULE_COUNT;
5862
5863 if (ruleIndexMap != NULL)
5864 RuleIndexMapFree(&ruleIndexMap);
5865 ruleIndexMap = RuleIndexMapCreate(MAX_RULE_COUNT);
5866 if (ruleIndexMap == NULL)
5867 {
5868 ParseError("Failed to create rule index map.\n");
5869 }
5870
5871 /* This is for determining if a config option has already been
5872 * configured. Most can only be configured once */
5873 memset(config_opt_configured, 0, sizeof(config_opt_configured));
5874 }
5875
ParseRules(SnortConfig * sc)5876 void ParseRules(SnortConfig *sc)
5877 {
5878 tSfPolicyId policy_id;
5879
5880 if ((sc == NULL) || (snort_conf_file == NULL))
5881 return;
5882
5883 file_line = 0;
5884 file_name = snort_conf_file;
5885
5886 LogMessage("\n");
5887 LogMessage("+++++++++++++++++++++++++++++++++++++++++++++++++++\n");
5888 LogMessage("Initializing rule chains...\n");
5889
5890 /* Global set for parsing a configuration file to tell it whether
5891 * we're parsing rules or not - see ParseConfigFile */
5892 parse_rules = 1;
5893
5894 /* Set to default policy */
5895 policy_id = sfGetDefaultPolicy(sc->policy_config);
5896 setParserPolicy(sc, policy_id);
5897
5898 ParseConfigFile(sc, sc->targeted_policies[policy_id], snort_conf_file);
5899
5900 /* Parse rules in targeted policies */
5901 for (policy_id = 0;
5902 policy_id < sfPolicyNumAllocated(sc->policy_config);
5903 policy_id++)
5904 {
5905 char *fname = sfPolicyGet(sc->policy_config, policy_id);
5906
5907 if (policy_id == sfGetDefaultPolicy(sc->policy_config))
5908 continue;
5909
5910 if (fname != NULL)
5911 {
5912 setParserPolicy(sc, policy_id);
5913 ParseInclude(sc, sc->targeted_policies[policy_id], fname);
5914 }
5915 }
5916
5917 LogMessage("%d Snort rules read\n", rule_count);
5918 LogMessage(" %d detection rules\n", detect_rule_count);
5919 LogMessage(" %d decoder rules\n", decode_rule_count);
5920 LogMessage(" %d preprocessor rules\n", preproc_rule_count);
5921 LogMessage("%d Option Chains linked into %d Chain Headers\n", otn_count, head_count);
5922 LogMessage("+++++++++++++++++++++++++++++++++++++++++++++++++++\n");
5923 LogMessage("\n");
5924
5925
5926 #ifdef DEBUG_MSGS
5927 DumpRuleChains(sc->rule_lists);
5928 #endif
5929
5930 IntegrityCheckRules(sc);
5931 /*FindMaxSegSize();*/
5932
5933 /* Compile/Finish and Print the PortList Tables */
5934 PortTablesFinish(sc->port_tables, sc->fast_pattern_config);
5935
5936 LogMessage("+-------------------[Rule Port Counts]---------------------------------------\n");
5937 LogMessage("|%8s%8s%8s%8s%8s\n", " ", "tcp", "udp", "icmp", "ip");
5938 LogMessage("|%8s%8u%8u%8u%8u\n", "src", tcpCnt.src, udpCnt.src, icmpCnt.src, ipCnt.src);
5939 LogMessage("|%8s%8u%8u%8u%8u\n", "dst", tcpCnt.dst, udpCnt.dst, icmpCnt.dst, ipCnt.dst);
5940 LogMessage("|%8s%8u%8u%8u%8u\n", "any", tcpCnt.aa, udpCnt.aa, icmpCnt.aa, ipCnt.aa);
5941 LogMessage("|%8s%8u%8u%8u%8u\n", "nc", tcpCnt.nc, udpCnt.nc, icmpCnt.nc, ipCnt.nc);
5942 LogMessage("|%8s%8u%8u%8u%8u\n", "s+d", tcpCnt.sd, udpCnt.sd, icmpCnt.sd, ipCnt.sd);
5943 LogMessage("+----------------------------------------------------------------------------\n");
5944
5945 ///print_rule_index_map( ruleIndexMap );
5946 ///port_list_print( &port_list );
5947
5948 /* Reset these. The only issue in not reseting would be if we were
5949 * parsing a command line again, but do it anyway */
5950 file_name = NULL;
5951 file_line = 0;
5952 }
5953
ParseInclude(SnortConfig * sc,SnortPolicy * p,char * arg)5954 static void ParseInclude(SnortConfig *sc, SnortPolicy *p, char *arg)
5955 {
5956 struct stat file_stat; /* for include path testing */
5957 /* Save place in previous file */
5958 char *stored_file_name = file_name;
5959 int stored_file_line = file_line;
5960
5961 /* Including top level snort conf file */
5962 if (strcmp(arg, snort_conf_file) == 0)
5963 {
5964 ParseError("Cannot include \"%s\" in an include directive.",
5965 snort_conf_file);
5966 }
5967
5968 /* XXX Maybe not allow an include in an included file to avoid
5969 * potential recursion issues */
5970
5971 file_line = 0;
5972 file_name = SnortStrdup(arg);
5973
5974 /* Stat the file. If that fails, stat it relative to the directory
5975 * that the top level snort configuration file was in */
5976 if (stat(file_name, &file_stat) == -1)
5977 {
5978 int path_len = strlen(snort_conf_dir) + strlen(arg) + 1;
5979
5980 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"ParseConfigFile: stat "
5981 "on %s failed - going to config_dir\n", file_name););
5982
5983 free(file_name);
5984
5985 file_name = (char *)SnortAlloc(path_len);
5986 snprintf(file_name, path_len, "%s%s", snort_conf_dir, arg);
5987
5988 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"ParseConfigFile: Opening "
5989 "and parsing %s\n", file_name););
5990 }
5991
5992 ParseConfigFile(sc, p, file_name);
5993
5994 free(file_name);
5995
5996 file_name = stored_file_name;
5997 file_line = stored_file_line;
5998 }
5999
ParseConfigFile(SnortConfig * sc,SnortPolicy * p,char * fname)6000 static void ParseConfigFile(SnortConfig *sc, SnortPolicy *p, char *fname)
6001 {
6002 /* Used for line continuation */
6003 int continuation = 0;
6004 char *saved_line = NULL;
6005 char *new_line = NULL;
6006 char *buf = (char *)SnortAlloc(MAX_LINE_LENGTH + 1);
6007 FILE *fp = fopen(fname, "r");
6008
6009 /* open the rules file */
6010 if (fp == NULL)
6011 {
6012 ParseError("Unable to open rules file \"%s\": %s.\n",
6013 fname, strerror(errno));
6014 }
6015
6016 /* loop thru each file line and send it to the rule parser */
6017 while ((fgets(buf, MAX_LINE_LENGTH, fp)) != NULL)
6018 {
6019 /* buffer indexing pointer */
6020 char *index = buf;
6021
6022 /* Increment the line counter so the error messages know which
6023 * line to bitch about */
6024 file_line++;
6025
6026 /* fgets always appends a null, so doing a strlen should be safe */
6027 if ((strlen(buf) + 1) == MAX_LINE_LENGTH)
6028 {
6029 ParseError("Line greater than or equal to %u characters which is "
6030 "more than the parser is willing to handle. Try "
6031 "splitting it up on multiple lines if possible.",
6032 MAX_LINE_LENGTH);
6033 }
6034
6035 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Got line %s (%d): %s\n",
6036 fname, file_line, buf););
6037
6038 /* advance through any whitespace at the beginning of the line */
6039 while (isspace((int)*index))
6040 index++;
6041
6042 /* If it's an empty line or starts with a comment character */
6043 if ((strlen(index) == 0) || (*index == '#') || (*index == ';'))
6044 continue;
6045
6046 if (continuation)
6047 {
6048 int new_line_len = strlen(saved_line) + strlen(index) + 1;
6049
6050 if (new_line_len >= PARSERULE_SIZE)
6051 {
6052 ParseError("Rule greater than or equal to %u characters which "
6053 "is more than the parser is willing to handle. "
6054 "Submit a bug to bugs@snort.org if you legitimately "
6055 "feel like your rule or keyword configuration needs "
6056 "more than this amount of space.", PARSERULE_SIZE);
6057 }
6058
6059 new_line = (char *)SnortAlloc(new_line_len);
6060 snprintf(new_line, new_line_len, "%s%s", saved_line, index);
6061
6062 free(saved_line);
6063 saved_line = NULL;
6064 index = new_line;
6065
6066 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"concat rule: %s\n",
6067 new_line););
6068 }
6069
6070 /* check for a '\' continuation character at the end of the line
6071 * if it's there we need to get the next line in the file */
6072 if (ContinuationCheck(index) == 0)
6073 {
6074 char **toks;
6075 int num_toks;
6076 char *keyword;
6077 char *args;
6078 int i;
6079
6080 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,
6081 "[*] Processing keyword: %s\n", index););
6082
6083 /* Get the keyword and args */
6084 toks = mSplit(index, " \t", 2, &num_toks, 0);
6085 if (num_toks != 2)
6086 ParseError("Invalid configuration line: %s", index);
6087
6088 keyword = SnortStrdup(ExpandVars(sc, toks[0]));
6089 args = toks[1];
6090
6091 for (i = 0; snort_conf_keywords[i].name != NULL; i++)
6092 {
6093 if (strcasecmp(keyword, snort_conf_keywords[i].name) == 0)
6094 {
6095 if ((getParserPolicy(sc) != getDefaultPolicy()) &&
6096 snort_conf_keywords[i].default_policy_only)
6097 {
6098 /* Keyword only configurable in the default policy*/
6099 DEBUG_WRAP(DebugMessage(DEBUG_INIT,
6100 "Config option \"%s\" configurable only by default policy. Ignoring it", toks[0]));
6101 break;
6102 }
6103
6104 if (((snort_conf_keywords[i].type == KEYWORD_TYPE__RULE) &&
6105 !parse_rules) ||
6106 ((snort_conf_keywords[i].type == KEYWORD_TYPE__MAIN) &&
6107 parse_rules))
6108 {
6109 break;
6110 }
6111
6112 if (snort_conf_keywords[i].expand_vars)
6113 args = SnortStrdup(ExpandVars(sc, toks[1]));
6114
6115 /* Special parsing case is ruletype.
6116 * Need to send the file pointer so it can parse what's
6117 * between '{' and '}' which can span multiple lines
6118 * without a line continuation character */
6119 if (strcasecmp(keyword, SNORT_CONF_KEYWORD__RULE_TYPE) == 0)
6120 _ParseRuleTypeDeclaration(sc, fp, args, parse_rules);
6121 else
6122 snort_conf_keywords[i].parse_func(sc, p, args);
6123
6124 break;
6125 }
6126 }
6127
6128 /* Didn't find any pre-defined snort_conf_keywords. Look for a user defined
6129 * rule type */
6130
6131 if ((snort_conf_keywords[i].name == NULL) && parse_rules)
6132 {
6133 RuleListNode *node;
6134
6135 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Unknown rule type, "
6136 "might be declared\n"););
6137
6138 for (node = sc->rule_lists; node != NULL; node = node->next)
6139 {
6140 if (strcasecmp(node->name, keyword) == 0)
6141 break;
6142 }
6143
6144 if (node == NULL)
6145 ParseError("Unknown rule type: %s.", toks[0]);
6146
6147 if ( node->mode == RULE_TYPE__DROP )
6148 {
6149 if ( ScTreatDropAsAlertNewConf(sc) )
6150 ParseRule(sc, p, args, RULE_TYPE__ALERT, node->RuleList);
6151
6152 else if ( ScKeepDropRules(sc) || ScLoadAsDropRules(sc) )
6153 ParseRule(sc, p, args, node->mode, node->RuleList);
6154 }
6155 else if ( node->mode == RULE_TYPE__SDROP )
6156 {
6157 if ( ScKeepDropRules(sc) && !ScTreatDropAsAlertNewConf(sc) )
6158 ParseRule(sc, p, args, node->mode, node->RuleList);
6159
6160 else if ( ScLoadAsDropRules(sc) )
6161 ParseRule(sc, p, args, RULE_TYPE__DROP, node->RuleList);
6162 }
6163 else
6164 {
6165 ParseRule(sc, p, args, node->mode, node->RuleList);
6166 }
6167 }
6168
6169 if (args != toks[1])
6170 free(args);
6171
6172 free(keyword);
6173 mSplitFree(&toks, num_toks);
6174
6175 if(new_line != NULL)
6176 {
6177 free(new_line);
6178 new_line = NULL;
6179 continuation = 0;
6180 }
6181 }
6182 else
6183 {
6184 /* save the current line */
6185 saved_line = SnortStrdup(index);
6186
6187 /* current line was a continuation itself... */
6188 if (new_line != NULL)
6189 {
6190 free(new_line);
6191 new_line = NULL;
6192 }
6193
6194 /* set the flag to let us know the next line is
6195 * a continuation line */
6196 continuation = 1;
6197 }
6198 }
6199
6200 if (saved_line != NULL)
6201 free(saved_line);
6202
6203 fclose(fp);
6204 free(buf);
6205 }
6206
ContinuationCheck(char * rule)6207 static int ContinuationCheck(char *rule)
6208 {
6209 char *idx; /* indexing var for moving around on the string */
6210
6211 idx = rule + strlen(rule) - 1;
6212
6213 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"initial idx set to \'%c\'\n",
6214 *idx););
6215
6216 while(isspace((int)*idx))
6217 {
6218 idx--;
6219 }
6220
6221 if(*idx == '\\')
6222 {
6223 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Got continuation char, "
6224 "clearing char and returning 1\n"););
6225
6226 /* clear the '\' so there isn't a problem on the appended string */
6227 *idx = '\x0';
6228 return 1;
6229 }
6230
6231 return 0;
6232 }
6233
ConfigAlertBeforePass(SnortConfig * sc,char * args)6234 void ConfigAlertBeforePass(SnortConfig *sc, char *args)
6235 {
6236 if (sc == NULL)
6237 return;
6238
6239 sc->run_flags |= RUN_FLAG__ALERT_BEFORE_PASS;
6240 }
6241
ConfigAlertFile(SnortConfig * sc,char * args)6242 void ConfigAlertFile(SnortConfig *sc, char *args)
6243 {
6244 if ((args == NULL) || (sc == NULL) || (sc->alert_file != NULL))
6245 return;
6246
6247 sc->alert_file = SnortStrdup(args);
6248
6249 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"alertfile set to: %s\n",
6250 sc->alert_file););
6251 }
6252
ConfigAlertWithInterfaceName(SnortConfig * sc,char * args)6253 void ConfigAlertWithInterfaceName(SnortConfig *sc, char *args)
6254 {
6255 if (sc == NULL)
6256 return;
6257
6258 sc->output_flags |= OUTPUT_FLAG__ALERT_IFACE;
6259 }
6260
ConfigAsn1(SnortConfig * sc,char * args)6261 void ConfigAsn1(SnortConfig *sc, char *args)
6262 {
6263 long int num_nodes;
6264 char *endptr;
6265
6266 if ((sc == NULL) || (args == NULL))
6267 return;
6268
6269 num_nodes = SnortStrtol(args, &endptr, 0);
6270 if ((errno == ERANGE) || (*endptr != '\0') || (num_nodes <= 0))
6271 {
6272 ParseError("Invalid argument to 'asn1' configuration. "
6273 "Must be a positive integer.");
6274 }
6275
6276 sc->asn1_mem = num_nodes;
6277 }
6278
ConfigAutogenPreprocDecoderRules(SnortConfig * sc,char * args)6279 void ConfigAutogenPreprocDecoderRules(SnortConfig *sc, char *args)
6280 {
6281 SnortPolicy* policy;
6282
6283 if (sc == NULL)
6284 return;
6285
6286 /* config autogenerate_preprocessor_decoder_rules */
6287 UpdateDecodeRulesArray(0, ENABLE_RULE, ENABLE_ALL_RULES);
6288 policy = sc->targeted_policies[getParserPolicy(sc)];
6289 policy->policy_flags |= POLICY_FLAG__AUTO_OTN;
6290 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Autogenerating Preprocessor and Decoder OTNs\n"););
6291 }
6292
ConfigBinding(SnortConfig * sc,char * args)6293 void ConfigBinding(SnortConfig *sc, char *args)
6294 {
6295 int num_toks;
6296 int num_toks1;
6297 char **toks;
6298 char **toks1;
6299 char *fileName;
6300 int bindingType;
6301 toks1 = mSplit(args, " \t", 3, &num_toks1, 0);
6302 if(num_toks1 < 3)
6303 {
6304 mSplitFree(&toks1, num_toks1);
6305 ParseError("Need at least two arguments to 'config binding'");
6306 return;
6307 }
6308
6309 if (!strcmp("policy_id", toks1[1]))
6310 {
6311 bindingType = SF_BINDING_TYPE_POLICY_ID;
6312 }
6313 #ifndef POLICY_BY_ID_ONLY
6314 else if (!strcmp("vlan", toks1[1]))
6315 {
6316 bindingType = SF_BINDING_TYPE_VLAN;
6317 }
6318 else if (!strcmp("net", toks1[1]))
6319 {
6320 bindingType = SF_BINDING_TYPE_NETWORK;
6321 }
6322 #endif
6323 else
6324 {
6325 mSplitFree(&toks1, num_toks1);
6326 ParseError("Invalid binding type in 'config binding'");
6327 return;
6328 }
6329 fileName = toks1[0];
6330 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Policy File: %s\n", fileName););
6331
6332 #define MAX_BOUND_ADDRS_PER_LINE 512
6333 toks = mSplit(toks1[2], ",", MAX_BOUND_ADDRS_PER_LINE + 1, &num_toks, 0);
6334
6335 if (num_toks < 1)
6336 {
6337 mSplitFree(&toks1, num_toks1);
6338 mSplitFree(&toks, num_toks);
6339 ParseError(" Invalid arguments to 'config binding'");
6340 return;
6341 }
6342
6343 if (num_toks >= 512)
6344 {
6345 mSplitFree(&toks1, num_toks1);
6346 mSplitFree(&toks, num_toks);
6347 ParseError(" Too many network addresses specified in 'config binding'. "
6348 " Maximum is %d.\n", MAX_BOUND_ADDRS_PER_LINE);
6349 return;
6350 }
6351
6352 if (bindingType == SF_BINDING_TYPE_POLICY_ID)
6353 {
6354 if (ParsePolicyIdBindingLine(sc->policy_config, num_toks, &toks[0], fileName))
6355 {
6356 FatalError("%s(%d) Formatting error in binding config for %s\n", file_name, file_line, fileName);
6357 }
6358 }
6359 else if (bindingType == SF_BINDING_TYPE_VLAN)
6360 {
6361 if (ParseVlanBindingLine(sc->policy_config, num_toks, &toks[0], fileName))
6362 {
6363 FatalError("%s(%d) Formatting error in binding config for %s\n", file_name, file_line, fileName);
6364 }
6365 }
6366 else
6367 {
6368 if (ParseNetworkBindingLine(sc->policy_config, num_toks, &toks[0], fileName))
6369 {
6370 FatalError("%s(%d) Formatting error in binding config for %s\n", file_name, file_line, fileName);
6371 }
6372 }
6373 mSplitFree(&toks1, num_toks1);
6374 mSplitFree(&toks, num_toks);
6375 }
6376
ConfigBpfFile(SnortConfig * sc,char * args)6377 void ConfigBpfFile(SnortConfig *sc, char *args)
6378 {
6379 if ((args == NULL) || (sc == NULL) || (sc->bpf_file != NULL))
6380 return;
6381
6382 sc->bpf_file = SnortStrdup(args);
6383 }
6384
ConfigChecksumDrop(SnortConfig * sc,char * args)6385 void ConfigChecksumDrop(SnortConfig *sc, char *args)
6386 {
6387 if (sc == NULL)
6388 return;
6389
6390 if (sc->targeted_policies == NULL)
6391 {
6392 //This is the case for command line argument
6393 sc->checksum_drop_flags = GetChecksumFlags(args);
6394 sc->checksum_drop_flags_modified = 1;
6395 }
6396 else
6397 {
6398 SnortPolicy *pPolicy = sc->targeted_policies[getParserPolicy(sc)];
6399
6400 pPolicy->checksum_drop_flags = GetChecksumFlags(args);
6401 pPolicy->checksum_drop_flags_modified = 1;
6402 }
6403 }
6404
ConfigChecksumMode(SnortConfig * sc,char * args)6405 void ConfigChecksumMode(SnortConfig *sc, char *args)
6406 {
6407 if (sc == NULL)
6408 return;
6409
6410 if (sc->targeted_policies == NULL)
6411 {
6412 //This is the case for command line argument
6413 sc->checksum_flags = GetChecksumFlags(args);
6414 sc->checksum_flags_modified = 1;
6415 }
6416 else
6417 {
6418 SnortPolicy *pPolicy = sc->targeted_policies[getParserPolicy(sc)];
6419
6420 pPolicy->checksum_flags = GetChecksumFlags(args);
6421 pPolicy->checksum_flags_modified = 1;
6422 }
6423
6424 }
6425
GetChecksumFlags(char * args)6426 static int GetChecksumFlags(char *args)
6427 {
6428 char **toks;
6429 int num_toks;
6430 int i;
6431 int negative_flags = 0;
6432 int positive_flags = 0;
6433 int got_positive_flag = 0;
6434 int got_negative_flag = 0;
6435 int ret_flags = 0;
6436
6437 if (args == NULL)
6438 return CHECKSUM_FLAG__ALL;
6439
6440 toks = mSplit(args, " \t", 10, &num_toks, 0);
6441 for (i = 0; i < num_toks; i++)
6442 {
6443 if (strcasecmp(toks[i], CHECKSUM_MODE_OPT__ALL) == 0)
6444 {
6445 positive_flags = CHECKSUM_FLAG__ALL;
6446 negative_flags = 0;
6447 got_positive_flag = 1;
6448 }
6449 else if (strcasecmp(toks[i], CHECKSUM_MODE_OPT__NONE) == 0)
6450 {
6451 positive_flags = 0;
6452 negative_flags = CHECKSUM_FLAG__ALL;
6453 got_negative_flag = 1;
6454 }
6455 else if (strcasecmp(toks[i], CHECKSUM_MODE_OPT__IP) == 0)
6456 {
6457 positive_flags |= CHECKSUM_FLAG__IP;
6458 negative_flags &= ~CHECKSUM_FLAG__IP;
6459 got_positive_flag = 1;
6460 }
6461 else if (strcasecmp(toks[i], CHECKSUM_MODE_OPT__NO_IP) == 0)
6462 {
6463 positive_flags &= ~CHECKSUM_FLAG__IP;
6464 negative_flags |= CHECKSUM_FLAG__IP;
6465 got_negative_flag = 1;
6466 }
6467 else if (strcasecmp(toks[i], CHECKSUM_MODE_OPT__TCP) == 0)
6468 {
6469 positive_flags |= CHECKSUM_FLAG__TCP;
6470 negative_flags &= ~CHECKSUM_FLAG__TCP;
6471 got_positive_flag = 1;
6472 }
6473 else if (strcasecmp(toks[i], CHECKSUM_MODE_OPT__NO_TCP) == 0)
6474 {
6475 positive_flags &= ~CHECKSUM_FLAG__TCP;
6476 negative_flags |= CHECKSUM_FLAG__TCP;
6477 got_negative_flag = 1;
6478 }
6479 else if (strcasecmp(toks[i], CHECKSUM_MODE_OPT__UDP) == 0)
6480 {
6481 positive_flags |= CHECKSUM_FLAG__UDP;
6482 negative_flags &= ~CHECKSUM_FLAG__UDP;
6483 got_positive_flag = 1;
6484 }
6485 else if (strcasecmp(toks[i], CHECKSUM_MODE_OPT__NO_UDP) == 0)
6486 {
6487 positive_flags &= ~CHECKSUM_FLAG__UDP;
6488 negative_flags |= CHECKSUM_FLAG__UDP;
6489 got_negative_flag = 1;
6490 }
6491 else if (strcasecmp(toks[i], CHECKSUM_MODE_OPT__ICMP) == 0)
6492 {
6493 positive_flags |= CHECKSUM_FLAG__ICMP;
6494 negative_flags &= ~CHECKSUM_FLAG__ICMP;
6495 got_positive_flag = 1;
6496 }
6497 else if (strcasecmp(toks[i], CHECKSUM_MODE_OPT__NO_ICMP) == 0)
6498 {
6499 positive_flags &= ~CHECKSUM_FLAG__ICMP;
6500 negative_flags |= CHECKSUM_FLAG__ICMP;
6501 got_negative_flag = 1;
6502 }
6503 else
6504 {
6505 ParseError("Unknown command line checksum option: %s.", toks[i]);
6506 }
6507 }
6508
6509 /* Invert the negative flags with all checksums */
6510 negative_flags ^= CHECKSUM_FLAG__ALL;
6511 negative_flags &= CHECKSUM_FLAG__ALL;
6512
6513 if (got_positive_flag && got_negative_flag)
6514 {
6515 /* If we got both positive and negative flags just take the
6516 * combination of the two */
6517 ret_flags = positive_flags & negative_flags;
6518 }
6519 else if (got_positive_flag)
6520 {
6521 /* If we got a positive flag assume the user wants checksums
6522 * to be cleared */
6523 ret_flags = positive_flags;
6524 }
6525 else /* got a negative flag */
6526 {
6527 /* If we got a negative flag assume the user thinks all
6528 * checksums are on */
6529 ret_flags = negative_flags;
6530 }
6531
6532 mSplitFree(&toks, num_toks);
6533 return ret_flags;
6534 }
6535
ConfigChrootDir(SnortConfig * sc,char * args)6536 void ConfigChrootDir(SnortConfig *sc, char *args)
6537 {
6538 #ifdef WIN32
6539 ParseError("Setting the chroot directory is not supported in "
6540 "the WIN32 port of snort!");
6541 #else
6542 if ((args == NULL) || (sc == NULL) || (sc->chroot_dir != NULL))
6543 return;
6544
6545 sc->chroot_dir = SnortStrdup(args);
6546 #endif
6547 }
6548
ConfigClassification(SnortConfig * sc,char * args)6549 void ConfigClassification(SnortConfig *sc, char *args)
6550 {
6551 char **toks;
6552 int num_toks;
6553 char *endptr;
6554 ClassType *new_node, *current;
6555 int max_id = 0;
6556
6557 if ((args == NULL) || (sc == NULL))
6558 return;
6559
6560 toks = mSplit(args, ",", 0, &num_toks, '\\');
6561 if (num_toks != 3)
6562 ParseError("Invalid classification config: %s.", args);
6563
6564 /* create the new node */
6565 new_node = (ClassType *)SnortAlloc(sizeof(ClassType));
6566
6567 new_node->type = SnortStrdup(toks[0]);
6568 new_node->name = SnortStrdup(toks[1]);
6569
6570 new_node->priority = SnortStrtol(toks[2], &endptr, 0);
6571 if ((errno == ERANGE) || (*endptr != '\0') || (new_node->priority <= 0))
6572 {
6573 ParseError("Invalid argument for classification priority "
6574 "configuration: %s. Must be a positive integer.", toks[2]);
6575 }
6576
6577 current = sc->classifications;
6578 while (current != NULL)
6579 {
6580 /* dup check */
6581 if (strcasecmp(current->type, new_node->type) == 0)
6582 {
6583 if (getParserPolicy(sc) == getDefaultPolicy())
6584 {
6585 ParseWarning("Duplicate classification \"%s\""
6586 "found, ignoring this line\n", new_node->type);
6587 }
6588
6589 break;
6590 }
6591
6592 if (current->id > max_id)
6593 max_id = current->id;
6594
6595 current = current->next;
6596 }
6597
6598 /* Got a dup */
6599 if (current != NULL)
6600 {
6601 free(new_node->name);
6602 free(new_node->type);
6603 free(new_node);
6604 mSplitFree(&toks, num_toks);
6605 return;
6606 }
6607
6608 /* insert node */
6609 new_node->id = max_id + 1;
6610 new_node->next = sc->classifications;
6611 sc->classifications = new_node;
6612
6613 mSplitFree(&toks, num_toks);
6614 }
6615
ConfigCreatePidFile(SnortConfig * sc,char * args)6616 void ConfigCreatePidFile(SnortConfig *sc, char *args)
6617 {
6618 if (sc == NULL)
6619 return;
6620
6621 sc->run_flags |= RUN_FLAG__CREATE_PID_FILE;
6622 }
6623
ConfigDaemon(SnortConfig * sc,char * args)6624 void ConfigDaemon(SnortConfig *sc, char *args)
6625 {
6626 #ifdef WIN32
6627 ParseError("Setting the Daemon mode is not supported in the "
6628 "WIN32 port of snort! Use 'snort /SERVICE ...' instead.");
6629 #else
6630 if (sc == NULL)
6631 return;
6632
6633 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Daemon mode flag set\n"););
6634 sc->run_flags |= RUN_FLAG__DAEMON;
6635 sc->logging_flags |= LOGGING_FLAG__QUIET;
6636 #endif
6637 }
6638
ConfigDecodeDataLink(SnortConfig * sc,char * args)6639 void ConfigDecodeDataLink(SnortConfig *sc, char *args)
6640 {
6641 if (sc == NULL)
6642 return;
6643
6644 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Decode DLL set\n"););
6645 sc->output_flags |= OUTPUT_FLAG__SHOW_DATA_LINK;
6646 }
6647
ConfigDefaultRuleState(SnortConfig * sc,char * args)6648 void ConfigDefaultRuleState(SnortConfig *sc, char *args)
6649 {
6650 if (sc == NULL)
6651 return;
6652
6653 LogMessage("Found rule_state config directive\n");
6654
6655 if (args == NULL)
6656 {
6657 sc->default_rule_state = RULE_STATE_ENABLED;
6658 }
6659 else if (strcasecmp(args, RULE_STATE_OPT__DISABLED) == 0)
6660 {
6661 sc->default_rule_state = RULE_STATE_DISABLED;
6662 }
6663 else
6664 {
6665 /* Any other word and just call it enabled */
6666 sc->default_rule_state = RULE_STATE_ENABLED;
6667 }
6668 }
6669
ConfigDetection(SnortConfig * sc,char * args)6670 void ConfigDetection(SnortConfig *sc, char *args)
6671 {
6672 int i;
6673 char **toks;
6674 int num_toks;
6675 FastPatternConfig *fp;
6676 int old_stream_inserts = -1;
6677 int old_max_queue_events = -1;
6678
6679 if ((sc == NULL) || (args == NULL))
6680 return;
6681
6682 fp = sc->fast_pattern_config;
6683
6684 if (fp->configured)
6685 {
6686 ParseWarning("Reconfiguring detection options.");
6687
6688 /* Save max queue events and stream inserts in case they are
6689 * not configured again - these will carry over into the new
6690 * configuration */
6691 old_max_queue_events = fp->max_queue_events;
6692 old_stream_inserts = fp->inspect_stream_insert;
6693
6694 fpSetDefaults(fp);
6695 }
6696
6697 toks = mSplit(args, ", ", 20, &num_toks, 0);
6698
6699 for (i = 0; i < num_toks; i++)
6700 {
6701 if (strcasecmp(toks[i], DETECTION_OPT__SEARCH_OPTIMIZE) == 0)
6702 {
6703 fpSetDetectSearchOpt(fp, 1);
6704 }
6705 else if (strcasecmp(toks[i], DETECTION_OPT__ENABLE_SINGLE_RULE_GROUP) == 0)
6706 {
6707 fpDetectSetSingleRuleGroup(fp);
6708 LogMessage("Using Single-Rule-Group Detection\n");
6709 }
6710 else if (strcasecmp(toks[i], DETECTION_OPT__DEBUG_PRINT_NOCONTENT_RULE_TESTS) == 0)
6711 {
6712 fpDetectSetDebugPrintNcRules(fp);
6713 }
6714 else if (strcasecmp(toks[i], DETECTION_OPT__DEBUG_PRINT_RULE_GROUP_BUILD_DETAILS) == 0)
6715 {
6716 fpDetectSetDebugPrintRuleGroupBuildDetails(fp);
6717 }
6718 else if (strcasecmp(toks[i], DETECTION_OPT__DEBUG_PRINT_RULE_GROUPS_UNCOMPILED) == 0)
6719 {
6720 fpDetectSetDebugPrintRuleGroupsUnCompiled(fp);
6721 }
6722 else if (strcasecmp(toks[i], DETECTION_OPT__DEBUG_PRINT_RULE_GROUPS_COMPILED) == 0)
6723 {
6724 fpDetectSetDebugPrintRuleGroupsCompiled(fp);
6725 }
6726 else if (strcasecmp(toks[i], DETECTION_OPT__DEBUG) == 0)
6727 {
6728 fpSetDebugMode(fp);
6729 }
6730 else if (strcasecmp(toks[i], DETECTION_OPT__NO_STREAM_INSERTS) == 0)
6731 {
6732 fpSetStreamInsert(fp);
6733 old_stream_inserts = -1; /* Don't reset to old value */
6734 }
6735 else if (strcasecmp(toks[i], DETECTION_OPT__BLEEDOVER_WARNINGS_ENABLED) == 0)
6736 {
6737 fpDetectSetBleedOverWarnings(fp);
6738 }
6739 else if (strcasecmp(toks[i], DETECTION_OPT__SEARCH_METHOD) == 0)
6740 {
6741 i++;
6742 if (i < num_toks)
6743 {
6744 if (fpSetDetectSearchMethod(fp, toks[i]) == -1)
6745 {
6746 ParseError("Invalid argument to 'search-method': %s.", toks[i]);
6747 }
6748 }
6749 else
6750 {
6751 ParseError("Need an argument to 'search-method'.");
6752 }
6753 }
6754 else if (strcasecmp(toks[i], DETECTION_OPT__BLEEDOVER_PORT_LIMIT) == 0)
6755 {
6756 i++;
6757 if (i < num_toks)
6758 {
6759 char *endptr;
6760 int n = SnortStrtol(toks[i], &endptr, 0);
6761
6762 if ((errno == ERANGE) || (*endptr != '\0') || (n <= 0))
6763 {
6764 ParseError("Invalid argument for bleedover limit: %s. "
6765 "Need a non-negative integer.", toks[i]);
6766 }
6767
6768 fpDetectSetBleedOverPortLimit(fp, n);
6769 LogMessage("Bleedover Port Limit : %d\n",n);
6770 }
6771 else
6772 {
6773 ParseError("Missing port-count argument to 'bleedover_port_limit'.");
6774 }
6775 }
6776 else if (strcasecmp(toks[i], DETECTION_OPT__MAX_QUEUE_EVENTS) == 0)
6777 {
6778 i++;
6779 if (i < num_toks)
6780 {
6781 char *endptr;
6782 int n = SnortStrtol(toks[i], &endptr, 0);
6783
6784 if ((errno == ERANGE) || (*endptr != '\0') || (n <= 0))
6785 {
6786 ParseError("Invalid argument for max_queue_events: %s. "
6787 "Need a non-negative integer.", toks[i]);
6788 }
6789
6790 fpSetMaxQueueEvents(fp, n);
6791 old_max_queue_events = -1; /* Don't reset to old value */
6792 }
6793 else
6794 {
6795 ParseError("Missing argument to 'max_queue_events'.");
6796 }
6797 }
6798 else if (strcasecmp(toks[i], DETECTION_OPT__SPLIT_ANY_ANY) == 0)
6799 {
6800 fpDetectSetSplitAnyAny(fp, 1);
6801 }
6802 else if (strcasecmp(toks[i], DETECTION_OPT__MAX_PATTERN_LEN) == 0)
6803 {
6804 i++;
6805 if (i < num_toks)
6806 {
6807 char *endptr;
6808 int n = SnortStrtol(toks[i], &endptr, 0);
6809
6810 if ((errno == ERANGE) || (*endptr != '\0') || (n < 0))
6811 {
6812 ParseError("Invalid argument for max-pattern-len: %s. "
6813 "Need a non-negative integer.", toks[i]);
6814 }
6815
6816 fpSetMaxPatternLen(fp, n);
6817 }
6818 else
6819 {
6820 ParseError("Missing argument to 'max-pattern-len'.");
6821 }
6822 }
6823 else if (strcasecmp(toks[i], DETECTION_OPT__DEBUG_PRINT_FAST_PATTERN) == 0)
6824 {
6825 fpDetectSetDebugPrintFastPatterns(fp, 1);
6826 }
6827 else
6828 {
6829 ParseError("'%s' is an invalid option to the 'config detection' "
6830 "configuration.", toks[i]);
6831 }
6832 }
6833
6834 mSplitFree(&toks, num_toks);
6835
6836 if (old_max_queue_events != -1)
6837 fp->max_queue_events = old_max_queue_events;
6838 if (old_stream_inserts != -1)
6839 fp->inspect_stream_insert = old_stream_inserts;
6840
6841 fp->configured = 1;
6842 }
6843
ConfigDetectionFilter(SnortConfig * sc,char * args)6844 void ConfigDetectionFilter(SnortConfig *sc, char *args)
6845 {
6846 char **toks;
6847 int num_toks;
6848
6849 if ((sc == NULL) || (args == NULL))
6850 return;
6851
6852 if (!sc->detection_filter_config->enabled)
6853 return;
6854
6855 toks = mSplit(args, " \t", 2, &num_toks, 0);
6856 if (num_toks != 2)
6857 {
6858 ParseError("Detection filter memcap requires a positive "
6859 "integer argument.");
6860 }
6861
6862 if (strcasecmp(toks[0], THRESHOLD_OPT__MEMCAP) == 0)
6863 {
6864 char *endptr;
6865
6866 sc->detection_filter_config->memcap = SnortStrtol(toks[1], &endptr, 0);
6867 if ((errno == ERANGE) || (*endptr != '\0') ||
6868 (sc->detection_filter_config->memcap < 0))
6869 {
6870 ParseError("Invalid detection filter memcap: %s. Must be a "
6871 "positive integer.", toks[1]);
6872 }
6873 }
6874 else
6875 {
6876 ParseError("Unknown argument to threshold configuration: %s.", toks[0]);
6877 }
6878
6879 mSplitFree(&toks, num_toks);
6880
6881 }
6882
ConfigDisableDecodeAlerts(SnortConfig * sc,char * args)6883 void ConfigDisableDecodeAlerts(SnortConfig *sc, char *args)
6884 {
6885 if (sc == NULL)
6886 return;
6887
6888 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the decoder alerts\n"););
6889 sc->targeted_policies[getParserPolicy(sc)]->decoder_alert_flags &= ~DECODE_EVENT_FLAG__DEFAULT;
6890 }
6891
ConfigDisableDecodeDrops(SnortConfig * sc,char * args)6892 void ConfigDisableDecodeDrops(SnortConfig *sc, char *args)
6893 {
6894 if (sc == NULL)
6895 return;
6896
6897 /* OBSOLETE -- default is disabled */
6898 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of decoder alerts\n"););
6899 sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags &= ~DECODE_EVENT_FLAG__DEFAULT;
6900 }
6901
6902 #ifdef INLINE_FAILOPEN
ConfigDisableInlineFailopen(SnortConfig * sc,char * args)6903 void ConfigDisableInlineFailopen(SnortConfig *sc, char *args)
6904 {
6905 if (sc == NULL)
6906 return;
6907
6908 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Inline Init Failopen disabled\n"););
6909 sc->run_flags |= RUN_FLAG__DISABLE_FAILOPEN;
6910 }
6911 #endif
6912
ConfigDisableIpOptAlerts(SnortConfig * sc,char * args)6913 void ConfigDisableIpOptAlerts(SnortConfig *sc, char *args)
6914 {
6915 if (sc == NULL)
6916 return;
6917
6918 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the alert of all the ipopt alerts\n"););
6919 sc->targeted_policies[getParserPolicy(sc)]->decoder_alert_flags &= ~DECODE_EVENT_FLAG__IP_OPT_ANOMALY;
6920 }
6921
ConfigDisableIpOptDrops(SnortConfig * sc,char * args)6922 void ConfigDisableIpOptDrops(SnortConfig *sc, char *args)
6923 {
6924 if (sc == NULL)
6925 return;
6926
6927 /* OBSOLETE -- default is disabled */
6928 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of all the ipopt alerts\n"););
6929 sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags &= ~DECODE_EVENT_FLAG__IP_OPT_ANOMALY;
6930 }
6931
ConfigDisableTcpOptAlerts(SnortConfig * sc,char * args)6932 void ConfigDisableTcpOptAlerts(SnortConfig *sc, char *args)
6933 {
6934 if (sc == NULL)
6935 return;
6936
6937 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the all the other tcpopt alerts\n"););
6938 sc->targeted_policies[getParserPolicy(sc)]->decoder_alert_flags &= ~DECODE_EVENT_FLAG__TCP_OPT_ANOMALY;
6939 }
6940
ConfigDisableTcpOptDrops(SnortConfig * sc,char * args)6941 void ConfigDisableTcpOptDrops(SnortConfig *sc, char *args)
6942 {
6943 if (sc == NULL)
6944 return;
6945
6946 /* OBSOLETE -- default is disabled */
6947 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of all other tcpopt alerts\n"););
6948 sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags &= ~DECODE_EVENT_FLAG__TCP_OPT_ANOMALY;
6949 }
6950
ConfigDisableTcpOptExperimentalAlerts(SnortConfig * sc,char * args)6951 void ConfigDisableTcpOptExperimentalAlerts(SnortConfig *sc, char *args)
6952 {
6953 if (sc == NULL)
6954 return;
6955
6956 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the tcpopt experimental alerts\n"););
6957 sc->targeted_policies[getParserPolicy(sc)]->decoder_alert_flags &= ~DECODE_EVENT_FLAG__TCP_EXP_OPT;
6958 }
6959
ConfigDisableTcpOptExperimentalDrops(SnortConfig * sc,char * args)6960 void ConfigDisableTcpOptExperimentalDrops(SnortConfig *sc, char *args)
6961 {
6962 if (sc == NULL)
6963 return;
6964
6965 /* OBSOLETE -- default is disabled */
6966 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of tcpopt exprimental alerts\n"););
6967 sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags &= ~DECODE_EVENT_FLAG__TCP_EXP_OPT;
6968 }
6969
ConfigDisableTcpOptObsoleteAlerts(SnortConfig * sc,char * args)6970 void ConfigDisableTcpOptObsoleteAlerts(SnortConfig *sc, char *args)
6971 {
6972 if (sc == NULL)
6973 return;
6974
6975 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the tcpopt obsolete alerts\n"););
6976 sc->targeted_policies[getParserPolicy(sc)]->decoder_alert_flags &= ~DECODE_EVENT_FLAG__TCP_OBS_OPT;
6977 }
6978
ConfigDisableTcpOptObsoleteDrops(SnortConfig * sc,char * args)6979 void ConfigDisableTcpOptObsoleteDrops(SnortConfig *sc, char *args)
6980 {
6981 if (sc == NULL)
6982 return;
6983
6984 /* OBSOLETE -- default is disabled */
6985 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of tcpopt obsolete alerts\n"););
6986 sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags &= ~DECODE_EVENT_FLAG__TCP_OBS_OPT;
6987 }
6988
ConfigDisableTTcpAlerts(SnortConfig * sc,char * args)6989 void ConfigDisableTTcpAlerts(SnortConfig *sc, char *args)
6990 {
6991 if (sc == NULL)
6992 return;
6993
6994 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the ttcp alerts\n"););
6995 sc->targeted_policies[getParserPolicy(sc)]->decoder_alert_flags &= ~DECODE_EVENT_FLAG__TCP_TTCP_OPT;
6996 }
6997
ConfigDisableTTcpDrops(SnortConfig * sc,char * args)6998 void ConfigDisableTTcpDrops(SnortConfig *sc, char *args)
6999 {
7000 if (sc == NULL)
7001 return;
7002
7003 /* OBSOLETE -- default is disabled */
7004 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of ttcp alerts\n"););
7005 sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags &= ~DECODE_EVENT_FLAG__TCP_TTCP_OPT;
7006 }
7007
ConfigDumpCharsOnly(SnortConfig * sc,char * args)7008 void ConfigDumpCharsOnly(SnortConfig *sc, char *args)
7009 {
7010 if (sc == NULL)
7011 return;
7012
7013 /* dump the application layer as text only */
7014 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Character payload dump set\n"););
7015 sc->output_flags |= OUTPUT_FLAG__CHAR_DATA;
7016 }
7017
ConfigDumpPayload(SnortConfig * sc,char * args)7018 void ConfigDumpPayload(SnortConfig *sc, char *args)
7019 {
7020 if (sc == NULL)
7021 return;
7022
7023 /* dump the application layer */
7024 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Payload dump set\n"););
7025 sc->output_flags |= OUTPUT_FLAG__APP_DATA;
7026 }
7027
ConfigDumpPayloadVerbose(SnortConfig * sc,char * args)7028 void ConfigDumpPayloadVerbose(SnortConfig *sc, char *args)
7029 {
7030 if (sc == NULL)
7031 return;
7032
7033 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Verbose packet bytecode dumps enabled\n"););
7034 sc->output_flags |= OUTPUT_FLAG__VERBOSE_DUMP;
7035 }
7036
ConfigEnableDecodeDrops(SnortConfig * sc,char * args)7037 void ConfigEnableDecodeDrops(SnortConfig *sc, char *args)
7038 {
7039 if (sc == NULL)
7040 return;
7041
7042 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Enabling the drop of decoder alerts\n"););
7043 sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags |= DECODE_EVENT_FLAG__DEFAULT;
7044 }
7045
ConfigEnableDecodeOversizedAlerts(SnortConfig * sc,char * args)7046 void ConfigEnableDecodeOversizedAlerts(SnortConfig *sc, char *args)
7047 {
7048 if (sc == NULL)
7049 return;
7050
7051 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Enabling the decoder oversized packet alerts\n"););
7052 sc->targeted_policies[getParserPolicy(sc)]->decoder_alert_flags |= DECODE_EVENT_FLAG__OVERSIZED;
7053 }
7054
ConfigEnableDecodeOversizedDrops(SnortConfig * sc,char * args)7055 void ConfigEnableDecodeOversizedDrops(SnortConfig *sc, char *args)
7056 {
7057 if (sc == NULL)
7058 return;
7059
7060 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Enabling the drop of decoder oversized packets\n"););
7061 sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags |= DECODE_EVENT_FLAG__OVERSIZED;
7062 }
7063
ConfigEnableDeepTeredoInspection(SnortConfig * sc,char * args)7064 void ConfigEnableDeepTeredoInspection(SnortConfig *sc, char *args)
7065 {
7066 if (sc == NULL)
7067 return;
7068
7069 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Enabling deep Teredo inspection\n"););
7070 sc->enable_teredo = 1; /* TODO: add this to some existing flag bitfield? */
7071 }
7072
7073 #define GTP_U_PORT 2152
7074 #define GTP_U_PORT_V0 3386
ConfigEnableGTPDecoding(SnortConfig * sc,char * args)7075 void ConfigEnableGTPDecoding(SnortConfig *sc, char *args)
7076 {
7077 PortObject *portObject;
7078 int numberOfPorts = 0;
7079
7080 if (sc == NULL)
7081 return;
7082
7083 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Enabling GTP decoding\n"););
7084 sc->enable_gtp = 1;
7085
7086 /*Set the ports*/
7087
7088 portObject = PortVarTableFind( sc->targeted_policies[getParserPolicy(sc)]->portVarTable, "GTP_PORTS");
7089 if (portObject)
7090 {
7091 sc->gtp_ports = PortObjectCharPortArray(sc->gtp_ports,portObject, &numberOfPorts);
7092 }
7093
7094 if (!sc->gtp_ports || (0 == numberOfPorts))
7095 {
7096 /*No ports defined, use default GTP ports*/
7097 sc->gtp_ports = (char *)SnortAlloc(UINT16_MAX);
7098 sc->gtp_ports[GTP_U_PORT] = 1;
7099 sc->gtp_ports[GTP_U_PORT_V0] = 1;
7100
7101 }
7102 }
7103
ConfigEnableEspDecoding(SnortConfig * sc,char * args)7104 void ConfigEnableEspDecoding(SnortConfig *sc, char *args)
7105 {
7106 int ret;
7107 if (sc == NULL)
7108 return;
7109
7110 if (args)
7111 {
7112 ret = ParseBool(args);
7113 if (ret == -1)
7114 {
7115 ParseError("Invalid argument to ESP decoder argument: %s\n"
7116 "Please specify \"enable\" or \"disable\".", args);
7117 }
7118
7119 sc->enable_esp = ret;
7120 }
7121
7122 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Changing ESP decoding\n"););
7123 }
7124
ConfigEnableIpOptDrops(SnortConfig * sc,char * args)7125 void ConfigEnableIpOptDrops(SnortConfig *sc, char *args)
7126 {
7127 if (sc == NULL)
7128 return;
7129
7130 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of all the ipopt alerts\n"););
7131 sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags |= DECODE_EVENT_FLAG__IP_OPT_ANOMALY;
7132 }
7133
7134 #ifdef MPLS
ConfigEnableMplsMulticast(SnortConfig * sc,char * args)7135 void ConfigEnableMplsMulticast(SnortConfig *sc, char *args)
7136 {
7137 if (sc == NULL)
7138 return;
7139
7140 sc->run_flags |= RUN_FLAG__MPLS_MULTICAST;
7141 }
7142
ConfigEnableMplsOverlappingIp(SnortConfig * sc,char * args)7143 void ConfigEnableMplsOverlappingIp(SnortConfig *sc, char *args)
7144 {
7145 if (sc == NULL)
7146 return;
7147
7148 sc->run_flags |= RUN_FLAG__MPLS_OVERLAPPING_IP;
7149 }
7150 #endif
7151
ConfigEnableTcpOptDrops(SnortConfig * sc,char * args)7152 void ConfigEnableTcpOptDrops(SnortConfig *sc, char *args)
7153 {
7154 if (sc == NULL)
7155 return;
7156
7157 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of all other tcpopt alerts\n"););
7158 sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags |= DECODE_EVENT_FLAG__TCP_OPT_ANOMALY;
7159 }
7160
ConfigEnableTcpOptExperimentalDrops(SnortConfig * sc,char * args)7161 void ConfigEnableTcpOptExperimentalDrops(SnortConfig *sc, char *args)
7162 {
7163 if (sc == NULL)
7164 return;
7165
7166 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "enabling the drop of tcpopt exprimental alerts\n"););
7167 sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags |= DECODE_EVENT_FLAG__TCP_EXP_OPT;
7168 }
7169
ConfigEnableTcpOptObsoleteDrops(SnortConfig * sc,char * args)7170 void ConfigEnableTcpOptObsoleteDrops(SnortConfig *sc, char *args)
7171 {
7172 if (sc == NULL)
7173 return;
7174
7175 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of tcpopt obsolete alerts\n"););
7176 sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags |= DECODE_EVENT_FLAG__TCP_OBS_OPT;
7177 }
7178
ConfigEnableTTcpDrops(SnortConfig * sc,char * args)7179 void ConfigEnableTTcpDrops(SnortConfig *sc, char *args)
7180 {
7181 if (sc == NULL)
7182 return;
7183
7184 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of ttcp alerts\n"););
7185 sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags &= ~DECODE_EVENT_FLAG__TCP_TTCP_OPT;
7186 }
7187
ConfigEventFilter(SnortConfig * sc,char * args)7188 void ConfigEventFilter(SnortConfig *sc, char *args)
7189 {
7190 char **toks;
7191 int num_toks;
7192
7193 if ((sc == NULL) || (args == NULL))
7194 return;
7195
7196 if (!sc->threshold_config->enabled)
7197 return;
7198
7199 toks = mSplit(args, " \t", 2, &num_toks, 0);
7200 if (num_toks != 2)
7201 {
7202 ParseError("Threshold memcap requires a positive integer argument.");
7203 }
7204
7205 if (strcasecmp(toks[0], THRESHOLD_OPT__MEMCAP) == 0)
7206 {
7207 char *endptr;
7208
7209 sc->threshold_config->memcap = SnortStrtol(toks[1], &endptr, 0);
7210 if ((errno == ERANGE) || (*endptr != '\0') ||
7211 (sc->threshold_config->memcap < 0))
7212 {
7213 ParseError("Invalid threshold memcap: %s. Must be a "
7214 "positive integer.", toks[1]);
7215 }
7216 }
7217 else
7218 {
7219 ParseError("Unknown argument to threshold configuration: %s.", toks[0]);
7220 }
7221
7222 mSplitFree(&toks, num_toks);
7223 }
7224
ConfigEventQueue(SnortConfig * sc,char * args)7225 void ConfigEventQueue(SnortConfig *sc, char *args)
7226 {
7227 char **toks;
7228 int num_toks;
7229 int i;
7230 EventQueueConfig *eq;
7231
7232 if ((sc == NULL) || (args == NULL))
7233 return;
7234
7235 eq = sc->event_queue_config;
7236
7237 toks = mSplit(args, ", ", 0, &num_toks, 0);
7238
7239 for (i = 0; i < num_toks; i++)
7240 {
7241 if (strcasecmp(toks[i], EVENT_QUEUE_OPT__MAX_QUEUE) == 0)
7242 {
7243 i++;
7244 if (i < num_toks)
7245 {
7246 char *endptr;
7247
7248 eq->max_events = SnortStrtol(toks[i], &endptr, 0);
7249 if ((errno == ERANGE) || (*endptr != '\0') ||
7250 (eq->max_events <= 0))
7251 {
7252 ParseError("Invalid argument for max_queue: %s. Must "
7253 "be a positive integer.", toks[i]);
7254 }
7255 }
7256 else
7257 {
7258 ParseError("No argument to 'max_queue'. Argument must "
7259 "be a positive integer.");
7260 }
7261 }
7262 else if (strcasecmp(toks[i], EVENT_QUEUE_OPT__LOG) == 0)
7263 {
7264 i++;
7265 if (i < num_toks)
7266 {
7267 char *endptr;
7268
7269 eq->log_events = SnortStrtol(toks[i], &endptr, 0);
7270 if ((errno == ERANGE) || (*endptr != '\0') ||
7271 (eq->log_events <= 0))
7272 {
7273 ParseError("Invalid argument for 'log': %s. Must be "
7274 "a positive integer.", toks[i]);
7275 }
7276 }
7277 else
7278 {
7279 ParseError("No argument to 'log'. Argument must be a "
7280 "positive integer.");
7281 }
7282 }
7283 else if (strcasecmp(toks[i], EVENT_QUEUE_OPT__ORDER_EVENTS) == 0)
7284 {
7285 i++;
7286 if(i < num_toks)
7287 {
7288 if (strcasecmp(toks[i], ORDER_EVENTS_OPT__PRIORITY) == 0)
7289 {
7290 eq->order = SNORT_EVENTQ_PRIORITY;
7291 }
7292 else if (strcasecmp(toks[i], ORDER_EVENTS_OPT__CONTENT_LENGTH) == 0)
7293 {
7294 eq->order = SNORT_EVENTQ_CONTENT_LEN;
7295 }
7296 else
7297 {
7298 ParseError("Invalid argument to 'order_events': %s. "
7299 "Arguments may be either 'priority' or "
7300 "content_length.", toks[i]);
7301 }
7302 }
7303 else
7304 {
7305 ParseError("No argument to 'order_events'. Arguments may be "
7306 "either 'priority' or content_length.");
7307 }
7308 }
7309 else if (strcasecmp(toks[i], EVENT_QUEUE_OPT__PROCESS_ALL_EVENTS) == 0)
7310 {
7311 eq->process_all_events = 1;
7312 }
7313 else
7314 {
7315 ParseError("Invalid argument to 'event_queue'. To configure "
7316 "event_queue, the options 'max_queue', 'log', and "
7317 "'order_events' must be configured.");
7318 }
7319 }
7320
7321 if (eq->max_events < eq->log_events )
7322 eq->max_events = eq->log_events;
7323
7324 mSplitFree(&toks, num_toks);
7325 }
7326
ConfigEventTrace(SnortConfig * sc,char * args)7327 void ConfigEventTrace(SnortConfig *sc, char *args)
7328 {
7329 char **toks;
7330 int num_toks = 0;
7331 int i;
7332
7333 if ( !sc )
7334 return;
7335
7336 sc->event_trace_file = EVENT_TRACE_OPT__FILE_DEFAULT;
7337 sc->event_trace_max = EVENT_TRACE_OPT__MAX_DATA_DEFAULT;
7338
7339 if ( args )
7340 toks = mSplit(args, ", ", 0, &num_toks, 0);
7341
7342 for (i = 0; i < num_toks; i++)
7343 {
7344 if (strcasecmp(toks[i], EVENT_TRACE_OPT__MAX_DATA) == 0)
7345 {
7346 i++;
7347 if (i < num_toks)
7348 {
7349 char* endptr;
7350 long max = SnortStrtol(toks[i], &endptr, 0);
7351
7352 if ( (errno == ERANGE) || (*endptr != '\0') ||
7353 (max <= 0) || (max > 65535) )
7354 {
7355 ParseError("Invalid argument for %s: %s. Must be a positive "
7356 "integer < 65536.", EVENT_TRACE_OPT__MAX_DATA, toks[i]);
7357 }
7358 sc->event_trace_max = (uint16_t)max;
7359 }
7360 else
7361 {
7362 ParseError("No argument to %s. Argument must be a positive "
7363 "integer < 65536.", EVENT_TRACE_OPT__MAX_DATA);
7364 }
7365 }
7366 else if (strcasecmp(toks[i], EVENT_TRACE_OPT__FILE) == 0)
7367 {
7368 i++;
7369 if(i < num_toks)
7370 sc->event_trace_file = toks[i];
7371 else
7372 {
7373 ParseError("No argument to %s. Argument must be a string."
7374 EVENT_TRACE_OPT__FILE);
7375 }
7376 }
7377 else
7378 {
7379 ParseError("Invalid argument to 'event_trace'. To configure "
7380 "event_trace, only the options 'file' and 'max_data' can "
7381 "can be specified. Defaults are %s and %d.",
7382 EVENT_TRACE_OPT__FILE_DEFAULT, EVENT_TRACE_OPT__MAX_DATA_DEFAULT);
7383 }
7384 }
7385 sc->event_trace_file = SnortStrdup(sc->event_trace_file);
7386
7387 mSplitFree(&toks, num_toks);
7388 }
7389
ConfigReact(SnortConfig * sc,char * args)7390 void ConfigReact (SnortConfig *sc, char *args)
7391 {
7392 if ((sc == NULL) || (args == NULL))
7393 return;
7394
7395 sc->react_page = SnortStrdup(args);
7396
7397 DEBUG_WRAP(DebugMessage(DEBUG_INIT,
7398 "react: page is %s\n", sc->react_page););
7399 }
7400
7401 #ifdef ENABLE_RESPONSE3
ConfigFlexresp2Interface(SnortConfig * sc,char * args)7402 void ConfigFlexresp2Interface(SnortConfig *sc, char *args)
7403 {
7404 ParseWarning("flexresp2_interface is no longer supported.\n");
7405 }
7406
ConfigFlexresp2Attempts(SnortConfig * sc,char * args)7407 void ConfigFlexresp2Attempts(SnortConfig *sc, char *args)
7408 {
7409 ParseWarning("flexresp2_attempts is no longer supported; "
7410 "you must use config response: attempts <#> instead.\n");
7411 }
7412
ConfigFlexresp2Memcap(SnortConfig * sc,char * args)7413 void ConfigFlexresp2Memcap(SnortConfig *sc, char *args)
7414 {
7415 ParseWarning("flexresp2_memcap is no longer supported.\n");
7416 }
7417
ConfigFlexresp2Rows(SnortConfig * sc,char * args)7418 void ConfigFlexresp2Rows(SnortConfig *sc, char *args)
7419 {
7420 ParseWarning("flexresp2_rows is no longer supported.\n");
7421 }
7422 #endif
7423
7424 #ifdef ACTIVE_RESPONSE
7425 // TBD: once code can be checked in, move all config funcs
7426 // from parser.[ch] to [parser-]config.[ch] *or* at least move
7427 // Config* declarations from parser.h to parser.c or parser-config.h.
ConfigResponse(SnortConfig * sc,char * args)7428 void ConfigResponse (SnortConfig *sc, char *args)
7429 {
7430 char **toks;
7431 int num_toks;
7432 int i;
7433
7434 if ((sc == NULL) || (args == NULL))
7435 return;
7436
7437 toks = mSplit(args, ", ", 0, &num_toks, 0);
7438
7439 for (i = 0; i < num_toks; i++)
7440 {
7441 if ( !strcasecmp(toks[i], RESPONSE_OPT__ATTEMPTS) )
7442 {
7443 if ( ++i < num_toks )
7444 {
7445 char *endptr;
7446 long int value = strtol(toks[i], &endptr, 0);
7447
7448 if ((errno == ERANGE) || (*endptr != '\0') ||
7449 (value < 1) || (value > 20))
7450 {
7451 ParseError("Invalid argument for attempts: %s. "
7452 "Argument must be between 1 and 20 inclusive.", toks[i]);
7453 }
7454 sc->respond_attempts = (uint8_t)value;
7455 }
7456 else
7457 {
7458 ParseError("No argument to 'attempts'. "
7459 "Argument must be between 1 and 20 inclusive.");
7460 }
7461 }
7462 else if ( !strcasecmp(toks[i], RESPONSE_OPT__DEVICE) )
7463 {
7464 if ( ++i < num_toks )
7465 {
7466 sc->respond_device = SnortStrdup(toks[i]);
7467 }
7468 else
7469 {
7470 ParseError("No argument to 'device'. Use 'ip' for network "
7471 "layer responses or 'eth0' etc. for link layer responses.");
7472 }
7473 }
7474 else if ( !strcasecmp(toks[i], RESPONSE_OPT__DST_MAC) )
7475 {
7476 if ( ++i < num_toks )
7477 {
7478 eth_addr_t dst;
7479 if (eth_pton( toks[i], &dst) < 0)
7480 {
7481 ParseError("Format check failed: %s, Use format like 12:34:56:78:90:1a", toks[i]);
7482 }
7483 sc->eth_dst = SnortAlloc (sizeof(dst.data));
7484 memcpy(sc->eth_dst, dst.data, sizeof(dst.data));
7485 }
7486 else
7487 {
7488 ParseError("No argument to 'dst_mac'. Use format 12:34:56:78:90:1a");
7489 }
7490 }
7491 else
7492 {
7493 ParseError("Invalid config response option '%s'", toks[i]);
7494 }
7495 }
7496 mSplitFree(&toks, num_toks);
7497 }
7498 #endif
7499
ConfigFlowbitsSize(SnortConfig * sc,char * args)7500 void ConfigFlowbitsSize(SnortConfig *sc, char *args)
7501 {
7502 if ((sc == NULL) || (args == NULL))
7503 return;
7504 setFlowbitSize(args);
7505 sc->flowbit_size = (uint16_t)getFlowbitSizeInBytes();
7506 }
7507
7508 /****************************************************************************
7509 *
7510 * Purpose: Parses a protocol plus a list of ports.
7511 * The protocol should be "udp" or "tcp".
7512 * The ports list should be a list of numbers or pairs of numbers.
7513 * Each element of the list is separated by a space character.
7514 * Each pair of numbers is separated by a colon character.
7515 * So the string passed in is e.g. "tcp 443 578 6667:6681 13456"
7516 * The numbers do not have to be in numerical order.
7517 *
7518 * Arguments:
7519 * SnortConfig *
7520 * The snort config to store ignored ports.
7521 * char *
7522 * string containing protocol plus list of ports
7523 *
7524 * Returns: void function
7525 *
7526 *****************************************************************************/
ConfigIgnorePorts(SnortConfig * sc,char * args)7527 void ConfigIgnorePorts(SnortConfig *sc, char *args)
7528 {
7529 char ** toks;
7530 int num_toks = 0;
7531 int i, p;
7532 uint16_t hi_port = 0, lo_port = 0;
7533 int protocol;
7534 int not_flag;
7535
7536 if ((sc == NULL) || (args == NULL))
7537 return;
7538
7539 LogMessage("Found ignore_ports config directive (%s)\n", args);
7540
7541 toks = mSplit(args, " \t", 0, &num_toks, 0);
7542
7543 if ( !num_toks )
7544 ParseError("config ignore_ports: Empty port list.");
7545
7546 protocol = GetRuleProtocol(toks[0]);
7547
7548 if ( !(protocol == IPPROTO_TCP || protocol == IPPROTO_UDP) )
7549 {
7550 ParseError("Invalid protocol: %s.", toks[0]);
7551 }
7552
7553 for ( i = 1; i < num_toks; i++ )
7554 {
7555 /* Re-use function from rules processing */
7556 ParsePort(sc, toks[i], &hi_port, &lo_port, toks[0], ¬_flag);
7557
7558 for ( p = lo_port; p <= hi_port; p++ )
7559 {
7560 if (protocol == IPPROTO_TCP)
7561 sc->ignore_ports[p] |= PROTO_BIT__TCP;
7562 else if (protocol == IPPROTO_UDP)
7563 sc->ignore_ports[p] |= PROTO_BIT__UDP;
7564 }
7565 }
7566
7567 mSplitFree(&toks, num_toks);
7568 }
7569
ConfigIncludeVlanInAlert(SnortConfig * sc,char * args)7570 void ConfigIncludeVlanInAlert(SnortConfig *sc, char *args)
7571 {
7572 if (sc == NULL)
7573 return;
7574
7575 sc->output_flags |= OUTPUT_FLAG__ALERT_VLAN;
7576 }
7577
ConfigInterface(SnortConfig * sc,char * args)7578 void ConfigInterface(SnortConfig *sc, char *args)
7579 {
7580 if ((args == NULL) || (sc == NULL) || (sc->interface != NULL))
7581 return;
7582
7583 #ifdef WIN32
7584 /* first, try to handle the "-i1" case, where an interface
7585 * is specified by number. If this fails, then fall-through
7586 * to the case outside the ifdef/endif, where an interface
7587 * can be specified by its fully qualified name, like as is
7588 * shown by running 'snort -W', ie.
7589 * "\Device\Packet_{12345678-90AB-CDEF-1234567890AB}"
7590 */
7591 {
7592 char errorbuf[PCAP_ERRBUF_SIZE];
7593 int adaplen = atoi(args);
7594
7595 if (adaplen > 0)
7596 {
7597 pcap_if_t *alldevs;
7598 pcap_if_t *dev;
7599 int i = 1;
7600
7601 if (pcap_findalldevs(&alldevs, errorbuf) == -1)
7602 ParseError("Could not get device list: %s.", errorbuf);
7603
7604 for (dev = alldevs; dev != NULL; dev = dev->next)
7605 {
7606 if (i == adaplen)
7607 break;
7608 i++;
7609 }
7610
7611 if (dev == NULL)
7612 ParseError("Invalid device number: %d.", adaplen);
7613
7614 sc->interface = SnortStrdup(dev->name);
7615 pcap_freealldevs(alldevs);
7616 return;
7617 }
7618 }
7619 #endif /* WIN32 */
7620
7621 /* this code handles the case in which the user specifies
7622 * the entire name of the interface and it is compiled
7623 * regardless of which OS you have */
7624 sc->interface = SnortStrdup(args);
7625 }
7626
ConfigIpv6Frag(SnortConfig * sc,char * args)7627 void ConfigIpv6Frag(SnortConfig *sc, char *args)
7628 {
7629 int num_opts;
7630 char **opt_toks;
7631 int i;
7632
7633 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"IPv6 Rule Option\n"););
7634
7635 if ((sc == NULL) || (args == NULL))
7636 return;
7637
7638 opt_toks = mSplit(args, ",", 0, &num_opts, 0);
7639
7640 for (i = 0; i < num_opts; i++)
7641 {
7642 char **arg_toks;
7643 int num_args;
7644
7645 arg_toks = mSplit(opt_toks[i], " \t", 2, &num_args, 0);
7646
7647 if(num_args != 2 || !arg_toks[1])
7648 {
7649 ParseError("ipv6_frag option '%s' requires an argument.",
7650 arg_toks[0]);
7651 continue;
7652 }
7653
7654 if(!strcasecmp(arg_toks[0], "bsd_icmp_frag_alert"))
7655 {
7656 DEBUG_WRAP(DebugMessage(DEBUG_INIT,
7657 "disabling the BSD ICMP fragmentation alert\n"););
7658 if(!strcasecmp(arg_toks[1], "off"))
7659 sc->targeted_policies[getParserPolicy(sc)]->decoder_alert_flags &= ~DECODE_EVENT_FLAG__IPV6_BSD_ICMP_FRAG;
7660 }
7661 else if(!strcasecmp(arg_toks[0], "bad_ipv6_frag_alert"))
7662 {
7663 DEBUG_WRAP(DebugMessage(DEBUG_INIT,
7664 "disabling the IPv6 bad fragmentation packet alerts\n"););
7665 if(!strcasecmp(arg_toks[1], "off"))
7666 sc->targeted_policies[getParserPolicy(sc)]->decoder_alert_flags &= ~DECODE_EVENT_FLAG__IPV6_BAD_FRAG;
7667
7668 }
7669 else if (!strcasecmp(arg_toks[0], "frag_timeout"))
7670 {
7671 long val;
7672 char *endp;
7673
7674 val = strtol(arg_toks[1], &endp, 0);
7675 if(val <= 0 || val > 3600)
7676 {
7677 ParseError("ipv6_frag_timeout: Invalid argument '%s'. "
7678 "Must be greater that 0 and less than 3600 "
7679 "secnods.", arg_toks[1]);
7680 }
7681
7682 if(args == endp || *endp)
7683 {
7684 ParseError("ipv6_frag_timeout: Invalid argument '%s'.",
7685 arg_toks[1]);
7686 }
7687
7688 sc->ipv6_frag_timeout = val;
7689 }
7690 else if (!strcasecmp(arg_toks[0], "max_frag_sessions"))
7691 {
7692 long val;
7693 char *endp;
7694
7695 val = strtol(arg_toks[1], &endp, 0);
7696 if (val <= 0)
7697 {
7698 ParseError("ipv6_max_frag_sessions: Invalid number of sessions "
7699 "'%s'. Must be greater than 0.", arg_toks[1]);
7700 }
7701
7702 if(args == endp || *endp)
7703 {
7704 ParseError("ipv6_max_frag_sessions: Invalid number of "
7705 "sessions '%s'.", arg_toks[1]);
7706 }
7707
7708 sc->ipv6_max_frag_sessions = val;
7709 }
7710 else if (!strcasecmp(arg_toks[0], "drop_bad_ipv6_frag"))
7711 {
7712 if(!strcasecmp(arg_toks[1], "off"))
7713 {
7714 DEBUG_WRAP(DebugMessage(DEBUG_INIT,
7715 "disabling the BSD ICMP fragmentation alert\n"););
7716 sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags &= ~DECODE_EVENT_FLAG__IPV6_BAD_FRAG;
7717 }
7718 }
7719 else
7720 {
7721 ParseError("Invalid option to ipv6_frag '%s %s'.",
7722 arg_toks[0], arg_toks[1]);
7723 }
7724
7725 mSplitFree(&arg_toks, num_args);
7726 }
7727
7728 mSplitFree(&opt_toks, num_opts);
7729 }
7730
ConfigLayer2Resets(SnortConfig * sc,char * args)7731 void ConfigLayer2Resets(SnortConfig *sc, char *args)
7732 {
7733 ParseWarning("layer2resets is deprecated.\n");
7734 }
7735
ConfigLogDir(SnortConfig * sc,char * args)7736 void ConfigLogDir(SnortConfig *sc, char *args)
7737 {
7738 if ((args == NULL) || (sc == NULL) || (sc->log_dir != NULL))
7739 return;
7740
7741 sc->log_dir = SnortStrdup(args);
7742 }
7743
ConfigDaqType(SnortConfig * sc,char * args)7744 void ConfigDaqType(SnortConfig *sc, char *args)
7745 {
7746 if ( !args || !sc )
7747 return;
7748
7749 if ( sc->daq_type )
7750 ParseError("Setting DAQ to %s but %s already selected.\n",
7751 args, sc->daq_type);
7752
7753 // will be validated later after paths are established
7754 sc->daq_type = SnortStrdup(args);
7755 }
7756
ConfigDaqMode(SnortConfig * sc,char * args)7757 void ConfigDaqMode(SnortConfig *sc, char *args)
7758 {
7759 if ( !args || !sc || sc->daq_mode )
7760 return;
7761
7762 // will be validated later when daq is instantiated
7763 sc->daq_mode = SnortStrdup(args);
7764 }
7765
ConfigDaqVar(SnortConfig * sc,char * args)7766 void ConfigDaqVar(SnortConfig *sc, char *args)
7767 {
7768 if ( !args || !sc )
7769 return;
7770
7771 if ( !sc->daq_vars )
7772 {
7773 sc->daq_vars = StringVector_New();
7774
7775 if ( !sc->daq_vars )
7776 ParseError("can't allocate memory for daq_var '%s'.", args);
7777 }
7778 if ( !StringVector_Add(sc->daq_vars, args) )
7779 ParseError("can't allocate memory for daq_var '%s'.", args);
7780 }
7781
ConfigDaqDir(SnortConfig * sc,char * args)7782 void ConfigDaqDir(SnortConfig *sc, char *args)
7783 {
7784 if ( !args || !sc )
7785 return;
7786
7787 if ( !sc->daq_dirs )
7788 {
7789 sc->daq_dirs = StringVector_New();
7790
7791 if ( !sc->daq_dirs )
7792 ParseError("can't allocate memory for daq_dir '%s'.", args);
7793 }
7794 if ( !StringVector_Add(sc->daq_dirs, args) )
7795 ParseError("can't allocate memory for daq_dir '%s'.", args);
7796 }
7797
ConfigDirtyPig(SnortConfig * sc,char * args)7798 void ConfigDirtyPig(SnortConfig *sc, char *args)
7799 {
7800 if ( sc )
7801 sc->dirty_pig = 1;
7802 }
7803
7804 #ifdef TARGET_BASED
ConfigMaxAttributeHosts(SnortConfig * sc,char * args)7805 void ConfigMaxAttributeHosts(SnortConfig *sc, char *args)
7806 {
7807 uint32_t val = 0;
7808 char *endp;
7809
7810 if ((sc == NULL) || (args == NULL))
7811 return;
7812
7813 val = strtoul(args, &endp, 10);
7814 if (args == endp || *endp || (val == 0))
7815 {
7816 ParseError("max_attribute_hosts: Invalid number of hosts '%s'. Must "
7817 "be unsigned positive integer value.", args);
7818 }
7819 if ((val > MAX_MAX_ATTRIBUTE_HOSTS) || (val < MIN_MAX_ATTRIBUTE_HOSTS))
7820 {
7821 ParseError("max_atttribute_hosts: Invalid number of hosts %s'. "
7822 "Must be between %d and %d.", args,
7823 MIN_MAX_ATTRIBUTE_HOSTS, MAX_MAX_ATTRIBUTE_HOSTS);
7824 }
7825
7826 sc->max_attribute_hosts = val;
7827 }
7828
ConfigMaxAttributeServicesPerHost(SnortConfig * sc,char * args)7829 void ConfigMaxAttributeServicesPerHost(SnortConfig *sc, char *args)
7830 {
7831 uint32_t val = 0;
7832 char *endp;
7833
7834 if ((sc == NULL) || (args == NULL))
7835 return;
7836
7837 val = strtoul(args, &endp, 10);
7838 if (args == endp || *endp || (val == 0))
7839 {
7840 ParseError("max_attribute_services_per_host: Invalid number of services '%s'. Must "
7841 "be unsigned positive integer value.", args);
7842 }
7843 if ((val > MAX_MAX_ATTRIBUTE_SERVICES_PER_HOST) || (val < MIN_MAX_ATTRIBUTE_SERVICES_PER_HOST))
7844 {
7845 ParseError("max_atttribute_services_per_host: Invalid number of services %s'. "
7846 "Must be between %d and %d.", args,
7847 MIN_MAX_ATTRIBUTE_SERVICES_PER_HOST, MAX_MAX_ATTRIBUTE_SERVICES_PER_HOST);
7848 }
7849
7850 sc->max_attribute_services_per_host = val;
7851 }
7852
ConfigMaxMetadataServices(SnortConfig * sc,char * args)7853 void ConfigMaxMetadataServices(SnortConfig *sc, char *args)
7854 {
7855 uint32_t val = 0;
7856 char *endp;
7857
7858 if ((sc == NULL) || (args == NULL))
7859 return;
7860
7861 val = strtoul(args, &endp, 10);
7862 if (args == endp || *endp || (val == 0))
7863 {
7864 ParseError("max_metadata_services: Invalid number of hosts '%s'. Must "
7865 "be unsigned positive integer value.", args);
7866 }
7867 if ((val > MAX_MAX_METADATA_SERVICES) || (val < MIN_MAX_METADATA_SERVICES))
7868 {
7869 ParseError("max_metadata_services: Invalid number of hosts '%s'. "
7870 "Must be between %d and %d.", args,
7871 MIN_MAX_METADATA_SERVICES, MAX_MAX_METADATA_SERVICES);
7872 }
7873
7874 sc->max_metadata_services = val;
7875 }
7876
ConfigDisableAttributeReload(SnortConfig * sc,char * args)7877 void ConfigDisableAttributeReload(SnortConfig *sc, char *args)
7878 {
7879 if (sc == NULL)
7880 return;
7881
7882 sc->run_flags |= RUN_FLAG__DISABLE_ATTRIBUTE_RELOAD_THREAD;
7883 }
7884 #endif
7885
7886 #ifdef MPLS
ConfigMaxMplsLabelChain(SnortConfig * sc,char * args)7887 void ConfigMaxMplsLabelChain(SnortConfig *sc, char *args)
7888 {
7889 char *endp;
7890 long val = 0;
7891
7892 if (sc == NULL)
7893 return;
7894
7895 if (args != NULL)
7896 {
7897 val = strtol(args, &endp, 0);
7898 if ((args == endp) || *endp || (val < -1))
7899 val = DEFAULT_LABELCHAIN_LENGTH;
7900 }
7901 else
7902 {
7903 val = DEFAULT_LABELCHAIN_LENGTH;
7904 }
7905
7906 sc->mpls_stack_depth = val;
7907 }
7908
ConfigMplsPayloadType(SnortConfig * sc,char * args)7909 void ConfigMplsPayloadType(SnortConfig *sc, char *args)
7910 {
7911 if (sc == NULL)
7912 return;
7913
7914 if (args != NULL)
7915 {
7916 if (strcasecmp(args, MPLS_PAYLOAD_OPT__IPV4) == 0)
7917 {
7918 sc->mpls_payload_type = MPLS_PAYLOADTYPE_IPV4;
7919 }
7920 else if (strcasecmp(args, MPLS_PAYLOAD_OPT__IPV6) == 0)
7921 {
7922 sc->mpls_payload_type = MPLS_PAYLOADTYPE_IPV6;
7923 }
7924 else if (strcasecmp(args, MPLS_PAYLOAD_OPT__ETHERNET) == 0)
7925 {
7926 sc->mpls_payload_type = MPLS_PAYLOADTYPE_ETHERNET;
7927 }
7928 else
7929 {
7930 ParseError("Non supported mpls payload type: %s.", args);
7931 }
7932 }
7933 else
7934 {
7935 sc->mpls_payload_type = DEFAULT_MPLS_PAYLOADTYPE;
7936 }
7937 }
7938 #endif
7939
ConfigMinTTL(SnortConfig * sc,char * args)7940 void ConfigMinTTL(SnortConfig *sc, char *args)
7941 {
7942 long int value;
7943 char *endptr;
7944
7945 if ((sc == NULL) || (args == NULL))
7946 return;
7947
7948 value = strtol(args, &endptr, 0);
7949
7950 if ((errno == ERANGE) || (*endptr != '\0') ||
7951 (value < 1) || (value > UINT8_MAX))
7952 {
7953 ParseError("Invalid argument to 'min_ttl' configuration: %s. "
7954 "Must be a positive integer.", args);
7955 }
7956
7957 {
7958 SnortPolicy* pPolicy = sc->targeted_policies[getParserPolicy(sc)];
7959 pPolicy->min_ttl = (uint8_t)value;
7960 }
7961 }
7962
7963 #ifdef NORMALIZER
ConfigNewTTL(SnortConfig * sc,char * args)7964 void ConfigNewTTL(SnortConfig *sc, char *args)
7965 {
7966 long int value;
7967 char *endptr;
7968
7969 if ((sc == NULL) || (args == NULL))
7970 return;
7971
7972 value = strtol(args, &endptr, 0);
7973
7974 if ((errno == ERANGE) || (*endptr != '\0') ||
7975 (value < 1) || (value > UINT8_MAX))
7976 {
7977 ParseError("Invalid argument to 'new_ttl' configuration: %s. "
7978 "Must be a non-negative integer.", args);
7979 }
7980
7981 {
7982 SnortPolicy* pPolicy = sc->targeted_policies[getParserPolicy(sc)];
7983 pPolicy->new_ttl = (uint8_t)value;
7984 }
7985 }
7986 #endif
7987
ConfigNoLog(SnortConfig * sc,char * args)7988 void ConfigNoLog(SnortConfig *sc, char *args)
7989 {
7990 if (sc == NULL)
7991 return;
7992
7993 sc->no_log = 1;
7994 }
7995
ConfigNoLoggingTimestamps(SnortConfig * sc,char * args)7996 void ConfigNoLoggingTimestamps(SnortConfig *sc, char *args)
7997 {
7998 if (sc == NULL)
7999 return;
8000
8001 sc->output_flags |= OUTPUT_FLAG__NO_TIMESTAMP;
8002 }
8003
ConfigNoPcre(SnortConfig * sc,char * args)8004 void ConfigNoPcre(SnortConfig *sc, char *args)
8005 {
8006 if (sc == NULL)
8007 return;
8008
8009 sc->run_flags |= RUN_FLAG__NO_PCRE;
8010 }
8011
ConfigNoPromiscuous(SnortConfig * sc,char * args)8012 void ConfigNoPromiscuous(SnortConfig *sc, char *args)
8013 {
8014 if (sc == NULL)
8015 return;
8016
8017 sc->run_flags |= RUN_FLAG__NO_PROMISCUOUS;
8018 }
8019
ConfigObfuscate(SnortConfig * sc,char * args)8020 void ConfigObfuscate(SnortConfig *sc, char *args)
8021 {
8022 if (sc == NULL)
8023 return;
8024
8025 sc->output_flags |= OUTPUT_FLAG__OBFUSCATE;
8026 }
8027
ConfigObfuscationMask(SnortConfig * sc,char * args)8028 void ConfigObfuscationMask(SnortConfig *sc, char *args)
8029 {
8030
8031 if ((sc == NULL) || (args == NULL))
8032 return;
8033
8034 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Got obfus data: %s\n", args););
8035
8036 sc->output_flags |= OUTPUT_FLAG__OBFUSCATE;
8037
8038 sfip_pton(args, &sc->obfuscation_net);
8039 }
8040
ConfigPafMax(SnortConfig * sc,char * args)8041 void ConfigPafMax (SnortConfig *sc, char *args)
8042 {
8043 long int value;
8044 char *endptr;
8045
8046
8047 const unsigned max = MAXIMUM_PAF_MAX;
8048
8049 if ((sc == NULL) || (args == NULL))
8050 return;
8051
8052 value = SnortStrtoulRange(args, &endptr, 0, 0, max);
8053
8054 if ( (errno == ERANGE) || (*endptr != '\0') )
8055 {
8056 ParseError(
8057 "Invalid argument to '%s' configuration: %s. "
8058 "Must be between 0 (off) and %u (max).",
8059 CONFIG_OPT__PAF_MAX, args, max);
8060 }
8061
8062 {
8063 sc->paf_max = (uint32_t)value;
8064 }
8065 }
8066
ConfigRuleListOrder(SnortConfig * sc,char * args)8067 void ConfigRuleListOrder(SnortConfig *sc, char *args)
8068 {
8069 OrderRuleLists(sc, args);
8070 }
8071
ConfigPcreMatchLimit(SnortConfig * sc,char * args)8072 void ConfigPcreMatchLimit(SnortConfig *sc, char *args)
8073 {
8074 char *endp;
8075 long val = 0;
8076
8077 if ((sc == NULL) || (args == NULL))
8078 return;
8079
8080 val = strtol(args, &endp, 0);
8081 if ((args == endp) || *endp || (val < -1))
8082 {
8083 ParseError("pcre_match_limit: Invalid value '%s'.", args);
8084 }
8085
8086 sc->pcre_match_limit = val;
8087
8088 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "pcre_match_limit: %d\n",
8089 sc->pcre_match_limit););
8090 }
8091
ConfigPcreMatchLimitRecursion(SnortConfig * sc,char * args)8092 void ConfigPcreMatchLimitRecursion(SnortConfig *sc, char *args)
8093 {
8094 char *endp;
8095 long val = 0;
8096
8097 if ((sc == NULL) || (args == NULL))
8098 return;
8099
8100 val = strtol(args, &endp, 0);
8101 if ((args == endp) || *endp || (val < -1))
8102 {
8103 ParseError("pcre_match_limit_recursion: Invalid value '%s'.", args);
8104 }
8105
8106 sc->pcre_match_limit_recursion = val;
8107
8108 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "pcre_match_limit_recursion: %d\n",
8109 sc->pcre_match_limit_recursion););
8110 }
8111
ConfigPerfFile(SnortConfig * sc,char * args)8112 void ConfigPerfFile(SnortConfig *sc, char *args)
8113 {
8114 if ((sc == NULL) || (args == NULL))
8115 return;
8116
8117 sc->perf_file = SnortStrdup(args);
8118 }
8119
ConfigDumpPeriodicMemStatsFile(SnortConfig * sc,char * args)8120 void ConfigDumpPeriodicMemStatsFile(SnortConfig *sc, char *args)
8121 {
8122 if ((sc == NULL) || (args == NULL))
8123 return;
8124
8125 sc->memdump_file = SnortStrdup(args);
8126 }
8127
ConfigPacketCount(SnortConfig * sc,char * args)8128 void ConfigPacketCount(SnortConfig *sc, char *args)
8129 {
8130 char *endptr;
8131 long count;
8132
8133 if ((sc == NULL) || (args == NULL))
8134 return;
8135
8136 count = SnortStrtoul(args, &endptr, 0);
8137 if ((errno == ERANGE) || (*endptr != '\0'))
8138 {
8139 ParseError("Invalid packet count: %s. Packet count must be between "
8140 "0 and %u inclusive.", args, UINT32_MAX);
8141 }
8142
8143 if ( count > 0 )
8144 {
8145 sc->pkt_cnt = count;
8146 LogMessage("Exiting after " STDu64 " packets\n", sc->pkt_cnt);
8147 return;
8148 }
8149 #ifdef REG_TEST
8150 sc->pkt_skip = -count;
8151 LogMessage("Processing after " STDu64 " packets\n", sc->pkt_skip);
8152 #else
8153 ParseError("Invalid packet count: %s. Packet count must be greater than zero.");
8154 #endif
8155 }
8156
ConfigPacketSnaplen(SnortConfig * sc,char * args)8157 void ConfigPacketSnaplen(SnortConfig *sc, char *args)
8158 {
8159 char *endptr;
8160 uint32_t snaplen;
8161
8162 if ((sc == NULL) || (args == NULL))
8163 return;
8164
8165 snaplen = SnortStrtoul(args, &endptr, 0);
8166
8167 if ((errno == ERANGE) || (*endptr != '\0') ||
8168 ((snaplen != 0) && (snaplen < MIN_SNAPLEN)) ||
8169 (snaplen > MAX_SNAPLEN) )
8170 {
8171 ParseError("Invalid snaplen: %s. Snaplen must be between "
8172 "%u and %u inclusive or 0 for default = %u.",
8173 args, MIN_SNAPLEN, MAX_SNAPLEN, DAQ_GetSnapLen());
8174 }
8175
8176 sc->pkt_snaplen = snaplen;
8177
8178 DEBUG_WRAP(DebugMessage(DEBUG_INIT,
8179 "Snap length of packets set to: %d\n", sc->pkt_snaplen););
8180 }
8181
ConfigPidPath(SnortConfig * sc,char * args)8182 void ConfigPidPath(SnortConfig *sc, char *args)
8183 {
8184 if ((args == NULL) || (sc == NULL))
8185 return;
8186
8187 LogMessage("Found pid path directive (%s)\n", args);
8188
8189 sc->run_flags |= RUN_FLAG__CREATE_PID_FILE;
8190 if (SnortStrncpy(sc->pid_path, args, sizeof(sc->pid_path)) != SNORT_STRNCPY_SUCCESS)
8191 ParseError("Pid path too long.");
8192
8193 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Pid Path directory = %s\n",
8194 sc->pid_path););
8195 }
8196
ConfigPolicy(SnortConfig * sc,char * args)8197 void ConfigPolicy(SnortConfig *sc, char *args)
8198 {
8199 int num_toks;
8200 char **toks;
8201
8202 if ((sc == NULL) || (sc->targeted_policies == NULL))
8203 return;
8204
8205 toks = mSplit(args, " \t,", 20, &num_toks, 0);
8206
8207 if (num_toks != 1)
8208 {
8209 mSplitFree(&toks, num_toks);
8210 return;
8211 }
8212
8213 sc->targeted_policies[getParserPolicy(sc)]->configPolicyId = (unsigned short)(atoi(toks[0]));
8214
8215 mSplitFree(&toks, num_toks);
8216 }
8217
ConfigIpsPolicyMode(SnortConfig * sc,char * args)8218 void ConfigIpsPolicyMode(SnortConfig *sc, char *args)
8219 {
8220 if ((sc == NULL) || (sc->targeted_policies == NULL))
8221 return;
8222
8223 sc->targeted_policies[getParserPolicy(sc)]->ips_policy_mode = GetPolicyMode(args, sc->run_flags);
8224 }
8225
ConfigNapPolicyMode(SnortConfig * sc,char * args)8226 void ConfigNapPolicyMode(SnortConfig *sc, char *args)
8227 {
8228 if ((sc == NULL) || (sc->targeted_policies == NULL))
8229 return;
8230
8231 sc->targeted_policies[getParserPolicy(sc)]->nap_policy_mode = GetPolicyMode(args, sc->run_flags);
8232 }
8233
GetPolicyMode(char * args,int run_flags)8234 static int GetPolicyMode(char *args, int run_flags)
8235 {
8236 char **toks;
8237 int num_toks;
8238 int i;
8239 int mode = 0;
8240
8241 if (args == NULL)
8242 {
8243 if ( run_flags & RUN_FLAG__INLINE )
8244 return POLICY_MODE__INLINE;
8245 else if ( run_flags & RUN_FLAG__INLINE_TEST )
8246 return POLICY_MODE__INLINE_TEST;
8247 else
8248 return POLICY_MODE__PASSIVE;
8249 }
8250
8251 toks = mSplit(args, " \t", 10, &num_toks, 0);
8252 for (i = 0; i < num_toks; i++)
8253 {
8254 if (strcasecmp(toks[i], POLICY_MODE_PASSIVE) == 0)
8255 {
8256 if ( ScAdapterInlineTestMode() )
8257 mode = POLICY_MODE__INLINE_TEST;
8258 else
8259 mode = POLICY_MODE__PASSIVE;
8260 }
8261 else if (strcasecmp(toks[i], POLICY_MODE_INLINE) == 0)
8262 {
8263 /* If --enable-inline-test is specified it overwrites
8264 * policy_mode: inline */
8265 if( ScAdapterInlineTestMode() )
8266 mode = POLICY_MODE__INLINE_TEST;
8267 else if (!ScAdapterInlineMode())
8268 {
8269 ParseWarning("Adapter is in Passive Mode. Hence switching "
8270 "policy mode to tap.");
8271 mode = POLICY_MODE__PASSIVE;
8272
8273 }
8274 else
8275 mode = POLICY_MODE__INLINE;
8276 }
8277 else if (strcasecmp(toks[i], POLICY_MODE_INLINE_TEST) == 0)
8278 {
8279 mode = POLICY_MODE__INLINE_TEST;
8280 }
8281 else
8282 {
8283 ParseError("Unknown command line policy mode option: %s.", toks[i]);
8284 }
8285 }
8286
8287 mSplitFree(&toks, num_toks);
8288 return mode;
8289 }
8290
ConfigPolicyVersion(SnortConfig * sc,char * args)8291 void ConfigPolicyVersion(SnortConfig *sc, char *args)
8292 {
8293 char **toks;
8294 int num_toks;
8295
8296 if ((sc == NULL) || (sc->targeted_policies == NULL) ||
8297 (snort_conf_file == NULL) || (args == NULL))
8298 {
8299 return;
8300 }
8301
8302 toks = mSplit(args, " \t", 0, &num_toks, 0);
8303
8304 if (num_toks == 1)
8305 {
8306 if (getParserPolicy(sc) != getDefaultPolicy())
8307 {
8308 ParseError("Targeted policies must have base policy version and "
8309 "targeted policy version.");
8310 }
8311
8312 if (sc->base_version == NULL)
8313 {
8314 sc->base_version = SnortStrdup(toks[0]);
8315 }
8316 else
8317 {
8318 if (strcmp(sc->base_version, toks[0]) != 0)
8319 {
8320 ParseError("Base policy version mismatch: Current base "
8321 "version: %s, %s: %s",
8322 sc->base_version, file_name, toks[0]);
8323 }
8324 }
8325 }
8326 else if (num_toks == 2)
8327 {
8328 SnortPolicy *p = sc->targeted_policies[getParserPolicy(sc)];
8329
8330 if (getParserPolicy(sc) == getDefaultPolicy())
8331 ParseError("Base policy must only have one policy version.");
8332
8333 if (sc->base_version == NULL)
8334 {
8335 ParseError("Config option \"%s\" must be configured in \"%s\"",
8336 CONFIG_OPT__POLICY_VERSION, snort_conf_file);
8337 }
8338
8339 if (strcmp(sc->base_version, toks[0]) != 0)
8340 {
8341 ParseError("Base policy version mismatch: Current base "
8342 "version: %s, %s: %s",
8343 sc->base_version, file_name, toks[0]);
8344 }
8345
8346 if (p->policy_version == NULL)
8347 {
8348 p->policy_version = SnortStrdup(toks[1]);
8349 }
8350 else
8351 {
8352 if (strcmp(p->policy_version, toks[1]) != 0)
8353 {
8354 ParseError("Targeted policy version mismatch: Current targeted "
8355 "policy version: %s, %s: %s",
8356 p->policy_version, file_name, toks[1]);
8357 }
8358 }
8359 }
8360 else
8361 {
8362 ParseError("Invalid number of arguments to \"%s\": %s.",
8363 CONFIG_OPT__POLICY_VERSION, args);
8364 }
8365
8366 mSplitFree(&toks, num_toks);
8367 }
8368
ConfigProtectedContent(SnortConfig * sc,char * args)8369 void ConfigProtectedContent(SnortConfig *sc, char *args)
8370 {
8371 int num_toks;
8372 char **toks;
8373
8374 if ((sc == NULL) || (args == NULL))
8375 return;
8376
8377 toks = mSplit(args, " \t", 2, &num_toks, 0);
8378
8379 if( num_toks != 2 )
8380 ParseError("Invalid argument to protected_content");
8381
8382 if( strcasecmp(toks[0], PROTECTED_CONTENT_OPT__HASH_TYPE) != 0 )
8383 ParseError("Invalid argument to protected_content");
8384
8385 if( (sc->Default_Protected_Content_Hash_Type = SecHash_Name2Type( toks[1] )) == SECHASH_NONE )
8386 ParseError("Invalid protected content hash type");
8387
8388 mSplitFree(&toks, num_toks);
8389 }
8390
8391 #ifdef PPM_MGR
8392 /*
8393 * config ppm: feature, feature, feature,..
8394 *
8395 * config ppm: max-pkt-time usecs,
8396 * disable-pkt-inspection,
8397 * max-rule-time usecs,
8398 * disable-rule-inspection, threshold 5,
8399 * max-suspend-time secs,
8400 * rule-events alert|syslog|console,
8401 * pkt-events alert|syslog|console,
8402 * debug,
8403 * debug-pkts
8404 */
ConfigPPM(SnortConfig * sc,char * args)8405 void ConfigPPM(SnortConfig *sc, char *args)
8406 {
8407 char **toks;
8408 int num_toks;
8409 int i;
8410 char *endptr;
8411 unsigned long int val;
8412 char **opts;
8413 int num_opts;
8414 int pktOpts = 0, ruleOpts = 0;
8415
8416 if (sc == NULL)
8417 return;
8418
8419 toks = mSplit(args, ",", 0, &num_toks, 0);
8420
8421 if (!sc->ppm_cfg.enabled)
8422 ppm_init(&sc->ppm_cfg);
8423
8424 /* defaults are set by ppm_init() */
8425 for(i = 0; i < num_toks; i++)
8426 {
8427 opts = mSplit(toks[i], " \t", 0, &num_opts, 0);
8428
8429 if (strcasecmp(opts[0], PPM_OPT__MAX_PKT_TIME) == 0)
8430 {
8431 if (num_opts != 2)
8432 {
8433 ParseError("config ppm: missing argument for '%s'.", opts[0]);
8434 }
8435
8436 val = SnortStrtoul(opts[1], &endptr, 0);
8437 if ((opts[1][0] == '-') || (errno == ERANGE) || (*endptr != '\0'))
8438 {
8439 ParseError("config ppm: Invalid %s '%s'.", opts[0], opts[1]);
8440 }
8441
8442 ppm_set_max_pkt_time(&sc->ppm_cfg, val);
8443 }
8444 else if (strcasecmp(opts[0], PPM_OPT__MAX_RULE_TIME) == 0)
8445 {
8446 if (num_opts != 2)
8447 {
8448 ParseError("config ppm: missing argument for '%s'.", opts[0]);
8449 }
8450
8451 val = SnortStrtoul(opts[1], &endptr, 0);
8452 if ((opts[1][0] == '-') || (errno == ERANGE) || (*endptr != '\0'))
8453 {
8454 ParseError("config ppm: Invalid %s '%s'.", opts[0], opts[1]);
8455 }
8456
8457 ppm_set_max_rule_time(&sc->ppm_cfg, val);
8458 }
8459 else if (strcasecmp(opts[0], PPM_OPT__SUSPEND_TIMEOUT) == 0)
8460 {
8461 if (num_opts != 2)
8462 {
8463 ParseError("config ppm: missing argument for '%s'.", opts[0]);
8464 }
8465
8466 val = SnortStrtoul(opts[1], &endptr, 0);
8467 if ((opts[1][0] == '-') || (errno == ERANGE) || (*endptr != '\0'))
8468 {
8469 ParseError("config ppm: Invalid %s '%s'.", opts[0], opts[1]);
8470 }
8471
8472 ppm_set_max_suspend_time(&sc->ppm_cfg, val);
8473 ruleOpts++;
8474 }
8475 else if (strcasecmp(opts[0], PPM_OPT__SUSPEND_EXP_RULES) == 0)
8476 {
8477 if (num_opts != 1)
8478 {
8479 ParseError("config ppm: too many arguments for '%s'.", opts[0]);
8480 }
8481
8482 ppm_set_rule_action(&sc->ppm_cfg, PPM_ACTION_SUSPEND);
8483 ruleOpts++;
8484 }
8485 else if (strcasecmp(opts[0], PPM_OPT__THRESHOLD) == 0)
8486 {
8487 if (num_opts != 2)
8488 {
8489 ParseError("config ppm: missing argument for '%s'.", opts[0]);
8490 }
8491
8492 val = SnortStrtoul(opts[1], &endptr, 0);
8493 if ((opts[1][0] == '-') || (errno == ERANGE) || (*endptr != '\0'))
8494 {
8495 ParseError("config ppm: Invalid %s '%s'.", opts[0], opts[1]);
8496 }
8497
8498 ppm_set_rule_threshold(&sc->ppm_cfg, val);
8499 ruleOpts++;
8500 }
8501 else if (strcasecmp(opts[0], PPM_OPT__FAST_PATH_EXP_PKTS) == 0)
8502 {
8503 if (num_opts != 1)
8504 {
8505 ParseError("config ppm: too many arguments for '%s'.", opts[0]);
8506 }
8507
8508 ppm_set_pkt_action(&sc->ppm_cfg, PPM_ACTION_SUSPEND);
8509 pktOpts++;
8510 }
8511 else if (strcasecmp(opts[0], PPM_OPT__PKT_LOG) == 0)
8512 {
8513 if (num_opts == 1)
8514 {
8515 ppm_set_pkt_log(&sc->ppm_cfg, PPM_LOG_MESSAGE);
8516 }
8517 else
8518 {
8519 int k;
8520
8521 for (k = 1; k < num_opts; k++)
8522 {
8523 if (strcasecmp(opts[k], PPM_OPT__ALERT) == 0)
8524 {
8525 ppm_set_pkt_log(&sc->ppm_cfg, PPM_LOG_ALERT);
8526 }
8527 else if (strcasecmp(opts[k], PPM_OPT__LOG) == 0)
8528 {
8529 ppm_set_pkt_log(&sc->ppm_cfg, PPM_LOG_MESSAGE);
8530 }
8531 else
8532 {
8533 ParseError("config ppm: Invalid %s arg '%s'.", opts[0], opts[k]);
8534 }
8535 }
8536 }
8537 pktOpts++;
8538 }
8539 else if (strcasecmp(opts[0], PPM_OPT__RULE_LOG) == 0)
8540 {
8541 int k;
8542
8543 if (num_opts == 1)
8544 {
8545 ParseError("config ppm: insufficient %s opts.", opts[0]);
8546 }
8547
8548 for (k = 1; k < num_opts; k++)
8549 {
8550 if (strcasecmp(opts[k], PPM_OPT__ALERT) == 0)
8551 {
8552 ppm_set_rule_log(&sc->ppm_cfg, PPM_LOG_ALERT);
8553 }
8554 else if (strcasecmp(opts[k], PPM_OPT__LOG) == 0)
8555 {
8556 ppm_set_rule_log(&sc->ppm_cfg, PPM_LOG_MESSAGE);
8557 }
8558 else
8559 {
8560 ParseError("config ppm: Invalid %s arg '%s'.", opts[0], opts[k]);
8561 }
8562 }
8563
8564 ruleOpts++;
8565 }
8566 #ifdef DEBUG
8567 else if (strcasecmp(opts[0], PPM_OPT__DEBUG_PKTS) == 0)
8568 {
8569 if (num_opts != 1)
8570 {
8571 ParseError("config ppm: too many arguments for '%s'.", opts[0]);
8572 }
8573
8574 ppm_set_debug_pkts(&sc->ppm_cfg, 1);
8575 pktOpts++;
8576 }
8577 #if 0
8578 else if(!strcasecmp(opts[0], "debug-rules"))
8579 {
8580 if( 1 != num_opts )
8581 ParseError("config ppm: too many arguments for '%s'.", opts[0]);
8582 ppm_set_debug_rules(1);
8583 }
8584 #endif
8585 #endif
8586 else
8587 {
8588 ParseError("'%s' is an invalid option to the 'config ppm:' "
8589 "configuration.", opts[0]);
8590 }
8591
8592 mSplitFree(&opts, num_opts);
8593 }
8594
8595 mSplitFree(&toks, num_toks);
8596 }
8597 #endif
8598
ConfigProcessAllEvents(SnortConfig * sc,char * args)8599 void ConfigProcessAllEvents(SnortConfig *sc, char *args)
8600 {
8601 if (sc == NULL)
8602 return;
8603
8604 sc->run_flags |= RUN_FLAG__PROCESS_ALL_EVENTS;
8605 }
8606
8607 #ifdef PERF_PROFILING
8608 /* Profiling configurations are done later after log directory has
8609 * absolutely been set */
_ConfigProfilePreprocs(SnortConfig * sc,char * args)8610 static void _ConfigProfilePreprocs(SnortConfig *sc, char *args)
8611 {
8612 return;
8613 }
8614
ConfigProfilePreprocs(SnortConfig * sc,char * args)8615 void ConfigProfilePreprocs(SnortConfig *sc, char *args)
8616 {
8617 char **toks;
8618 int num_toks;
8619 int i;
8620
8621 if (sc == NULL)
8622 return;
8623
8624 LogMessage("Found profile_preprocs config directive (%s)\n",
8625 args == NULL ? "<no args>" : args);
8626
8627 /* Initialize the defaults */
8628 sc->profile_preprocs.num = -1;
8629 sc->profile_preprocs.sort = PROFILE_SORT_AVG_TICKS;
8630
8631 toks = mSplit(args, ",", 0, &num_toks, 0);
8632
8633 if (num_toks > 3)
8634 {
8635 ParseError("profile_preprocs speciified with invalid options (%s)", args);
8636 }
8637
8638 for (i = 0; i < num_toks; i++)
8639 {
8640 char **opts;
8641 int num_opts;
8642 int opt_filename = 0;
8643 char *endptr;
8644
8645 opts = mSplit(toks[i], " \t", 0, &num_opts, 0);
8646 if (num_opts > 0)
8647 {
8648 opt_filename = strcasecmp(opts[0], PROFILE_OPT__FILENAME) == 0;
8649 }
8650
8651 if ((!opt_filename && (num_opts != 2)) ||
8652 (opt_filename && ((num_opts > 3) || (num_opts < 2))))
8653 {
8654 ParseError("profile_preprocs has an invalid option (%s)", toks[i]);
8655 }
8656
8657 if (strcasecmp(opts[0], PROFILE_OPT__PRINT) == 0)
8658 {
8659 if (strcasecmp(opts[1], PROFILE_OPT__ALL) == 0)
8660 {
8661 sc->profile_preprocs.num = -1;
8662 }
8663 else
8664 {
8665 sc->profile_preprocs.num = SnortStrtol(opts[1], &endptr, 10);
8666 if ((errno == ERANGE) || (*endptr != '\0'))
8667 {
8668 ParseError("Invalid argument to profile_preprocs 'print' "
8669 "configuration: %s", opts[1]);
8670 }
8671 }
8672 }
8673 else if (strcasecmp(opts[0], PROFILE_OPT__SORT) == 0)
8674 {
8675 if (strcasecmp(opts[1], PROFILE_OPT__CHECKS) == 0)
8676 {
8677 sc->profile_preprocs.sort = PROFILE_SORT_CHECKS;
8678 }
8679 else if (strcasecmp(opts[1], PROFILE_OPT__AVG_TICKS) == 0)
8680 {
8681 sc->profile_preprocs.sort = PROFILE_SORT_AVG_TICKS;
8682 }
8683 else if (strcasecmp(opts[1], PROFILE_OPT__TOTAL_TICKS) == 0)
8684 {
8685 sc->profile_preprocs.sort = PROFILE_SORT_TOTAL_TICKS;
8686 }
8687 else
8688 {
8689 ParseError("profile_preprocs has an invalid sort option (%s)", toks[i]);
8690 }
8691 }
8692 else if (strcasecmp(opts[0], PROFILE_OPT__FILENAME) == 0)
8693 {
8694 sc->profile_preprocs.filename = ProcessFileOption(sc, opts[1]);
8695 if (opts[2] && (strcasecmp(opts[2], PROFILE_OPT__APPEND) == 0))
8696 {
8697 sc->profile_preprocs.append = 1;
8698 }
8699 else
8700 {
8701 sc->profile_preprocs.append = 0;
8702 }
8703 }
8704 else
8705 {
8706 ParseError("profile_preprocs has an invalid option (%s)", toks[i]);
8707 }
8708
8709 mSplitFree(&opts, num_opts);
8710 }
8711
8712 mSplitFree(&toks, num_toks);
8713 }
8714
_ConfigProfileRules(SnortConfig * sc,char * args)8715 static void _ConfigProfileRules(SnortConfig *sc, char *args)
8716 {
8717 return;
8718 }
8719
ConfigProfileRules(SnortConfig * sc,char * args)8720 void ConfigProfileRules(SnortConfig *sc, char *args)
8721 {
8722 char **toks;
8723 int num_toks;
8724 int i;
8725
8726 if (sc == NULL)
8727 return;
8728
8729 LogMessage("Found profile_rules config directive (%s)\n",
8730 args == NULL ? "<no args>" : args);
8731
8732 /* Initialize the defaults */
8733 sc->profile_rules.num = -1;
8734 sc->profile_rules.sort = PROFILE_SORT_AVG_TICKS;
8735
8736 toks = mSplit(args, ",", 0, &num_toks, 0);
8737
8738 if (num_toks > 3)
8739 {
8740 ParseError("profile_rules speciified with invalid options (%s)", args);
8741 }
8742
8743 for (i = 0; i < num_toks;i++)
8744 {
8745 char **opts;
8746 int num_opts;
8747 int opt_filename = 0;
8748 char *endptr;
8749
8750 opts = mSplit(toks[i], " \t", 0, &num_opts, 0);
8751 if (num_opts > 0)
8752 {
8753 opt_filename = strcasecmp(opts[0], PROFILE_OPT__FILENAME) == 0;
8754 }
8755
8756 if ((!opt_filename && (num_opts != 2)) ||
8757 (opt_filename && ((num_opts > 3) || (num_opts < 2))))
8758 {
8759 ParseError("profile_rules has an invalid option (%s)", toks[i]);
8760 }
8761
8762 if (strcasecmp(opts[0], PROFILE_OPT__PRINT) == 0)
8763 {
8764 if (strcasecmp(opts[1], PROFILE_OPT__ALL) == 0)
8765 {
8766 sc->profile_rules.num = -1;
8767 }
8768 else
8769 {
8770 sc->profile_rules.num = SnortStrtol(opts[1], &endptr, 10);
8771 if ((errno == ERANGE) || (*endptr != '\0'))
8772 {
8773 ParseError("Invalid argument to profile_rules 'print' "
8774 "configuration: %s", opts[1]);
8775 }
8776 }
8777 }
8778 else if (strcasecmp(opts[0], PROFILE_OPT__SORT) == 0)
8779 {
8780 if (strcasecmp(opts[1], PROFILE_OPT__CHECKS) == 0)
8781 {
8782 sc->profile_rules.sort = PROFILE_SORT_CHECKS;
8783 }
8784 else if (strcasecmp(opts[1], PROFILE_OPT__MATCHES) == 0)
8785 {
8786 sc->profile_rules.sort = PROFILE_SORT_MATCHES;
8787 }
8788 else if (strcasecmp(opts[1], PROFILE_OPT__NO_MATCHES) == 0)
8789 {
8790 sc->profile_rules.sort = PROFILE_SORT_NOMATCHES;
8791 }
8792 else if (strcasecmp(opts[1], PROFILE_OPT__AVG_TICKS) == 0)
8793 {
8794 sc->profile_rules.sort = PROFILE_SORT_AVG_TICKS;
8795 }
8796 else if (strcasecmp(opts[1], PROFILE_OPT__AVG_TICKS_PER_MATCH) == 0)
8797 {
8798 sc->profile_rules.sort = PROFILE_SORT_AVG_TICKS_PER_MATCH;
8799 }
8800 else if (strcasecmp(opts[1], PROFILE_OPT__AVG_TICKS_PER_NO_MATCH) == 0)
8801 {
8802 sc->profile_rules.sort = PROFILE_SORT_AVG_TICKS_PER_NOMATCH;
8803 }
8804 else if (strcasecmp(opts[1], PROFILE_OPT__TOTAL_TICKS) == 0)
8805 {
8806 sc->profile_rules.sort = PROFILE_SORT_TOTAL_TICKS;
8807 }
8808 else
8809 {
8810 ParseError("profile_rules has an invalid sort option (%s)", toks[i]);
8811 }
8812 }
8813 else if (strcasecmp(opts[0], PROFILE_OPT__FILENAME) == 0)
8814 {
8815 sc->profile_rules.filename = ProcessFileOption(sc, opts[1]);
8816 if (opts[2] && (strcasecmp(opts[2], PROFILE_OPT__APPEND) == 0))
8817 {
8818 sc->profile_rules.append = 1;
8819 }
8820 else
8821 {
8822 sc->profile_rules.append = 0;
8823 }
8824 }
8825 else
8826 {
8827 ParseError("profile_rules has an invalid option (%s)", toks[i]);
8828 }
8829
8830 mSplitFree(&opts, num_opts);
8831 }
8832
8833 mSplitFree(&toks, num_toks);
8834 }
8835 #endif
8836
ConfigQuiet(SnortConfig * sc,char * args)8837 void ConfigQuiet(SnortConfig *sc, char *args)
8838 {
8839 if (sc == NULL)
8840 return;
8841
8842 sc->logging_flags |= LOGGING_FLAG__QUIET;
8843 sc->internal_log_level = INTERNAL_LOG_LEVEL__ERROR;
8844 }
8845
8846 /*
8847 * Process the 'config rate_filter: memcap <#bytes>'
8848 */
8849 // TBD refactor - was cloned from sfthreshold.c
ConfigRateFilter(SnortConfig * sc,char * args)8850 void ConfigRateFilter(SnortConfig *sc, char *args)
8851 {
8852 char **toks;
8853 int num_toks;
8854
8855 if ((sc == NULL) || (args == NULL))
8856 return;
8857
8858 toks = mSplit(args, " \t", 2, &num_toks, 0);
8859 if (num_toks != 2)
8860 {
8861 ParseError("Rate filter memcap requires a positive integer argument.");
8862 }
8863
8864 if (strcasecmp(toks[0], "memcap") == 0)
8865 {
8866 char *endptr;
8867
8868 sc->rate_filter_config->memcap = SnortStrtol(toks[1], &endptr, 0);
8869 if ((errno == ERANGE) || (*endptr != '\0') ||
8870 (sc->rate_filter_config->memcap < 0))
8871 {
8872 ParseError("Invalid rate filter memcap: %s. Must be a "
8873 "positive integer.", toks[1]);
8874 }
8875 }
8876 else
8877 {
8878 ParseError("Unknown argument to rate filter configuration: %s.", toks[0]);
8879 }
8880
8881 mSplitFree(&toks, num_toks);
8882 }
8883
ConfigReference(SnortConfig * sc,char * args)8884 void ConfigReference(SnortConfig *sc, char *args)
8885 {
8886 char **toks;
8887 int num_toks;
8888 char *url = NULL;
8889
8890 if ((sc == NULL) || (args == NULL))
8891 return;
8892
8893 /* 2 tokens: name <url> */
8894 toks = mSplit(args, " \t", 0, &num_toks, 0);
8895 if (num_toks > 2)
8896 {
8897 ParseError("Reference config requires at most two arguments: "
8898 "\"name [<url>]\".");
8899 }
8900
8901 if (num_toks == 2)
8902 url = toks[1];
8903
8904 ReferenceSystemAdd(&sc->references, toks[0], url);
8905
8906 mSplitFree(&toks, num_toks);
8907 }
8908
8909 /*
8910 * Function: ConfigReferenceNet
8911 *
8912 * Purpose: Translate the command line character string into its equivalent
8913 * 32-bit network byte ordered value (with netmask)
8914 *
8915 * Arguments: args => The address/CIDR block
8916 *
8917 * Returns: void function
8918 */
ConfigReferenceNet(SnortConfig * sc,char * args)8919 void ConfigReferenceNet(SnortConfig *sc, char *args)
8920 {
8921
8922 if ((sc == NULL) || (args == NULL))
8923 return;
8924
8925 sfip_pton(args, &sc->homenet);
8926 }
8927
ConfigSetGid(SnortConfig * sc,char * args)8928 void ConfigSetGid(SnortConfig *sc, char *args)
8929 {
8930 #ifdef WIN32
8931 ParseError("Setting the group id is not supported in the "
8932 "WIN32 port of snort!");
8933 #else
8934 size_t i;
8935 char *endptr;
8936
8937 if ((sc == NULL) || (args == NULL))
8938 return;
8939
8940 for (i = 0; i < strlen(args); i++)
8941 {
8942 /* If we get something other than a digit, assume it's
8943 * a group name */
8944 if (!isdigit((int)args[i]))
8945 {
8946 struct group *gr = getgrnam(args);
8947
8948 if (gr == NULL)
8949 ParseError("Group \"%s\" unknown.", args);
8950
8951 sc->group_id = gr->gr_gid;
8952 break;
8953 }
8954 }
8955
8956 /* It's all digits. Assume it's a group id */
8957 if (i == strlen(args))
8958 {
8959 sc->group_id = SnortStrtol(args, &endptr, 10);
8960 if ((errno == ERANGE) || (*endptr != '\0') ||
8961 (sc->group_id < 0))
8962 {
8963 ParseError("Group id \"%s\" out of range.", args);
8964 }
8965 }
8966 #endif
8967 }
8968
ConfigSetUid(SnortConfig * sc,char * args)8969 void ConfigSetUid(SnortConfig *sc, char *args)
8970 {
8971 #ifdef WIN32
8972 ParseError("Setting the user id is not supported in the "
8973 "WIN32 port of snort!");
8974 #else
8975 size_t i;
8976 char *endptr;
8977
8978 if ((sc == NULL) || (args == NULL))
8979 return;
8980
8981 for (i = 0; i < strlen(args); i++)
8982 {
8983 /* If we get something other than a digit, assume it's
8984 * a user name */
8985 if (!isdigit((int)args[i]))
8986 {
8987 struct passwd *pw = getpwnam(args);
8988
8989 if (pw == NULL)
8990 ParseError("User \"%s\" unknown.", args);
8991
8992 sc->user_id = (int)pw->pw_uid;
8993
8994 /* Why would someone want to run as another user
8995 * but still as root group? */
8996 if (sc->group_id == -1)
8997 sc->group_id = (int)pw->pw_gid;
8998
8999 break;
9000 }
9001 }
9002
9003 /* It's all digits. Assume it's a user id */
9004 if (i == strlen(args))
9005 {
9006 sc->user_id = SnortStrtol(args, &endptr, 10);
9007 if ((errno == ERANGE) || (*endptr != '\0'))
9008 ParseError("User id \"%s\" out of range.", args);
9009
9010 /* Set group id to user's default group if not
9011 * already set */
9012 if (sc->group_id == -1)
9013 {
9014 struct passwd *pw = getpwuid((uid_t)sc->user_id);
9015
9016 if (pw == NULL)
9017 ParseError("User \"%s\" unknown.", args);
9018
9019 sc->group_id = (int)pw->pw_gid;
9020 }
9021 }
9022
9023 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "UserID: %d GroupID: %d.\n",
9024 sc->user_id, sc->group_id););
9025 #endif /* !WIN32 */
9026 }
9027
ConfigShowYear(SnortConfig * sc,char * args)9028 void ConfigShowYear(SnortConfig *sc, char *args)
9029 {
9030 if (sc == NULL)
9031 return;
9032
9033 sc->output_flags |= OUTPUT_FLAG__INCLUDE_YEAR;
9034 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Enabled year in timestamp\n"););
9035 }
9036
ConfigSoRuleMemcap(SnortConfig * sc,char * args)9037 void ConfigSoRuleMemcap(SnortConfig *sc, char *args)
9038 {
9039 char *endptr;
9040
9041 if ((sc == NULL) || (args == NULL))
9042 return;
9043
9044 sc->so_rule_memcap = SnortStrtoul(args, &endptr, 0);
9045 if ((errno == ERANGE) || (*endptr != '\0'))
9046 {
9047 ParseError("Invalid so rule memcap: %s. Memcap must be between "
9048 "0 and %u inclusive.", args, UINT32_MAX);
9049 }
9050 }
9051
ConfigStateful(SnortConfig * sc,char * args)9052 void ConfigStateful(SnortConfig *sc, char *args)
9053 {
9054 if (sc == NULL)
9055 return;
9056
9057 /* If stream5 is configured, the STATEFUL flag is set. This is
9058 * somewhat misnamed and is used to assure a session is established */
9059 sc->run_flags |= RUN_FLAG__ASSURE_EST;
9060 }
9061
ConfigTaggedPacketLimit(SnortConfig * sc,char * args)9062 void ConfigTaggedPacketLimit(SnortConfig *sc, char *args)
9063 {
9064 char *endptr;
9065
9066 if ((sc == NULL) || (args == NULL))
9067 return;
9068
9069 sc->tagged_packet_limit = SnortStrtol(args, &endptr, 0);
9070 if ((errno == ERANGE) || (*endptr != '\0') ||
9071 (sc->tagged_packet_limit < 0))
9072 {
9073 ParseError("Invalid tagged_packet_limit: %s. Must be a "
9074 "positive integer.", args);
9075 }
9076 }
9077
9078 /*
9079 Process the 'config threshold: memcap #bytes, option2-name option2-value, ...'
9080
9081 config threshold: memcap #bytes
9082 */
ConfigThreshold(SnortConfig * sc,char * args)9083 void ConfigThreshold(SnortConfig *sc, char *args)
9084 {
9085 static int warned = 0;
9086
9087 if (!warned)
9088 {
9089 ParseWarning("config threshold is deprecated;"
9090 " use config event_filter instead.\n");
9091
9092 warned = 1;
9093 }
9094
9095 ConfigEventFilter(sc, args);
9096 }
9097
ConfigTreatDropAsAlert(SnortConfig * sc,char * args)9098 void ConfigTreatDropAsAlert(SnortConfig *sc, char *args)
9099 {
9100 if (sc == NULL)
9101 return;
9102
9103 sc->run_flags |= RUN_FLAG__TREAT_DROP_AS_ALERT;
9104 }
9105
ConfigTreatDropAsIgnore(SnortConfig * sc,char * args)9106 void ConfigTreatDropAsIgnore(SnortConfig *sc, char *args)
9107 {
9108 if (sc == NULL)
9109 return;
9110
9111 sc->run_flags |= RUN_FLAG__TREAT_DROP_AS_IGNORE;
9112 }
9113
ConfigUmask(SnortConfig * sc,char * args)9114 void ConfigUmask(SnortConfig *sc, char *args)
9115 {
9116 #ifdef WIN32
9117 ParseError("Setting the umask is not supported in the "
9118 "WIN32 port of snort!");
9119 #else
9120 char *endptr;
9121 long mask;
9122
9123 if ((sc == NULL) || (args == NULL))
9124 return;
9125
9126 mask = SnortStrtol(args, &endptr, 0);
9127
9128 if ((errno == ERANGE) || (*endptr != '\0') ||
9129 (mask < 0) || (mask & ~FILEACCESSBITS))
9130 {
9131 ParseError("Bad umask: %s", args);
9132 }
9133 sc->file_mask = (mode_t)mask;
9134 #endif
9135 }
9136
ConfigUtc(SnortConfig * sc,char * args)9137 void ConfigUtc(SnortConfig *sc, char *args)
9138 {
9139 if (sc == NULL)
9140 return;
9141
9142 sc->output_flags |= OUTPUT_FLAG__USE_UTC;
9143 }
9144
ConfigVerbose(SnortConfig * sc,char * args)9145 void ConfigVerbose(SnortConfig *sc, char *args)
9146 {
9147 if (sc == NULL)
9148 return;
9149
9150 sc->logging_flags |= LOGGING_FLAG__VERBOSE;
9151 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Verbose Flag active\n"););
9152 }
9153
ConfigVlanAgnostic(SnortConfig * sc,char * args)9154 void ConfigVlanAgnostic(SnortConfig *sc, char *args)
9155 {
9156 if (sc == NULL)
9157 return;
9158
9159 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "VLAN Agnostic active\n"););
9160 sc->vlan_agnostic = 1; /* TODO: add this to some existing flag bitfield? */
9161 }
9162
ConfigAddressSpaceAgnostic(SnortConfig * sc,char * args)9163 void ConfigAddressSpaceAgnostic(SnortConfig *sc, char *args)
9164 {
9165 if (sc == NULL)
9166 return;
9167
9168 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Address Space Agnostic active\n"););
9169 sc->addressspace_agnostic = 1; /* TODO: add this to some existing flag bitfield? */
9170 }
9171
ConfigLogIPv6Extra(SnortConfig * sc,char * args)9172 void ConfigLogIPv6Extra(SnortConfig *sc, char *args)
9173 {
9174 if (sc == NULL)
9175 return;
9176
9177 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "LOG IPV6 EXTRA DATA active\n"););
9178 sc->log_ipv6_extra = 1; /* TODO: add this to some existing flag bitfield? */
9179 }
9180
ConfigDumpDynamicRulesPath(SnortConfig * sc,char * args)9181 void ConfigDumpDynamicRulesPath(SnortConfig *sc, char *args)
9182 {
9183 if (sc == NULL)
9184 return;
9185 sc->run_mode_flags |= RUN_MODE_FLAG__RULE_DUMP;
9186 if ( args != NULL )
9187 sc->dynamic_rules_path = SnortStrdup(args);
9188 }
9189
ConfigControlSocketDirectory(SnortConfig * sc,char * args)9190 void ConfigControlSocketDirectory(SnortConfig *sc, char *args)
9191 {
9192 if (sc == NULL)
9193 return;
9194 if ( args != NULL )
9195 sc->cs_dir = SnortStrdup(args);
9196 }
9197
ConfigFile(SnortConfig * sc,char * args)9198 void ConfigFile(SnortConfig *sc, char *args)
9199 {
9200 if (sc == NULL)
9201 return;
9202 if ( args != NULL )
9203 {
9204 if (!sc->file_config)
9205 sc->file_config = file_service_config_create();
9206 file_service_config(sc, args, sc->file_config);
9207 }
9208 }
9209
ConfigTunnelVerdicts(SnortConfig * sc,char * args)9210 void ConfigTunnelVerdicts ( SnortConfig *sc, char *args )
9211 {
9212 char* tmp, *tok;
9213
9214 if (sc == NULL)
9215 return;
9216
9217 tmp = SnortStrdup(args);
9218 tok = strtok(tmp, " ,");
9219
9220 while ( tok )
9221 {
9222 if ( !strcasecmp(tok, "gtp") )
9223 sc->tunnel_mask |= TUNNEL_GTP;
9224
9225 else if ( !strcasecmp(tok, "teredo") )
9226 sc->tunnel_mask |= TUNNEL_TEREDO;
9227
9228 else if ( !strcasecmp(tok, "gre") )
9229 sc->tunnel_mask |= TUNNEL_GRE;
9230
9231 else if ( !strcasecmp(tok, "6in4") )
9232 sc->tunnel_mask |= TUNNEL_6IN4;
9233
9234 else if ( !strcasecmp(tok, "4in6") )
9235 sc->tunnel_mask |= TUNNEL_4IN6;
9236
9237 else if ( !strcasecmp(tok, "4in4") )
9238 sc->tunnel_mask |= TUNNEL_4IN4;
9239
9240 else if ( !strcasecmp(tok, "6in6") )
9241 sc->tunnel_mask |= TUNNEL_6IN6;
9242
9243 else if ( !strcasecmp(tok, "mpls") )
9244 sc->tunnel_mask |= TUNNEL_MPLS;
9245
9246 else
9247 ParseError("Unknown tunnel bypass protocol");
9248
9249 tok = strtok(NULL, " ,");
9250 }
9251 free(tmp);
9252 }
9253
9254 #ifdef SIDE_CHANNEL
ConfigSideChannel(SnortConfig * sc,char * args)9255 static void ConfigSideChannel(SnortConfig *sc, char *args)
9256 {
9257 if (sc == NULL)
9258 return;
9259 sc->side_channel_config.enabled = true;
9260 if (args != NULL)
9261 sc->side_channel_config.opts = SnortStrdup(args);
9262 }
9263 #endif
9264
ConfigMaxIP6Extensions(SnortConfig * sc,char * args)9265 void ConfigMaxIP6Extensions(SnortConfig *sc, char *args)
9266 {
9267 char *endptr;
9268 unsigned long parsed_value;
9269
9270 if ((sc == NULL) || (args == NULL))
9271 return;
9272
9273 parsed_value = SnortStrtoul(args, &endptr, 0);
9274
9275 if ((*endptr != '\0') || (parsed_value > UINT8_MAX))
9276 {
9277 ParseError("Max IP6 extension count must be a value between 0 and %d (inclusive), not: '%s'.", UINT8_MAX, args);
9278 }
9279
9280 sc->max_ip6_extensions = (uint8_t) parsed_value;
9281 }
9282
ConfigDisableReplace(SnortConfig * sc,char * args)9283 void ConfigDisableReplace(SnortConfig *sc, char *args)
9284 {
9285 if(sc == NULL)
9286 return;
9287 sc->disable_replace_opt = 1;
9288 }
9289
9290 #ifdef DUMP_BUFFER
ConfigBufferDump(SnortConfig * sc,char * args)9291 void ConfigBufferDump(SnortConfig *sc, char *args)
9292 {
9293 if ( !sc )
9294 return;
9295
9296 sc->no_log = 0;
9297
9298 if (!args)
9299 return;
9300
9301 if ( !sc->buffer_dump_file )
9302 {
9303 sc->buffer_dump_file = StringVector_New();
9304
9305 if ( !sc->buffer_dump_file )
9306 ParseError("can't allocate memory for buffer_dump_file '%s'.", args);
9307 }
9308 if ( !StringVector_Add(sc->buffer_dump_file, args) )
9309 ParseError("can't allocate memory for buffer_dump '%s'.", args);
9310 }
9311 #endif
9312
9313 /****************************************************************************
9314 *
9315 * Function: ParseRule()
9316 *
9317 * Purpose: Process an individual rule and add it to the rule list
9318 *
9319 * Arguments: rule => rule string
9320 *
9321 * Returns: void function
9322 *
9323 ***************************************************************************/
ParseRule(SnortConfig * sc,SnortPolicy * p,char * args,RuleType rule_type,ListHead * list)9324 static void ParseRule(SnortConfig *sc, SnortPolicy *p, char *args,
9325 RuleType rule_type, ListHead *list)
9326 {
9327 char **toks = NULL;
9328 int num_toks = 0;
9329 int protocol = 0;
9330 RuleTreeNode test_rtn;
9331 RuleTreeNode *rtn;
9332 OptTreeNode *otn;
9333 char *roptions = NULL;
9334 port_entry_t pe;
9335 PortVarTable *portVarTable = p->portVarTable;
9336 PortTable *nonamePortVarTable = p->nonamePortVarTable;
9337
9338 if ((sc == NULL) || (args == NULL))
9339 return;
9340
9341 memset(&test_rtn, 0, sizeof(RuleTreeNode));
9342
9343 memset(&pe, 0, sizeof(pe));
9344
9345 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"[*] Rule start\n"););
9346
9347 /* We have a preproc or decoder rule - we assume a header of 'tcp any any -> any any ' */
9348 if (*args == '(')
9349 {
9350 test_rtn.flags |= ANY_DST_PORT;
9351 test_rtn.flags |= ANY_SRC_PORT;
9352 test_rtn.flags |= ANY_DST_IP;
9353 test_rtn.flags |= ANY_SRC_IP;
9354 test_rtn.flags |= BIDIRECTIONAL;
9355 test_rtn.type = rule_type;
9356 protocol = IPPROTO_TCP;
9357
9358 roptions = args;
9359
9360 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Preprocessor Rule detected\n"););
9361 }
9362 else
9363 {
9364 /* proto ip port dir ip port r*/
9365 toks = mSplit(args, " \t", 7, &num_toks, '\\');
9366
9367 /* A rule might not have rule options */
9368 if (num_toks < 6)
9369 {
9370 ParseError("Bad rule in rules file: %s", args);
9371 }
9372
9373 if (num_toks == 7)
9374 roptions = toks[6];
9375
9376 test_rtn.type = rule_type;
9377
9378 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Non-Preprocessor Rule detected\n"););
9379
9380 /* Set the rule protocol - fatal errors if protocol not found */
9381 protocol = GetRuleProtocol(toks[0]);
9382 test_rtn.proto = protocol;
9383
9384 switch (protocol)
9385 {
9386 case IPPROTO_TCP:
9387 sc->ip_proto_array[IPPROTO_TCP] = 1;
9388 break;
9389 case IPPROTO_UDP:
9390 sc->ip_proto_array[IPPROTO_UDP] = 1;
9391 break;
9392 case IPPROTO_ICMP:
9393 sc->ip_proto_array[IPPROTO_ICMP] = 1;
9394 sc->ip_proto_array[IPPROTO_ICMPV6] = 1;
9395 break;
9396 case ETHERNET_TYPE_IP:
9397 /* This will be set via ip_protos */
9398 break;
9399 default:
9400 ParseError("Bad protocol: %s", toks[0]);
9401 break;
9402 }
9403
9404
9405 /* Process the IP address and CIDR netmask - changed version 1.2.1
9406 * "any" IP's are now set to addr 0, netmask 0, and the normal rules are
9407 * applied instead of checking the flag if we see a "!<ip number>" we
9408 * need to set a flag so that we can properly deal with it when we are
9409 * processing packets. */
9410 ProcessIP(sc, toks[1], &test_rtn, SRC, 0);
9411
9412 /* Check to make sure that the user entered port numbers.
9413 * Sometimes they forget/don't know that ICMP rules need them */
9414 if ((strcasecmp(toks[2], RULE_DIR_OPT__DIRECTIONAL) == 0) ||
9415 (strcasecmp(toks[2], RULE_DIR_OPT__BIDIRECTIONAL) == 0))
9416 {
9417 ParseError("Port value missing in rule!");
9418 }
9419
9420 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"Src-Port: %s\n",toks[2]););
9421
9422 if (ParsePortList(&test_rtn, portVarTable, nonamePortVarTable,
9423 toks[2], protocol, 0 /* =src port */ ))
9424 {
9425 ParseError("Bad source port: '%s'", toks[2]);
9426 }
9427
9428 /* changed version 1.8.4
9429 * Die when someone has tried to define a rule character other
9430 * than -> or <> */
9431 if ((strcmp(toks[3], RULE_DIR_OPT__DIRECTIONAL) != 0) &&
9432 (strcmp(toks[3], RULE_DIR_OPT__BIDIRECTIONAL) != 0))
9433 {
9434 ParseError("Illegal direction specifier: %s", toks[3]);
9435 }
9436
9437 /* New in version 1.3: support for bidirectional rules
9438 * This checks the rule "direction" token and sets the bidirectional
9439 * flag if the token = '<>' */
9440 if (strcmp(toks[3], RULE_DIR_OPT__BIDIRECTIONAL) == 0)
9441 {
9442 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Bidirectional rule!\n"););
9443 test_rtn.flags |= BIDIRECTIONAL;
9444 }
9445
9446 /* changed version 1.2.1
9447 * "any" IP's are now set to addr 0, netmask 0, and the normal rules are
9448 * applied instead of checking the flag
9449 * If we see a "!<ip number>" we need to set a flag so that we can
9450 * properly deal with it when we are processing packets */
9451 ProcessIP(sc, toks[4], &test_rtn, DST, 0);
9452
9453 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"Dst-Port: %s\n", toks[5]););
9454
9455 if (ParsePortList(&test_rtn, portVarTable, nonamePortVarTable,
9456 toks[5], protocol, 1 /* =dst port */ ))
9457 {
9458 ParseError("Bad destination port: '%s'", toks[5]);
9459 }
9460 }
9461
9462 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"test_rtn.flags = 0x%X\n", test_rtn.flags););
9463 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Processing Head Node....\n"););
9464
9465 test_rtn.listhead = list;
9466
9467 rtn = ProcessHeadNode(sc, &test_rtn, list);
9468 /* The IPs in the test node get free'd in ProcessHeadNode if there is
9469 * already a matching RTN. The portobjects will get free'd when the
9470 * port var table is free'd */
9471
9472 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Parsing Rule Options...\n"););
9473
9474 otn = ParseRuleOptions(sc, &rtn, roptions, rule_type, protocol);
9475 if (otn == NULL)
9476 {
9477 /* This otn is a dup and we're choosing to keep the old one */
9478 mSplitFree(&toks, num_toks);
9479 return;
9480 }
9481
9482 rule_count++;
9483
9484 /* Get rule option info */
9485 pe.gid = otn->sigInfo.generator;
9486 pe.sid = otn->sigInfo.id;
9487
9488 /* Have to have at least 6 toks */
9489 if (num_toks != 0)
9490 {
9491 pe.protocol = SnortStrdup(toks[0]);
9492 pe.src_port = SnortStrdup(toks[2]);
9493 pe.dst_port = SnortStrdup(toks[5]);
9494 }
9495
9496 /* See what kind of content is going in the fast pattern matcher */
9497 if (otn->ds_list[PLUGIN_DYNAMIC] != NULL)
9498 {
9499 DynamicData *dd = (DynamicData *)otn->ds_list[PLUGIN_DYNAMIC];
9500 if (dd->contentFlags & CONTENT_HTTP)
9501 pe.uricontent = 1;
9502 else if (dd->contentFlags & CONTENT_NORMAL)
9503 pe.content = 1;
9504 }
9505 else
9506 {
9507 /* Since http_cookie content is not used in fast pattern matcher,
9508 * need to iterate the entire list */
9509 if (otn->ds_list[PLUGIN_PATTERN_MATCH_URI] != NULL)
9510 {
9511 PatternMatchData *pmd = otn->ds_list[PLUGIN_PATTERN_MATCH_URI];
9512
9513 for (; pmd != NULL; pmd = pmd->next)
9514 {
9515 if ( IsHttpBufFpEligible(pmd->http_buffer) )
9516 {
9517 pe.uricontent = 1;
9518 break;
9519 }
9520 }
9521 }
9522
9523 if (!pe.uricontent && ((otn->ds_list[PLUGIN_PATTERN_MATCH] != NULL)
9524 || (otn->ds_list[PLUGIN_PATTERN_MATCH_OR] != NULL)))
9525 {
9526 pe.content = 1;
9527 }
9528 }
9529
9530 if (rtn->flags & BIDIRECTIONAL)
9531 pe.dir = 1;
9532
9533 pe.proto = protocol;
9534 pe.rule_type = rule_type;
9535
9536 port_list_add_entry(&port_list, &pe);
9537
9538 /*
9539 * The src/dst port parsing must be done before the Head Nodes are processed, since they must
9540 * compare the ports/port_objects to find the right rtn list to add the otn rule to.
9541 *
9542 * After otn processing we can finalize port object processing for this rule
9543 */
9544 if (FinishPortListRule(sc->port_tables, rtn, otn, protocol, &pe, sc->fast_pattern_config))
9545 ParseError("Failed to finish a port list rule.");
9546
9547 mSplitFree(&toks, num_toks);
9548 }
9549
9550 /****************************************************************************
9551 *
9552 * Function: ProcessHeadNode(RuleTreeNode *, ListHead *, int)
9553 *
9554 * Purpose: Process the header block info and add to the block list if
9555 * necessary
9556 *
9557 * Arguments: test_node => data generated by the rules parsers
9558 * list => List Block Header refernece
9559 * protocol => ip protocol
9560 *
9561 * Returns: void function
9562 *
9563 ***************************************************************************/
ProcessHeadNode(SnortConfig * sc,RuleTreeNode * test_node,ListHead * list)9564 static RuleTreeNode * ProcessHeadNode(SnortConfig *sc, RuleTreeNode *test_node,
9565 ListHead *list)
9566 {
9567 RuleTreeNode *rtn = findHeadNode(sc, test_node, getParserPolicy(sc));
9568
9569 /* if it doesn't match any of the existing nodes, make a new node and
9570 * stick it at the end of the list */
9571 if (rtn == NULL)
9572 {
9573 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Building New Chain head node\n"););
9574
9575 rtn = (RuleTreeNode *)SnortAlloc(sizeof(RuleTreeNode));
9576
9577 rtn->otnRefCount++;
9578
9579 /* copy the prototype header info into the new header block */
9580 XferHeader(test_node, rtn);
9581
9582 head_count++;
9583 rtn->head_node_number = head_count;
9584
9585 /* initialize the function list for the new RTN */
9586 SetupRTNFuncList(rtn);
9587
9588 /* add link to parent listhead */
9589 rtn->listhead = list;
9590
9591 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,
9592 "New Chain head flags = 0x%X\n", rtn->flags););
9593 }
9594 else
9595 {
9596 rtn->otnRefCount++;
9597 FreeRuleTreeNode(test_node);
9598 }
9599
9600 return rtn;
9601 }
9602
9603 #if 0
9604 #ifdef DEBUG_MSGS
9605 static void PrintRtnPorts(RuleTreeNode *rtn_list)
9606 {
9607 int i = 0;
9608 char buf[STD_BUF];
9609
9610 SnortSnprintf(buf, STD_BUF, "%s", " ");
9611
9612 while (rtn_list != NULL)
9613 {
9614 if (rtn_list->flags & EXCEPT_DST_PORT)
9615 {
9616 SnortSnprintfAppend(buf, STD_BUF, "!");
9617 }
9618
9619 SnortSnprintfAppend(buf, STD_BUF, "%d ", rtn_list->ldp);
9620
9621 rtn_list = rtn_list->right;
9622
9623 if (i == 15)
9624 {
9625 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "%s\n", buf););
9626
9627 i = 0;
9628
9629 SnortSnprintf(buf, STD_BUF, "%s", " ");
9630 }
9631
9632 i++;
9633 }
9634
9635 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "%s\n", buf););
9636 }
9637 #endif
9638 #endif
9639
ParseAlert(SnortConfig * sc,SnortPolicy * p,char * args)9640 static void ParseAlert(SnortConfig *sc, SnortPolicy *p, char *args)
9641 {
9642 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Alert\n"););
9643 ParseRule(sc, p, args, RULE_TYPE__ALERT, &sc->Alert);
9644 }
9645
ParseDrop(SnortConfig * sc,SnortPolicy * p,char * args)9646 static void ParseDrop(SnortConfig *sc, SnortPolicy *p, char *args)
9647 {
9648 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Drop\n"););
9649
9650 /* Parse as an alert if we're treating drops as alerts */
9651 if (ScTreatDropAsAlertNewConf(sc))
9652 ParseRule(sc, p, args, RULE_TYPE__ALERT, &sc->Alert);
9653
9654 else if ( ScKeepDropRules(sc) || ScLoadAsDropRules(sc) )
9655 ParseRule(sc, p, args, RULE_TYPE__DROP, &sc->Drop);
9656 }
9657
ParseLog(SnortConfig * sc,SnortPolicy * p,char * args)9658 static void ParseLog(SnortConfig *sc, SnortPolicy *p, char *args)
9659 {
9660 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Log\n"););
9661 ParseRule(sc, p, args, RULE_TYPE__LOG, &sc->Log);
9662 }
9663
ParsePass(SnortConfig * sc,SnortPolicy * p,char * args)9664 static void ParsePass(SnortConfig *sc, SnortPolicy *p, char *args)
9665 {
9666 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Pass\n"););
9667 ParseRule(sc, p, args, RULE_TYPE__PASS, &sc->Pass);
9668 }
9669
ParseReject(SnortConfig * sc,SnortPolicy * p,char * args)9670 static void ParseReject(SnortConfig *sc, SnortPolicy *p, char *args)
9671 {
9672 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Reject\n"););
9673 ParseRule(sc, p, args, RULE_TYPE__REJECT, &sc->Reject);
9674 #ifdef ACTIVE_RESPONSE
9675 Active_SetEnabled(1);
9676 #endif
9677 }
9678
ParseSdrop(SnortConfig * sc,SnortPolicy * p,char * args)9679 static void ParseSdrop(SnortConfig *sc, SnortPolicy *p, char *args)
9680 {
9681 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "SDrop\n"););
9682
9683 if ( ScKeepDropRules(sc) && !ScTreatDropAsAlertNewConf(sc) )
9684 ParseRule(sc, p, args, RULE_TYPE__SDROP, &sc->SDrop);
9685 }
9686
ParsePortVar(SnortConfig * sc,SnortPolicy * p,char * args)9687 static void ParsePortVar(SnortConfig *sc, SnortPolicy *p, char *args)
9688 {
9689 char **toks;
9690 int num_toks;
9691
9692 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "PortVar\n"););
9693
9694 toks = mSplit(args, " \t", 0, &num_toks, 0);
9695 if (num_toks != 2)
9696 {
9697 ParseError("Missing argument to %s", toks[0]);
9698 }
9699
9700 /* Check command line variables to see if this has already
9701 * been defined */
9702 if (cmd_line_var_list != NULL)
9703 {
9704 VarNode *tmp = cmd_line_var_list;
9705
9706 while (tmp != NULL)
9707 {
9708 /* Already defined this via command line */
9709 if (strcasecmp(toks[0], tmp->name) == 0)
9710 {
9711 mSplitFree(&toks, num_toks);
9712 return;
9713 }
9714
9715 tmp = tmp->next;
9716 }
9717 }
9718
9719 PortVarDefine(sc, toks[0], toks[1]);
9720
9721 mSplitFree(&toks, num_toks);
9722 }
9723
ParseIpVar(SnortConfig * sc,SnortPolicy * p,char * args)9724 static void ParseIpVar(SnortConfig *sc, SnortPolicy *p, char *args)
9725 {
9726 char **toks;
9727 int num_toks;
9728 int ret;
9729
9730 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "IpVar\n"););
9731
9732 toks = mSplit(args, " \t", 0, &num_toks, 0);
9733 if (num_toks != 2)
9734 {
9735 ParseError("Missing argument to %s", toks[0]);
9736 }
9737
9738 /* Check command line variables to see if this has already
9739 * been defined */
9740 if (cmd_line_var_list != NULL)
9741 {
9742 VarNode *tmp = cmd_line_var_list;
9743
9744 while (tmp != NULL)
9745 {
9746 /* Already defined this via command line */
9747 if (strcasecmp(toks[0], tmp->name) == 0)
9748 {
9749 mSplitFree(&toks, num_toks);
9750 return;
9751 }
9752
9753 tmp = tmp->next;
9754 }
9755 }
9756
9757 DisallowCrossTableDuplicateVars(sc, toks[0], VAR_TYPE__IPVAR);
9758
9759 if((ret = sfvt_define(p->ip_vartable, toks[0], toks[1])) != SFIP_SUCCESS)
9760 {
9761 switch(ret) {
9762 case SFIP_ARG_ERR:
9763 ParseError("The following is not allowed: %s.", toks[1]);
9764 break;
9765
9766 case SFIP_DUPLICATE:
9767 ParseMessage("Var '%s' redefined.", toks[0]);
9768 break;
9769
9770 case SFIP_CONFLICT:
9771 ParseError("Negated IP ranges that are more general than "
9772 "non-negated ranges are not allowed. Consider "
9773 "inverting the logic in %s.", toks[0]);
9774 break;
9775
9776 case SFIP_NOT_ANY:
9777 ParseError("!any is not allowed in %s.", toks[0]);
9778 break;
9779
9780 case SFIP_INVALID_VAR:
9781 ParseError("Variable name should contain minimum 1 alphabetic character."
9782 " Following variable name is not allowed: %s.", toks[0]);
9783 break;
9784
9785 default:
9786 ParseError("Failed to parse the IP address: %s.", toks[1]);
9787 }
9788 }
9789
9790 mSplitFree(&toks, num_toks);
9791 }
9792
ParseVar(SnortConfig * sc,SnortPolicy * p,char * args)9793 static void ParseVar(SnortConfig *sc, SnortPolicy *p, char *args)
9794 {
9795 char **toks;
9796 int num_toks;
9797
9798 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Variable\n"););
9799
9800 toks = mSplit(args, " \t", 0, &num_toks, 0);
9801 if (num_toks != 2)
9802 {
9803 ParseError("Missing argument to %s", toks[0]);
9804 }
9805
9806 /* Check command line variables to see if this has already
9807 * been defined */
9808 if (cmd_line_var_list != NULL)
9809 {
9810 VarNode *tmp = cmd_line_var_list;
9811
9812 while (tmp != NULL)
9813 {
9814 // Already defined this via command line
9815 if (strcasecmp(toks[0], tmp->name) == 0)
9816 {
9817 mSplitFree(&toks, num_toks);
9818 return;
9819 }
9820
9821 tmp = tmp->next;
9822 }
9823 }
9824
9825 AddVarToTable(sc, toks[0], toks[1]);
9826 mSplitFree(&toks, num_toks);
9827 }
9828
ParseFile(SnortConfig * sc,SnortPolicy * p,char * args)9829 static void ParseFile(SnortConfig *sc, SnortPolicy *p, char *args)
9830 {
9831 if (!sc->file_config)
9832 sc->file_config = file_service_config_create();
9833 file_rule_parse(args, sc->file_config);
9834 }
9835
AddVarToTable(SnortConfig * sc,char * name,char * value)9836 static void AddVarToTable(SnortConfig *sc, char *name, char *value)
9837 {
9838 //TODO: snort.cfg and rules should use PortVar instead ...this allows compatability for now.
9839 if (strstr(name, "_PORT") || strstr(name, "PORT_"))
9840 {
9841 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"PortVar\n"););
9842 PortVarDefine(sc, name, value);
9843 }
9844 else
9845 {
9846 VarDefine(sc, name, value);
9847 }
9848 }
9849
ParseThreshFilter(SnortConfig * sc,SnortPolicy * p,char * args,const char * ERR_KEY)9850 static void ParseThreshFilter(
9851 SnortConfig *sc, SnortPolicy *p, char *args, const char* ERR_KEY
9852 ) {
9853 char **toks;
9854 int num_toks;
9855 int count_flag = 0;
9856 int seconds_flag = 0;
9857 int type_flag = 0;
9858 int tracking_flag = 0;
9859 int genid_flag = 0;
9860 int sigid_flag = 0;
9861 int i;
9862 THDX_STRUCT thdx;
9863
9864 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Event Filter\n"););
9865
9866 memset(&thdx, 0, sizeof(THDX_STRUCT));
9867
9868 toks = mSplit(args, ",", 0, &num_toks, 0); /* get rule option pairs */
9869
9870 for (i = 0; i < num_toks; i++)
9871 {
9872 char **pairs;
9873 int num_pairs;
9874
9875 pairs = mSplit(toks[i], " \t", 0, &num_pairs, 0); /* get rule option pairs */
9876
9877 if (num_pairs != 2)
9878 {
9879 ParseError(ERR_NOT_PAIRED);
9880 }
9881
9882 if (strcasecmp(pairs[0], THRESHOLD_OPT__COUNT) == 0)
9883 {
9884 if ( count_flag++ )
9885 {
9886 ParseError(ERR_EXTRA_OPTION);
9887 }
9888
9889 thdx.count = xatol(pairs[1],"event_filter: count");
9890
9891 if ((thdx.count < 1) && (thdx.count != THD_NO_THRESHOLD))
9892 {
9893 ParseError("event_filter: count must be > 0 or %d\n",
9894 THD_NO_THRESHOLD);
9895 }
9896 }
9897 else if (strcasecmp(pairs[0], THRESHOLD_OPT__SECONDS) == 0)
9898 {
9899 if ( seconds_flag++ )
9900 {
9901 ParseError(ERR_EXTRA_OPTION);
9902 }
9903
9904 thdx.seconds = xatoup(pairs[1],"event_filter: seconds");
9905 }
9906 else if (strcasecmp(pairs[0], THRESHOLD_OPT__TYPE) == 0)
9907 {
9908 if ( type_flag++ )
9909 {
9910 ParseError(ERR_EXTRA_OPTION);
9911 }
9912
9913 if (strcasecmp(pairs[1], THRESHOLD_TYPE__LIMIT) == 0)
9914 {
9915 thdx.type = THD_TYPE_LIMIT;
9916 }
9917 else if (strcasecmp(pairs[1], THRESHOLD_TYPE__THRESHOLD) == 0)
9918 {
9919 thdx.type = THD_TYPE_THRESHOLD;
9920 }
9921 else if (strcasecmp(pairs[1], THRESHOLD_TYPE__BOTH) == 0)
9922 {
9923 thdx.type = THD_TYPE_BOTH;
9924 }
9925 else
9926 {
9927 ParseError(ERR_BAD_VALUE);
9928 }
9929 }
9930 else if (strcasecmp(pairs[0], THRESHOLD_OPT__TRACK) == 0)
9931 {
9932 if ( tracking_flag++ )
9933 {
9934 ParseError(ERR_EXTRA_OPTION);
9935 }
9936
9937 if (strcasecmp(pairs[1], THRESHOLD_TRACK__BY_SRC) == 0)
9938 {
9939 thdx.tracking = THD_TRK_SRC;
9940 }
9941 else if (strcasecmp(pairs[1], THRESHOLD_TRACK__BY_DST) == 0)
9942 {
9943 thdx.tracking = THD_TRK_DST;
9944 }
9945 else
9946 {
9947 ParseError(ERR_BAD_VALUE);
9948 }
9949 }
9950 else if (strcasecmp(pairs[0], THRESHOLD_OPT__GID) == 0)
9951 {
9952 if ( genid_flag++ )
9953 {
9954 ParseError(ERR_EXTRA_OPTION);
9955 }
9956
9957 thdx.gen_id = xatou(pairs[1], "event_filter: gen_id");
9958 }
9959 else if (strcasecmp(pairs[0], THRESHOLD_OPT__SID) == 0)
9960 {
9961 if ( sigid_flag++ )
9962 {
9963 ParseError(ERR_EXTRA_OPTION);
9964 }
9965
9966 thdx.sig_id = xatou(pairs[1], "event_filter: sig_id");
9967 }
9968 else
9969 {
9970 ParseError(ERR_BAD_OPTION);
9971 }
9972
9973 mSplitFree(&pairs, num_pairs);
9974 }
9975
9976 if ((count_flag + tracking_flag + type_flag + seconds_flag + genid_flag
9977 + sigid_flag) != 6)
9978 {
9979 ParseError(ERR_BAD_ARG_COUNT);
9980 }
9981
9982 if (sfthreshold_create(sc, sc->threshold_config, &thdx))
9983 {
9984 if (thdx.sig_id == 0)
9985 {
9986 ParseError(ERR_CREATE_EX, "only one per gen_id != 0");
9987 }
9988 else if (thdx.gen_id == 0)
9989 {
9990 ParseError(ERR_CREATE_EX, "gen_id = 0 requires sig_id = 0");
9991 }
9992 else
9993 {
9994 ParseError(ERR_CREATE_EX, "gen_id, sig_id must be unique");
9995 }
9996 }
9997
9998 mSplitFree(&toks, num_toks);
9999 }
10000
10001 /*
10002 threshold gen_id #, sig_id #, type limit|threshold|both, \
10003 track by_src|by_dst, count #, seconds #
10004 */
ParseThreshold(SnortConfig * sc,SnortPolicy * p,char * args)10005 static void ParseThreshold(SnortConfig *sc, SnortPolicy *p, char *args)
10006 {
10007 static int warned = 0;
10008
10009 if (!warned)
10010 {
10011 ParseWarning("threshold (standalone) is deprecated; "
10012 "use event_filter instead.\n");
10013 warned = 1;
10014 }
10015
10016 ParseThreshFilter(sc, p, args, "standalone threshold");
10017 }
10018
ParseEventFilter(SnortConfig * sc,SnortPolicy * p,char * args)10019 static void ParseEventFilter(SnortConfig *sc, SnortPolicy *p, char *args)
10020 {
10021 ParseThreshFilter(sc, p, args, "event_filter");
10022 }
10023
10024 /*
10025 suppress gen_id #, sig_id #, track by_src|by_dst, ip cidr'
10026 */
ParseSuppress(SnortConfig * sc,SnortPolicy * p,char * args)10027 static void ParseSuppress(SnortConfig *sc, SnortPolicy *p, char *args)
10028 {
10029 char **toks;
10030 int num_toks;
10031 int tracking_flag = 0;
10032 int genid_flag = 0;
10033 int sigid_flag = 0;
10034 int ip_flag = 0;
10035 int i;
10036 THDX_STRUCT thdx;
10037 const char* ERR_KEY = "suppress";
10038
10039 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Suppress\n"););
10040
10041 memset(&thdx, 0, sizeof(THDX_STRUCT));
10042
10043 thdx.type = THD_TYPE_SUPPRESS;
10044 thdx.priority = THD_PRIORITY_SUPPRESS;
10045 thdx.tracking = THD_TRK_NONE;
10046
10047 /* Potential IP list might be present so we can't split on commas
10048 * Change commas to semi-colons */
10049 args = FixSeparators(args, ';', "suppress");
10050 toks = mSplit(args, ";", 0, &num_toks, 0); /* get rule option pairs */
10051
10052 for (i = 0; i < num_toks; i++)
10053 {
10054 char **pairs;
10055 int num_pairs;
10056
10057 pairs = mSplit(toks[i], " \t", 2, &num_pairs, 0); /* get rule option pairs */
10058
10059 if (num_pairs != 2)
10060 {
10061 ParseError(ERR_NOT_PAIRED);
10062 }
10063
10064 if (strcasecmp(pairs[0], THRESHOLD_OPT__TRACK) == 0)
10065 {
10066 if ( tracking_flag++ )
10067 {
10068 ParseError(ERR_EXTRA_OPTION);
10069 }
10070
10071 if (strcasecmp(pairs[1], THRESHOLD_TRACK__BY_SRC) == 0)
10072 {
10073 thdx.tracking = THD_TRK_SRC;
10074 }
10075 else if (strcasecmp(pairs[1], THRESHOLD_TRACK__BY_DST) == 0)
10076 {
10077 thdx.tracking = THD_TRK_DST;
10078 }
10079 else
10080 {
10081 ParseError(ERR_BAD_VALUE);
10082 }
10083 }
10084 else if (strcasecmp(pairs[0], THRESHOLD_OPT__GID) == 0)
10085 {
10086 if ( genid_flag++ )
10087 {
10088 ParseError(ERR_EXTRA_OPTION);
10089 }
10090
10091 thdx.gen_id = xatou(pairs[1], "suppress: gen_id");
10092 }
10093 else if (strcasecmp(pairs[0], THRESHOLD_OPT__SID) == 0)
10094 {
10095 if ( sigid_flag++ )
10096 {
10097 ParseError(ERR_EXTRA_OPTION);
10098 }
10099
10100 thdx.sig_id = xatou(pairs[1], "suppress: sig_id");
10101 }
10102 else if (strcasecmp(pairs[0], THRESHOLD_OPT__IP) == 0)
10103 {
10104 if ( ip_flag++ )
10105 {
10106 ParseError(ERR_EXTRA_OPTION);
10107 }
10108
10109 thdx.ip_address = IpAddrSetParse(sc, pairs[1]);
10110 }
10111 else
10112 {
10113 ParseError(ERR_BAD_OPTION);
10114 }
10115
10116 mSplitFree(&pairs, num_pairs);
10117 }
10118
10119 if (((genid_flag + sigid_flag) != 2) ||
10120 (((tracking_flag + ip_flag) != 0) && ((tracking_flag + ip_flag) != 2)))
10121 {
10122 ParseError(ERR_BAD_ARG_COUNT);
10123 }
10124
10125 if (sfthreshold_create(sc, sc->threshold_config, &thdx))
10126 {
10127 ParseError(ERR_CREATE);
10128 }
10129
10130 mSplitFree(&toks, num_toks);
10131 }
10132
ParseOtnClassType(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10133 static void ParseOtnClassType(SnortConfig *sc, RuleTreeNode *rtn,
10134 OptTreeNode *otn, RuleType rtype, char *args)
10135 {
10136 ClassType *class_type;
10137
10138 if (args == NULL)
10139 {
10140 ParseWarning("ClassType without an argument!");
10141 return;
10142 }
10143
10144 class_type = ClassTypeLookupByType(sc, args);
10145 if (class_type == NULL)
10146 ParseError("Unknown ClassType: %s", args);
10147
10148 otn->sigInfo.classType = class_type;
10149
10150 /* Add the class_id to class_id so we can reference it for all rules,
10151 * whether they have a class_id or not. */
10152 otn->sigInfo.class_id = class_type->id;
10153
10154 if (otn->sigInfo.priority == 0)
10155 otn->sigInfo.priority = class_type->priority;
10156
10157 /* XXX deprecated */
10158 otn->event_data.classification = class_type->id;
10159 if (otn->event_data.priority == 0)
10160 otn->event_data.priority = class_type->priority;
10161 }
10162
ParseOtnDetectionFilter(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10163 static void ParseOtnDetectionFilter(SnortConfig *sc, RuleTreeNode *rtn,
10164 OptTreeNode *otn, RuleType rtype, char *args)
10165 {
10166 int count_flag = 0;
10167 int seconds_flag = 0;
10168 int tracking_flag = 0;
10169 char **toks;
10170 int num_toks;
10171 int i;
10172 static THDX_STRUCT thdx;
10173 const char* ERR_KEY = "detection_filter";
10174
10175 memset(&thdx, 0, sizeof(THDX_STRUCT));
10176
10177 toks = mSplit(args, ",", 0, &num_toks, 0);
10178
10179 /* Parameter Check - enough args ?*/
10180 if (num_toks != 3)
10181 {
10182 ParseError(ERR_PAIR_COUNT, 3);
10183 }
10184
10185 for (i = 0; i < num_toks; i++)
10186 {
10187 char **pairs;
10188 int num_pairs;
10189
10190 pairs = mSplit(toks[i], " \t", 0, &num_pairs, 0);
10191 if (num_pairs != 2)
10192 {
10193 ParseError(ERR_NOT_PAIRED);
10194 }
10195
10196 if (strcasecmp(pairs[0], THRESHOLD_OPT__COUNT) == 0)
10197 {
10198 if ( count_flag++ )
10199 {
10200 ParseError(ERR_EXTRA_OPTION);
10201 }
10202
10203 thdx.count = xatoup(pairs[1],"detection_filter: count");
10204 }
10205 else if (strcasecmp(pairs[0], THRESHOLD_OPT__SECONDS) == 0)
10206 {
10207 if ( seconds_flag++ )
10208 {
10209 ParseError(ERR_EXTRA_OPTION);
10210 }
10211
10212 thdx.seconds = xatoup(pairs[1],"detection_filter: seconds");
10213 }
10214 else if (strcasecmp(pairs[0], THRESHOLD_OPT__TRACK) == 0)
10215 {
10216 if ( tracking_flag++ )
10217 {
10218 ParseError(ERR_EXTRA_OPTION);
10219 }
10220
10221 if (strcasecmp(pairs[1], THRESHOLD_TRACK__BY_SRC) == 0)
10222 {
10223 thdx.tracking = THD_TRK_SRC;
10224 }
10225 else if (strcasecmp(pairs[1], THRESHOLD_TRACK__BY_DST) == 0)
10226 {
10227 thdx.tracking = THD_TRK_DST;
10228 }
10229 else
10230 {
10231 ParseError(ERR_BAD_VALUE);
10232 }
10233 }
10234 else
10235 {
10236 ParseError(ERR_BAD_OPTION);
10237 }
10238
10239 mSplitFree(&pairs, num_pairs);
10240 }
10241
10242 if ((count_flag + tracking_flag + seconds_flag) != 3)
10243 {
10244 ParseError(ERR_BAD_ARG_COUNT);
10245 }
10246
10247 mSplitFree(&toks, num_toks);
10248
10249 thdx.type = THD_TYPE_DETECT;
10250
10251 otn->detection_filter =
10252 detection_filter_create(sc->detection_filter_config, &thdx);
10253 }
10254
ParseOtnGid(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10255 static void ParseOtnGid(SnortConfig *sc, RuleTreeNode *rtn,
10256 OptTreeNode *otn, RuleType rtype, char *args)
10257 {
10258 unsigned long int gid;
10259 char *endptr;
10260
10261 if (args == NULL)
10262 ParseError("Gid rule option requires an argument.");
10263
10264 gid = SnortStrtoul(args, &endptr, 0);
10265 if ((errno == ERANGE) || (*endptr != '\0'))
10266 {
10267 ParseError("Invalid argument to 'gid' rule option: %s. "
10268 "Must be a positive integer.", args);
10269 }
10270
10271 otn->sigInfo.generator = (uint32_t)gid;
10272 otn->event_data.sig_generator = (uint32_t)gid;
10273 }
10274
10275 /****************************************************************************
10276 * Function: ParseOtnLogTo()
10277 *
10278 * Purpose: stuff the special log filename onto the proper rule option
10279 *
10280 * Arguments:
10281 * OptTreeNode *
10282 * The otn for this rule option
10283 * RuleType
10284 * The rule type of the rule using this option
10285 * char *
10286 * The arguments to this rule option
10287 *
10288 * Returns: None
10289 *
10290 ***************************************************************************/
ParseOtnLogTo(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10291 static void ParseOtnLogTo(SnortConfig *sc, RuleTreeNode *rtn,
10292 OptTreeNode *otn, RuleType rtype, char *args)
10293 {
10294 char *sptr;
10295 char *eptr;
10296
10297 if (args == NULL)
10298 ParseError("'logto' requires a file name as an argument.");
10299
10300 /* grab everything between the starting " and the end one */
10301 sptr = strchr(args, '"');
10302 eptr = strrchr(args, '"');
10303
10304 if ((sptr != NULL) && (eptr != NULL))
10305 {
10306 /* increment past the first quote */
10307 sptr++;
10308
10309 /* zero out the second one */
10310 *eptr = 0;
10311 }
10312 else
10313 {
10314 sptr = args;
10315 }
10316
10317 /* alloc up a nice shiny clean buffer */
10318 otn->logto = SnortStrdup(sptr);
10319 }
10320
10321 /****************************************************************************
10322 * Function: ParseOtnMessage()
10323 *
10324 * Purpose: Stuff the alert message onto the rule
10325 *
10326 * Arguments:
10327 * OptTreeNode *
10328 * The otn for this rule option
10329 * RuleType
10330 * The rule type of the rule using this option
10331 * char *
10332 * The arguments to this rule option
10333 *
10334 * Returns: None
10335 *
10336 ***************************************************************************/
ParseOtnMessage(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10337 static void ParseOtnMessage(SnortConfig *sc, RuleTreeNode *rtn,
10338 OptTreeNode *otn, RuleType rtype, char *args)
10339 {
10340 size_t i;
10341 int escaped = 0;
10342 char msg_buf[2048]; /* Arbitrary length, but should be enough */
10343
10344 if (args == NULL)
10345 ParseError("Message rule option requires an argument.");
10346
10347 if (*args == '"')
10348 {
10349 /* Have to have at least quote, char, quote */
10350 if (strlen(args) < 3)
10351 ParseError("Empty argument passed to rule option 'msg'.");
10352
10353 if (args[strlen(args) - 1] != '"')
10354 {
10355 ParseError("Unmatch quote in rule option 'msg'.");
10356 }
10357
10358 /* Move past first quote and NULL terminate last quote */
10359 args++;
10360 args[strlen(args) - 1] = '\0';
10361
10362 /* If last quote is escaped, fatal error.
10363 * Make sure the backslash is not escaped */
10364 if ((args[strlen(args) - 1] == '\\') &&
10365 (strlen(args) > 1) && (args[strlen(args) - 2] != '\\'))
10366 {
10367 ParseError("Unmatch quote in rule option 'msg'.");
10368 }
10369 }
10370
10371 /* Only valid escaped chars are ';', '"' and '\' */
10372 /* Would be ok except emerging threats rules are escaping other chars */
10373 for (i = 0; (i < sizeof(msg_buf)) && (*args != '\0');)
10374 {
10375 if (escaped)
10376 {
10377 #if 0
10378 if ((*args != ';') && (*args != '"') && (*args != '\\'))
10379 {
10380 ParseError("Invalid escaped character in 'msg' rule "
10381 "option: '%c'. Valid characters to escape are "
10382 "';', '\"' and '\\'.\n", *args);
10383 }
10384 #endif
10385
10386 msg_buf[i++] = *args;
10387 escaped = 0;
10388 }
10389 else if (*args == '\\')
10390 {
10391 escaped = 1;
10392 }
10393 else
10394 {
10395 msg_buf[i++] = *args;
10396 }
10397
10398 args++;
10399 }
10400
10401 if (escaped)
10402 {
10403 ParseError("Message in 'msg' rule option has invalid escape character\n");
10404 }
10405
10406 if (i == sizeof(msg_buf))
10407 {
10408 ParseError("Message in 'msg' rule option too long. Please limit "
10409 "to %d characters.", sizeof(msg_buf));
10410 }
10411
10412 msg_buf[i] = '\0';
10413
10414 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Message: %s\n", msg_buf););
10415
10416 otn->sigInfo.message = SnortStrdup(msg_buf);
10417 }
10418
10419 /*
10420 * metadata may be key/value pairs or just keys
10421 *
10422 * metadata: key [=] value, key [=] value, key [=] value, key, key, ... ;
10423 *
10424 * This option may be used one or more times, with one or more key/value pairs.
10425 *
10426 * updated 8/28/06 - man
10427 *
10428 * keys:
10429 *
10430 * engine
10431 * rule-flushing
10432 * rule-type
10433 * soid
10434 * service
10435 */
ParseOtnMetadata(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10436 static void ParseOtnMetadata(SnortConfig *sc, RuleTreeNode *rtn,
10437 OptTreeNode *otn, RuleType rtype, char *args)
10438 {
10439 char **metadata_toks;
10440 int num_metadata_toks;
10441 int i;
10442
10443 char **key_value_toks = NULL;
10444 int num_key_value_toks = 0;
10445
10446
10447 if (args == NULL)
10448 ParseError("Metadata rule option requires an argument.");
10449
10450 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "metadata: %s\n", args););
10451
10452 metadata_toks = mSplit(args, ",", 100, &num_metadata_toks, 0);
10453
10454 for (i = 0; i < num_metadata_toks; i++)
10455 {
10456 char *key = NULL;
10457 char *value = NULL;
10458
10459 // After the first loop iteration, free the |key_value_toks|
10460 if (key_value_toks != NULL) {
10461 mSplitFree(&key_value_toks, num_key_value_toks);
10462 key_value_toks = NULL;
10463 num_key_value_toks = 0;
10464 }
10465
10466 key_value_toks = mSplit(metadata_toks[i], "= ", 2, &num_key_value_toks, 0);
10467
10468 key = key_value_toks[0];
10469 if (num_key_value_toks == 2)
10470 value = key_value_toks[1];
10471
10472 DEBUG_WRAP( DebugMessage(DEBUG_CONFIGRULES, "metadata: key=%s\n", key);
10473 if(value) DebugMessage(DEBUG_CONFIGRULES, " value=%s\n", value); );
10474
10475 /* process key/value pairs */
10476 if (strcasecmp(key, METADATA_KEY__ENGINE) == 0)
10477 {
10478 if (value == NULL)
10479 ParseError("Metadata key '%s' requires a value", key);
10480
10481 if (strcasecmp(value, METADATA_VALUE__SHARED) != 0)
10482 ParseError("Metadata key '%s', passed an invalid value '%s'.", key, value);
10483
10484 otn->sigInfo.shared = 1;
10485 }
10486 /* this should follow 'rule-type' since it changes rule_flusing defaults set by rule-type */
10487 else if (strcasecmp(key, METADATA_KEY__RULE_FLUSHING) == 0)
10488 {
10489 if (value == NULL)
10490 ParseError("Metadata key '%s' requires a value.", key);
10491
10492 if ((strcasecmp(value, METADATA_VALUE__ENABLED) == 0) ||
10493 (strcasecmp(value, METADATA_VALUE__ON) == 0))
10494 {
10495 otn->sigInfo.rule_flushing = SI_RULE_FLUSHING_ON;
10496 }
10497 else if ((strcasecmp(value, METADATA_VALUE__DISABLED) == 0) ||
10498 (strcasecmp(value, METADATA_VALUE__OFF) == 0))
10499 {
10500 otn->sigInfo.rule_flushing = SI_RULE_FLUSHING_OFF;
10501 }
10502 else
10503 {
10504 ParseError("Metadata key '%s', passed an invalid value '%s'.",
10505 key, value);
10506 }
10507 }
10508 else if (strcasecmp(key, METADATA_KEY__RULE_TYPE) == 0)
10509 {
10510 if (value == NULL)
10511 ParseError("Metadata key '%s' requires a value.", key);
10512
10513 if (strcasecmp(value, METADATA_VALUE__PREPROC) == 0)
10514 {
10515 otn->sigInfo.rule_type = SI_RULE_TYPE_PREPROC;
10516 otn->sigInfo.rule_flushing = SI_RULE_FLUSHING_OFF;
10517 }
10518 else if (strcasecmp(value, METADATA_VALUE__DECODE) == 0)
10519 {
10520 if ( otn->sigInfo.id >= DECODE_INDEX_MAX )
10521 {
10522 ParseError("Unknown 'sid' for rule-type decode.");
10523 }
10524 else
10525 {
10526 otn->sigInfo.rule_type = SI_RULE_TYPE_DECODE;
10527 otn->sigInfo.rule_flushing = SI_RULE_FLUSHING_OFF;
10528 }
10529 }
10530 else if (strcasecmp(value, METADATA_VALUE__DETECT) == 0)
10531 {
10532 otn->sigInfo.rule_type = SI_RULE_TYPE_DETECT;
10533 otn->sigInfo.rule_flushing = SI_RULE_FLUSHING_ON;
10534 }
10535 else
10536 {
10537 ParseError("Metadata key '%s', passed an invalid value '%s'.",
10538 key, value);
10539 }
10540 }
10541 else if (strcasecmp(key, METADATA_KEY__SOID) == 0)
10542 {
10543 char **toks;
10544 int num_toks;
10545 char *endptr;
10546 uint64_t long_val;
10547
10548 if (value == NULL)
10549 ParseError("Metadata key '%s' requires a value.", key);
10550
10551 /* value is a '|' separated pair of gid|sid representing the
10552 * GID/SID of the original rule. This is used when the rule
10553 * is duplicated rule by a user with different IP/port info.
10554 */
10555 toks = mSplit(value, "|", 2, &num_toks, 0);
10556 if (num_toks != 2)
10557 {
10558 ParseError("Metadata Key '%s' Invalid Value. Must be a pipe "
10559 "(|) separated pair.", key);
10560 }
10561
10562 long_val = SnortStrtoul(toks[0], &endptr, 10);
10563 if ((errno == ERANGE) || (*endptr != '\0') || (long_val > UINT32_MAX))
10564 ParseError("Bogus gid %s", toks[0]);
10565
10566 otn->sigInfo.otnKey.gid = (uint32_t)long_val;
10567
10568 long_val = SnortStrtoul(toks[1], &endptr, 10);
10569 if ((errno == ERANGE) || (*endptr != '\0') || (long_val > UINT32_MAX))
10570 ParseError("Bogus sid %s", toks[1]);
10571
10572 otn->sigInfo.otnKey.sid = (uint32_t)long_val;
10573
10574 mSplitFree(&toks, num_toks);
10575 }
10576 #ifdef TARGET_BASED
10577 /* track all of the rules for each service */
10578 else if (strcasecmp(key, METADATA_KEY__SERVICE) == 0 )
10579 {
10580 // metadata: service http, ... ;
10581 unsigned j, svc_count = otn->sigInfo.num_services;
10582 int16_t ordinal = 0;
10583 bool found = false;
10584
10585 if (value == NULL)
10586 {
10587 ParseError("Metadata key '%s' requires a value.", key);
10588 }
10589
10590 if (otn->sigInfo.num_services >= sc->max_metadata_services)
10591 {
10592 ParseError("Too many service's specified for rule.");
10593 }
10594
10595 if (otn->sigInfo.services == NULL)
10596 {
10597 otn->sigInfo.services = SnortAlloc(sizeof(ServiceInfo) * sc->max_metadata_services);
10598 }
10599
10600 // Service Override(s)
10601 if ( strcmp(value, "and-ports") == 0 )
10602 {
10603 if (otn->sigInfo.service_override != ServiceOverride_Nil)
10604 ParseWarning("Multiple service overrides specified: using '%s'", value);
10605
10606 otn->sigInfo.service_override = ServiceOverride_AndPorts;
10607 continue;
10608 }
10609 else if ( strcmp(value, "or-ports") == 0 )
10610 {
10611 if (otn->sigInfo.service_override != ServiceOverride_Nil)
10612 ParseWarning("Multiple service overrides specified: using '%s'", value);
10613
10614 otn->sigInfo.service_override = ServiceOverride_OrPorts;
10615 continue;
10616 }
10617 else if ( strcmp(value, "else-ports") == 0 )
10618 {
10619 if (otn->sigInfo.service_override != ServiceOverride_Nil)
10620 ParseWarning("Multiple service overrides specified: using '%s'", value);
10621
10622 otn->sigInfo.service_override = ServiceOverride_ElsePorts;
10623 continue;
10624 }
10625 else if ( strcmp(value, "unknown") == 0 )
10626 {
10627 if (otn->sigInfo.service_override != ServiceOverride_Nil)
10628 ParseWarning("Multiple service overrides specified: using '%s'", value);
10629
10630 // "Unknown" is a convenient synonym for "else-ports".
10631 // It emulates pre-Snort 2.9.8 behavior on "port-only" rules.
10632 otn->sigInfo.service_override = ServiceOverride_ElsePorts;
10633 continue;
10634 }
10635 else
10636 {
10637 ordinal = FindProtocolReference(value);
10638 if (ordinal == SFTARGET_UNKNOWN_PROTOCOL)
10639 ordinal = AddProtocolReference(value);
10640 }
10641
10642 for ( j = 0; j < svc_count; j++ )
10643 {
10644 if (otn->sigInfo.services[j].service_ordinal == ordinal)
10645 {
10646 ParseWarning("Duplicate service metadata \"%s\" found.", value);
10647 found = true;
10648 break;
10649 }
10650 }
10651
10652 if ( !found )
10653 {
10654 otn->sigInfo.services[svc_count].service = SnortStrdup(value);
10655 otn->sigInfo.services[svc_count].service_ordinal = ordinal;
10656 otn->sigInfo.num_services++;
10657 }
10658 }
10659 #endif // TARGET_BASED
10660 }
10661
10662 mSplitFree(&key_value_toks, num_key_value_toks);
10663 mSplitFree(&metadata_toks, num_metadata_toks);
10664 }
10665
ParseOtnPriority(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10666 static void ParseOtnPriority(SnortConfig *sc, RuleTreeNode *rtn,
10667 OptTreeNode *otn, RuleType rtype, char *args)
10668 {
10669 unsigned long int priority;
10670 char *endptr;
10671
10672 if (args == NULL)
10673 ParseError("Priority rule option requires an argument.");
10674
10675 priority = SnortStrtoul(args, &endptr, 0);
10676 if ((errno == ERANGE) || (*endptr != '\0'))
10677 {
10678 ParseError("Invalid argument to 'gid' rule option: %s. "
10679 "Must be a positive integer.", args);
10680 }
10681
10682 otn->sigInfo.priority = (uint32_t)priority;
10683 /* deprecated */
10684 otn->event_data.priority = (uint32_t)priority;
10685 }
10686
ParseOtnReference(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10687 static void ParseOtnReference(SnortConfig *sc, RuleTreeNode *rtn,
10688 OptTreeNode *otn, RuleType rtype, char *args)
10689 {
10690 char **toks;
10691 int num_toks;
10692
10693 if (args == NULL)
10694 ParseError("Reference rule option requires an argument.");
10695
10696 /* 2 tokens: system, id */
10697 toks = mSplit(args, ",", 2, &num_toks, 0);
10698 if (num_toks != 2)
10699 {
10700 ParseWarning("Ignoring invalid Reference spec '%s'.", args);
10701 mSplitFree(&toks, num_toks);
10702 return;
10703 }
10704
10705 AddReference(sc, &otn->sigInfo.refs, toks[0], toks[1]);
10706
10707 mSplitFree(&toks, num_toks);
10708 }
10709
ParseOtnRevision(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10710 static void ParseOtnRevision(SnortConfig *sc, RuleTreeNode *rtn,
10711 OptTreeNode *otn, RuleType rtype, char *args)
10712 {
10713 unsigned long int rev;
10714 char *endptr;
10715
10716 if (args == NULL)
10717 ParseError("Revision rule option requires an argument.");
10718
10719 rev = SnortStrtoul(args, &endptr, 0);
10720 if ((errno == ERANGE) || (*endptr != '\0'))
10721 {
10722 ParseError("Invalid argument to 'rev' rule option: %s. "
10723 "Must be a positive integer.", args);
10724 }
10725
10726 otn->sigInfo.rev = (uint32_t)rev;
10727 /* deprecated */
10728 otn->event_data.sig_rev = (uint32_t)rev;
10729 }
10730
ParseOtnSid(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10731 static void ParseOtnSid(SnortConfig *sc, RuleTreeNode *rtn,
10732 OptTreeNode *otn, RuleType rtype, char *args)
10733 {
10734 unsigned long int sid;
10735 char *endptr;
10736
10737 if (args == NULL)
10738 ParseError("Revision rule option requires an argument.");
10739
10740 sid = SnortStrtoul(args, &endptr, 0);
10741 if ((errno == ERANGE) || (*endptr != '\0'))
10742 {
10743 ParseError("Invalid argument to 'sid' rule option: %s. "
10744 "Must be a positive integer.", args);
10745 }
10746
10747 otn->sigInfo.id = (uint32_t)sid;
10748 /* deprecated */
10749 otn->event_data.sig_id = (uint32_t)sid;
10750 }
10751
ParseOtnTag(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10752 static void ParseOtnTag(SnortConfig *sc, RuleTreeNode *rtn,
10753 OptTreeNode *otn, RuleType rtype, char *args)
10754 {
10755 int type = 0;
10756 int count = 0;
10757 int metric = 0;
10758 int packets = 0;
10759 int seconds = 0;
10760 int bytes = 0;
10761 int direction = 0;
10762 int i;
10763 char **toks;
10764 int num_toks;
10765 uint8_t got_count = 0;
10766
10767 if (otn->tag != NULL)
10768 ParseError("Can only use 'tag' rule option once per rule.");
10769
10770 DEBUG_WRAP(DebugMessage(DEBUG_RULES, "Parsing tag args: %s\n", args););
10771 toks = mSplit(args, " ,", 0, &num_toks, 0);
10772
10773 if (num_toks < 1)
10774 ParseError("Invalid tag arguments: %s", args);
10775
10776 if (strcasecmp(toks[0], TAG_OPT__SESSION) == 0)
10777 type = TAG_SESSION;
10778 else if (strcasecmp(toks[0], TAG_OPT__HOST) == 0)
10779 type = TAG_HOST;
10780 else
10781 ParseError("Invalid tag type: %s", toks[0]);
10782
10783 for (i = 1; i < num_toks; i++)
10784 {
10785 if (!got_count)
10786 {
10787 if (isdigit((int)toks[i][0]))
10788 {
10789 long int val;
10790 char *endptr;
10791
10792 val = SnortStrtol(toks[i], &endptr, 0);
10793 if ((errno == ERANGE) || (*endptr != '\0') ||
10794 (val < 0) || (val > INT32_MAX))
10795 {
10796 ParseError("Invalid argument to 'tag' rule option. "
10797 "Numbers must be between 0 and %d.", INT32_MAX);
10798 }
10799
10800 count = (int)val;
10801 got_count = 1;
10802 }
10803 else
10804 {
10805 /* Check for src/dst/exclusive */
10806 break;
10807 }
10808 }
10809 else
10810 {
10811 if (strcasecmp(toks[i], TAG_OPT__SECONDS) == 0)
10812 {
10813 if (metric & TAG_METRIC_SECONDS)
10814 ParseError("Can only configure seconds metric to tag rule option once");
10815 if (!count)
10816 ParseError("Tag seconds metric must have a positive count");
10817
10818 metric |= TAG_METRIC_SECONDS;
10819 seconds = count;
10820 }
10821 else if (strcasecmp(toks[i], TAG_OPT__PACKETS) == 0)
10822 {
10823 if (metric & (TAG_METRIC_PACKETS|TAG_METRIC_UNLIMITED))
10824 ParseError("Can only configure packets metric to tag rule option once");
10825 if (count)
10826 metric |= TAG_METRIC_PACKETS;
10827 else
10828 metric |= TAG_METRIC_UNLIMITED;
10829
10830 packets = count;
10831 }
10832 else if (strcasecmp(toks[i], TAG_OPT__BYTES) == 0)
10833 {
10834 if (metric & TAG_METRIC_BYTES)
10835 ParseError("Can only configure bytes metric to tag rule option once");
10836 if (!count)
10837 ParseError("Tag bytes metric must have a positive count");
10838
10839 metric |= TAG_METRIC_BYTES;
10840 bytes = count;
10841 }
10842 else
10843 {
10844 ParseError("Invalid tag metric: %s", toks[i]);
10845 }
10846 got_count = 0;
10847 }
10848 }
10849
10850 if ( got_count )
10851 ParseError("Invalid tag rule option: %s", args);
10852
10853 if ((metric & TAG_METRIC_UNLIMITED) &&
10854 !(metric & (TAG_METRIC_BYTES|TAG_METRIC_SECONDS)))
10855 {
10856 ParseError("Invalid Tag options. 'packets' parameter '0' but "
10857 "neither seconds or bytes specified: %s", args);
10858 }
10859
10860 if (i < num_toks)
10861 {
10862 if (type == TAG_HOST)
10863 {
10864 if (strcasecmp(toks[i], TAG_OPT__SRC) == 0)
10865 direction = TAG_HOST_SRC;
10866 else if (strcasecmp(toks[i], TAG_OPT__DST) == 0)
10867 direction = TAG_HOST_DST;
10868 else
10869 ParseError("Invalid 'tag:host' option: %s.", toks[i]);
10870 }
10871 else
10872 {
10873 if (strcasecmp(toks[i], TAG_OPT__EXCLUSIVE) == 0)
10874 metric |= TAG_METRIC_SESSION;
10875 else
10876 ParseError("Invalid 'tag:session' option: %s.", toks[i]);
10877 }
10878 i++;
10879 }
10880 else if (type == TAG_HOST)
10881 {
10882 ParseError("Tag host type must specify direction");
10883 }
10884
10885 if ( !metric || (i != num_toks) )
10886 ParseError("Invalid 'tag' option: %s.", args);
10887
10888 mSplitFree(&toks, num_toks);
10889
10890 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Set type: %d metric: %x count: %d\n", type,
10891 metric, count););
10892
10893 otn->tag = (TagData *)SnortAlloc(sizeof(TagData));
10894
10895 otn->tag->tag_type = type;
10896 otn->tag->tag_metric = metric;
10897 otn->tag->tag_seconds = seconds;
10898 otn->tag->tag_bytes = bytes;
10899 otn->tag->tag_packets = packets;
10900 otn->tag->tag_direction = direction;
10901 }
10902
10903 /*
10904 Parse Threshold Rule option parameters for each RULE
10905
10906 'threshold: type limit|threshold|both, track by_src|by_dst, count #, seconds #;'
10907 */
ParseOtnThreshold(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10908 static void ParseOtnThreshold(SnortConfig *sc, RuleTreeNode *rtn,
10909 OptTreeNode *otn, RuleType rtype, char *args)
10910 {
10911 int count_flag = 0;
10912 int seconds_flag = 0;
10913 int type_flag = 0;
10914 int tracking_flag = 0;
10915 char **toks;
10916 int num_toks;
10917 static THDX_STRUCT thdx;
10918 int i;
10919 static int warned = 0;
10920 const char* ERR_KEY = "rule threshold";
10921
10922 if (args == NULL)
10923 ParseError("Threshold rule option requires an argument.");
10924
10925 if (!warned)
10926 {
10927 ParseWarning("threshold (in rule) is deprecated; "
10928 "use detection_filter instead.\n");
10929
10930 warned = 1;
10931 }
10932
10933 memset(&thdx, 0, sizeof(THDX_STRUCT));
10934
10935 /* Make this lower than standalone threshold command defaults ??? */
10936 thdx.priority = -1;
10937
10938 toks = mSplit(args, ",", 0, &num_toks, 0);
10939
10940 /* Parameter Check - enough args ?*/
10941 if (num_toks != 4)
10942 {
10943 ParseError(ERR_PAIR_COUNT, 4);
10944 }
10945
10946 for (i = 0; i < num_toks; i++)
10947 {
10948 char **pairs;
10949 int num_pairs;
10950
10951 pairs = mSplit(toks[i], " \t", 0, &num_pairs, 0);
10952 if (num_pairs != 2)
10953 {
10954 ParseError(ERR_NOT_PAIRED);
10955 }
10956
10957 if (strcasecmp(pairs[0], THRESHOLD_OPT__COUNT) == 0)
10958 {
10959 if ( count_flag++ )
10960 {
10961 ParseError(ERR_EXTRA_OPTION);
10962 }
10963
10964 thdx.count = xatoup(pairs[1],"threshold: count");
10965 }
10966 else if (strcasecmp(pairs[0], THRESHOLD_OPT__SECONDS) == 0)
10967 {
10968 if ( seconds_flag++ )
10969 {
10970 ParseError(ERR_EXTRA_OPTION);
10971 }
10972
10973 thdx.seconds = xatoup(pairs[1],"threshold: seconds");
10974 }
10975 else if (strcasecmp(pairs[0], THRESHOLD_OPT__TYPE) == 0)
10976 {
10977 if ( type_flag++ )
10978 {
10979 ParseError(ERR_EXTRA_OPTION);
10980 }
10981
10982 if (strcasecmp(pairs[1], THRESHOLD_TYPE__LIMIT) == 0)
10983 {
10984 thdx.type = THD_TYPE_LIMIT;
10985 }
10986 else if (strcasecmp(pairs[1], THRESHOLD_TYPE__THRESHOLD) == 0)
10987 {
10988 thdx.type = THD_TYPE_THRESHOLD;
10989 }
10990 else if (strcasecmp(pairs[1], THRESHOLD_TYPE__BOTH) == 0)
10991 {
10992 thdx.type = THD_TYPE_BOTH;
10993 }
10994 else
10995 {
10996 ParseError(ERR_BAD_VALUE);
10997 }
10998 }
10999 else if (strcasecmp(pairs[0], THRESHOLD_OPT__TRACK) == 0)
11000 {
11001 if ( tracking_flag++ )
11002 {
11003 ParseError(ERR_EXTRA_OPTION);
11004 }
11005
11006 if (strcasecmp(pairs[1], THRESHOLD_TRACK__BY_SRC) == 0)
11007 {
11008 thdx.tracking = THD_TRK_SRC;
11009 }
11010 else if (strcasecmp(pairs[1], THRESHOLD_TRACK__BY_DST) == 0)
11011 {
11012 thdx.tracking = THD_TRK_DST;
11013 }
11014 else
11015 {
11016 ParseError(ERR_BAD_VALUE);
11017 }
11018 }
11019 else
11020 {
11021 ParseError(ERR_BAD_OPTION);
11022 }
11023
11024 mSplitFree(&pairs, num_pairs);
11025 }
11026
11027 if ((count_flag + tracking_flag + type_flag + seconds_flag) != 4)
11028 {
11029 ParseError(ERR_BAD_ARG_COUNT);
11030 }
11031
11032 mSplitFree(&toks, num_toks);
11033
11034 /* Save this since we still need to add gid and sid */
11035 thdx_tmp = &thdx;
11036 }
11037
CreateDefaultRules(SnortConfig * sc)11038 static void CreateDefaultRules(SnortConfig *sc)
11039 {
11040 if (sc == NULL)
11041 return;
11042
11043 CreateRuleType(sc, RULE_LIST_TYPE__PASS, RULE_TYPE__PASS, 0, &sc->Pass); /* changed on Jan 06 */
11044 CreateRuleType(sc, RULE_LIST_TYPE__DROP, RULE_TYPE__DROP, 1, &sc->Drop);
11045 CreateRuleType(sc, RULE_LIST_TYPE__SDROP, RULE_TYPE__SDROP, 0, &sc->SDrop);
11046 CreateRuleType(sc, RULE_LIST_TYPE__REJECT, RULE_TYPE__REJECT, 1, &sc->Reject);
11047 CreateRuleType(sc, RULE_LIST_TYPE__ALERT, RULE_TYPE__ALERT, 1, &sc->Alert);
11048 CreateRuleType(sc, RULE_LIST_TYPE__LOG, RULE_TYPE__LOG, 1, &sc->Log);
11049 }
11050
GetRuleType(char * arg)11051 static RuleType GetRuleType(char *arg)
11052 {
11053 if (arg == NULL)
11054 return RULE_TYPE__NONE;
11055
11056 if (strcasecmp(arg, SNORT_CONF_KEYWORD__ALERT) == 0)
11057 return RULE_TYPE__ALERT;
11058 else if (strcasecmp(arg, SNORT_CONF_KEYWORD__DROP) == 0)
11059 return RULE_TYPE__DROP;
11060 else if (strcasecmp(arg, SNORT_CONF_KEYWORD__BLOCK) == 0)
11061 return RULE_TYPE__DROP;
11062 else if (strcasecmp(arg, SNORT_CONF_KEYWORD__LOG) == 0)
11063 return RULE_TYPE__LOG;
11064 else if (strcasecmp(arg, SNORT_CONF_KEYWORD__PASS) == 0)
11065 return RULE_TYPE__PASS;
11066 else if (strcasecmp(arg, SNORT_CONF_KEYWORD__REJECT) == 0)
11067 return RULE_TYPE__REJECT;
11068 else if (strcasecmp(arg, SNORT_CONF_KEYWORD__SDROP) == 0)
11069 return RULE_TYPE__SDROP;
11070 else if (strcasecmp(arg, SNORT_CONF_KEYWORD__SBLOCK) == 0)
11071 return RULE_TYPE__SDROP;
11072
11073 return RULE_TYPE__NONE;
11074 }
11075
FreeRuleTreeNodes(SnortConfig * sc)11076 static void FreeRuleTreeNodes(SnortConfig *sc)
11077 {
11078 RuleTreeNode *rtn;
11079 OptTreeNode *otn;
11080 tSfPolicyId policyId;
11081 SFGHASH_NODE *hashNode;
11082
11083 if (sc->otn_map == NULL)
11084 return;
11085
11086 for (hashNode = sfghash_findfirst(sc->otn_map);
11087 hashNode;
11088 hashNode = sfghash_findnext(sc->otn_map))
11089 {
11090 otn = (OptTreeNode *)hashNode->data;
11091
11092 /* Autogenerated OTNs along with their respective pseudo RTN
11093 * will get cleaned up when the OTN is free'd */
11094 if (otn->generated)
11095 continue;
11096
11097 for (policyId = 0;
11098 policyId < otn->proto_node_num;
11099 policyId++)
11100 {
11101 rtn = getRtnFromOtn(otn, policyId);
11102 DestroyRuleTreeNode(rtn);
11103
11104 otn->proto_nodes[policyId] = NULL;
11105 }
11106 }
11107 }
11108
FreeOutputLists(ListHead * list)11109 static void FreeOutputLists(ListHead *list)
11110 {
11111 if (list->AlertList != NULL)
11112 FreeOutputList(list->AlertList);
11113
11114 if (list->LogList != NULL)
11115 FreeOutputList(list->LogList);
11116 }
11117
FreeRuleLists(SnortConfig * sc)11118 void FreeRuleLists(SnortConfig *sc)
11119 {
11120 if (sc == NULL)
11121 return;
11122
11123 FreeRuleTreeNodes(sc);
11124
11125 FreeOutputLists(&sc->Drop);
11126 FreeOutputLists(&sc->SDrop);
11127 FreeOutputLists(&sc->Reject);
11128 FreeOutputLists(&sc->Alert);
11129 FreeOutputLists(&sc->Log);
11130 FreeOutputLists(&sc->Pass);
11131 FreeOutputLists(&sc->Activation);
11132 FreeOutputLists(&sc->Dynamic);
11133
11134 /* Iterate through the user-defined types */
11135 if (sc->rule_lists != NULL)
11136 {
11137 RuleListNode *node = sc->rule_lists;
11138
11139 while (node != NULL)
11140 {
11141 RuleListNode *tmp = node;
11142
11143 node = node->next;
11144
11145 if ((tmp->RuleList != &sc->Drop) &&
11146 (tmp->RuleList != &sc->SDrop) &&
11147 (tmp->RuleList != &sc->Reject) &&
11148 (tmp->RuleList != &sc->Alert) &&
11149 (tmp->RuleList != &sc->Log) &&
11150 (tmp->RuleList != &sc->Pass) &&
11151 (tmp->RuleList != &sc->Activation) &&
11152 (tmp->RuleList != &sc->Dynamic))
11153 {
11154 FreeOutputLists(tmp->RuleList);
11155 free(tmp->RuleList);
11156 }
11157
11158 if (tmp->name)
11159 free(tmp->name);
11160
11161 free(tmp);
11162 }
11163
11164 sc->rule_lists = NULL;
11165 }
11166 }
11167
port_entry_free(port_entry_t * pentry)11168 static void port_entry_free(port_entry_t *pentry)
11169 {
11170 if (pentry->src_port != NULL)
11171 {
11172 free(pentry->src_port);
11173 pentry->src_port = NULL;
11174 }
11175
11176 if (pentry->dst_port != NULL)
11177 {
11178 free(pentry->dst_port);
11179 pentry->dst_port = NULL;
11180 }
11181
11182 if (pentry->protocol != NULL)
11183 {
11184 free(pentry->protocol);
11185 pentry->protocol = NULL;
11186 }
11187 }
11188
port_list_add_entry(port_list_t * plist,port_entry_t * pentry)11189 static int port_list_add_entry( port_list_t * plist, port_entry_t * pentry)
11190 {
11191 int ret;
11192
11193 if( !plist )
11194 {
11195 port_entry_free(pentry);
11196 return -1;
11197 }
11198
11199 if( plist->pl_cnt >= plist->pl_max )
11200 {
11201 port_entry_free(pentry);
11202 return -1;
11203 }
11204
11205 ret = SafeMemcpy( &plist->pl_array[plist->pl_cnt], pentry, sizeof(port_entry_t),
11206 &plist->pl_array[plist->pl_cnt],
11207 (char*)(&plist->pl_array[plist->pl_cnt]) + sizeof(port_entry_t));
11208 if (ret != SAFEMEM_SUCCESS)
11209 {
11210 ParseError("%s SafeMemcpy() Failed !!!", __FUNCTION__);
11211 return -1;
11212 }
11213
11214 plist->pl_cnt++;
11215
11216 return 0;
11217 }
11218
11219 #if 0
11220 static port_entry_t * port_list_get( port_list_t * plist, int index)
11221 {
11222 if( index < plist->pl_max )
11223 {
11224 return &plist->pl_array[index];
11225 }
11226 return NULL;
11227 }
11228
11229 static void port_list_print( port_list_t * plist)
11230 {
11231 int i;
11232 for(i=0;i<plist->pl_cnt;i++)
11233 {
11234 LogMessage("rule %d { ", i);
11235 LogMessage(" gid %u sid %u",plist->pl_array[i].gid,plist->pl_array[i].sid );
11236 LogMessage(" protocol %s", plist->pl_array[i].protocol);
11237 LogMessage(" dir %d",plist->pl_array[i].dir);
11238 LogMessage(" src_port %s dst_port %s ",
11239 plist->pl_array[i].src_port,
11240 plist->pl_array[i].dst_port );
11241 LogMessage(" content %d",
11242 plist->pl_array[i].content);
11243 LogMessage(" uricontent %d",
11244 plist->pl_array[i].uricontent);
11245 LogMessage(" }\n");
11246 }
11247 }
11248 #endif
11249
port_list_free(port_list_t * plist)11250 static void port_list_free( port_list_t * plist)
11251 {
11252 int i;
11253 for(i=0;i<plist->pl_cnt;i++)
11254 {
11255 port_entry_free(&plist->pl_array[i]);
11256 }
11257 plist->pl_cnt = 0;
11258 }
11259
11260 /* Finish processing/setup Port Tables */
finish_portlist_table(FastPatternConfig * fp,char * s,PortTable * pt)11261 static void finish_portlist_table(FastPatternConfig *fp, char *s, PortTable *pt)
11262 {
11263 PortTableSortUniqRules(pt);
11264
11265 if( fpDetectGetDebugPrintRuleGroupsUnCompiled(fp) )
11266 {
11267 LogMessage("***\n***Port-Table : %s Ports/Rules-UnCompiled\n",s);
11268 PortTablePrintInputEx( pt, rule_index_map_print_index );
11269 }
11270
11271 PortTableCompile( pt );
11272
11273 if( fpDetectGetDebugPrintRuleGroupsCompiled(fp) )
11274 {
11275 LogMessage("***\n***Port-Table : %s Ports/Rules-Compiled\n",s);
11276 PortTablePrintCompiledEx( pt, rule_index_map_print_index );
11277 LogMessage("*** End of Compiled Group\n");
11278 }
11279 }
11280
rule_index_map_print_index(int index,char * buf,int bufsize)11281 void rule_index_map_print_index( int index, char *buf, int bufsize )
11282 {
11283 if( index < ruleIndexMap->num_rules )
11284 {
11285 SnortSnprintfAppend(buf, bufsize, "%u:%u ",
11286 ruleIndexMap->map[index].gid,
11287 ruleIndexMap->map[index].sid);
11288 }
11289 }
11290
PortTablesNew(void)11291 static rule_port_tables_t * PortTablesNew(void)
11292 {
11293 rule_port_tables_t *rpt =
11294 (rule_port_tables_t *)SnortAlloc(sizeof(rule_port_tables_t));
11295
11296 /* No content rule objects */
11297 rpt->tcp_nocontent = PortObjectNew();
11298 if (rpt->tcp_nocontent == NULL)
11299 ParseError("ParseRulesFile nocontent PortObjectNew() failed");
11300 PortObjectAddPortAny(rpt->tcp_nocontent);
11301
11302 rpt->udp_nocontent = PortObjectNew();
11303 if (rpt->udp_nocontent == NULL)
11304 ParseError("ParseRulesFile nocontent PortObjectNew() failed");
11305 PortObjectAddPortAny(rpt->udp_nocontent);
11306
11307 rpt->icmp_nocontent = PortObjectNew();
11308 if (rpt->icmp_nocontent == NULL)
11309 ParseError("ParseRulesFile nocontent PortObjectNew() failed");
11310 PortObjectAddPortAny(rpt->icmp_nocontent);
11311
11312 rpt->ip_nocontent = PortObjectNew();
11313 if (rpt->ip_nocontent == NULL)
11314 ParseError("ParseRulesFile nocontent PortObjectNew() failed");
11315 PortObjectAddPortAny(rpt->ip_nocontent);
11316
11317 /* Create the Any-Any Port Objects for each protocol */
11318 rpt->tcp_anyany = PortObjectNew();
11319 if (rpt->tcp_anyany == NULL)
11320 ParseError("ParseRulesFile tcp any-any PortObjectNew() failed");
11321 PortObjectAddPortAny(rpt->tcp_anyany);
11322
11323 rpt->udp_anyany = PortObjectNew();
11324 if (rpt->udp_anyany == NULL)
11325 ParseError("ParseRulesFile udp any-any PortObjectNew() failed");
11326 PortObjectAddPortAny(rpt->udp_anyany);
11327
11328 rpt->icmp_anyany = PortObjectNew();
11329 if (rpt->icmp_anyany == NULL)
11330 ParseError("ParseRulesFile icmp any-any PortObjectNew() failed");
11331 PortObjectAddPortAny(rpt->icmp_anyany);
11332
11333 rpt->ip_anyany = PortObjectNew();
11334 if (rpt->ip_anyany == NULL)
11335 ParseError("ParseRulesFile ip PortObjectNew() failed");
11336 PortObjectAddPortAny(rpt->ip_anyany);
11337
11338 /* Create the tcp Rules PortTables */
11339 rpt->tcp_src = PortTableNew();
11340 if (rpt->tcp_src == NULL)
11341 ParseError("ParseRulesFile tcp-src PortTableNew() failed");
11342
11343 rpt->tcp_dst = PortTableNew();
11344 if (rpt->tcp_dst == NULL)
11345 ParseError("ParseRulesFile tcp-dst PortTableNew() failed");
11346
11347 /* Create the udp Rules PortTables */
11348 rpt->udp_src = PortTableNew();
11349 if (rpt->udp_src == NULL)
11350 ParseError("ParseRulesFile udp-src PortTableNew() failed");
11351
11352 rpt->udp_dst = PortTableNew();
11353 if (rpt->udp_dst == NULL)
11354 ParseError("ParseRulesFile udp-dst PortTableNew() failed");
11355
11356 /* Create the icmp Rules PortTables */
11357 rpt->icmp_src = PortTableNew();
11358 if (rpt->icmp_src == NULL)
11359 ParseError("ParseRulesFile icmp-src PortTableNew() failed");
11360
11361 rpt->icmp_dst = PortTableNew();
11362 if (rpt->icmp_dst == NULL)
11363 ParseError("ParseRulesFile icmp-dst PortTableNew() failed");
11364
11365 /* Create the ip Rules PortTables */
11366 rpt->ip_src = PortTableNew();
11367 if (rpt->ip_src == NULL)
11368 ParseError("ParseRulesFile ip-src PortTableNew() failed");
11369
11370 rpt->ip_dst = PortTableNew();
11371 if (rpt->ip_dst == NULL)
11372 ParseError("ParseRulesFile ip-dst PortTableNew() failed");
11373
11374 /*
11375 * someday these could be read from snort.conf, something like...
11376 * 'config portlist: large-rule-count <val>'
11377 */
11378 rpt->tcp_src->pt_lrc = DEFAULT_LARGE_RULE_GROUP;
11379 rpt->tcp_dst->pt_lrc = DEFAULT_LARGE_RULE_GROUP;
11380 rpt->udp_src->pt_lrc = DEFAULT_LARGE_RULE_GROUP;
11381 rpt->udp_dst->pt_lrc = DEFAULT_LARGE_RULE_GROUP;
11382 rpt->icmp_src->pt_lrc= DEFAULT_LARGE_RULE_GROUP;
11383 rpt->icmp_dst->pt_lrc= DEFAULT_LARGE_RULE_GROUP;
11384 rpt->ip_src->pt_lrc = DEFAULT_LARGE_RULE_GROUP;
11385 rpt->ip_dst->pt_lrc = DEFAULT_LARGE_RULE_GROUP;
11386
11387 #ifdef TARGET_BASED
11388 // if TARGET_BASED is not enabled, ensure that these
11389 // port tables are NULL.
11390 rpt->ns_tcp_src = NULL;
11391 rpt->ns_tcp_dst = NULL;
11392 rpt->ns_udp_src = NULL;
11393 rpt->ns_udp_dst = NULL;
11394 rpt->ns_icmp_src = NULL;
11395 rpt->ns_icmp_dst = NULL;
11396 rpt->ns_ip_src = NULL;
11397 rpt->ns_ip_dst = NULL;
11398 #endif
11399
11400 #ifdef TARGET_BASED
11401 // Create NOSERVICE port tables
11402 rpt->ns_tcp_src = PortTableNew();
11403 if (rpt->ns_tcp_src == NULL)
11404 ParseError("ParseRulesFile tcp-src PortTableNew() failed");
11405
11406 rpt->ns_tcp_dst = PortTableNew();
11407 if (rpt->ns_tcp_dst == NULL)
11408 ParseError("ParseRulesFile tcp-dst PortTableNew() failed");
11409
11410 /* Create the udp Rules PortTables */
11411 rpt->ns_udp_src = PortTableNew();
11412 if (rpt->ns_udp_src == NULL)
11413 ParseError("ParseRulesFile udp-src PortTableNew() failed");
11414
11415 rpt->ns_udp_dst = PortTableNew();
11416 if (rpt->ns_udp_dst == NULL)
11417 ParseError("ParseRulesFile udp-dst PortTableNew() failed");
11418
11419 /* Create the icmp Rules PortTables */
11420 rpt->ns_icmp_src = PortTableNew();
11421 if (rpt->ns_icmp_src == NULL)
11422 ParseError("ParseRulesFile icmp-src PortTableNew() failed");
11423
11424 rpt->ns_icmp_dst = PortTableNew();
11425 if (rpt->ns_icmp_dst == NULL)
11426 ParseError("ParseRulesFile icmp-dst PortTableNew() failed");
11427
11428 /* Create the ip Rules PortTables */
11429 rpt->ns_ip_src = PortTableNew();
11430 if (rpt->ns_ip_src == NULL)
11431 ParseError("ParseRulesFile ip-src PortTableNew() failed");
11432
11433 rpt->ns_ip_dst = PortTableNew();
11434 if (rpt->ns_ip_dst == NULL)
11435 ParseError("ParseRulesFile ip-dst PortTableNew() failed");
11436
11437 rpt->ns_tcp_src->pt_lrc = DEFAULT_LARGE_RULE_GROUP;
11438 rpt->ns_tcp_dst->pt_lrc = DEFAULT_LARGE_RULE_GROUP;
11439 rpt->ns_udp_src->pt_lrc = DEFAULT_LARGE_RULE_GROUP;
11440 rpt->ns_udp_dst->pt_lrc = DEFAULT_LARGE_RULE_GROUP;
11441 rpt->ns_icmp_src->pt_lrc = DEFAULT_LARGE_RULE_GROUP;
11442 rpt->ns_icmp_dst->pt_lrc = DEFAULT_LARGE_RULE_GROUP;
11443 rpt->ns_ip_src->pt_lrc = DEFAULT_LARGE_RULE_GROUP;
11444 rpt->ns_ip_dst->pt_lrc = DEFAULT_LARGE_RULE_GROUP;
11445 #endif // TARGET_BASED
11446
11447 return rpt;
11448 }
11449
PortTablesFinish(rule_port_tables_t * port_tables,FastPatternConfig * fp)11450 static void PortTablesFinish(rule_port_tables_t *port_tables, FastPatternConfig *fp)
11451 {
11452 /* TCP-SRC */
11453 if (fpDetectGetDebugPrintRuleGroupsCompiled(fp))
11454 {
11455 LogMessage("*** TCP-Any-Any Port List\n");
11456 PortObjectPrintEx(port_tables->tcp_anyany,
11457 rule_index_map_print_index);
11458 }
11459
11460 finish_portlist_table(fp, "tcp src", port_tables->tcp_src);
11461 finish_portlist_table(fp, "tcp dst", port_tables->tcp_dst);
11462
11463 /* UDP-SRC */
11464 if (fpDetectGetDebugPrintRuleGroupsCompiled(fp))
11465 {
11466 LogMessage("*** UDP-Any-Any Port List\n");
11467 PortObjectPrintEx(port_tables->udp_anyany,
11468 rule_index_map_print_index);
11469 }
11470
11471 finish_portlist_table(fp, "udp src", port_tables->udp_src);
11472 finish_portlist_table(fp, "udp dst", port_tables->udp_dst);
11473
11474 /* ICMP-SRC */
11475 if (fpDetectGetDebugPrintRuleGroupsCompiled(fp))
11476 {
11477 LogMessage("*** ICMP-Any-Any Port List\n");
11478 PortObjectPrintEx(port_tables->icmp_anyany,
11479 rule_index_map_print_index);
11480 }
11481
11482 finish_portlist_table(fp, "icmp src", port_tables->icmp_src);
11483 finish_portlist_table(fp, "icmp dst", port_tables->icmp_dst);
11484
11485 /* IP-SRC */
11486 if (fpDetectGetDebugPrintRuleGroupsCompiled(fp))
11487 {
11488 LogMessage("IP-Any-Any Port List\n");
11489 PortObjectPrintEx(port_tables->ip_anyany,
11490 rule_index_map_print_index);
11491 }
11492
11493 finish_portlist_table(fp, "ip src", port_tables->ip_src);
11494 finish_portlist_table(fp, "ip dst", port_tables->ip_dst);
11495
11496 #ifdef TARGET_BASED
11497 // NOSERVICE Port Tables
11498 finish_portlist_table(fp, "tcp src noservice", port_tables->ns_tcp_src);
11499 finish_portlist_table(fp, "tcp dst noservice", port_tables->ns_tcp_dst);
11500
11501 finish_portlist_table(fp, "udp src noservice", port_tables->ns_udp_src);
11502 finish_portlist_table(fp, "udp dst noservice", port_tables->ns_udp_dst);
11503
11504 finish_portlist_table(fp, "icmp src noservice", port_tables->ns_icmp_src);
11505 finish_portlist_table(fp, "icmp dst noservice", port_tables->ns_icmp_dst);
11506
11507 finish_portlist_table(fp, "ip src noservice", port_tables->ns_ip_src);
11508 finish_portlist_table(fp, "ip dst noservice", port_tables->ns_ip_dst);
11509 #endif // TARGET_BASED
11510
11511 RuleListSortUniq(port_tables->tcp_anyany->rule_list);
11512 RuleListSortUniq(port_tables->udp_anyany->rule_list);
11513 RuleListSortUniq(port_tables->icmp_anyany->rule_list);
11514 RuleListSortUniq(port_tables->ip_anyany->rule_list);
11515 RuleListSortUniq(port_tables->tcp_nocontent->rule_list);
11516 RuleListSortUniq(port_tables->udp_nocontent->rule_list);
11517 RuleListSortUniq(port_tables->icmp_nocontent->rule_list);
11518 RuleListSortUniq(port_tables->ip_nocontent->rule_list);
11519 }
11520
VarTablesFree(SnortConfig * sc)11521 void VarTablesFree(SnortConfig *sc)
11522 {
11523 tSfPolicyId i;
11524
11525 if (sc == NULL)
11526 return;
11527
11528 for (i = 0; i < sc->num_policies_allocated; i++)
11529 {
11530 SnortPolicy *p = sc->targeted_policies[i];
11531
11532 if (p == NULL)
11533 continue;
11534
11535 if (p->var_table != NULL)
11536 {
11537 DeleteVars(p->var_table);
11538 p->var_table = NULL;
11539 }
11540
11541 if (p->ip_vartable != NULL)
11542 {
11543 sfvt_free_table(p->ip_vartable);
11544 p->ip_vartable = NULL;
11545 }
11546
11547 if (p->portVarTable != NULL)
11548 {
11549 PortVarTableFree(p->portVarTable);
11550 p->portVarTable = NULL;
11551 }
11552
11553 if (p->nonamePortVarTable != NULL)
11554 {
11555 PortTableFree(p->nonamePortVarTable);
11556 p->nonamePortVarTable = NULL;
11557 }
11558 }
11559 }
11560
PortTablesFree(rule_port_tables_t * port_tables)11561 void PortTablesFree(rule_port_tables_t *port_tables)
11562 {
11563 if (port_tables == NULL)
11564 return;
11565
11566 if (port_tables->tcp_src)
11567 PortTableFree(port_tables->tcp_src);
11568 if (port_tables->tcp_dst)
11569 PortTableFree(port_tables->tcp_dst);
11570 if (port_tables->udp_src)
11571 PortTableFree(port_tables->udp_src);
11572 if (port_tables->udp_dst)
11573 PortTableFree(port_tables->udp_dst);
11574 if (port_tables->icmp_src)
11575 PortTableFree(port_tables->icmp_src);
11576 if (port_tables->icmp_dst)
11577 PortTableFree(port_tables->icmp_dst);
11578 if (port_tables->ip_src)
11579 PortTableFree(port_tables->ip_src);
11580 if (port_tables->ip_dst)
11581 PortTableFree(port_tables->ip_dst);
11582
11583 if (port_tables->tcp_anyany)
11584 PortObjectFree(port_tables->tcp_anyany);
11585 if (port_tables->udp_anyany)
11586 PortObjectFree(port_tables->udp_anyany);
11587 if (port_tables->icmp_anyany)
11588 PortObjectFree(port_tables->icmp_anyany);
11589 if (port_tables->ip_anyany)
11590 PortObjectFree(port_tables->ip_anyany);
11591
11592 if (port_tables->tcp_nocontent)
11593 PortObjectFree(port_tables->tcp_nocontent);
11594 if (port_tables->udp_nocontent)
11595 PortObjectFree(port_tables->udp_nocontent);
11596 if (port_tables->icmp_nocontent)
11597 PortObjectFree(port_tables->icmp_nocontent);
11598 if (port_tables->ip_nocontent)
11599 PortObjectFree(port_tables->ip_nocontent);
11600
11601 #ifdef TARGET_BASED
11602 if (port_tables->ns_tcp_src)
11603 PortTableFree(port_tables->ns_tcp_src);
11604 if (port_tables->ns_tcp_dst)
11605 PortTableFree(port_tables->ns_tcp_dst);
11606
11607 if (port_tables->ns_udp_src)
11608 PortTableFree(port_tables->ns_udp_src);
11609 if (port_tables->ns_udp_dst)
11610 PortTableFree(port_tables->ns_udp_dst);
11611
11612 if (port_tables->ns_icmp_src)
11613 PortTableFree(port_tables->ns_icmp_src);
11614 if (port_tables->ns_icmp_dst)
11615 PortTableFree(port_tables->ns_icmp_dst);
11616
11617 if (port_tables->ns_ip_src)
11618 PortTableFree(port_tables->ns_ip_src);
11619 if (port_tables->ns_ip_dst)
11620 PortTableFree(port_tables->ns_ip_dst);
11621 #endif
11622
11623 free(port_tables);
11624 }
11625
11626 /****************************************************************************
11627 *
11628 * Function: CreateRuleType
11629 *
11630 * Purpose: Creates a new type of rule and adds it to the end of the rule list
11631 *
11632 * Arguments: name = name of this rule type
11633 * mode = the mode for this rule type
11634 * rval = return value for this rule type (for detect events)
11635 * head = list head to use (or NULL to create a new one)
11636 *
11637 * Returns: the ListHead for the rule type
11638 *
11639 ***************************************************************************/
CreateRuleType(SnortConfig * sc,char * name,RuleType mode,int rval,ListHead * head)11640 static ListHead * CreateRuleType(SnortConfig *sc, char *name,
11641 RuleType mode, int rval, ListHead *head)
11642 {
11643 RuleListNode *node;
11644 int evalIndex = 0;
11645
11646 if (sc == NULL)
11647 return NULL;
11648
11649 node = (RuleListNode *)SnortAlloc(sizeof(RuleListNode));
11650
11651 /* If this is the first rule list node, then we need to
11652 * create a new list. */
11653 if (sc->rule_lists == NULL)
11654 {
11655 sc->rule_lists = node;
11656 }
11657 else
11658 {
11659 RuleListNode *tmp = sc->rule_lists;
11660 RuleListNode *last;
11661
11662 do
11663 {
11664 /* We do not allow multiple rules types with the same name. */
11665 if (strcasecmp(tmp->name, name) == 0)
11666 {
11667 free(node);
11668 return NULL;
11669 }
11670
11671 evalIndex++;
11672 last = tmp;
11673 tmp = tmp->next;
11674
11675 } while (tmp != NULL);
11676
11677 last->next = node;
11678 }
11679
11680 /* User defined rule type so we need to create a list head for it */
11681 if (head == NULL)
11682 {
11683 node->RuleList = (ListHead *)SnortAlloc(sizeof(ListHead));
11684 }
11685 else
11686 {
11687 /* Our default rules already have list heads */
11688 node->RuleList = head;
11689 }
11690
11691 node->RuleList->ruleListNode = node;
11692 node->mode = mode;
11693 node->rval = rval;
11694 node->name = SnortStrdup(name);
11695 node->evalIndex = evalIndex;
11696
11697 sc->evalOrder[node->mode] = evalIndex;
11698 sc->num_rule_types++;
11699
11700 return node->RuleList;
11701 }
11702
OtnInit(SnortConfig * sc)11703 static void OtnInit(SnortConfig *sc)
11704 {
11705 if (sc == NULL)
11706 return;
11707
11708 /* Don't initialize this more than once */
11709 if ((sc->so_rule_otn_map != NULL) || (sc->otn_map != NULL))
11710 return;
11711
11712 /* Init sid-gid -> otn map */
11713 sc->so_rule_otn_map = SoRuleOtnLookupNew();
11714 if (sc->so_rule_otn_map == NULL)
11715 ParseError("ParseRulesFile so_otn_map sfghash_new failed.\n");
11716
11717 /* Init sid-gid -> otn map */
11718 sc->otn_map = OtnLookupNew();
11719 if (sc->otn_map == NULL)
11720 ParseError("ParseRulesFile otn_map sfghash_new failed.\n");
11721 }
11722
11723 #ifndef SOURCEFIRE
11724 #define IFACE_VARS_MAX 128
11725 typedef struct iface_var
11726 {
11727 char name[128];
11728 uint32_t net;
11729 uint32_t netmask;
11730 } iface_var_t;
11731
11732 /****************************************************************************
11733 *
11734 * Function : DefineAllIfaceVars()
11735 * Purpose : Find all up interfaces and define iface_ADDRESS vars for them
11736 * Arguments : none
11737 * Returns : void function
11738 *
11739 ****************************************************************************/
DefineAllIfaceVars(SnortConfig * sc)11740 static void DefineAllIfaceVars(SnortConfig *sc)
11741 {
11742 /* Cache retrieved devs so if user is running with dropped privs and
11743 * does a reload, we can use previous values */
11744 static int num_vars = 0;
11745 /* Should be more than enough to cover the number of
11746 * interfaces on a machine */
11747 static iface_var_t iface_vars[IFACE_VARS_MAX];
11748
11749 if (num_vars > 0)
11750 {
11751 int i;
11752
11753 for (i = 0; i < num_vars; i++)
11754 {
11755 DefineIfaceVar(sc, iface_vars[i].name,
11756 (uint8_t *)&iface_vars[i].net,
11757 (uint8_t *)&iface_vars[i].netmask);
11758 }
11759 }
11760 else
11761 {
11762 char errbuf[PCAP_ERRBUF_SIZE];
11763 pcap_if_t *alldevs;
11764 pcap_if_t *dev;
11765 bpf_u_int32 net, netmask;
11766 #ifdef WIN32
11767 int i = 1;
11768 #endif
11769
11770 if (pcap_findalldevs(&alldevs, errbuf) == -1)
11771 return;
11772
11773 for (dev = alldevs; dev != NULL; dev = dev->next)
11774 {
11775 if (pcap_lookupnet(dev->name, &net, &netmask, errbuf) == 0)
11776 {
11777 /* We've hit the maximum variables we can cache */
11778 if (num_vars >= IFACE_VARS_MAX)
11779 break;
11780 #ifdef WIN32
11781 /* For windows, define var as the index that it will be */
11782 SnortSnprintf(iface_vars[num_vars].name,
11783 sizeof(iface_vars[num_vars].name), "%d", i);
11784 #else
11785 SnortSnprintf(iface_vars[num_vars].name,
11786 sizeof(iface_vars[num_vars].name), "%s", dev->name);
11787 #endif
11788 DefineIfaceVar(sc, iface_vars[num_vars].name,
11789 (uint8_t *)&net,
11790 (uint8_t *)&netmask);
11791
11792 iface_vars[num_vars].net = net;
11793 iface_vars[num_vars].netmask = netmask;
11794 num_vars++;
11795 }
11796
11797 #ifdef WIN32
11798 i++;
11799 #endif
11800 }
11801
11802 pcap_freealldevs(alldevs);
11803 }
11804 }
11805
11806 /****************************************************************************
11807 *
11808 * Function : DefineIfaceVar()
11809 * Purpose : Assign network address and network mask to IFACE_ADDR_VARNAME
11810 * variable.
11811 * Arguments : interface name (string) netaddress and netmask (4 octets each)
11812 * Returns : void function
11813 *
11814 ****************************************************************************/
DefineIfaceVar(SnortConfig * sc,char * iname,uint8_t * network,uint8_t * netmask)11815 static void DefineIfaceVar(SnortConfig *sc, char *iname, uint8_t *network, uint8_t *netmask)
11816 {
11817 char valbuf[32];
11818 char varbuf[BUFSIZ];
11819
11820 if ((network == NULL) || (*network == 0))
11821 return;
11822
11823 SnortSnprintf(varbuf, BUFSIZ, "%s_ADDRESS", iname);
11824
11825 SnortSnprintf(valbuf, 32, "%d.%d.%d.%d/%d.%d.%d.%d",
11826 network[0] & 0xff, network[1] & 0xff, network[2] & 0xff,
11827 network[3] & 0xff, netmask[0] & 0xff, netmask[1] & 0xff,
11828 netmask[2] & 0xff, netmask[3] & 0xff);
11829
11830 VarDefine(sc, varbuf, valbuf);
11831 }
11832 #endif
11833
PrintRuleOrder(RuleListNode * rule_lists)11834 void PrintRuleOrder(RuleListNode *rule_lists)
11835 {
11836 printRuleListOrder(rule_lists);
11837 }
11838
11839 /****************************************************************************
11840 *
11841 * Function: OrderRuleLists
11842 *
11843 * Purpose: Orders the rule lists into the specefied order.
11844 *
11845 * Returns: void function
11846 *
11847 ***************************************************************************/
OrderRuleLists(SnortConfig * sc,char * order)11848 void OrderRuleLists(SnortConfig *sc, char *order)
11849 {
11850 int i;
11851 int evalIndex = 0;
11852 RuleListNode *ordered_list = NULL;
11853 RuleListNode *prev;
11854 RuleListNode *node;
11855 char **toks;
11856 int num_toks;
11857
11858 toks = mSplit(order, " \t", 0, &num_toks, 0);
11859
11860 for( i = 0; i < num_toks; i++ )
11861 {
11862 prev = NULL;
11863 node = sc->rule_lists;
11864
11865 while (node != NULL)
11866 {
11867 if (strcmp(toks[i], node->name) == 0)
11868 {
11869 if (prev == NULL)
11870 sc->rule_lists = node->next;
11871 else
11872 prev->next = node->next;
11873
11874 /* Add node to ordered list */
11875 ordered_list = addNodeToOrderedList(ordered_list, node, evalIndex++);
11876 sc->evalOrder[node->mode] = evalIndex;
11877
11878 break;
11879 }
11880 else
11881 {
11882 prev = node;
11883 node = node->next;
11884 }
11885 }
11886
11887 if( node == NULL )
11888 {
11889 ParseError("Ruletype \"%s\" does not exist or "
11890 "has already been ordered.", toks[i]);
11891 }
11892 }
11893
11894 mSplitFree(&toks, num_toks);
11895
11896 /* anything left in the rule lists needs to be moved to the ordered lists */
11897 while (sc->rule_lists != NULL)
11898 {
11899 node = sc->rule_lists;
11900 sc->rule_lists = node->next;
11901 /* Add node to ordered list */
11902 ordered_list = addNodeToOrderedList(ordered_list, node, evalIndex++);
11903 sc->evalOrder[node->mode] = evalIndex;
11904 }
11905
11906 /* set the rulelists to the ordered list */
11907 sc->rule_lists = ordered_list;
11908 }
11909
addNodeToOrderedList(RuleListNode * ordered_list,RuleListNode * node,int evalIndex)11910 static RuleListNode *addNodeToOrderedList(RuleListNode *ordered_list,
11911 RuleListNode *node, int evalIndex)
11912 {
11913 RuleListNode *prev;
11914
11915 prev = ordered_list;
11916
11917 /* set the eval order for this rule set */
11918 node->evalIndex = evalIndex;
11919
11920 if(!prev)
11921 {
11922 ordered_list = node;
11923 }
11924 else
11925 {
11926 while(prev->next)
11927 prev = prev->next;
11928 prev->next = node;
11929 }
11930
11931 node->next = NULL;
11932
11933 return ordered_list;
11934 }
11935
printRuleListOrder(RuleListNode * node)11936 static void printRuleListOrder(RuleListNode * node)
11937 {
11938 char buf[STD_BUF];
11939 RuleListNode *first_node = node;
11940
11941 SnortSnprintf(buf, STD_BUF, "Rule application order: ");
11942
11943 while( node != NULL )
11944 {
11945 SnortSnprintfAppend(buf, STD_BUF, "%s%s",
11946 node == first_node ? "" : "->", node->name);
11947
11948 node = node->next;
11949 }
11950
11951 LogMessage("%s\n", buf);
11952 }
11953
ParseError(const char * format,...)11954 NORETURN void ParseError(const char *format, ...)
11955 {
11956 char buf[STD_BUF+1];
11957 va_list ap;
11958
11959 va_start(ap, format);
11960 vsnprintf(buf, STD_BUF, format, ap);
11961 va_end(ap);
11962
11963 buf[STD_BUF] = '\0';
11964
11965 if (file_name != NULL)
11966 FatalError("%s(%d) %s\n", file_name, file_line, buf);
11967 else
11968 FatalError("%s\n", buf);
11969 }
11970
ParseWarning(const char * format,...)11971 void ParseWarning(const char *format, ...)
11972 {
11973 char buf[STD_BUF+1];
11974 va_list ap;
11975
11976 va_start(ap, format);
11977 vsnprintf(buf, STD_BUF, format, ap);
11978 va_end(ap);
11979
11980 buf[STD_BUF] = '\0';
11981
11982 if (file_name != NULL)
11983 LogMessage("WARNING: %s(%d) %s\n", file_name, file_line, buf);
11984 else
11985 LogMessage("%s\n", buf);
11986 }
11987
ParseMessage(const char * format,...)11988 void ParseMessage(const char *format, ...)
11989 {
11990 char buf[STD_BUF+1];
11991 va_list ap;
11992
11993 va_start(ap, format);
11994 vsnprintf(buf, STD_BUF, format, ap);
11995 va_end(ap);
11996
11997 buf[STD_BUF] = '\0';
11998
11999 if (file_name != NULL)
12000 LogMessage("%s(%d) %s\n", file_name, file_line, buf);
12001 else
12002 LogMessage("%s\n", buf);
12003 }
12004
12005 typedef struct _RuleTreeNodeKey
12006 {
12007 RuleTreeNode *rtn;
12008 tSfPolicyId policyId;
12009 } RuleTreeNodeKey;
12010
12011 // RuleTreeNode *getRtnFromOtn() made in line
12012
12013 /**Delete rtn from OTN.
12014 *
12015 * @param otn pointer to structure OptTreeNode.
12016 * @param policyId policy id
12017 *
12018 * @return pointer to deleted RTN, NULL otherwise.
12019 */
deleteRtnFromOtn(SnortConfig * sc,OptTreeNode * otn,tSfPolicyId policyId)12020 RuleTreeNode * deleteRtnFromOtn(
12021 SnortConfig *sc,
12022 OptTreeNode *otn,
12023 tSfPolicyId policyId
12024 )
12025 {
12026 RuleTreeNode *rtn = NULL;
12027
12028 if (otn->proto_nodes
12029 && (otn->proto_node_num >= (policyId+1)))
12030 {
12031 rtn = getRtnFromOtn(otn, policyId);
12032 otn->proto_nodes[policyId] = NULL;
12033
12034 if (rtn)
12035 {
12036 RuleTreeNodeKey key;
12037 key.policyId = policyId;
12038 key.rtn = rtn;
12039
12040 if (sc && sc->rtn_hash_table)
12041 {
12042 sfxhash_remove(sc->rtn_hash_table, &key);
12043 }
12044 }
12045
12046 return rtn;
12047 }
12048
12049 return NULL;
12050 }
12051
rtn_hash_func(SFHASHFCN * p,unsigned char * k,int n)12052 uint32_t rtn_hash_func(SFHASHFCN *p, unsigned char *k, int n)
12053 {
12054 uint32_t a,b,c;
12055 RuleTreeNodeKey* rtnk = (RuleTreeNodeKey *)k;
12056 RuleTreeNode *rtn = rtnk->rtn;
12057
12058 a = rtn->type;
12059 b = rtn->flags;
12060 c = (uint32_t)(uintptr_t)rtn->listhead;
12061
12062 mix(a,b,c);
12063
12064 a += (uint32_t)(uintptr_t)rtn->src_portobject;
12065 b += (uint32_t)(uintptr_t)rtn->dst_portobject;
12066 c += (uint32_t)(uintptr_t)rtnk->policyId;
12067
12068 final(a,b,c);
12069
12070 return c;
12071 }
12072
rtn_compare_func(const void * k1,const void * k2,size_t n)12073 int rtn_compare_func(const void *k1, const void *k2, size_t n)
12074 {
12075 RuleTreeNodeKey* rtnk1 = (RuleTreeNodeKey *)k1;
12076 RuleTreeNodeKey* rtnk2 = (RuleTreeNodeKey *)k2;
12077
12078 if (!rtnk1 || !rtnk2)
12079 return 1;
12080
12081 if (rtnk1->policyId != rtnk2->policyId)
12082 return 1;
12083
12084 if (TestHeader( rtnk1->rtn, rtnk2->rtn))
12085 return 0;
12086 else
12087 return 1;
12088 }
12089
12090 /**Add RTN to OTN for a particular OTN.
12091 * @param otn pointer to structure OptTreeNode.
12092 * @param policyId policy id
12093 * @param rtn pointer to RuleTreeNode structure
12094 *
12095 * @return 0 if successful,
12096 * -ve otherwise
12097 */
addRtnToOtn(SnortConfig * sc,OptTreeNode * otn,tSfPolicyId policyId,RuleTreeNode * rtn)12098 int addRtnToOtn(
12099 SnortConfig *sc,
12100 OptTreeNode *otn,
12101 tSfPolicyId policyId,
12102 RuleTreeNode *rtn
12103 )
12104 {
12105 RuleTreeNodeKey key;
12106
12107 if (otn->proto_node_num <= policyId)
12108 {
12109 /* realloc the list, initialize missing elements to 0 and add
12110 * policyId */
12111 RuleTreeNode **tmpNodeArray;
12112 unsigned int numNodes = (policyId + 1);
12113
12114 tmpNodeArray = SnortAlloc(sizeof(RuleTreeNode *) * numNodes);
12115
12116 /* copy original contents, the remaining elements are already
12117 * zeroed out by snortAlloc */
12118 if (otn->proto_nodes)
12119 {
12120 memcpy(tmpNodeArray, otn->proto_nodes,
12121 sizeof(RuleTreeNode *) * otn->proto_node_num);
12122 free(otn->proto_nodes);
12123 }
12124
12125 otn->proto_node_num = numNodes;
12126 otn->proto_nodes = tmpNodeArray;
12127 }
12128
12129 //add policyId
12130 if (otn->proto_nodes[policyId])
12131 {
12132 DestroyRuleTreeNode(rtn);
12133 return -1;
12134 }
12135
12136 otn->proto_nodes[policyId] = rtn;
12137
12138 // Optimized for parsing only, this check avoids adding run time rtn
12139 if (!sc)
12140 return 0;
12141
12142 if (!sc->rtn_hash_table)
12143 {
12144 sc->rtn_hash_table = sfxhash_new(10000, sizeof(RuleTreeNodeKey), 0, 0, 0, NULL, NULL, 1);
12145
12146 if (sc->rtn_hash_table == NULL)
12147 FatalError("Failed to create rule tree node hash table");
12148
12149 sfxhash_set_keyops(sc->rtn_hash_table, rtn_hash_func, rtn_compare_func);
12150
12151 }
12152
12153 key.policyId = policyId;
12154 key.rtn = rtn;
12155 sfxhash_add(sc->rtn_hash_table, &key, rtn);
12156
12157 return 0; //success
12158 }
12159
12160 // the presence of ip lists exceeds mSplit's one-level parsing
12161 // so we transform rule string into something that mSplit can
12162 // handle by changing ',' to c outside ip lists.
12163 // we also strip the leading keyword.
FixSeparators(char * rule,char c,const char * err)12164 char* FixSeparators (char* rule, char c, const char* err)
12165 {
12166 int list = 0;
12167 char* p = strchr(rule, c);
12168
12169 if ( p && err )
12170 {
12171 FatalError("%s(%d) => %s: '%c' not allowed in argument\n",
12172 file_name, file_line, err, c);
12173 }
12174 while ( isspace((int)*rule) ) rule++;
12175
12176 p = rule;
12177
12178 while ( *p ) {
12179 if ( *p == '[' ) list++;
12180 else if ( *p == ']' ) list--;
12181 else if ( *p == ',' && !list ) *p = c;
12182 p++;
12183 }
12184 return rule;
12185 }
12186
GetNameValue(char * arg,char ** nam,char ** val,const char * err)12187 void GetNameValue (char* arg, char** nam, char** val, const char* err)
12188 {
12189 while ( isspace((int)*arg) ) arg++;
12190 *nam = arg;
12191
12192 while ( *arg && !isspace((int)*arg) ) arg++;
12193 if ( *arg ) *arg++ = '\0';
12194 *val = arg;
12195
12196 if ( err && !**val )
12197 {
12198 FatalError("%s(%d) => %s: name value pair expected: %s\n",
12199 file_name, file_line, err, *nam);
12200 }
12201 }
12202
IntegrityCheckRules(SnortConfig * sc)12203 static void IntegrityCheckRules(SnortConfig *sc)
12204 {
12205 OptFpList *ofl_idx = NULL;
12206 int opt_func_count;
12207 SFGHASH_NODE *hashNode = NULL;
12208 OptTreeNode *otn = NULL;
12209 tSfPolicyId policyId = 0;
12210 RuleTreeNode *rtn = NULL;
12211
12212 for (hashNode = sfghash_findfirst(sc->otn_map);
12213 hashNode;
12214 hashNode = sfghash_findnext(sc->otn_map))
12215 {
12216 otn = (OptTreeNode *)hashNode->data;
12217
12218 for (policyId = 0;
12219 policyId < otn->proto_node_num;
12220 policyId++)
12221 {
12222 rtn = getRtnFromOtn(otn, policyId);
12223
12224 if (!rtn)
12225 {
12226 continue;
12227 }
12228
12229 if ((rtn->proto == IPPROTO_TCP) || (rtn->proto == IPPROTO_UDP)
12230 || (rtn->proto == IPPROTO_ICMP) || (rtn->proto == ETHERNET_TYPE_IP))
12231 {
12232 //do operation
12233 ofl_idx = otn->opt_func;
12234 opt_func_count = 0;
12235
12236 while(ofl_idx != NULL)
12237 {
12238 opt_func_count++;
12239 //DEBUG_WRAP(DebugMessage(DEBUG_DETECT, "%p->",ofl_idx->OptTestFunc););
12240 ofl_idx = ofl_idx->next;
12241 }
12242
12243 if(opt_func_count == 0)
12244 {
12245 ParseError("Zero Length OTN List\n");
12246 }
12247 //DEBUG_WRAP(DebugMessage(DEBUG_DETECT,"\n"););
12248
12249 }
12250 }
12251 }
12252
12253 //DEBUG_WRAP(DebugMessage(DEBUG_DETECT, "OK\n"););
12254 }
12255
12256 /**returns matched header node.
12257 */
findHeadNode(SnortConfig * sc,RuleTreeNode * testNode,tSfPolicyId policyId)12258 static RuleTreeNode * findHeadNode(SnortConfig *sc, RuleTreeNode *testNode,
12259 tSfPolicyId policyId)
12260 {
12261 if (sc->rtn_hash_table)
12262 {
12263 RuleTreeNodeKey key;
12264 key.policyId = policyId;
12265 key.rtn = testNode;
12266 return ((RuleTreeNode *)sfxhash_find(sc->rtn_hash_table, &key));
12267 }
12268 else
12269 return NULL;
12270 }
12271
configOptsPrint()12272 void configOptsPrint()
12273 {
12274 int i;
12275
12276 printf("Global policy only options\n");
12277 for (i = 0; config_opts[i].name != NULL; i++)
12278 {
12279 if(config_opts[i].default_policy_only )
12280 {
12281 printf("\t%s,\t%s\n", config_opts[i].name, config_opts[i].only_once ? "Once":"");
12282 }
12283 }
12284
12285 printf("\nPolicy Specific options\n");
12286 for (i = 0; config_opts[i].name != NULL; i++)
12287 {
12288 if(config_opts[i].default_policy_only == 0)
12289 {
12290 printf("\t%s,\t%s\n", config_opts[i].name, config_opts[i].only_once ? "Once":"");
12291 }
12292 }
12293 }
12294
SnortPolicyNew(void)12295 SnortPolicy * SnortPolicyNew(void)
12296 {
12297 SnortPolicy *pPolicy = (SnortPolicy *)SnortAlloc(sizeof(SnortPolicy));
12298
12299 if (pPolicy)
12300 {
12301 // minimum possible (allows all but errors to pass by default)
12302 pPolicy->min_ttl = 1;
12303
12304 #ifdef NORMALIZER
12305 pPolicy->new_ttl = 5;
12306 #endif
12307
12308 /* Turn on all decoder alerts by default except for oversized alert.
12309 * Useful for bug reports ... */
12310 pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__DEFAULT;
12311 pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__TCP_EXP_OPT;
12312 pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__TCP_OBS_OPT;
12313 pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__TCP_TTCP_OPT;
12314 pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__TCP_OPT_ANOMALY;
12315 pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__IP_OPT_ANOMALY;
12316 pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__IPV6_BAD_FRAG;
12317 pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__IPV6_BSD_ICMP_FRAG;
12318
12319 pPolicy->decoder_drop_flags |= DECODE_EVENT_FLAG__IPV6_BAD_FRAG;
12320
12321 pPolicy->checksum_flags = CHECKSUM_FLAG__ALL;
12322
12323 memset( pPolicy->pp_enabled, 0, sizeof( PreprocEnableMask ) * MAX_PORTS );
12324 }
12325
12326 return pPolicy;
12327 }
12328
SnortPolicyFree(SnortPolicy * pPolicy)12329 void SnortPolicyFree(SnortPolicy *pPolicy)
12330 {
12331 if (pPolicy == NULL)
12332 return;
12333
12334 if (pPolicy->policy_version != NULL)
12335 free(pPolicy->policy_version);
12336
12337 #ifdef TARGET_BASED
12338 if (pPolicy->target_based_config.args != NULL)
12339 {
12340 free(pPolicy->target_based_config.args);
12341 if (pPolicy->target_based_config.file_name != NULL)
12342 free(pPolicy->target_based_config.file_name);
12343 }
12344 #endif
12345 }
12346
12347
12348 /* Parse a boolean argument, with many ways to say "on" or "off".
12349 Arguments:
12350 char * arg => string argument to parse
12351 Returns:
12352 1: Parsed a positive argument ("1", "on", "yes", "enable", "true")
12353 0: Parsed a negative argument ("0", "off", "no", "disable", "false")
12354 -1: Error
12355 */
ParseBool(char * arg)12356 int ParseBool(char *arg)
12357 {
12358 if (arg == NULL)
12359 return -1;
12360
12361 /* Trim leading whitespace */
12362 while (isspace(*arg))
12363 arg++;
12364
12365 if ( (strcasecmp(arg, "1") == 0) ||
12366 (strcasecmp(arg, "on") == 0) ||
12367 (strcasecmp(arg, "yes") == 0) ||
12368 (strcasecmp(arg, "enable") == 0) ||
12369 (strcasecmp(arg, "true") == 0) )
12370 return 1;
12371
12372 if ( (strcasecmp(arg, "0") == 0) ||
12373 (strcasecmp(arg, "off") == 0) ||
12374 (strcasecmp(arg, "no") == 0) ||
12375 (strcasecmp(arg, "disable") == 0) ||
12376 (strcasecmp(arg, "false") == 0) )
12377 return 0;
12378
12379 /* Other values are invalid! */
12380 return -1;
12381 }
12382