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