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