"Fossies" - the Fresh Open Source Software Archive 
Member "snort-2.9.17/src/preprocessors/spp_httpinspect.c" (16 Oct 2020, 81030 Bytes) of package /linux/misc/snort-2.9.17.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "spp_httpinspect.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
2.9.16.1_vs_2.9.17.
1 /****************************************************************************
2 *
3 * Copyright (C) 2014-2020 Cisco and/or its affiliates. All rights reserved.
4 * Copyright (C) 2003-2013 Sourcefire, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License Version 2 as
8 * published by the Free Software Foundation. You may not use, modify or
9 * distribute this program under any other version of the GNU General
10 * Public License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 ****************************************************************************/
22
23 /**
24 ** @file preproc_setup.c
25 **
26 ** @author Daniel Roelker <droelker@sourcefire.com>
27 **
28 ** @brief This file initializes HttpInspect as a Snort
29 ** preprocessor.
30 **
31 ** This file registers the HttpInspect initialization function,
32 ** adds the HttpInspect function into the preprocessor list, reads
33 ** the user configuration in the snort.conf file, and prints out
34 ** the configuration that is read.
35 **
36 ** In general, this file is a wrapper to HttpInspect functionality,
37 ** by interfacing with the Snort preprocessor functions. The rest
38 ** of HttpInspect should be separate from the preprocessor hooks.
39 **
40 ** NOTES
41 **
42 ** - 2.10.03: Initial Development. DJR
43 */
44
45 #include <assert.h>
46 #include <string.h>
47 #include <sys/types.h>
48
49 #ifdef HAVE_CONFIG_H
50 #include "config.h"
51 #endif
52
53 #include "decode.h"
54 #include "plugbase.h"
55 #include "snort_debug.h"
56 #include "util.h"
57 #include "parser.h"
58
59 #include "hi_ui_config.h"
60 #include "hi_ui_server_lookup.h"
61 #include "hi_client.h"
62 #include "hi_norm.h"
63 #include "snort_httpinspect.h"
64 #include "hi_util_kmap.h"
65 #include "hi_util_xmalloc.h"
66 #include "hi_cmd_lookup.h"
67 #include "hi_paf.h"
68 #include "h2_paf.h"
69
70 #ifdef DUMP_BUFFER
71 #include "hi_buffer_dump.h"
72 #endif
73
74 #include "file_decomp.h"
75
76 #include "snort.h"
77 #include "profiler.h"
78 #include "mstring.h"
79 #include "sp_preprocopt.h"
80 #include "detection_util.h"
81
82 #ifdef TARGET_BASED
83 #include "session_api.h"
84 #include "stream_api.h"
85 #include "sftarget_protocol_reference.h"
86 #endif
87
88 #include "sfPolicy.h"
89 #include "mempool.h"
90 #include "file_api.h"
91 #include "sf_email_attach_decode.h"
92
93 #ifdef SNORT_RELOAD
94 #include "reload.h"
95 #include "file_mime_process.h"
96 #ifdef REG_TEST
97 #include "reg_test.h"
98 #endif
99 #endif
100
101 #if defined(FEAT_OPEN_APPID)
102 #include "spp_stream6.h"
103 #endif /* defined(FEAT_OPEN_APPID) */
104
105 /*
106 ** Defines for preprocessor initialization
107 */
108 /**
109 ** snort.conf preprocessor keyword
110 */
111 #define GLOBAL_KEYWORD "http_inspect"
112 #define SERVER_KEYWORD "http_inspect_server"
113
114 const char *PROTOCOL_NAME = "HTTP";
115
116 /**
117 ** The length of the error string buffer.
118 */
119 #define ERRSTRLEN 1000
120
121 /*
122 ** External Global Variables
123 ** Variables that we need from Snort to log errors correctly and such.
124 */
125 extern char *file_name;
126 extern int file_line;
127
128 /*
129 ** Global Variables
130 ** This is the only way to work with Snort preprocessors because
131 ** the user configuration must be kept between the Init function
132 ** the actual preprocessor. There is no interaction between the
133 ** two except through global variable usage.
134 */
135 tSfPolicyUserContextId hi_config = NULL;
136
137 #ifdef TARGET_BASED
138 /* Store the protocol id received from the stream reassembler */
139 int16_t hi_app_protocol_id;
140 int16_t h2_app_protocol_id;
141 #endif
142
143 #ifdef PERF_PROFILING
144 PreprocStats hiPerfStats;
145 PreprocStats hi2PerfStats;
146 PreprocStats hi2InitPerfStats;
147 PreprocStats hi2PayloadPerfStats;
148 PreprocStats hi2PseudoPerfStats;
149 PreprocStats hiDetectPerfStats;
150 int hiDetectCalled = 0;
151 #endif
152
153 static tSfPolicyId httpCurrentPolicy = 0;
154
155 MemPool *hi_gzip_mempool = NULL;
156 fd_config_t hi_fd_conf;
157 uint8_t decompression_buffer[65535];
158
159 uint8_t dechunk_buffer[65535];
160
161 MemPool *http_mempool = NULL;
162 MemPool *mime_decode_mempool = NULL;
163 MemPool *mime_log_mempool = NULL;
164 int hex_lookup[256];
165 int valid_lookup[256];
166
167 char** xffFields = NULL;
168 static char** oldXffFields = NULL;
169
170 /*
171 ** Prototypes
172 */
173 static void HttpInspectDropStats(int);
174 static void HttpInspect(Packet *, void *);
175 static void HttpInspectCleanExit(int, void *);
176 static void HttpInspectReset(int, void *);
177 static void HttpInspectResetStats(int, void *);
178 static void HttpInspectInit(struct _SnortConfig *, char *);
179 static void addServerConfPortsToStream(struct _SnortConfig *sc, void *);
180 static void HttpInspectFreeConfigs(tSfPolicyUserContextId);
181 static void HttpInspectFreeConfig(HTTPINSPECT_GLOBAL_CONF *);
182 static int HttpInspectCheckConfig(struct _SnortConfig *);
183 static void HttpInspectAddPortsOfInterest(struct _SnortConfig *, HTTPINSPECT_GLOBAL_CONF *, tSfPolicyId);
184 static int HttpEncodeInit(struct _SnortConfig *, char *, char *, void **);
185 static int HttpEncodeEval(void *, const uint8_t **, void *);
186 static void HttpEncodeCleanup(void *);
187 static void HttpInspectRegisterRuleOptions(struct _SnortConfig *);
188 static void HttpInspectRegisterXtraDataFuncs(HTTPINSPECT_GLOBAL_CONF *);
189 static inline void InitLookupTables(void);
190 #ifdef TARGET_BASED
191 static void HttpInspectAddServicesOfInterest(struct _SnortConfig *, HTTPINSPECT_GLOBAL_CONF *, tSfPolicyId);
192 #endif
193
194 #ifdef SNORT_RELOAD
195 static int HttpMempoolFreeUsedBucket(MemPool *memory_pool);
196 static unsigned HttpMempoolAdjust(MemPool *memory_pool, unsigned httpMaxWork);
197 static bool HttpGzipReloadAdjust(bool idle, tSfPolicyId raPolicyId, void* userData);
198 static bool HttpFdReloadAdjust(bool idle, tSfPolicyId raPolicyId, void* userData);
199 static bool HttpMempoolReloadAdjust(bool idle, tSfPolicyId raPolicyId, void* userData);
200 static bool HttpMimeReloadAdjust(bool idle, tSfPolicyId raPolicyId, void* userData);
201 static bool HttpLogReloadAdjust(bool idle, tSfPolicyId raPolicyId, void* userData);
202 #ifdef REG_TEST
203 static void display_http_mempool(MemPool *mempool, const char* old_new, const char *pool_type);
204 static int HttpInspectUnlimitedDecompressIterate(void *data);
205 static int HttpInspectUnlimitedDecompress(struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void *pData);
206 static void display_gzip_fd_config_changes(HTTPINSPECT_GLOBAL_CONF* configOld, HTTPINSPECT_GLOBAL_CONF* configNew,
207 bool old_gzip, bool new_gzip, bool old_fd, bool new_fd, bool old_ud, bool new_ud);
208 #endif
209 static void update_gzip_mempool(bool old_gzip, bool new_gzip, uint32_t max_sessions);
210 static void update_fd_mempool(bool old_fd, bool new_fd, uint32_t max_sessions);
211 static void update_gzip_fd_mempools(HTTPINSPECT_GLOBAL_CONF* configNew, bool old_gzip, bool new_gzip, bool old_fd, bool new_fd);
212 static void update_http_mempool(uint32_t new_memcap, uint32_t old_memcap);
213 static void HttpInspectReloadGlobal(struct _SnortConfig *, char *, void **);
214 static void HttpInspectReload(struct _SnortConfig *, char *, void **);
215 static int HttpInspectReloadVerify(struct _SnortConfig *, void *);
216 static void * HttpInspectReloadSwap(struct _SnortConfig *, void *);
217 static void HttpInspectReloadSwapFree(void *);
218 #endif
219
220
221 /*
222 ** NAME
223 ** HttpInspect::
224 */
225 /**
226 ** This function wraps the functionality in the generic HttpInspect
227 ** processing. We get a Packet structure and pass this into the
228 ** HttpInspect module where the first stage in HttpInspect is the
229 ** Session Inspection stage where most of the other Snortisms are
230 ** taken care of. After that, the modules should be fairly generic,
231 ** and that's what we're trying to do here.
232 **
233 ** @param p a Packet structure that contains Snort info about the
234 ** packet.
235 **
236 ** @return void
237 */
238 static void HttpInspect(Packet *p, void *context)
239 {
240 tSfPolicyId policy_id = getNapRuntimePolicy();
241 HTTPINSPECT_GLOBAL_CONF *pPolicyConfig = NULL ;
242 PROFILE_VARS;
243 sfPolicyUserPolicySet (hi_config, policy_id);
244 pPolicyConfig = (HTTPINSPECT_GLOBAL_CONF *)sfPolicyUserDataGetCurrent(hi_config);
245
246 if ( pPolicyConfig == NULL)
247 return;
248
249 // preconditions - what we registered for
250 assert(IsTCP(p) && p->dsize && p->data);
251
252 PREPROC_PROFILE_START(hiPerfStats);
253
254 /*
255 ** Pass in the configuration and the packet.
256 */
257 SnortHttpInspect(pPolicyConfig, p);
258
259 ClearHttpBuffers();
260
261 /* XXX:
262 * NOTE: this includes the HTTPInspect directly
263 * calling the detection engine -
264 * to get the true HTTPInspect only stats, have another
265 * var inside SnortHttpInspect that tracks the time
266 * spent in Detect().
267 * Subtract the ticks from this if iCallDetect == 0
268 */
269 PREPROC_PROFILE_END(hiPerfStats);
270 #ifdef PERF_PROFILING
271 if (hiDetectCalled)
272 {
273 hiPerfStats.ticks -= hiDetectPerfStats.ticks;
274 /* And Reset ticks to 0 */
275 hiDetectPerfStats.ticks = 0;
276 hiDetectCalled = 0;
277 }
278 #endif
279
280 return;
281 }
282
283 static void HttpInspectDropStats(int exiting)
284 {
285 if(!hi_stats.total)
286 return;
287
288 LogMessage("HTTP Inspect - encodings (Note: stream-reassembled "
289 "packets included):\n");
290
291 #ifdef WIN32
292 LogMessage(" POST methods: %-10I64u\n", hi_stats.post);
293 LogMessage(" GET methods: %-10I64u\n", hi_stats.get);
294 LogMessage(" HTTP Request Headers extracted: %-10I64u\n", hi_stats.req_headers);
295 #ifdef DEBUG
296 if (hi_stats.req_headers == 0)
297 LogMessage(" Avg Request Header length: %-10s\n", "n/a");
298 else
299 LogMessage(" Avg Request Header length: %-10.2f\n", (double)hi_stats.req_header_len / (double)hi_stats.req_headers);
300 #endif
301 LogMessage(" HTTP Request cookies extracted: %-10I64u\n", hi_stats.req_cookies);
302 #ifdef DEBUG
303 if (hi_stats.req_cookies == 0)
304 LogMessage(" Avg Request Cookie length: %-10s\n", "n/a");
305 else
306 LogMessage(" Avg Request Cookie length: %-10.2f\n", (double)hi_stats.req_cookie_len / (double)hi_stats.req_cookies);
307 #endif
308 LogMessage(" Post parameters extracted: %-10I64u\n", hi_stats.post_params);
309 LogMessage(" HTTP Response Headers extracted: %-10I64u\n", hi_stats.resp_headers);
310 #ifdef DEBUG
311 if (hi_stats.resp_headers == 0)
312 LogMessage(" Avg Response Header length: %-10s\n", "n/a");
313 else
314 LogMessage(" Avg Response Header length: %-10.2f\n", (double)hi_stats.resp_header_len / (double)hi_stats.resp_headers);
315 #endif
316 LogMessage(" HTTP Response cookies extracted: %-10I64u\n", hi_stats.resp_cookies);
317 #ifdef DEBUG
318 if (hi_stats.resp_cookies == 0)
319 LogMessage(" Avg Response Cookie length: %-10s\n", "n/a");
320 else
321 LogMessage(" Avg Response Cookie length: %-10.2f\n", (double)hi_stats.resp_cookie_len / (double)hi_stats.resp_cookies);
322 #endif
323 LogMessage(" Unicode: %-10I64u\n", hi_stats.unicode);
324 LogMessage(" Double unicode: %-10I64u\n", hi_stats.double_unicode);
325 LogMessage(" Non-ASCII representable: %-10I64u\n", hi_stats.non_ascii);
326 LogMessage(" Directory traversals: %-10I64u\n", hi_stats.dir_trav);
327 LogMessage(" Extra slashes (\"//\"): %-10I64u\n", hi_stats.slashes);
328 LogMessage(" Self-referencing paths (\"./\"): %-10I64u\n", hi_stats.self_ref);
329 LogMessage(" HTTP Response Gzip packets extracted: %-10I64u\n", hi_stats.gzip_pkts);
330 if (hi_stats.gzip_pkts == 0)
331 {
332 LogMessage(" Gzip Compressed Data Processed: %-10s\n", "n/a");
333 LogMessage(" Gzip Decompressed Data Processed: %-10s\n", "n/a");
334 }
335 else
336 {
337 LogMessage(" Gzip Compressed Data Processed: %-10.2f\n", (double)hi_stats.compr_bytes_read);
338 LogMessage(" Gzip Decompressed Data Processed: %-10.2f\n", (double)hi_stats.decompr_bytes_read);
339 }
340 LogMessage(" Http/2 Rebuilt Packets: %-10I64u\n", hi_stats.h2_rebuilt_packets);
341 LogMessage(" Total packets processed: %-10I64u\n", hi_stats.total);
342 LogMessage(" Non-mempool session memory: %-10I64u\n", hi_stats.mem_used +
343 (hi_paf_get_size() * hi_stats.session_count));
344 LogMessage(" http_mempool used: %-10I64u\n",
345 http_mempool ? http_mempool->used_memory:0);
346 LogMessage(" hi_gzip_mempool used: %-10I64u\n",
347 hi_gzip_mempool ? hi_gzip_mempool->used_memory:0);
348 LogMessage(" mime_decode_mempool used: %-10I64u\n",
349 mime_decode_mempool ? mime_decode_mempool->used_memory:0);
350 LogMessage(" mime_log_mempool used: %-10I64u\n",
351 mime_log_mempool ? mime_log_mempool->used_memory:0);
352 LogMessage(" Current active session: %-10I64u\n", hi_stats.session_count);
353 #else
354 LogMessage(" POST methods: "FMTu64("-10")"\n", hi_stats.post);
355 LogMessage(" GET methods: "FMTu64("-10")"\n", hi_stats.get);
356 LogMessage(" HTTP Request Headers extracted: "FMTu64("-10")"\n", hi_stats.req_headers);
357 #ifdef DEBUG
358 if (hi_stats.req_headers == 0)
359 LogMessage(" Avg Request Header length: %-10s\n", "n/a");
360 else
361 LogMessage(" Avg Request Header length: %-10.2f\n", (double)hi_stats.req_header_len / (double)hi_stats.req_headers);
362 #endif
363 LogMessage(" HTTP Request Cookies extracted: "FMTu64("-10")"\n", hi_stats.req_cookies);
364 #ifdef DEBUG
365 if (hi_stats.req_cookies == 0)
366 LogMessage(" Avg Request Cookie length: %-10s\n", "n/a");
367 else
368 LogMessage(" Avg Request Cookie length: %-10.2f\n", (double)hi_stats.req_cookie_len / (double)hi_stats.req_cookies);
369 #endif
370 LogMessage(" Post parameters extracted: "FMTu64("-10")"\n", hi_stats.post_params);
371 LogMessage(" HTTP response Headers extracted: "FMTu64("-10")"\n", hi_stats.resp_headers);
372 #ifdef DEBUG
373 if (hi_stats.resp_headers == 0)
374 LogMessage(" HTTP response Avg Header length: %-10s\n", "n/a");
375 else
376 LogMessage(" Avg Response Header length: %-10.2f\n", (double)hi_stats.resp_header_len / (double)hi_stats.resp_headers);
377 #endif
378 LogMessage(" HTTP Response Cookies extracted: "FMTu64("-10")"\n", hi_stats.resp_cookies);
379 #ifdef DEBUG
380 if (hi_stats.resp_cookies == 0)
381 LogMessage(" Avg Response Cookie length: %-10s\n", "n/a");
382 else
383 LogMessage(" Avg Response Cookie length: %-10.2f\n", (double)hi_stats.resp_cookie_len / (double)hi_stats.resp_cookies);
384 #endif
385 LogMessage(" Unicode: "FMTu64("-10")"\n", hi_stats.unicode);
386 LogMessage(" Double unicode: "FMTu64("-10")"\n", hi_stats.double_unicode);
387 LogMessage(" Non-ASCII representable: "FMTu64("-10")"\n", hi_stats.non_ascii);
388 LogMessage(" Directory traversals: "FMTu64("-10")"\n", hi_stats.dir_trav);
389 LogMessage(" Extra slashes (\"//\"): "FMTu64("-10")"\n", hi_stats.slashes);
390 LogMessage(" Self-referencing paths (\"./\"): "FMTu64("-10")"\n", hi_stats.self_ref);
391 LogMessage(" HTTP Response Gzip packets extracted: "FMTu64("-10")"\n", hi_stats.gzip_pkts);
392 if (hi_stats.gzip_pkts == 0)
393 {
394 LogMessage(" Gzip Compressed Data Processed: %-10s\n", "n/a");
395 LogMessage(" Gzip Decompressed Data Processed: %-10s\n", "n/a");
396 }
397 else
398 {
399 LogMessage(" Gzip Compressed Data Processed: %-10.2f\n", (double)hi_stats.compr_bytes_read);
400 LogMessage(" Gzip Decompressed Data Processed: %-10.2f\n", (double)hi_stats.decompr_bytes_read);
401 }
402 LogMessage(" Http/2 Rebuilt Packets: "FMTu64("-10")"\n", hi_stats.h2_rebuilt_packets);
403 LogMessage(" Total packets processed: "FMTu64("-10")"\n", hi_stats.total);
404 LogMessage(" Non-mempool session memory: "FMTu64("-10")"\n", hi_stats.mem_used +
405 (hi_paf_get_size() * hi_stats.session_count));
406 LogMessage(" http_mempool used: "FMTu64("-10")"\n",
407 http_mempool ? http_mempool->used_memory:0);
408 LogMessage(" hi_gzip_mempool used: "FMTu64("-10")"\n",
409 hi_gzip_mempool ? hi_gzip_mempool->used_memory:0);
410 LogMessage(" mime_decode_mempool used: "FMTu64("-10")"\n",
411 mime_decode_mempool ? mime_decode_mempool->used_memory:0);
412 LogMessage(" mime_log_mempool used: "FMTu64("-10")"\n",
413 mime_log_mempool ? mime_log_mempool->used_memory:0);
414 LogMessage(" Current active session: "FMTu64("-10")"\n", hi_stats.session_count);
415 #endif
416 }
417
418 static void HttpInspectCleanExit(int signal, void *data)
419 {
420 (void)File_Decomp_CleanExit();
421
422 hi_paf_term();
423
424 HI_SearchFree();
425
426 oldXffFields = xffFields;
427 HttpInspectFreeConfigs(hi_config);
428
429 if (mempool_destroy(hi_gzip_mempool) == 0)
430 {
431 free(hi_gzip_mempool);
432 hi_gzip_mempool = NULL;
433 }
434
435 if (mempool_destroy(http_mempool) == 0)
436 {
437 free(http_mempool);
438 http_mempool = NULL;
439 }
440 if (mempool_destroy(mime_decode_mempool) == 0)
441 {
442 free(mime_decode_mempool);
443 mime_decode_mempool = NULL;
444 }
445 if (mempool_destroy(mime_log_mempool) == 0)
446 {
447 free(mime_log_mempool);
448 mime_log_mempool = NULL;
449 }
450 }
451
452 static void HttpInspectReset(int signal, void *data)
453 {
454 return;
455 }
456
457 static void HttpInspectResetStats(int signal, void *data)
458 {
459 memset(&hi_stats, 0, sizeof(hi_stats));
460 }
461
462 static void CheckGzipConfig(HTTPINSPECT_GLOBAL_CONF *pPolicyConfig,
463 tSfPolicyUserContextId context)
464 {
465 HTTPINSPECT_GLOBAL_CONF *defaultConfig =
466 (HTTPINSPECT_GLOBAL_CONF *)sfPolicyUserDataGetDefault(context);
467
468 if (pPolicyConfig == defaultConfig)
469 {
470 if (!pPolicyConfig->max_gzip_mem)
471 pPolicyConfig->max_gzip_mem = DEFAULT_MAX_GZIP_MEM;
472
473 if (!pPolicyConfig->compr_depth)
474 pPolicyConfig->compr_depth = DEFAULT_COMP_DEPTH;
475
476 if (!pPolicyConfig->decompr_depth)
477 pPolicyConfig->decompr_depth = DEFAULT_DECOMP_DEPTH;
478
479 /* Until we determine exact usage of extract_gzip and file_decomp options
480 we will set the max_gzip_sessions to the minimal/conservative value. */
481 pPolicyConfig->max_gzip_sessions = pPolicyConfig->max_gzip_mem /
482 (sizeof(DECOMPRESS_STATE) + sizeof(fd_session_t));
483 }
484 else if (defaultConfig == NULL)
485 {
486 if (pPolicyConfig->max_gzip_mem)
487 {
488 FatalError("http_inspect: max_gzip_mem must be "
489 "configured in the default policy.\n");
490 }
491
492 if (pPolicyConfig->compr_depth)
493 {
494 FatalError("http_inspect: compress_depth must be "
495 "configured in the default policy.\n");
496 }
497
498 if (pPolicyConfig->decompr_depth)
499 {
500 FatalError("http_inspect: decompress_depth must be "
501 "configured in the default policy.\n");
502 }
503 }
504 else
505 {
506 pPolicyConfig->max_gzip_mem = defaultConfig->max_gzip_mem;
507 pPolicyConfig->compr_depth = defaultConfig->compr_depth;
508 pPolicyConfig->decompr_depth = defaultConfig->decompr_depth;
509 pPolicyConfig->max_gzip_sessions = defaultConfig->max_gzip_sessions;
510 }
511 }
512
513
514 static void CheckMemcap(HTTPINSPECT_GLOBAL_CONF *pPolicyConfig,
515 tSfPolicyUserContextId context)
516 {
517 HTTPINSPECT_GLOBAL_CONF *defaultConfig =
518 (HTTPINSPECT_GLOBAL_CONF *)sfPolicyUserDataGetDefault(context);
519
520 if (pPolicyConfig == defaultConfig)
521 {
522 if (!pPolicyConfig->memcap)
523 pPolicyConfig->memcap = DEFAULT_HTTP_MEMCAP;
524
525 }
526 else if (defaultConfig == NULL)
527 {
528 if (pPolicyConfig->memcap)
529 {
530 FatalError("http_inspect: memcap must be "
531 "configured in the default policy.\n");
532 }
533
534 }
535 else
536 {
537 pPolicyConfig->memcap = defaultConfig->memcap;
538 }
539 }
540
541 #ifdef REG_TEST
542 static inline void PrintHTTPSize(void)
543 {
544 LogMessage("\nHTTP Session Size: %lu\n", (long unsigned int)sizeof(HttpSessionData));
545 }
546 #endif
547
548 /*
549 ** NAME
550 ** HttpInspectInit::
551 */
552 /**
553 ** This function initializes HttpInspect with a user configuration.
554 **
555 ** The function is called when HttpInspect is configured in
556 ** snort.conf. It gets passed a string of arguments, which gets
557 ** parsed into configuration constructs that HttpInspect understands.
558 **
559 ** This function gets called for every HttpInspect configure line. We
560 ** use this characteristic to split up the configuration, so each line
561 ** is a configuration construct. We need to keep track of what part
562 ** of the configuration has been configured, so we don't configure one
563 ** part, then configure it again.
564 **
565 ** Any upfront memory is allocated here (if necessary).
566 **
567 ** @param args a string to the preprocessor arguments.
568 **
569 ** @return void
570 */
571 static void HttpInspectInit(struct _SnortConfig *sc, char *args)
572 {
573 char ErrorString[ERRSTRLEN];
574 int iErrStrLen = ERRSTRLEN;
575 int iRet;
576 char *pcToken;
577 char *saveptr;
578 HTTPINSPECT_GLOBAL_CONF *pPolicyConfig = NULL;
579 tSfPolicyId policy_id = getParserPolicy(sc);
580
581 ErrorString[0] = '\0';
582
583 #ifdef REG_TEST
584 PrintHTTPSize();
585 #endif
586
587 if ((args == NULL) || (strlen(args) == 0))
588 ParseError("No arguments to HttpInspect configuration.");
589
590 /* Find out what is getting configured */
591 pcToken = strtok_r(args, CONF_SEPARATORS, &saveptr);
592 if (pcToken == NULL)
593 {
594 FatalError("%s(%d)strtok returned NULL when it should not.",
595 __FILE__, __LINE__);
596 }
597
598 if (!xffFields)
599 {
600 if ((xffFields = calloc(1, HTTP_MAX_XFF_FIELDS * sizeof(char *))) == NULL)
601 {
602 FatalError("http_inspect: %s(%d) failed to allocate memory for XFF fields\n",
603 __FILE__, __LINE__);
604 }
605 }
606
607 if (hi_config == NULL)
608 {
609 hi_config = sfPolicyConfigCreate();
610 memset(&hi_stats, 0, sizeof(HIStats));
611
612 /*
613 ** Remember to add any cleanup functions into the appropriate
614 ** lists.
615 */
616 AddFuncToPreprocCleanExitList(HttpInspectCleanExit, NULL, PRIORITY_APPLICATION, PP_HTTPINSPECT);
617 AddFuncToPreprocResetList(HttpInspectReset, NULL, PRIORITY_APPLICATION, PP_HTTPINSPECT);
618 AddFuncToPreprocResetStatsList(HttpInspectResetStats, NULL, PRIORITY_APPLICATION, PP_HTTPINSPECT);
619 AddFuncToConfigCheckList(sc, HttpInspectCheckConfig);
620
621 RegisterPreprocStats("http_inspect", HttpInspectDropStats);
622
623 #ifdef PERF_PROFILING
624 RegisterPreprocessorProfile("httpinspect", &hiPerfStats, 0, &totalPerfStats, NULL);
625 RegisterPreprocessorProfile("http2inspect", &hi2PerfStats, 0, &totalPerfStats, NULL);
626 RegisterPreprocessorProfile("h2_init", &hi2InitPerfStats, 1, &hi2PerfStats, NULL);
627 RegisterPreprocessorProfile("h2_payload", &hi2PayloadPerfStats, 1, &hi2PerfStats, NULL);
628 RegisterPreprocessorProfile("h2_pseudo", &hi2PseudoPerfStats, 1, &hi2PerfStats, NULL);
629 #endif
630
631 #ifdef TARGET_BASED
632 /* Find and cache protocol ID for packet comparison */
633 hi_app_protocol_id = AddProtocolReference("http");
634 h2_app_protocol_id = AddProtocolReference("http2");
635 // register with session to handle applications
636 session_api->register_service_handler( PP_HTTPINSPECT, hi_app_protocol_id );
637 session_api->register_service_handler( PP_HTTPINSPECT, h2_app_protocol_id);
638
639 #endif
640 hi_paf_init(0); // FIXTHIS is cap needed?
641 HI_SearchInit();
642 }
643
644 /*
645 ** Global Configuration Processing
646 ** We only process the global configuration once, but always check for
647 ** user mistakes, like configuring more than once. That's why we
648 ** still check for the global token even if it's been checked.
649 ** Force the first configuration to be the global one.
650 */
651 sfPolicyUserPolicySet (hi_config, policy_id);
652 pPolicyConfig = (HTTPINSPECT_GLOBAL_CONF *)sfPolicyUserDataGetCurrent(hi_config);
653 if (pPolicyConfig == NULL)
654 {
655 if (strcasecmp(pcToken, GLOBAL) != 0)
656 {
657 ParseError("Must configure the http inspect global "
658 "configuration first.");
659 }
660
661 HttpInspectRegisterRuleOptions(sc);
662
663 pPolicyConfig = (HTTPINSPECT_GLOBAL_CONF *)SnortAlloc(sizeof(HTTPINSPECT_GLOBAL_CONF));
664 if (!pPolicyConfig)
665 {
666 ParseError("HTTP INSPECT preprocessor: memory allocate failed.\n");
667 }
668
669 sfPolicyUserDataSetCurrent(hi_config, pPolicyConfig);
670
671 iRet = HttpInspectInitializeGlobalConfig(pPolicyConfig,
672 ErrorString, iErrStrLen);
673 if (iRet == 0)
674 {
675 iRet = ProcessGlobalConf(pPolicyConfig, ErrorString, iErrStrLen, &saveptr);
676
677 if (iRet == 0)
678 {
679 CheckGzipConfig(pPolicyConfig, hi_config);
680 CheckMemcap(pPolicyConfig, hi_config);
681 PrintGlobalConf(pPolicyConfig);
682
683 /* Add HttpInspect into the preprocessor list */
684 if ( pPolicyConfig->disabled )
685 return;
686 AddFuncToPreprocList(sc, HttpInspect, PRIORITY_APPLICATION, PP_HTTPINSPECT, PROTO_BIT__TCP);
687 }
688 }
689 }
690 else
691 {
692 if (strcasecmp(pcToken, SERVER) != 0)
693 {
694 if (strcasecmp(pcToken, GLOBAL) != 0)
695 ParseError("Must configure the http inspect global configuration first.");
696 else
697 ParseError("Invalid http inspect token: %s.", pcToken);
698 }
699
700 iRet = ProcessUniqueServerConf(sc, pPolicyConfig, ErrorString, iErrStrLen, &saveptr);
701 }
702
703
704
705 if (iRet)
706 {
707 if(iRet > 0)
708 {
709 /*
710 ** Non-fatal Error
711 */
712 if(*ErrorString)
713 {
714 ErrorMessage("%s(%d) => %s\n",
715 file_name, file_line, ErrorString);
716 }
717 }
718 else
719 {
720 /*
721 ** Fatal Error, log error and exit.
722 */
723 if(*ErrorString)
724 {
725 FatalError("%s(%d) => %s\n",
726 file_name, file_line, ErrorString);
727 }
728 else
729 {
730 /*
731 ** Check if ErrorString is undefined.
732 */
733 if(iRet == -2)
734 {
735 FatalError("%s(%d) => ErrorString is undefined.\n",
736 file_name, file_line);
737 }
738 else
739 {
740 FatalError("%s(%d) => Undefined Error.\n",
741 file_name, file_line);
742 }
743 }
744 }
745 }
746
747 }
748
749 /*
750 ** NAME
751 ** SetupHttpInspect::
752 */
753 /**
754 ** This function initializes HttpInspect as a Snort preprocessor.
755 **
756 ** It registers the preprocessor keyword for use in the snort.conf
757 ** and sets up the initialization module for the preprocessor, in
758 ** case it is configured.
759 **
760 ** This function must be called in InitPreprocessors() in plugbase.c
761 ** in order to be recognized by Snort.
762 **
763 ** @param none
764 **
765 ** @return void
766 */
767 void SetupHttpInspect(void)
768 {
769 #ifndef SNORT_RELOAD
770 RegisterPreprocessor(GLOBAL_KEYWORD, HttpInspectInit);
771 RegisterPreprocessor(SERVER_KEYWORD, HttpInspectInit);
772 #else
773 RegisterPreprocessor(GLOBAL_KEYWORD, HttpInspectInit, HttpInspectReloadGlobal,
774 HttpInspectReloadVerify, HttpInspectReloadSwap,
775 HttpInspectReloadSwapFree);
776 RegisterPreprocessor(SERVER_KEYWORD, HttpInspectInit,
777 HttpInspectReload, NULL, NULL, NULL);
778 #endif
779 #ifdef DUMP_BUFFER
780 RegisterBufferTracer(getHTTPDumpBuffers, HTTP_BUFFER_DUMP_FUNC);
781 #endif
782 InitLookupTables();
783 InitJSNormLookupTable();
784 (void)File_Decomp_OneTimeInit();
785
786 DEBUG_WRAP(DebugMessage(DEBUG_HTTPINSPECT, "Preprocessor: HttpInspect is "
787 "setup . . .\n"););
788 }
789
790 static void HttpInspectRegisterRuleOptions(struct _SnortConfig *sc)
791 {
792 RegisterPreprocessorRuleOption(sc, "http_encode", &HttpEncodeInit,
793 &HttpEncodeEval, &HttpEncodeCleanup , NULL, NULL, NULL, NULL );
794 }
795
796 static void HttpInspectRegisterXtraDataFuncs(HTTPINSPECT_GLOBAL_CONF *pPolicyConfig)
797 {
798 if (!stream_api || !pPolicyConfig)
799 return;
800
801 pPolicyConfig->xtra_trueip_id = stream_api->reg_xtra_data_cb(GetHttpTrueIP);
802 pPolicyConfig->xtra_uri_id = stream_api->reg_xtra_data_cb(GetHttpUriData);
803 pPolicyConfig->xtra_hname_id = stream_api->reg_xtra_data_cb(GetHttpHostnameData);
804 #ifndef SOURCEFIRE
805 pPolicyConfig->xtra_gzip_id = stream_api->reg_xtra_data_cb(GetHttpGzipData);
806 pPolicyConfig->xtra_jsnorm_id = stream_api->reg_xtra_data_cb(GetHttpJSNormData);
807 #endif
808
809 }
810
811 static void updateConfigFromFileProcessing (struct _SnortConfig *sc, HTTPINSPECT_GLOBAL_CONF *pPolicyConfig)
812 {
813 HTTPINSPECT_CONF *ServerConf = pPolicyConfig->global_server;
814 /*Either one is unlimited*/
815 int64_t fileDepth = file_api->get_max_file_depth(sc, true);
816
817 /*Config file policy*/
818 if (fileDepth > -1)
819 {
820 ServerConf->inspect_response = 1;
821 ServerConf->extract_gzip = 1;
822 ServerConf->log_uri = 1;
823 ServerConf->unlimited_decompress = 1;
824 pPolicyConfig->mime_conf.log_filename = 1;
825 ServerConf->file_policy = 1;
826 }
827
828 if (!fileDepth || (!ServerConf->server_flow_depth))
829 ServerConf->server_extract_size = 0;
830 else if (ServerConf->server_flow_depth > fileDepth)
831 ServerConf->server_extract_size = ServerConf->server_flow_depth;
832 else
833 ServerConf->server_extract_size = fileDepth;
834
835 if (!fileDepth || (!ServerConf->post_depth))
836 ServerConf->post_extract_size = 0;
837 else if (ServerConf->post_depth > fileDepth)
838 ServerConf->post_extract_size = ServerConf->post_depth;
839 else
840 ServerConf->post_extract_size = fileDepth;
841
842 }
843
844 static int HttpInspectVerifyPolicy(struct _SnortConfig *sc, tSfPolicyUserContextId config,
845 tSfPolicyId policyId, void* pData)
846 {
847 HTTPINSPECT_GLOBAL_CONF *pPolicyConfig = (HTTPINSPECT_GLOBAL_CONF *)pData;
848
849 HttpInspectRegisterXtraDataFuncs(pPolicyConfig);
850
851 if ( pPolicyConfig->disabled )
852 return 0;
853
854 if (!stream_api || (stream_api->version < STREAM_API_VERSION5))
855 {
856 ErrorMessage("HttpInspectConfigCheck() Streaming & reassembly "
857 "must be enabled\n");
858 return -1;
859 }
860
861
862 if (pPolicyConfig->global_server == NULL)
863 {
864 ErrorMessage("HttpInspectConfigCheck() default server configuration "
865 "not specified\n");
866 return -1;
867 }
868
869 #ifdef TARGET_BASED
870 HttpInspectAddServicesOfInterest(sc, pPolicyConfig, policyId);
871 #endif
872 updateConfigFromFileProcessing(sc, pPolicyConfig);
873 HttpInspectAddPortsOfInterest(sc, pPolicyConfig, policyId);
874 #if defined(FEAT_OPEN_APPID)
875 if (IsAnybodyRegisteredForHttpHeader())
876 {
877 pPolicyConfig->global_server->appid_enabled = 1;
878 }
879 #endif /* defined(FEAT_OPEN_APPID) */
880 return 0;
881 }
882
883
884 /** Add ports configured for http preprocessor to stream5 port filtering so that if
885 * any_any rules are being ignored them the the packet still reaches http-inspect.
886 *
887 * For ports in global_server configuration, server_lookup,
888 * add the port to stream5 port filter list.
889 */
890 static void HttpInspectAddPortsOfInterest(struct _SnortConfig *sc, HTTPINSPECT_GLOBAL_CONF *config, tSfPolicyId policy_id)
891 {
892 if (config == NULL)
893 return;
894
895 httpCurrentPolicy = policy_id;
896
897 addServerConfPortsToStream(sc, (void *)config->global_server);
898 hi_ui_server_iterate(sc, config->server_lookup, addServerConfPortsToStream);
899 }
900
901 /**Add server ports from http_inspect preprocessor from snort.conf file to pass through
902 * port filtering.
903 */
904 static void addServerConfPortsToStream(struct _SnortConfig *sc, void *pData)
905 {
906 unsigned int i;
907
908 HTTPINSPECT_CONF *pConf = (HTTPINSPECT_CONF *)pData;
909 if (pConf)
910 {
911 for (i = 0; i < MAXPORTS; i++)
912 {
913 if( isPortEnabled( pConf->ports, i ) )
914 {
915 bool client = (pConf->client_flow_depth > -1);
916 bool server = (pConf->server_extract_size > -1);
917 int64_t fileDepth = file_api->get_max_file_depth(sc, true);
918
919 //Add port the port
920 stream_api->set_port_filter_status(sc, IPPROTO_TCP,
921 (uint16_t) i,
922 PORT_MONITOR_SESSION,
923 httpCurrentPolicy,
924 1);
925
926 // there is a fundamental issue here in that both hi and s5
927 // can configure ports per ip independently of each other.
928 // as is, we enable paf for all http servers if any server
929 // has a flow depth enabled (per direction). still, if eg
930 // all server_flow_depths are -1, we will only enable client.
931 if (fileDepth > 0)
932 {
933 hi_paf_register_port(sc, (uint16_t)i, client, server, httpCurrentPolicy, true);
934 #ifdef HAVE_LIBNGHTTP2
935 if (pConf->h2_mode)
936 h2_paf_register_port(sc, (uint16_t)i, client, server, httpCurrentPolicy, true);
937 #endif /* HAVE_LIBNGHTTP2 */
938 }
939 else
940 {
941 hi_paf_register_port(sc, (uint16_t)i, client, server, httpCurrentPolicy, false);
942 #ifdef HAVE_LIBNGHTTP2
943 if (pConf->h2_mode)
944 h2_paf_register_port(sc, (uint16_t)i, client, server, httpCurrentPolicy, false);
945 #endif /* HAVE_LIBNGHTTP2 */
946 }
947 }
948 }
949 }
950 }
951
952 #ifdef TARGET_BASED
953 /**
954 * @param service ordinal number of service.
955 */
956 static void HttpInspectAddServicesOfInterest(struct _SnortConfig *sc, HTTPINSPECT_GLOBAL_CONF *config, tSfPolicyId policy_id)
957 {
958 if ((config == NULL) || (!config->global_server))
959 return;
960
961 /* Add ordinal number for the service into stream5 */
962 if (hi_app_protocol_id != SFTARGET_UNKNOWN_PROTOCOL)
963 {
964 stream_api->set_service_filter_status(sc, hi_app_protocol_id, PORT_MONITOR_SESSION, policy_id, 1);
965
966 if (file_api->get_max_file_depth(sc, true) > 0)
967 {
968 hi_paf_register_service(sc, hi_app_protocol_id, true, true, policy_id, true);
969 #ifdef HAVE_LIBNGHTTP2
970 if (config->global_server->h2_mode)
971 h2_paf_register_service(sc, hi_app_protocol_id, true, true, policy_id, true);
972 #endif
973 }
974 else
975 {
976 hi_paf_register_service(sc, hi_app_protocol_id, true, true, policy_id, false);
977 #ifdef HAVE_LIBNGHTTP2
978 if (config->global_server->h2_mode)
979 h2_paf_register_service(sc, hi_app_protocol_id, true, true, policy_id, false);
980 #endif
981 }
982 }
983
984 /*
985 #ifdef HAVE_LIBNGHTTP2
986 if ((config == NULL) || (!config->global_server))
987 return;
988
989 if ((h2_app_protocol_id != SFTARGET_UNKNOWN_PROTOCOL) && (config->global_server->h2_mode))
990 {
991 stream_api->set_service_filter_status(sc, h2_app_protocol_id, PORT_MONITOR_SESSION, policy_id, 1);
992
993 if (file_api->get_max_file_depth() > 0)
994 h2_paf_register_service(sc, h2_app_protocol_id, true, true, policy_id, true);
995 else
996 h2_paf_register_service(sc, h2_app_protocol_id, true, true, policy_id, false);
997 }
998
999 #endif */ /* HAVE_LIBNGHTTP2 */
1000 }
1001 #endif
1002
1003 typedef struct _HttpEncodeData
1004 {
1005 int http_type;
1006 int encode_type;
1007 }HttpEncodeData;
1008
1009 static int HttpEncodeInit(struct _SnortConfig *sc, char *name, char *parameters, void **dataPtr)
1010 {
1011 char **toks, **toks1;
1012 int num_toks, num_toks1;
1013 int i;
1014 char *etype;
1015 char *btype;
1016 char *findStr1, *findStr2;
1017 int negate_flag = 0;
1018 unsigned pos;
1019 HttpEncodeData *idx= NULL;
1020
1021 idx = (HttpEncodeData *) SnortAlloc(sizeof(HttpEncodeData));
1022 hi_stats.mem_used += sizeof(HttpEncodeData);
1023
1024 if(idx == NULL)
1025 {
1026 FatalError("%s(%d): Failed allocate data for %s option\n",
1027 file_name, file_line, name);
1028 }
1029
1030
1031 toks = mSplit(parameters, ",", 2, &num_toks, 0);
1032
1033 if(num_toks != 2 )
1034 {
1035 FatalError("%s (%d): %s option takes two parameters \n",
1036 file_name, file_line, name);
1037 }
1038
1039 btype = toks[0];
1040 if(!strcasecmp(btype, "uri"))
1041 {
1042 idx->http_type = HTTP_BUFFER_URI;
1043 }
1044 else if(!strcasecmp(btype, "header"))
1045 {
1046 idx->http_type = HTTP_BUFFER_HEADER;
1047 }
1048 /* This keyword will not be used until post normalization is turned on */
1049 /*else if(!strcasecmp(btype, "post"))
1050 {
1051 idx->http_type = HTTP_BUFFER_CLIENT_BODY;
1052 }*/
1053 else if(!strcasecmp(btype, "cookie"))
1054 {
1055 idx->http_type = HTTP_BUFFER_COOKIE;
1056 }
1057 /*check for a negation when OR is present. OR and negation is not supported*/
1058 findStr1 = strchr(toks[1], '|');
1059 if( findStr1 )
1060 {
1061 findStr2 = strchr(toks[1], '!' );
1062 if( findStr2 )
1063 {
1064 FatalError("%s (%d): \"|\" is not supported in conjunction with \"!\" for %s option \n",
1065 file_name, file_line, name);
1066 }
1067
1068 pos = findStr1 - toks[1];
1069 if ( pos == 0 || pos == (strlen(toks[1]) - 1) )
1070 {
1071 FatalError("%s (%d): Invalid Parameters for %s option \n",
1072 file_name, file_line, name);
1073 }
1074 }
1075
1076 toks1 = mSplit(toks[1], "|", 0, &num_toks1, 0);
1077
1078 for(i = 0; i < num_toks1; i++)
1079 {
1080 etype = toks1[i];
1081
1082 if( *etype == '!' )
1083 {
1084 negate_flag = 1;
1085 etype++;
1086 while(isspace((int)*etype)) {etype++;}
1087 }
1088
1089 if(!strcasecmp(etype, "utf8"))
1090 {
1091 if(negate_flag)
1092 idx->encode_type &= ~HTTP_ENCODE_TYPE__UTF8_UNICODE;
1093 else
1094 idx->encode_type |= HTTP_ENCODE_TYPE__UTF8_UNICODE;
1095 }
1096
1097 else if(!strcasecmp(etype, "double_encode"))
1098 {
1099 if(negate_flag)
1100 idx->encode_type &= ~HTTP_ENCODE_TYPE__DOUBLE_ENCODE;
1101 else idx->encode_type |= HTTP_ENCODE_TYPE__DOUBLE_ENCODE;
1102 }
1103
1104 else if(!strcasecmp(etype, "non_ascii"))
1105 {
1106 if(negate_flag) idx->encode_type &= ~HTTP_ENCODE_TYPE__NONASCII;
1107 else
1108 idx->encode_type |= HTTP_ENCODE_TYPE__NONASCII;
1109 }
1110
1111 /* Base 36 is deprecated and essentially a noop */
1112 else if(!strcasecmp(etype, "base36"))
1113 {
1114 ErrorMessage("WARNING: %s (%d): The \"base36\" argument to the "
1115 "\"http_encode\" rule option is deprecated and void "
1116 "of functionality.\n", file_name, file_line);
1117
1118 /* Set encode type so we can check below to see if base36 was the
1119 * only argument in the encode chain */
1120 idx->encode_type |= HTTP_ENCODE_TYPE__BASE36;
1121 }
1122
1123 else if(!strcasecmp(etype, "uencode"))
1124 {
1125 if(negate_flag)
1126 idx->encode_type &= ~HTTP_ENCODE_TYPE__UENCODE;
1127 else
1128 idx->encode_type |= HTTP_ENCODE_TYPE__UENCODE;
1129 }
1130
1131 else if(!strcasecmp(etype, "bare_byte"))
1132 {
1133 if(negate_flag)
1134 idx->encode_type &= ~HTTP_ENCODE_TYPE__BARE_BYTE;
1135 else
1136 idx->encode_type |= HTTP_ENCODE_TYPE__BARE_BYTE;
1137 }
1138 else if (!strcasecmp(etype, "iis_encode"))
1139 {
1140 if(negate_flag)
1141 idx->encode_type &= ~HTTP_ENCODE_TYPE__IIS_UNICODE;
1142 else
1143 idx->encode_type |= HTTP_ENCODE_TYPE__IIS_UNICODE;
1144 }
1145 else if (!strcasecmp(etype, "ascii"))
1146 {
1147 if(negate_flag)
1148 idx->encode_type &= ~HTTP_ENCODE_TYPE__ASCII;
1149 else
1150 idx->encode_type |= HTTP_ENCODE_TYPE__ASCII;
1151 }
1152
1153 else
1154 {
1155 FatalError("%s(%d): Unknown modifier \"%s\" for option \"%s\"\n",
1156 file_name, file_line, toks1[i], name);
1157 }
1158 negate_flag = 0;
1159 }
1160
1161 /* Only got base36 parameter which is deprecated. If it's the only
1162 * parameter in the chain make it so it always matches as if the
1163 * entire rule option were non-existent. */
1164 if (idx->encode_type == HTTP_ENCODE_TYPE__BASE36)
1165 {
1166 idx->encode_type = 0xffffffff;
1167 }
1168
1169 *dataPtr = idx;
1170 mSplitFree(&toks,num_toks);
1171 mSplitFree(&toks1,num_toks1);
1172
1173 return 0;
1174 }
1175
1176
1177 static int HttpEncodeEval(void *p, const uint8_t **cursor, void *dataPtr)
1178 {
1179 Packet* pkt = p;
1180 HttpEncodeData* idx = (HttpEncodeData *)dataPtr;
1181 const HttpBuffer* hb;
1182
1183 if ( !pkt || !idx )
1184 return DETECTION_OPTION_NO_MATCH;
1185
1186 hb = GetHttpBuffer(idx->http_type);
1187
1188 if ( hb && (hb->encode_type & idx->encode_type) )
1189 return DETECTION_OPTION_MATCH;
1190
1191 return DETECTION_OPTION_NO_MATCH;
1192 }
1193
1194 static void HttpEncodeCleanup(void *dataPtr)
1195 {
1196 HttpEncodeData *idx = dataPtr;
1197 if (idx)
1198 {
1199 free(idx);
1200 hi_stats.mem_used -= sizeof(HttpEncodeData);
1201 }
1202 }
1203
1204 static int HttpInspectFileDecompIterate(void *data)
1205 {
1206 HTTPINSPECT_CONF *server = (HTTPINSPECT_CONF *)data;
1207
1208 if (server == NULL)
1209 return 0;
1210
1211 if (server->file_decomp_modes != 0)
1212 return 1;
1213
1214 return 0;
1215 }
1216
1217 static int HttpInspectFileDecomp(struct _SnortConfig *sc,
1218 tSfPolicyUserContextId config,
1219 tSfPolicyId policyId, void *pData)
1220 {
1221 HTTPINSPECT_GLOBAL_CONF *context = (HTTPINSPECT_GLOBAL_CONF *)pData;
1222
1223 if (pData == NULL)
1224 return 0;
1225
1226 if(context->disabled)
1227 return 0;
1228
1229 if ((context->global_server != NULL) && (context->global_server->file_decomp_modes != 0))
1230 return 1;
1231
1232 if (context->server_lookup != NULL)
1233 {
1234 if (sfrt_iterate2(context->server_lookup, HttpInspectFileDecompIterate) != 0)
1235 return 1;
1236 }
1237
1238 return 0;
1239 }
1240
1241
1242 static int HttpInspectExtractGzipIterate(void *data)
1243 {
1244 HTTPINSPECT_CONF *server = (HTTPINSPECT_CONF *)data;
1245
1246 if (server == NULL)
1247 return 0;
1248
1249 if (server->extract_gzip)
1250 return 1;
1251
1252 return 0;
1253 }
1254
1255 static int HttpInspectExtractGzip(struct _SnortConfig *sc,
1256 tSfPolicyUserContextId config,
1257 tSfPolicyId policyId, void *pData)
1258 {
1259 HTTPINSPECT_GLOBAL_CONF *context = (HTTPINSPECT_GLOBAL_CONF *)pData;
1260
1261 if (pData == NULL)
1262 return 0;
1263
1264 if(context->disabled)
1265 return 0;
1266
1267 if ((context->global_server != NULL) && context->global_server->extract_gzip)
1268 return 1;
1269
1270 if (context->server_lookup != NULL)
1271 {
1272 if (sfrt_iterate2(context->server_lookup, HttpInspectExtractGzipIterate) != 0)
1273 return 1;
1274 }
1275
1276 return 0;
1277 }
1278
1279 static int HttpInspectExtractUriHostIterate(void *data)
1280 {
1281 HTTPINSPECT_CONF *server = (HTTPINSPECT_CONF *)data;
1282
1283 if (server == NULL)
1284 return 0;
1285
1286 #if defined(FEAT_OPEN_APPID)
1287 if (server->log_uri || server->log_hostname || server->appid_enabled)
1288 #else
1289 if (server->log_uri || server->log_hostname)
1290 #endif /* defined(FEAT_OPEN_APPID) */
1291 return 1;
1292
1293 return 0;
1294 }
1295
1296 static int HttpInspectExtractUriHost(struct _SnortConfig *sc,
1297 tSfPolicyUserContextId config,
1298 tSfPolicyId policyId, void *pData)
1299 {
1300 HTTPINSPECT_GLOBAL_CONF *context = (HTTPINSPECT_GLOBAL_CONF *)pData;
1301
1302 if (pData == NULL)
1303 return 0;
1304
1305 if(context->disabled)
1306 return 0;
1307
1308 #if defined(FEAT_OPEN_APPID)
1309 if ((context->global_server != NULL) && (context->global_server->log_uri || context->global_server->log_hostname || context->global_server->appid_enabled))
1310 #else
1311 if ((context->global_server != NULL) && (context->global_server->log_uri || context->global_server->log_hostname))
1312 #endif /* defined(FEAT_OPEN_APPID) */
1313 return 1;
1314
1315 if (context->server_lookup != NULL)
1316 {
1317 if (sfrt_iterate2(context->server_lookup, HttpInspectExtractUriHostIterate) != 0)
1318 return 1;
1319 }
1320
1321 return 0;
1322 }
1323
1324 static int HttpEnableDecoding(struct _SnortConfig *sc,
1325 tSfPolicyUserContextId config,
1326 tSfPolicyId policyId, void *pData)
1327 {
1328 HTTPINSPECT_GLOBAL_CONF *context = (HTTPINSPECT_GLOBAL_CONF *)pData;
1329
1330 if (pData == NULL)
1331 return 0;
1332
1333 if(context->disabled)
1334 return 0;
1335
1336 if((context->global_server != NULL) && (context->global_server->post_extract_size > -1)
1337 && (file_api->is_decoding_enabled(&(context->decode_conf))))
1338 return 1;
1339
1340 return 0;
1341 }
1342
1343 static int HttpEnableMimeLog(struct _SnortConfig *sc,
1344 tSfPolicyUserContextId config,
1345 tSfPolicyId policyId, void *pData)
1346 {
1347 HTTPINSPECT_GLOBAL_CONF *context = (HTTPINSPECT_GLOBAL_CONF *)pData;
1348
1349 if (pData == NULL)
1350 return 0;
1351
1352 if(context->disabled)
1353 return 0;
1354
1355 if((context->global_server != NULL) && (context->global_server->post_extract_size > -1)
1356 && (file_api->is_mime_log_enabled(&(context->mime_conf))))
1357 return 1;
1358
1359 return 0;
1360 }
1361
1362 static int ProcessGzipAndFDMemPools( struct _SnortConfig *sc,
1363 tSfPolicyUserContextId my_hi_config,
1364 HTTPINSPECT_GLOBAL_CONF *my_defaultConfig )
1365 {
1366 bool have_gzip, have_fd;
1367 uint32_t max_sessions = 0;
1368 uint32_t block_size = 0;
1369
1370 have_fd = (sfPolicyUserDataIterate(sc, my_hi_config, HttpInspectFileDecomp) != 0);
1371 have_gzip = (sfPolicyUserDataIterate(sc, my_hi_config, HttpInspectExtractGzip) != 0);
1372
1373 if( have_fd || have_gzip )
1374 {
1375 if (my_defaultConfig == NULL)
1376 {
1377 WarningMessage("http_inspect: Must configure a default global "
1378 "configuration if you want to enable gzip or file decomp in any "
1379 "server configuration.\n");
1380 return( -1 );
1381 }
1382
1383 if( have_fd )
1384 block_size += sizeof( fd_session_t );
1385 if( have_gzip )
1386 block_size += sizeof( DECOMPRESS_STATE );
1387
1388 if( block_size > my_defaultConfig->max_gzip_mem )
1389 FatalError("http_inspect: Error setting the \"max_gzip_mem\" \n");
1390
1391 max_sessions = my_defaultConfig->max_gzip_mem / block_size;
1392 my_defaultConfig->max_gzip_sessions = max_sessions;
1393
1394 if( have_fd )
1395 {
1396 hi_fd_conf.Max_Memory = (max_sessions * sizeof( fd_session_t ));
1397 if( File_Decomp_Config(&(hi_fd_conf)) != File_Decomp_OK )
1398 FatalError("http_inspect: Could not allocate file decomp mempool.\n");
1399 }
1400 else
1401 hi_fd_conf.fd_MemPool = NULL;
1402
1403 if( have_gzip )
1404 {
1405 hi_gzip_mempool = (MemPool *)SnortAlloc(sizeof(MemPool));
1406
1407 if( (hi_gzip_mempool == 0) ||
1408 (mempool_init(hi_gzip_mempool, max_sessions,
1409 sizeof(DECOMPRESS_STATE)) != 0) )
1410 FatalError("http_inspect: Could not allocate gzip mempool.\n");
1411 }
1412 else
1413 hi_gzip_mempool = NULL;
1414 }
1415 return( 0 );
1416 }
1417
1418 static int CheckFilePolicyConfig(
1419 struct _SnortConfig *sc,
1420 tSfPolicyUserContextId config,
1421 tSfPolicyId policyId,
1422 void* pData
1423 )
1424 {
1425 HTTPINSPECT_GLOBAL_CONF *context = (HTTPINSPECT_GLOBAL_CONF*)pData;
1426
1427 context->decode_conf.file_depth = file_api->get_max_file_depth(sc, true);
1428 if (context->decode_conf.file_depth > -1)
1429 context->mime_conf.log_filename = 1;
1430 updateMaxDepth(context->decode_conf.file_depth, &context->decode_conf.max_depth);
1431
1432 return 0;
1433 }
1434
1435 /*
1436 ** NAME
1437 ** HttpInspectCheckConfig::
1438 */
1439 /**
1440 ** This function verifies the HttpInspect configuration is complete
1441 **
1442 ** @return none
1443 */
1444 static int HttpInspectCheckConfig(struct _SnortConfig *sc)
1445 {
1446 HTTPINSPECT_GLOBAL_CONF *defaultConfig;
1447
1448 if (hi_config == NULL)
1449 return 0;
1450
1451 if (sfPolicyUserDataIterate (sc, hi_config, HttpInspectVerifyPolicy))
1452 return -1;
1453
1454 if (sfPolicyUserDataIterate (sc, hi_config, CheckFilePolicyConfig))
1455 return -1;
1456
1457 defaultConfig = (HTTPINSPECT_GLOBAL_CONF *)sfPolicyUserDataGetDefault(hi_config);
1458
1459 if( ProcessGzipAndFDMemPools( sc, hi_config, defaultConfig ) != 0 )
1460 return( -1 );
1461
1462 if (sfPolicyUserDataIterate(sc, hi_config, HttpInspectExtractUriHost) != 0)
1463 {
1464 uint32_t max_sessions_logged;
1465 if (defaultConfig == NULL)
1466 {
1467 WarningMessage("http_inspect: Must configure a default global "
1468 "configuration if you want to enable logging of uri or hostname in any "
1469 "server configuration.\n");
1470 return -1;
1471 }
1472
1473 max_sessions_logged = defaultConfig->memcap / (MAX_URI_EXTRACTED + MAX_HOSTNAME);
1474
1475 http_mempool = (MemPool *)SnortAlloc(sizeof(MemPool));
1476 if (mempool_init(http_mempool, max_sessions_logged, (MAX_URI_EXTRACTED + MAX_HOSTNAME)) != 0)
1477 {
1478 FatalError("http_inspect: Could not allocate HTTP mempool.\n");
1479 }
1480 }
1481
1482 if (sfPolicyUserDataIterate(sc, hi_config, HttpEnableDecoding) != 0)
1483 {
1484 if (defaultConfig == NULL)
1485 {
1486 WarningMessage("http_inspect: Must configure a default global "
1487 "configuration if you want to enable decoding in any "
1488 "server configuration.\n");
1489 return -1;
1490 }
1491 mime_decode_mempool = (MemPool *)file_api->init_mime_mempool(defaultConfig->decode_conf.max_mime_mem,
1492 defaultConfig->decode_conf.max_depth, mime_decode_mempool, PROTOCOL_NAME);
1493 }
1494
1495 if (sfPolicyUserDataIterate(sc, hi_config, HttpEnableMimeLog) != 0)
1496 {
1497 if (defaultConfig == NULL)
1498 {
1499 ErrorMessage("http_inspect: Must configure a default global "
1500 "configuration if you want to enable mime log in any "
1501 "server configuration.\n");
1502 return -1;
1503 }
1504 mime_log_mempool = (MemPool *)file_api->init_log_mempool(0,
1505 defaultConfig->mime_conf.memcap, mime_log_mempool, "HTTP");
1506 }
1507 return 0;
1508 }
1509
1510 static int HttpInspectFreeConfigPolicy(tSfPolicyUserContextId config,tSfPolicyId policyId, void* pData )
1511 {
1512 HTTPINSPECT_GLOBAL_CONF *pPolicyConfig = (HTTPINSPECT_GLOBAL_CONF *)pData;
1513 HttpInspectFreeConfig(pPolicyConfig);
1514 sfPolicyUserDataClear (config, policyId);
1515 return 0;
1516 }
1517
1518 static void HttpInspectFreeConfigs(tSfPolicyUserContextId config)
1519 {
1520 int i;
1521
1522 if(oldXffFields)
1523 {
1524 for (i = 0; (i < HTTP_MAX_XFF_FIELDS) && (oldXffFields[i]); i++)
1525 {
1526 free(oldXffFields[i]);
1527 oldXffFields[i] = NULL;
1528 }
1529
1530 free(oldXffFields);
1531 oldXffFields = NULL;
1532 }
1533
1534 if (config == NULL)
1535 return;
1536 sfPolicyUserDataFreeIterate (config, HttpInspectFreeConfigPolicy);
1537 sfPolicyConfigDelete(config);
1538
1539 }
1540
1541 static void HttpInspectFreeConfig(HTTPINSPECT_GLOBAL_CONF *config)
1542 {
1543 if (config == NULL)
1544 return;
1545
1546 hi_ui_server_lookup_destroy(config->server_lookup);
1547
1548 xfree(config->iis_unicode_map_filename);
1549 xfree(config->iis_unicode_map);
1550
1551 if (config->global_server != NULL)
1552 {
1553 int i;
1554 for( i=0; i<HTTP_MAX_XFF_FIELDS; i++ )
1555 if( config->global_server->xff_headers[i] != NULL )
1556 {
1557 free( config->global_server->xff_headers[i] );
1558 config->global_server->xff_headers[i] = NULL;
1559 }
1560
1561 http_cmd_lookup_cleanup(&(config->global_server->cmd_lookup));
1562 free(config->global_server);
1563 }
1564
1565 free(config);
1566 }
1567
1568 #ifdef SNORT_RELOAD
1569 static void _HttpInspectReload(struct _SnortConfig *sc, tSfPolicyUserContextId hi_swap_config, char *args)
1570 {
1571 char ErrorString[ERRSTRLEN];
1572 int iErrStrLen = ERRSTRLEN;
1573 int iRet;
1574 HTTPINSPECT_GLOBAL_CONF *pPolicyConfig = NULL;
1575 char *pcToken;
1576 char *saveptr;
1577 tSfPolicyId policy_id = getParserPolicy(sc);
1578
1579 ErrorString[0] = '\0';
1580
1581 if ((args == NULL) || (strlen(args) == 0))
1582 ParseError("No arguments to HttpInspect configuration.");
1583
1584 /* Find out what is getting configured */
1585 pcToken = strtok_r(args, CONF_SEPARATORS, &saveptr);
1586 if (pcToken == NULL)
1587 {
1588 FatalError("%s(%d)strtok returned NULL when it should not.",
1589 __FILE__, __LINE__);
1590 }
1591
1592 if (!oldXffFields)
1593 {
1594 oldXffFields = xffFields;
1595 if ((xffFields = calloc(1, HTTP_MAX_XFF_FIELDS * sizeof(char *))) == NULL)
1596 {
1597 FatalError("http_inspect: %s(%d) failed to allocate memory for XFF fields\n",
1598 __FILE__, __LINE__);
1599 }
1600 }
1601
1602 /*
1603 ** Global Configuration Processing
1604 ** We only process the global configuration once, but always check for
1605 ** user mistakes, like configuring more than once. That's why we
1606 ** still check for the global token even if it's been checked.
1607 ** Force the first configuration to be the global one.
1608 */
1609 sfPolicyUserPolicySet (hi_swap_config, policy_id);
1610 pPolicyConfig = (HTTPINSPECT_GLOBAL_CONF *)sfPolicyUserDataGetCurrent(hi_swap_config);
1611 if (pPolicyConfig == NULL)
1612 {
1613 if (strcasecmp(pcToken, GLOBAL) != 0)
1614 ParseError("Must configure the http inspect global configuration first.");
1615
1616 HttpInspectRegisterRuleOptions(sc);
1617
1618 pPolicyConfig = (HTTPINSPECT_GLOBAL_CONF *)SnortAlloc(sizeof(HTTPINSPECT_GLOBAL_CONF));
1619 if (!pPolicyConfig)
1620 {
1621 ParseError("HTTP INSPECT preprocessor: memory allocate failed.\n");
1622 }
1623 sfPolicyUserDataSetCurrent(hi_swap_config, pPolicyConfig);
1624 iRet = HttpInspectInitializeGlobalConfig(pPolicyConfig,
1625 ErrorString, iErrStrLen);
1626 if (iRet == 0)
1627 {
1628 iRet = ProcessGlobalConf(pPolicyConfig, ErrorString, iErrStrLen, &saveptr);
1629
1630 if (iRet == 0)
1631 {
1632 CheckGzipConfig(pPolicyConfig, hi_swap_config);
1633 CheckMemcap(pPolicyConfig, hi_swap_config);
1634 PrintGlobalConf(pPolicyConfig);
1635
1636 /* Add HttpInspect into the preprocessor list */
1637 if ( pPolicyConfig->disabled )
1638 return;
1639 AddFuncToPreprocList(sc, HttpInspect, PRIORITY_APPLICATION, PP_HTTPINSPECT, PROTO_BIT__TCP);
1640
1641 }
1642 }
1643 }
1644 else
1645 {
1646 if (strcasecmp(pcToken, SERVER) != 0)
1647 {
1648 if (strcasecmp(pcToken, GLOBAL) != 0)
1649 ParseError("Must configure the http inspect global configuration first.");
1650 else
1651 ParseError("Invalid http inspect token: %s.", pcToken);
1652 }
1653
1654 iRet = ProcessUniqueServerConf(sc, pPolicyConfig, ErrorString, iErrStrLen, &saveptr);
1655 }
1656
1657 if (iRet)
1658 {
1659 if(iRet > 0)
1660 {
1661 /*
1662 ** Non-fatal Error
1663 */
1664 if(*ErrorString)
1665 {
1666 ErrorMessage("%s(%d) => %s\n",
1667 file_name, file_line, ErrorString);
1668 }
1669 }
1670 else
1671 {
1672 /*
1673 ** Fatal Error, log error and exit.
1674 */
1675 if(*ErrorString)
1676 {
1677 FatalError("%s(%d) => %s\n",
1678 file_name, file_line, ErrorString);
1679 }
1680 else
1681 {
1682 /*
1683 ** Check if ErrorString is undefined.
1684 */
1685 if(iRet == -2)
1686 {
1687 FatalError("%s(%d) => ErrorString is undefined.\n",
1688 file_name, file_line);
1689 }
1690 else
1691 {
1692 FatalError("%s(%d) => Undefined Error.\n",
1693 file_name, file_line);
1694 }
1695 }
1696 }
1697 }
1698 }
1699
1700 static void HttpInspectReloadGlobal(struct _SnortConfig *sc, char *args, void **new_config)
1701 {
1702 tSfPolicyUserContextId hi_swap_config = (tSfPolicyUserContextId)*new_config;
1703 if (!hi_swap_config)
1704 {
1705 hi_swap_config = sfPolicyConfigCreate();
1706 if (!hi_swap_config)
1707 FatalError("No memory to allocate http inspect swap_configuration.\n");
1708 *new_config = hi_swap_config;
1709 }
1710 _HttpInspectReload(sc, hi_swap_config, args);
1711 }
1712
1713 static void HttpInspectReload(struct _SnortConfig *sc, char *args, void **new_config)
1714 {
1715 tSfPolicyUserContextId hi_swap_config;
1716 hi_swap_config = (tSfPolicyUserContextId)GetRelatedReloadData(sc, GLOBAL_KEYWORD);
1717 _HttpInspectReload(sc, hi_swap_config, args);
1718 }
1719
1720 static int HttpMempoolFreeUsedBucket(MemPool *memory_pool)
1721 {
1722 MemBucket *lru_bucket = NULL;
1723
1724 lru_bucket = mempool_get_lru_bucket(memory_pool);
1725 if(lru_bucket)
1726 {
1727 session_api->set_application_data(lru_bucket->scbPtr, PP_HTTPINSPECT, NULL, NULL);
1728 return 1;
1729 }
1730 return 0;
1731 }
1732
1733 static unsigned HttpMempoolAdjust(MemPool *memory_pool, unsigned httpMaxWork)
1734 {
1735 int retVal;
1736
1737 /* deleting MemBucket from free list in HTTP Mempool */
1738 httpMaxWork = mempool_prune_freelist(memory_pool, memory_pool->max_memory, httpMaxWork);
1739
1740 for( ; httpMaxWork && ((memory_pool->used_memory + memory_pool->free_memory) > memory_pool->max_memory); httpMaxWork--)
1741 {
1742 /* deleting least recently used MemBucket from Used list in HTTP Mempool */
1743 retVal = HttpMempoolFreeUsedBucket(memory_pool);
1744 if(!retVal)
1745 break;
1746 }
1747
1748 return httpMaxWork;
1749 }
1750
1751 static bool HttpGzipReloadAdjust(bool idle, tSfPolicyId raPolicyId, void* userData)
1752 {
1753 unsigned initialMaxWork = idle ? 512 : 5;
1754 unsigned maxWork;
1755
1756 maxWork = HttpMempoolAdjust(hi_gzip_mempool, initialMaxWork);
1757 /* This check will be true, when the gzip_mempool is disabled and mempool cleaning is also completed */
1758 if( hi_gzip_mempool->used_memory + hi_gzip_mempool->free_memory == 0 )
1759 {
1760 free(hi_gzip_mempool);
1761 hi_gzip_mempool = NULL;
1762 return true;
1763 }
1764
1765 return (maxWork == initialMaxWork) ? true : false;
1766 }
1767
1768 static bool HttpFdReloadAdjust(bool idle, tSfPolicyId raPolicyId, void* userData)
1769 {
1770 unsigned initialMaxWork = idle ? 512 : 5;
1771 unsigned maxWork;
1772
1773 maxWork = HttpMempoolAdjust(hi_fd_conf.fd_MemPool, initialMaxWork);
1774 /* This check will be true, when the fd_mempool is disabled and mempool cleaning is also completed */
1775 if( hi_fd_conf.fd_MemPool->used_memory + hi_fd_conf.fd_MemPool->free_memory == 0 )
1776 {
1777 free(hi_fd_conf.fd_MemPool);
1778 hi_fd_conf.fd_MemPool = NULL;
1779 return true;
1780 }
1781
1782 return (maxWork == initialMaxWork) ? true : false;
1783 }
1784
1785 static bool HttpMempoolReloadAdjust(bool idle, tSfPolicyId raPolicyId, void* userData)
1786 {
1787 unsigned initialMaxWork = idle ? 512 : 5;
1788 unsigned maxWork;
1789
1790 /* If new memcap is less than old configured memcap, need to adjust HTTP Mempool.
1791 * In order to adjust to new max_memory of http mempool, delete buckets from free list.
1792 * After deleting buckets from free list, still new max_memory is less than old value , delete buckets
1793 * (least recently used i.e head node of used list )from used list till total memory reaches to new max_memory.
1794 */
1795 maxWork = HttpMempoolAdjust(http_mempool, initialMaxWork);
1796
1797 return (maxWork == initialMaxWork) ? true : false;
1798 }
1799
1800 static bool HttpMimeReloadAdjust(bool idle, tSfPolicyId raPolicyId, void* userData)
1801 {
1802 unsigned initialMaxWork = idle ? 512 : 5;
1803 unsigned maxWork;
1804
1805 /* If new max_mime_mem is less than old configured max_mime_mem, need to adjust HTTP Mime Mempool.
1806 * In order to adjust to new max_memory of mime mempool, delete buckets from free list.
1807 * After deleting buckets from free list, still new max_memory is less than old value , delete buckets
1808 * (least recently used i.e head node of used list )from used list till total memory reaches to new max_memory.
1809 */
1810 maxWork = HttpMempoolAdjust(mime_decode_mempool, initialMaxWork);
1811
1812 return (maxWork == initialMaxWork) ? true : false;
1813 }
1814
1815 static bool HttpLogReloadAdjust(bool idle, tSfPolicyId raPolicyId, void* userData)
1816 {
1817 unsigned initialMaxWork = idle ? 512 : 5;
1818 unsigned maxWork;
1819
1820 /* If new memcap is less than old configured memcap, need to adjust HTTP Log Mempool.
1821 * In order to adjust to new max_memory of log mempool, delete buckets from free list.
1822 * After deleting buckets from free list, still new max_memory is less than old value , delete buckets
1823 * (least recently used i.e head node of used list )from used list till total memory reaches to new max_memory.
1824 */
1825 maxWork = HttpMempoolAdjust(mime_log_mempool, initialMaxWork);
1826
1827 return (maxWork == initialMaxWork) ? true : false;
1828 }
1829
1830 static int HttpInspectReloadVerify(struct _SnortConfig *sc, void *swap_config)
1831 {
1832 tSfPolicyUserContextId hi_swap_config = (tSfPolicyUserContextId)swap_config;
1833 HTTPINSPECT_GLOBAL_CONF *defaultConfig;
1834 HTTPINSPECT_GLOBAL_CONF *defaultSwapConfig;
1835 bool swap_gzip, swap_fd, curr_gzip, curr_fd;
1836 tSfPolicyId policy_id = 0;
1837
1838 if (hi_swap_config == NULL)
1839 return 0;
1840
1841 if (sfPolicyUserDataIterate (sc, hi_swap_config, HttpInspectVerifyPolicy))
1842 return -1;
1843
1844 defaultConfig = (HTTPINSPECT_GLOBAL_CONF *)sfPolicyUserDataGetDefault(hi_config);
1845 defaultSwapConfig = (HTTPINSPECT_GLOBAL_CONF *)sfPolicyUserDataGetDefault(hi_swap_config);
1846
1847 if (!defaultConfig)
1848 return 0;
1849
1850 curr_gzip = (hi_gzip_mempool != NULL);
1851 curr_fd = (hi_fd_conf.fd_MemPool != NULL);
1852
1853 policy_id = getParserPolicy(sc);
1854
1855 LogMessage("HTTPInspect: gzip old=%s, fd old=%s\n", curr_gzip ? "true": "false", curr_fd ? "true": "false");
1856 if( curr_gzip || curr_fd )
1857 {
1858 /* Look for the case where the current and swap configs have differing gzip & fd options. */
1859 swap_fd = (sfPolicyUserDataIterate(sc, hi_swap_config, HttpInspectFileDecomp) != 0);
1860 swap_gzip = (sfPolicyUserDataIterate(sc, hi_swap_config, HttpInspectExtractGzip) != 0);
1861
1862 LogMessage("HTTPInspect: gzip new=%s, fd new=%s\n", swap_gzip ? "true": "false", swap_fd ? "true": "false");
1863 if(defaultSwapConfig)
1864 {
1865 LogMessage("HTTPInspect: old gzip memcap=%u, new gzip memcap=%u\n", defaultConfig->max_gzip_mem, defaultSwapConfig->max_gzip_mem);
1866 if(curr_gzip)
1867 LogMessage("HTTPInspect: HTTP-GZIP-MEMPOOL used=%zu, free=%zu, max=%zu, obj_size=%zu\n",
1868 hi_gzip_mempool->used_memory, hi_gzip_mempool->free_memory, hi_gzip_mempool->max_memory, hi_gzip_mempool->obj_size);
1869 if(curr_fd)
1870 LogMessage("HTTPInspect: HTTP-FD-MEMPOOL used=%zu, free=%zu, max=%zu, obj_size=%zu\n",
1871 hi_fd_conf.fd_MemPool->used_memory, hi_fd_conf.fd_MemPool->free_memory, hi_fd_conf.fd_MemPool->max_memory, hi_fd_conf.fd_MemPool->obj_size);
1872 if(defaultSwapConfig->max_gzip_mem < defaultConfig->max_gzip_mem)
1873 {
1874 /* Change in max_gzip_mem value changes the number of max_sessions of hi_gzip_mempool and max_gzip_sessions.
1875 This value also changes max_memory and max_sessions of hi_fd_conf.fd_Mempool.
1876 So registering here to adjust these mempools when max_gzip_mem cahnges.
1877 */
1878 if( curr_gzip && curr_fd && swap_gzip && swap_fd )
1879 {
1880 ReloadAdjustRegister(sc, "HTTP-GZIP-MEMPOOL", policy_id, &HttpGzipReloadAdjust, NULL, NULL);
1881 ReloadAdjustRegister(sc, "HTTP-FD-MEMPOOL", policy_id, &HttpFdReloadAdjust, NULL, NULL);
1882 }
1883 if( curr_gzip && !curr_fd && swap_gzip)
1884 ReloadAdjustRegister(sc, "HTTP-GZIP-MEMPOOL", policy_id, &HttpGzipReloadAdjust, NULL, NULL);
1885 if( !curr_gzip && curr_fd && swap_fd)
1886 ReloadAdjustRegister(sc, "HTTP-FD-MEMPOOL", policy_id, &HttpFdReloadAdjust, NULL, NULL);
1887 }
1888 if(curr_gzip && !swap_gzip)
1889 ReloadAdjustRegister(sc, "HTTP-GZIP-MEMPOOL", policy_id, &HttpGzipReloadAdjust, NULL, NULL);
1890 if(curr_fd && !swap_fd)
1891 ReloadAdjustRegister(sc, "HTTP-FD-MEMPOOL", policy_id, &HttpFdReloadAdjust, NULL, NULL);
1892 }
1893 }
1894 else if (defaultSwapConfig != NULL)
1895 {
1896 ProcessGzipAndFDMemPools( sc, hi_swap_config, defaultSwapConfig );
1897 }
1898
1899 if (http_mempool != NULL)
1900 {
1901 if (defaultSwapConfig != NULL)
1902 {
1903 LogMessage("HTTPInspect: HTTP-MEMPOOL old memcap=%d, new_memcap=%d, used=%zu, free=%zu, max=%zu, obj_size=%zu\n",
1904 defaultConfig->memcap, defaultSwapConfig->memcap, http_mempool->used_memory, http_mempool->free_memory, http_mempool->max_memory, http_mempool->obj_size);
1905 if (defaultSwapConfig->memcap < defaultConfig->memcap)
1906 ReloadAdjustRegister(sc, "HTTP-MEMPOOL", policy_id, &HttpMempoolReloadAdjust, NULL, NULL);
1907 }
1908 }
1909 else
1910 {
1911 if (sfPolicyUserDataIterate(sc, hi_swap_config, HttpInspectExtractUriHost) != 0)
1912 {
1913 uint32_t max_sessions_logged;
1914
1915 if (defaultSwapConfig == NULL)
1916 {
1917 ErrorMessage("http_inspect: Must configure a default global "
1918 "configuration if you want to enable logging of uri or hostname in any "
1919 "server configuration.\n");
1920 return -1;
1921 }
1922
1923 max_sessions_logged = defaultSwapConfig->memcap / (MAX_URI_EXTRACTED + MAX_HOSTNAME);
1924
1925 http_mempool = (MemPool *)SnortAlloc(sizeof(MemPool));
1926
1927 if (mempool_init(http_mempool, max_sessions_logged,(MAX_URI_EXTRACTED + MAX_HOSTNAME)) != 0)
1928 {
1929 FatalError("http_inspect: Could not allocate HTTP mempool.\n");
1930 }
1931 }
1932
1933 }
1934 if (mime_decode_mempool != NULL)
1935 {
1936 if (sfPolicyUserDataIterate (sc, hi_swap_config, CheckFilePolicyConfig))
1937 return -1;
1938
1939 /* If max_mime_mem changes, mime mempool need to be adjusted bcz mempool max_memory will be changed.
1940 * Registering here to adjust Mime memory Pool when max_mime_mem changes.
1941 */
1942 if(defaultSwapConfig)
1943 {
1944 LogMessage("HTTPInspect: HTTP-MIME-MEMPOOL old memcap=%d, new_memcap=%d, used=%zu, free=%zu, max=%zu, obj_size=%zu\n",
1945 defaultConfig->decode_conf.max_mime_mem, defaultSwapConfig->decode_conf.max_mime_mem, mime_decode_mempool->used_memory,
1946 mime_decode_mempool->free_memory, mime_decode_mempool->max_memory, mime_decode_mempool->obj_size);
1947 if( defaultSwapConfig->decode_conf.max_mime_mem < defaultConfig->decode_conf.max_mime_mem )
1948 ReloadAdjustRegister(sc, "HTTP-MIME-MEMPOOL", policy_id, &HttpMimeReloadAdjust, NULL, NULL);
1949 }
1950
1951 }
1952 else
1953 {
1954 if (sfPolicyUserDataIterate(sc, hi_swap_config, HttpEnableDecoding) != 0)
1955 {
1956 if (defaultSwapConfig == NULL)
1957 {
1958 ErrorMessage("http_inspect: Must configure a default global "
1959 "configuration if you want to enable decoding in any "
1960 "server configuration.\n");
1961 return -1;
1962 }
1963 mime_decode_mempool = (MemPool *)file_api->init_mime_mempool(defaultSwapConfig->decode_conf.max_mime_mem,
1964 defaultSwapConfig->decode_conf.max_depth, mime_decode_mempool, PROTOCOL_NAME);
1965 }
1966 }
1967 if (mime_log_mempool != NULL)
1968 {
1969 if(defaultSwapConfig)
1970 {
1971 /* If memcap of HTTP mIme changes, log mempool need to be adjusted bcz mempool max_mempory will be changed.
1972 * Registering here to adjust Log memory Pool when memcap changes.
1973 */
1974 LogMessage("HTTPInspect: HTTP-LOG-MEMPOOL old memcap=%d, new_memcap=%d, used=%zu, free=%zu, max=%zu, obj_size=%zu\n",
1975 defaultConfig->mime_conf.memcap, defaultSwapConfig->mime_conf.memcap, mime_log_mempool->used_memory, mime_log_mempool->free_memory,
1976 mime_log_mempool->max_memory, mime_log_mempool->obj_size);
1977 if (defaultSwapConfig->mime_conf.memcap < defaultConfig->mime_conf.memcap)
1978 ReloadAdjustRegister(sc, "HTTP-LOG-MEMPOOL", policy_id, &HttpLogReloadAdjust, NULL, NULL);
1979 }
1980
1981 }
1982 else
1983 {
1984 if (sfPolicyUserDataIterate(sc, hi_swap_config, HttpEnableMimeLog) != 0)
1985 {
1986 if (defaultSwapConfig == NULL)
1987 {
1988 ErrorMessage("http_inspect: Must configure a default global "
1989 "configuration if you want to enable mime log in any "
1990 "server configuration.\n");
1991 return -1;
1992 }
1993 mime_log_mempool = (MemPool *)file_api->init_log_mempool(0,
1994 defaultSwapConfig->mime_conf.memcap, mime_log_mempool, PROTOCOL_NAME);
1995 }
1996 }
1997
1998 return 0;
1999 }
2000
2001 #ifdef REG_TEST
2002 static void display_http_mempool(MemPool *mempool, const char* old_new, const char *pool_type)
2003 {
2004 if(mempool)
2005 {
2006 printf("\n========== START# %s HTTP %s_mempool VALUES ==============================\n", old_new, pool_type);
2007 printf("%s_mempool object size: %s VALUE # %zu \n",pool_type, old_new, mempool->obj_size);
2008 printf("%s_mempool max memory : %s VALUE # %zu \n",pool_type, old_new, mempool->max_memory);
2009 if(mempool->obj_size)
2010 printf("%s_mempool total number of buckets: %s VALUE # %u \n",pool_type, old_new,(unsigned)(mempool->max_memory / mempool->obj_size));
2011 printf("========== END# %s HTTP %s_mempool VALUES ==============================\n", old_new, pool_type);
2012 fflush(stdout);
2013 }
2014 }
2015 #endif
2016
2017 static void update_gzip_mempool(bool old_gzip, bool new_gzip, uint32_t max_sessions)
2018 {
2019 if(old_gzip && !new_gzip)
2020 {
2021 if(hi_gzip_mempool)
2022 hi_gzip_mempool->max_memory = 0;
2023 }
2024 else
2025 {
2026 if(hi_gzip_mempool)
2027 {
2028 hi_gzip_mempool->max_memory = (max_sessions * sizeof( DECOMPRESS_STATE ) );
2029 hi_gzip_mempool->obj_size = sizeof(DECOMPRESS_STATE);
2030 }
2031 }
2032 }
2033 static void update_fd_mempool(bool old_fd, bool new_fd, uint32_t max_sessions)
2034 {
2035 if(old_fd && !new_fd)
2036 {
2037 if(hi_fd_conf.fd_MemPool)
2038 {
2039 hi_fd_conf.Max_Memory = 0;
2040 hi_fd_conf.fd_MemPool->max_memory = 0;
2041 }
2042 }
2043 else
2044 {
2045 if(hi_fd_conf.fd_MemPool)
2046 {
2047 hi_fd_conf.Max_Memory = (max_sessions * sizeof( fd_session_t ));
2048 hi_fd_conf.fd_MemPool->max_memory = (max_sessions * sizeof( fd_session_t ));
2049 hi_fd_conf.fd_MemPool->obj_size = sizeof( fd_session_t );
2050 }
2051 }
2052 }
2053 static void update_gzip_fd_mempools(HTTPINSPECT_GLOBAL_CONF* configNew,
2054 bool old_gzip, bool new_gzip, bool old_fd, bool new_fd)
2055 {
2056 uint32_t max_sessions = 0;
2057 uint32_t block_size = 0;
2058
2059 if( old_fd || old_gzip )
2060 {
2061 if( new_fd )
2062 block_size += sizeof( fd_session_t );
2063 if( new_gzip )
2064 block_size += sizeof( DECOMPRESS_STATE );
2065
2066 if( block_size > configNew->max_gzip_mem )
2067 FatalError("http_inspect: Error setting the \"max_gzip_mem\" \n");
2068
2069 if(block_size)
2070 max_sessions = configNew->max_gzip_mem / block_size;
2071 configNew->max_gzip_sessions = max_sessions;
2072
2073 update_fd_mempool(old_fd, new_fd, max_sessions);
2074 update_gzip_mempool(old_gzip, new_gzip, max_sessions);
2075 }
2076
2077 }
2078
2079 static void update_http_mempool(uint32_t new_memcap, uint32_t old_memcap)
2080 {
2081 uint32_t max_sessions_logged = 0;
2082 size_t obj_size = 0;
2083
2084 obj_size = (MAX_URI_EXTRACTED + MAX_HOSTNAME);
2085
2086 if(obj_size)
2087 max_sessions_logged = new_memcap / obj_size;
2088
2089 #ifdef REG_TEST
2090 if(REG_TEST_EMAIL_FLAG_HTTP_MEMPOOL_ADJUST & getRegTestFlagsForEmail())
2091 {
2092 printf("\nhttp memcap value is #(OLD VALUE) %u \n", old_memcap);
2093 display_http_mempool(http_mempool, "OLD", "http");
2094 printf("\nSetting memcap to new value # (NEW VALUE )%u\n",new_memcap);
2095 }
2096 #endif
2097
2098 http_mempool->max_memory = max_sessions_logged * obj_size;
2099 http_mempool->obj_size = obj_size;
2100
2101 #ifdef REG_TEST
2102 if(REG_TEST_EMAIL_FLAG_HTTP_MEMPOOL_ADJUST & getRegTestFlagsForEmail())
2103 display_http_mempool(http_mempool, "NEW", "http");
2104 #endif
2105 }
2106
2107 #ifdef REG_TEST
2108 static int HttpInspectUnlimitedDecompressIterate(void *data)
2109 {
2110 HTTPINSPECT_CONF *server = (HTTPINSPECT_CONF *)data;
2111
2112 if (server == NULL)
2113 return 0;
2114
2115 if (server->unlimited_decompress)
2116 return 1;
2117
2118 return 0;
2119 }
2120
2121 static int HttpInspectUnlimitedDecompress(struct _SnortConfig *sc,
2122 tSfPolicyUserContextId config,
2123 tSfPolicyId policyId, void *pData)
2124 {
2125 HTTPINSPECT_GLOBAL_CONF *context = (HTTPINSPECT_GLOBAL_CONF *)pData;
2126
2127 if (pData == NULL)
2128 return 0;
2129
2130 if(context->disabled)
2131 return 0;
2132
2133 if ((context->global_server != NULL) && context->global_server->unlimited_decompress)
2134 return 1;
2135
2136 if (context->server_lookup != NULL)
2137 {
2138 if (sfrt_iterate2(context->server_lookup, HttpInspectUnlimitedDecompressIterate) != 0)
2139 return 1;
2140 }
2141 return 0;
2142 }
2143 static void display_gzip_fd_config_changes(HTTPINSPECT_GLOBAL_CONF* configOld, HTTPINSPECT_GLOBAL_CONF* configNew,
2144 bool old_gzip, bool new_gzip, bool old_fd, bool new_fd, bool old_ud, bool new_ud)
2145 {
2146 if(configOld->max_gzip_mem != configNew->max_gzip_mem )
2147 {
2148 printf("\nmax_gzip_mem value is # %u",configOld->max_gzip_mem);
2149 printf("\nSetting max_gzip_value to new value # ( NEW VALUE ) %u\n", configNew->max_gzip_mem);
2150 }
2151 if(configOld->compr_depth != configNew->compr_depth)
2152 {
2153 printf("\nHttp Global Compression Depth is # OLD VALUE # %u",configOld->compr_depth);
2154 printf("\nSetting Http Global Compression depth to # NEW VALUE # %u\n", configNew->compr_depth);
2155 }
2156 if(configOld->decompr_depth != configNew->decompr_depth)
2157 {
2158 printf("\nHttp Global Decompression Depth is # OLD VALUE # %u",configOld->decompr_depth);
2159 printf("\nSetting Http Global Decompression depth to # NEW VALUE # %u\n", configNew->decompr_depth);
2160 }
2161 if( old_gzip != new_gzip )
2162 {
2163 printf("\nExtract GZIP is Enabled # OLD VALUE # %s",configOld->global_server->extract_gzip ? "YES" : "NO");
2164 printf("\n[Setting] Extract GZIP is Enabled # NEW VALUE # %s\n",configNew->global_server->extract_gzip ? "YES" : "NO");
2165 }
2166 if( old_fd != new_fd )
2167 {
2168 printf("\nFile Decompression modes # OLD VALUE # %lu",configOld->global_server->file_decomp_modes);
2169 printf("\nSetting File decompression modes to # NEW VALUE # %lu\n",configNew->global_server->file_decomp_modes);
2170 }
2171 if( old_ud != new_ud )
2172 {
2173 printf("\nUnlimited Decompression Enabled # OLD VALUE # %s",configOld->global_server->unlimited_decompress ? "YES" : "NO");
2174 printf("\n[Setting] Unlimited Decompression Enabled# NEW VALUE # %s\n",configNew->global_server->unlimited_decompress ? "YES" : "NO");
2175 }
2176 }
2177 #endif
2178
2179 static void * HttpInspectReloadSwap(struct _SnortConfig *sc, void *swap_config)
2180 {
2181 tSfPolicyUserContextId hi_swap_config = (tSfPolicyUserContextId)swap_config;
2182 tSfPolicyUserContextId old_config = hi_config;
2183 HTTPINSPECT_GLOBAL_CONF *configNew = NULL, *configOld = NULL;
2184 bool old_fd, old_gzip, new_fd, new_gzip;
2185 #ifdef REG_TEST
2186 bool old_ud, new_ud;
2187 #endif
2188
2189 if (hi_swap_config == NULL)
2190 return NULL;
2191
2192 configNew = (HTTPINSPECT_GLOBAL_CONF *)sfPolicyUserDataGetDefault(hi_swap_config);
2193 configOld = (HTTPINSPECT_GLOBAL_CONF *)sfPolicyUserDataGetDefault(old_config);
2194
2195 old_fd = (sfPolicyUserDataIterate(sc, old_config, HttpInspectFileDecomp) != 0);
2196 old_gzip = (sfPolicyUserDataIterate(sc, old_config, HttpInspectExtractGzip) != 0);
2197
2198 new_fd = (sfPolicyUserDataIterate(sc, hi_swap_config, HttpInspectFileDecomp) != 0);
2199 new_gzip = (sfPolicyUserDataIterate(sc, hi_swap_config, HttpInspectExtractGzip) != 0);
2200
2201
2202 if( configNew && configOld)
2203 {
2204 if(hi_gzip_mempool || hi_fd_conf.fd_MemPool)
2205 {
2206 #ifdef REG_TEST
2207 if( (REG_TEST_EMAIL_FLAG_GZIP_MEMPOOL_ADJUST & getRegTestFlagsForEmail() ) ||
2208 (REG_TEST_EMAIL_FLAG_FD_MEMPOOL_ADJUST & getRegTestFlagsForEmail()) )
2209 {
2210 old_ud = (sfPolicyUserDataIterate(sc, old_config, HttpInspectUnlimitedDecompress) != 0);
2211 new_ud = (sfPolicyUserDataIterate(sc, hi_swap_config, HttpInspectUnlimitedDecompress) != 0);
2212 display_gzip_fd_config_changes(configOld, configNew, old_gzip, new_gzip, old_fd, new_fd, old_ud, new_ud);
2213 }
2214 #endif
2215 if((configOld->max_gzip_mem != configNew->max_gzip_mem) ||
2216 (old_gzip != new_gzip) ||
2217 (old_fd != new_fd) )
2218 {
2219 update_gzip_fd_mempools(configNew, old_gzip, new_gzip, old_fd, new_fd);
2220 }
2221
2222 }
2223 if(http_mempool)
2224 {
2225 if(configOld->memcap != configNew->memcap)
2226 {
2227 update_http_mempool(configNew->memcap, configOld->memcap);
2228 }
2229 }
2230 if(mime_decode_mempool)
2231 {
2232 if( (configOld->decode_conf.max_mime_mem != configNew->decode_conf.max_mime_mem) ||
2233 (configOld->decode_conf.max_depth != configNew->decode_conf.max_depth) )
2234 {
2235 #ifdef REG_TEST
2236 displayMimeMempool(mime_decode_mempool,&(configOld->decode_conf), &(configNew->decode_conf));
2237 #endif
2238 /* Update the mime_decode_mempool with new max_memmory and object size when max_mime_mem changes. */
2239 update_mime_mempool(mime_decode_mempool, configNew->decode_conf.max_mime_mem, configNew->decode_conf.max_depth);
2240 }
2241 }
2242 if(mime_log_mempool)
2243 {
2244 if(configOld->mime_conf.memcap != configNew->mime_conf.memcap )
2245 {
2246 #ifdef REG_TEST
2247 displayLogMempool(mime_log_mempool, configOld->mime_conf.memcap, configNew->mime_conf.memcap);
2248 #endif
2249 /* Update the mime_log_mempool with new max_memory and objest size when memcap changes. */
2250 update_log_mempool(mime_log_mempool, configNew->mime_conf.memcap, 0);
2251 }
2252 }
2253 #ifdef REG_TEST
2254 displayDecodeDepth(&(configOld->decode_conf), &(configNew->decode_conf));
2255 #endif
2256
2257 }
2258
2259 hi_config = hi_swap_config;
2260
2261 return (void *)old_config;
2262 }
2263
2264 static void HttpInspectReloadSwapFree(void *data)
2265 {
2266 if (data == NULL)
2267 return;
2268
2269 HttpInspectFreeConfigs((tSfPolicyUserContextId)data);
2270 }
2271 #endif
2272
2273 static inline void InitLookupTables(void)
2274 {
2275 int iNum;
2276 int iCtr;
2277
2278 memset(hex_lookup, INVALID_HEX_VAL, sizeof(hex_lookup));
2279 memset(valid_lookup, INVALID_HEX_VAL, sizeof(valid_lookup));
2280
2281 iNum = 0;
2282 for(iCtr = 48; iCtr < 58; iCtr++)
2283 {
2284 hex_lookup[iCtr] = iNum;
2285 valid_lookup[iCtr] = HEX_VAL;
2286 iNum++;
2287 }
2288
2289 /*
2290 * Set the upper case values.
2291 */
2292 iNum = 10;
2293 for(iCtr = 65; iCtr < 71; iCtr++)
2294 {
2295 hex_lookup[iCtr] = iNum;
2296 valid_lookup[iCtr] = HEX_VAL;
2297 iNum++;
2298 }
2299
2300 /*
2301 * Set the lower case values.
2302 */
2303 iNum = 10;
2304 for(iCtr = 97; iCtr < 103; iCtr++)
2305 {
2306 hex_lookup[iCtr] = iNum;
2307 valid_lookup[iCtr] = HEX_VAL;
2308 iNum++;
2309 }
2310 }
2311