"Fossies" - the Fresh Open Source Software Archive 
Member "snort-2.9.17/src/preprocessors/HttpInspect/client/hi_client.c" (16 Oct 2020, 120433 Bytes) of package /linux/misc/snort-2.9.17.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "hi_client.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
2.9.16.1_vs_2.9.17.
1 /****************************************************************************
2 *
3 * Copyright (C) 2014-2020 Cisco and/or its affiliates. All rights reserved.
4 * Copyright (C) 2003-2013 Sourcefire, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License Version 2 as
8 * published by the Free Software Foundation. You may not use, modify or
9 * distribute this program under any other version of the GNU General
10 * Public License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 ****************************************************************************/
22
23 /**
24 ** @file hi_client.c
25 **
26 ** @author Daniel Roelker <droelker@sourcefire.com>
27 **
28 ** @brief Main file for all the client functions and inspection
29 ** flow.
30 **
31 **
32 ** The job of the client module is to analyze and inspect the HTTP
33 ** protocol, finding where the various fields begin and end. This must
34 ** be accomplished in a stateful and stateless manner.
35 **
36 ** While the fields are being determined, we also do checks for
37 ** normalization, so we don't normalize fields that don't need it.
38 **
39 ** Currently, the only fields we check for this is the URI and the
40 ** parameter fields.
41 **
42 ** NOTES:
43 ** - 3.8.03: Initial development. DJR
44 ** - 2.4.05: Added tab_uri_delimiter config option. AJM.
45 */
46
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include <ctype.h>
51 #include <sys/types.h>
52 #include <errno.h>
53
54 #ifdef HAVE_CONFIG_H
55 #include "config.h"
56 #endif
57
58 #include "hi_ui_config.h"
59 #include "hi_si.h"
60 #include "hi_mi.h"
61 #include "hi_client.h"
62 #include "hi_eo_log.h"
63 #include "hi_util.h"
64 #include "hi_util_hbm.h"
65 #include "hi_return_codes.h"
66 #include "util.h"
67 #include "mstring.h"
68 #include "sfutil/util_unfold.h"
69 #include "hi_cmd_lookup.h"
70 #include "detection_util.h"
71 #include "hi_paf.h"
72
73 #if defined(FEAT_OPEN_APPID)
74 #include "spp_stream6.h"
75 #endif /* defined(FEAT_OPEN_APPID) */
76
77 #define HEADER_NAME__COOKIE "Cookie"
78 #define HEADER_LENGTH__COOKIE 6
79 #define HEADER_NAME__CONTENT_LENGTH "Content-length"
80 #define HEADER_LENGTH__CONTENT_LENGTH 14
81 #define HEADER_NAME__XFF HTTP_XFF_FIELD_X_FORWARDED_FOR
82 #define HEADER_LENGTH__XFF (sizeof(HEADER_NAME__XFF)-1)
83 #define HEADER_NAME__TRUE_IP HTTP_XFF_FIELD_TRUE_CLIENT_IP
84 #define HEADER_LENGTH__TRUE_IP (sizeof(HEADER_NAME__TRUE_IP)-1)
85 #define HEADER_NAME__HOSTNAME "Host"
86 #define HEADER_LENGTH__HOSTNAME 4
87 #define HEADER_NAME__RANGE "Range"
88 #define HEADER_LENGTH__RANGE 5
89 #define HEADER_NAME__TRANSFER_ENCODING "Transfer-encoding"
90 #define HEADER_LENGTH__TRANSFER_ENCODING 17
91 #define HEADER_NAME__CONTENT_TYPE "Content-Type"
92 #define HEADER_LENGTH__CONTENT_TYPE 12
93 #define HEADER_NAME__CONTENT_DISP "Content-Disposition"
94 #define HEADER_LENGTH__CONTENT_DISP 19
95 #if defined(FEAT_OPEN_APPID)
96 #define HEADER_NAME__USER_AGENT "User-Agent"
97 #define HEADER_LENGTH__USER_AGENT sizeof(HEADER_NAME__USER_AGENT)-1
98 #define HEADER_NAME__REFERER "Referer"
99 #define HEADER_LENGTH__REFERER sizeof(HEADER_NAME__REFERER)-1
100 #define HEADER_NAME__VIA "Via"
101 #define HEADER_LENGTH__VIA sizeof(HEADER_NAME__VIA)-1
102 #endif /* defined(FEAT_OPEN_APPID) */
103
104 const u_char *proxy_start = NULL;
105 const u_char *proxy_end = NULL;
106
107 static const char *g_field_names[] =
108 {
109 HEADER_NAME__COOKIE,
110 HEADER_NAME__CONTENT_LENGTH,
111 HEADER_NAME__XFF,
112 HEADER_NAME__TRUE_IP,
113 HEADER_NAME__HOSTNAME,
114 HEADER_NAME__TRANSFER_ENCODING,
115 HEADER_NAME__CONTENT_TYPE,
116 NULL
117 };
118
119 /** This makes passing function arguments much more readable and easier
120 ** to follow.
121 */
122 typedef int (*LOOKUP_FCN)(HI_SESSION *, const u_char *, const u_char *, const u_char **,
123 URI_PTR *);
124
125 /*
126 ** The lookup table contains functions for different HTTP delimiters
127 ** (like whitespace and the HTTP delimiter \r and \n).
128 */
129 LOOKUP_FCN lookup_table[256];
130 int NextNonWhiteSpace(HI_SESSION *Session, const u_char *start,
131 const u_char *end, const u_char **ptr, URI_PTR *uri_ptr);
132 extern const u_char *extract_http_transfer_encoding(HI_SESSION *, HttpSessionData *,
133 const u_char *, const u_char *, const u_char *, HEADER_PTR *, int);
134
135 extern void CheckSkipAlertMultipleColon(HI_SESSION *Session, const u_char *start,
136 const u_char *end, const u_char **ptr, int iInspectMode);
137
138 char **hi_client_get_field_names() { return( (char **)g_field_names ); }
139
140 /*
141 ** NAME
142 ** CheckChunkEncoding::
143 */
144 /**
145 ** This routine checks for chunk encoding anomalies in an HTTP client request
146 ** packet.
147 **
148 ** We convert potential chunk lengths and test them against the user-defined
149 ** max chunk length. We log events on any chunk lengths that are over this
150 ** defined chunk lengths.
151 **
152 ** Chunks are skipped to save time when the chunk is contained in the packet.
153 **
154 ** We assume coming into this function that we are pointed at the beginning
155 ** of what may be a chunk length. That's why the iCheckChunk var is set
156 ** to 1.
157 **
158 ** @param Session pointer to the Session construct
159 ** @param start pointer to where to beginning of buffer
160 ** @param end pointer to the end of buffer
161 **
162 ** @return integer
163 **
164 ** @retval HI_SUCCESS function successful
165 ** @retval HI_INVALID_ARG invalid argument
166 */
167 int CheckChunkEncoding(HI_SESSION *Session, const u_char *start, const u_char *end,
168 const u_char **post_end, u_char *iChunkBuf, uint32_t max_size,
169 uint32_t chunk_remainder, uint32_t *updated_chunk_remainder, uint32_t *chunkRead, HttpSessionData *hsd,
170 int iInspectMode)
171 {
172 uint32_t iChunkLen = 0;
173 uint32_t iChunkChars = 0;
174 int chunkPresent = 0;
175 uint32_t iCheckChunk = 1;
176 const u_char *ptr;
177 const u_char *jump_ptr;
178 uint32_t iDataLen = 0;
179 uint32_t chunkBytesCopied = 0;
180 uint8_t stateless_chunk_count = 0;
181 uint8_t iChunkLenState = CHUNK_LEN_DEFAULT;
182 bool iChunkRemainder = false;
183
184 if(!start || !end)
185 return HI_INVALID_ARG;
186
187 ptr = start;
188
189 if (hsd)
190 iChunkLenState = hsd->resp_state.chunk_len_state;
191
192 if(chunk_remainder && iChunkLenState == CHUNK_LEN_DEFAULT)
193 {
194 iDataLen = end - ptr;
195
196 if( iDataLen < max_size)
197 {
198 if( chunk_remainder > iDataLen )
199 {
200 if(updated_chunk_remainder)
201 *updated_chunk_remainder = chunk_remainder - iDataLen ;
202 chunk_remainder = iDataLen;
203 iChunkRemainder = true;
204 }
205 }
206 else
207 {
208 if( chunk_remainder > max_size )
209 {
210 if(updated_chunk_remainder)
211 *updated_chunk_remainder = chunk_remainder - max_size ;
212 chunk_remainder = max_size;
213 iChunkRemainder = true;
214 }
215 }
216
217 jump_ptr = ptr + chunk_remainder - 1;
218
219 if(hi_util_in_bounds(start, end, jump_ptr))
220 {
221 chunkPresent = 1;
222 if(iChunkBuf)
223 {
224 memcpy(iChunkBuf, ptr, chunk_remainder);
225 chunkBytesCopied = chunk_remainder;
226 }
227 ptr = jump_ptr + 1;
228 }
229 }
230 else if(iChunkLenState == CHUNK_LEN_INCOMPLETE)
231 {
232 /* Chunk length incompletely read previously, continue to read the remaining bytes */
233 iChunkLen = chunk_remainder;
234 }
235
236 while(hi_util_in_bounds(start, end, ptr))
237 {
238 if(*ptr == '\n')
239 {
240 if(iCheckChunk && iChunkLen != 0)
241 {
242 if (((Session->server_conf->chunk_length != 0)
243 && (iInspectMode == HI_SI_CLIENT_MODE)
244 && (Session->server_conf->chunk_length < iChunkLen)
245 && hi_eo_generate_event(Session, HI_EO_CLIENT_LARGE_CHUNK)))
246 {
247 hi_eo_client_event_log(Session, HI_EO_CLIENT_LARGE_CHUNK,
248 NULL, NULL);
249 }
250
251 if (Session->server_conf->small_chunk_length.size != 0)
252 {
253 if (iChunkLen <= Session->server_conf->small_chunk_length.size)
254 {
255 uint8_t* chunk_count;
256 int (*log_func)(HI_SESSION *, int, void *, void (*)(void *));
257 int event;
258
259 if (iInspectMode == HI_SI_CLIENT_MODE)
260 {
261 if (hsd)
262 chunk_count = &hsd->cli_small_chunk_count;
263 else
264 chunk_count = &stateless_chunk_count;
265 log_func = hi_eo_client_event_log;
266 event = HI_EO_CLIENT_CONSECUTIVE_SMALL_CHUNKS;
267 }
268 else
269 {
270 if (hsd)
271 chunk_count = &hsd->srv_small_chunk_count;
272 else
273 chunk_count = &stateless_chunk_count;
274 log_func = hi_eo_server_event_log;
275 event = HI_EO_SERVER_CONSECUTIVE_SMALL_CHUNKS;
276 }
277
278 (*chunk_count)++;
279 if (hi_eo_generate_event(Session, event)
280 && (*chunk_count >= Session->server_conf->small_chunk_length.num))
281 {
282 log_func(Session, event, NULL, NULL);
283 *chunk_count = 0;
284 }
285 }
286 else
287 {
288 // Reset for non-consecutive small chunks
289 if (iInspectMode == HI_SI_CLIENT_MODE)
290 {
291 if (hsd)
292 hsd->cli_small_chunk_count = 0;
293 else
294 stateless_chunk_count = 0;
295 }
296 else
297 {
298 if (hsd)
299 hsd->srv_small_chunk_count = 0;
300 else
301 stateless_chunk_count = 0;
302 }
303 }
304 }
305
306 SkipBlankAndNewLine(start,end, &ptr);
307
308 if(*ptr == '\n')
309 ptr++;
310
311 iChunkLenState = CHUNK_LEN_DEFAULT;
312
313 if(!hi_util_in_bounds(start, end, ptr))
314 {
315 if(updated_chunk_remainder)
316 *updated_chunk_remainder = iChunkLen;
317 iChunkRemainder = true;
318 break;
319 }
320
321 iDataLen = end - ptr ;
322
323 if( iChunkLen > iDataLen)
324 {
325 if(updated_chunk_remainder)
326 *updated_chunk_remainder = iChunkLen - iDataLen;
327 iChunkRemainder = true;
328 iChunkLen = iDataLen;
329 }
330
331 jump_ptr = ptr + iChunkLen;
332
333 if(jump_ptr <= ptr)
334 {
335 break;
336 }
337
338 /* Since we're doing a memcpy end and jump_ptr can be the same
339 * but hi_util_in_bounds ensures last arg is less than so
340 * subtract 1 from jump_ptr */
341 if(hi_util_in_bounds(start, end, jump_ptr - 1))
342 {
343 chunkPresent = 1;
344 if(iChunkBuf && ((chunkBytesCopied + iChunkLen) <= max_size))
345 {
346 memcpy(iChunkBuf+chunkBytesCopied, ptr, iChunkLen);
347 chunkBytesCopied += iChunkLen;
348 }
349 ptr = jump_ptr;
350
351 if (!hi_util_in_bounds(start, end, ptr))
352 break;
353
354 /* Check to see if the chunks ends - LF or CRLF are valid */
355 if (hi_eo_generate_event(Session, HI_EO_CLIENT_CHUNK_SIZE_MISMATCH)
356 && (*ptr != '\n') && (*ptr != '\r')
357 && ((ptr + 1) < end) && (*(ptr + 1) != '\n'))
358 {
359 hi_eo_client_event_log(Session, HI_EO_CLIENT_CHUNK_SIZE_MISMATCH,
360 NULL, NULL);
361 }
362 }
363 else
364 {
365 /*
366 ** Chunk too large for packet, so we bail
367 */
368 break;
369 }
370 }
371
372 /*
373 ** If we've already evaluated the chunk, or we have a valid delimiter
374 ** for handling new chunks, we reset and starting evaluating possible
375 ** chunk lengths.
376 */
377 if(iCheckChunk || (hi_util_in_bounds(start, end, ptr) && *ptr == '\n'))
378 {
379 iCheckChunk = 1;
380 iChunkLen = 0;
381 iChunkChars = 0;
382 iChunkLenState = CHUNK_LEN_DEFAULT;
383 }
384
385 ptr++;
386 continue;
387 }
388
389 if(iCheckChunk)
390 {
391 if(valid_lookup[*ptr] != HEX_VAL)
392 {
393 if(*ptr == '\r')
394 {
395 while((hi_util_in_bounds(start, end, ptr)) && (*ptr == '\r'))
396 {
397 ptr++;
398 }
399
400 if(!hi_util_in_bounds(start, end, ptr))
401 break;
402
403 if(*ptr == '\n')
404 continue;
405 }
406 else if(*ptr != '\n')
407 {
408 /*
409 ** This is where we skip through the chunk name=value
410 ** field.
411 */
412 ptr = memchr(ptr, '\n', (end-ptr));
413 if(ptr == NULL)
414 {
415 ptr = end;
416 iChunkLenState = CHUNK_LEN_DEFAULT;
417 break;
418 }
419 else
420 continue;
421
422 }
423
424 iCheckChunk = 0;
425 iChunkLen = 0;
426 iChunkChars = 0;
427 iChunkLenState = CHUNK_LEN_DEFAULT;
428 }
429 else
430 {
431 if(iChunkChars >= 8)
432 {
433 if (((Session->server_conf->chunk_length != 0)
434 && (iInspectMode == HI_SI_CLIENT_MODE)
435 && (Session->server_conf->chunk_length < iChunkLen)
436 && hi_eo_generate_event(Session, HI_EO_CLIENT_LARGE_CHUNK)))
437 {
438 hi_eo_client_event_log(Session, HI_EO_CLIENT_LARGE_CHUNK,
439 NULL, NULL);
440 }
441
442 iCheckChunk = 0;
443 iChunkLen = 0;
444 iChunkChars = 0;
445 iChunkLenState = CHUNK_LEN_DEFAULT;
446 }
447 else
448 {
449 iChunkLen <<= 4;
450 iChunkLen |= (unsigned int)(hex_lookup[*ptr]);
451 iChunkChars++;
452 /*
453 ** Chunk length incompletely read i.e CRLF not found yet
454 ** Storing the bytes of chunk length, read till now
455 ** (to handle the split of chunk length itself across different packets)
456 */
457 iChunkLenState = CHUNK_LEN_INCOMPLETE;
458 if(updated_chunk_remainder)
459 *updated_chunk_remainder = iChunkLen;
460 }
461 }
462 }
463
464 ptr++;
465 }
466
467 /*
468 ** If we neither have Chunk data split across packets (or)
469 ** Chunk length itself split across packets then clear
470 */
471 if(!( iChunkRemainder || (iChunkLenState == CHUNK_LEN_INCOMPLETE) ))
472 {
473 if(updated_chunk_remainder)
474 *updated_chunk_remainder = 0;
475 }
476
477 if (hsd)
478 hsd->resp_state.chunk_len_state = iChunkLenState;
479
480 if (chunkPresent )
481 {
482 if(post_end)
483 {
484 *(post_end) = ptr;
485 }
486
487 if(chunkRead)
488 {
489 *chunkRead = chunkBytesCopied;
490 }
491 return 1;
492 }
493
494 return HI_SUCCESS;
495 }
496
497 /*
498 ** NAME
499 ** FindPipelineReq::
500 */
501 /**
502 ** Catch multiple requests per packet, by returning pointer to after the
503 ** end of the request header if there is another request.
504 **
505 ** There are 4 types of "valid" delimiters that we look for. They are:
506 ** "\r\n\r\n"
507 ** "\r\n\n"
508 ** "\n\r\n"
509 ** "\n\n"
510 ** The only patterns that we really only need to look for are:
511 ** "\n\r\n"
512 ** "\n\n"
513 ** The reason being that these two patterns are suffixes of the other
514 ** patterns. So once we find those, we are all good.
515 **
516 ** @param Session pointer to the session
517 ** @param start pointer to the start of text
518 ** @param end pointer to the end of text
519 **
520 ** @return pointer
521 **
522 ** @retval NULL Did not find pipeline request
523 ** @retval !NULL Found another possible request.
524 */
525 static inline const u_char *FindPipelineReq(HI_SESSION *Session,
526 const u_char *start, const u_char *end)
527 {
528 const u_char *p;
529 u_char *offset;
530
531 if(!start || !end)
532 return NULL;
533
534 p = start;
535
536 offset = (u_char*)p;
537
538 /*
539 ** We say end - 6 because we need at least six bytes to verify that
540 ** there is an end to the URI and still a request afterwards. To be
541 ** exact, we should only subtract 1, but we are not interested in a
542 ** 1 byte method, uri, etc.
543 **
544 ** a.k.a there needs to be data after the initial request to inspect
545 ** to make it worth our while.
546 */
547 while(p < (end - 6))
548 {
549 if(*p == '\n')
550 {
551 if(hi_eo_generate_event(Session, Session->server_conf->max_hdr_len)
552 && ((p - offset) >= Session->server_conf->max_hdr_len))
553 {
554 hi_eo_client_event_log(Session, HI_EO_CLIENT_LONG_HDR, NULL, NULL);
555 }
556
557 p++;
558
559 offset = (u_char*)p;
560
561 if(*p < 0x0E)
562 {
563 if(*p == '\r')
564 {
565 p++;
566
567 if(*p == '\n')
568 {
569 return ++p;
570 }
571 }
572 else if(*p == '\n')
573 {
574 return ++p;
575 }
576 }
577 }
578
579 p++;
580 }
581
582 /* Never observed an end-of-field. Maybe it's not there, but the header is long anyway: */
583 if(hi_eo_generate_event(Session, Session->server_conf->max_hdr_len)
584 && ((p - start) >= Session->server_conf->max_hdr_len))
585 {
586 hi_eo_client_event_log(Session, HI_EO_CLIENT_LONG_HDR, NULL, NULL);
587 }
588
589 return NULL;
590 }
591
592 /*
593 ** NAME
594 ** IsHttpVersion::
595 */
596 /**
597 ** This checks that there is a version following a space with in an HTTP
598 ** packet.
599 **
600 ** This function gets called when a whitespace area has ended, and we want
601 ** to know if a version identifier is followed directly after. So we look
602 ** for the rfc standard "HTTP/" and report appropriately. We also need
603 ** to make sure that the function succeeds given an end of buffer, so for
604 ** instance if the buffer ends like " HTT", we still assume that this is
605 ** a valid version identifier because of TCP segmentation.
606 **
607 ** We also check for the 0.9 standard of GET URI\r\n. When we see a \r or
608 ** a \n, then we just return with the pointer still pointing to that char.
609 ** The reason is because on the next loop, we'll do the evaluation that
610 ** we normally do and finish up processing there.
611 **
612 ** @param start pointer to the start of the version identifier
613 ** @param end pointer to the end of the buffer (could be the end of the
614 ** data section, or just to the beginning of the delimiter.
615 **
616 ** @return integer
617 **
618 ** @retval 1 this is an HTTP version identifier
619 ** @retval 0 this is not an HTTP identifier, or bad parameters
620 */
621 int IsHttpVersion(const u_char **ptr, const u_char *end)
622 {
623 static u_char s_acHttpDelimiter[] = "HTTP/";
624 static int s_iHttpDelimiterLen = 5;
625 int len;
626 int iCtr;
627
628 if(*ptr >= end)
629 {
630 return 0;
631 }
632
633 len = end - *ptr;
634 if(len > s_iHttpDelimiterLen)
635 {
636 len = s_iHttpDelimiterLen;
637 }
638
639 /*
640 ** This is where we check for the defunct method again. This method
641 ** allows a request of "GET /index.html \r[\n]". So we need to
642 ** check validate this as a legal identifier.
643 */
644 if(**ptr == '\n' || **ptr == '\r')
645 {
646 /*
647 ** We don't increment the pointer because we check for a legal
648 ** identifier in the delimiter checking. Read the comments for
649 ** setting the defunct variable in these functions.
650 */
651 return 1;
652 }
653
654 for(iCtr = 0; iCtr < len; iCtr++)
655 {
656 if(s_acHttpDelimiter[iCtr] != (u_char)toupper((int)**ptr))
657 {
658 return 0;
659 }
660
661 (*ptr)++;
662 }
663
664 /*
665 ** This means that we match all the chars that we could given the
666 ** remaining length so we should increment the pointer by that much
667 ** since we don't need to inspect this again.
668 */
669
670 /* This pointer is not used again. When 1 is returned it causes
671 * NextNonWhiteSpace to return also. */
672 #if 0
673 (*ptr)++;
674 #endif
675
676 return 1;
677 }
678
679 /*
680 ** NAME
681 ** find_rfc_delimiter::
682 */
683 /**
684 ** Check for standard RFC HTTP delimiter.
685 **
686 ** If we find the delimiter, we return that URI_PTR structures should
687 ** be checked, which bails us out of the loop. If there isn't a RFC
688 ** delimiter, then we bail with a no URI. Otherwise, we check for out
689 ** of bounds.
690 **
691 ** @param ServerConf pointer to the server configuration
692 ** @param start pointer to the start of payload
693 ** @param end pointer to the end of the payload
694 ** @param ptr pointer to the pointer of the current index
695 ** @param uri_ptr pointer to the URI_PTR construct
696 **
697 ** @return integer
698 **
699 ** @retval HI_OUT_OF_BOUNDS
700 ** @retval URI_END end of the URI is found, check URI_PTR.
701 ** @retval NO_URI malformed delimiter, no URI.
702 */
703 int find_rfc_delimiter(HI_SESSION *Session, const u_char *start,
704 const u_char *end, const u_char **ptr, URI_PTR *uri_ptr)
705 {
706 if(*ptr == start || !uri_ptr->uri)
707 return NO_URI;
708
709 /*
710 ** This is important to catch the defunct way of getting URIs without
711 ** specifying "HTTP/major.minor\r\n\r\n". This is a quick way for
712 ** us to tell if we are in that state.
713 **
714 ** We check for a legal identifier to deal with the case of
715 ** "some_of_the_uri_in segmented packet \r\n" in the defunct case.
716 ** Since we find a "valid" (still defunct) delimiter, we account for
717 ** it here, so that we don't set the uri_end to the delimiter.
718 **
719 ** NOTE:
720 ** We now assume that the defunct method is in effect and if there is
721 ** a valid identifier, then we don't update the uri_end because it's
722 ** already been set when the identifier was validated.
723 */
724
725 (*ptr)++;
726 if(!hi_util_in_bounds(start, end, *ptr))
727 {
728 return HI_OUT_OF_BOUNDS;
729 }
730
731 if(**ptr == '\n')
732 {
733 uri_ptr->delimiter = (*ptr)-1;
734
735 if(!uri_ptr->ident)
736 uri_ptr->uri_end = uri_ptr->delimiter;
737
738 return URI_END;
739 }
740
741 return NextNonWhiteSpace(Session, start, end, ptr, uri_ptr);
742 }
743
744 /*
745 ** NAME
746 ** find_non_rfc_delimiter::
747 */
748 /**
749 ** Check for non standard delimiter '\n'.
750 **
751 ** It now appears that apache and iis both take this non-standard
752 ** delimiter. So, we most likely will always look for it, but maybe
753 ** give off a special alert or something.
754 **
755 ** @param ServerConf pointer to the server configuration
756 ** @param start pointer to the start of payload
757 ** @param end pointer to the end of the payload
758 ** @param ptr pointer to the pointer of the current index
759 ** @param uri_ptr pointer to the URI_PTR construct
760 **
761 ** @return integer
762 **
763 ** @retval URI_END delimiter found, end of URI
764 ** @retval NO_URI
765 */
766 int find_non_rfc_delimiter(HI_SESSION *Session, const u_char *start,
767 const u_char *end, const u_char **ptr, URI_PTR *uri_ptr)
768 {
769 HTTPINSPECT_CONF *ServerConf = Session->server_conf;
770
771 if(*ptr == start || !uri_ptr->uri)
772 return NO_URI;
773
774 /*
775 ** This is important to catch the defunct way of getting URIs without
776 ** specifying "HTTP/major.minor\r\n\r\n". This is a quick way for
777 ** us to tell if we are in that state.
778 **
779 ** We check for a legal identifier to deal with the case of
780 ** "some_of_the_uri_in segmented packet \r\n" in the defunct case.
781 ** Since we find a "valid" (still defunct) delimiter, we account for
782 ** it here, so that we don't set the uri_end to the delimiter.
783 **
784 ** NOTE:
785 ** We now assume that the defunct method is in effect and if there is
786 ** a valid identifier, then we don't update the uri_end because it's
787 ** already been set when the identifier was validated.
788 */
789 if(ServerConf->iis_delimiter.on)
790 {
791 if(hi_eo_generate_event(Session, ServerConf->iis_delimiter.alert))
792 {
793 hi_eo_client_event_log(Session, HI_EO_CLIENT_IIS_DELIMITER,
794 NULL, NULL);
795 }
796
797 uri_ptr->delimiter = *ptr;
798
799 if(!uri_ptr->ident)
800 uri_ptr->uri_end = uri_ptr->delimiter;
801
802 return URI_END;
803 }
804
805 /*
806 ** This allows us to do something if the delimiter check is not turned
807 ** on. Most likely this is worthy of an alert, IF it's not normal to
808 ** see these requests.
809 **
810 ** But for now, we always return true.
811 */
812 uri_ptr->delimiter = *ptr;
813
814 if(!uri_ptr->ident)
815 uri_ptr->uri_end = uri_ptr->delimiter;
816
817 return URI_END;
818 }
819
820 /*
821 ** NAME
822 ** NextNonWhiteSpace::
823 */
824 /**
825 ** Update the URI_PTR fields spaces, find the next non-white space char,
826 ** and validate the HTTP version identifier after the spaces.
827 **
828 ** This is the main part of the URI algorithm. This verifies that there
829 ** isn't too many spaces in the data to be a URI, it checks that after the
830 ** second space that there is an HTTP identifier or otherwise it's no good.
831 ** Also, if we've found an identifier after the first whitespace, and
832 ** find another whitespace, there is no URI.
833 **
834 ** The uri and uri_end pointers are updated in this function depending
835 ** on what space we are at, and if the space was followed by the HTTP
836 ** identifier. (NOTE: the HTTP delimiter is no longer "HTTP/", but
837 ** can also be "\r\n", "\n", or "\r". This is the defunct method, and
838 ** we deal with it in the IsHttpVersion and delimiter functions.)
839 **
840 ** @param ServerConf pointer to the server configuration
841 ** @param start pointer to the start of payload
842 ** @param end pointer to the end of the payload
843 ** @param ptr pointer to the pointer of the current index
844 ** @param uri_ptr pointer to the URI_PTR construct
845 **
846 ** @return integer
847 **
848 ** @retval HI_SUCCESS found the next non-whitespace
849 ** @retval HI_OUT_OF_BOUNDS whitespace to the end of the buffer
850 ** @retval URI_END delimiter found, end of URI
851 ** @retval NO_URI
852 */
853 int NextNonWhiteSpace(HI_SESSION *Session, const u_char *start,
854 const u_char *end, const u_char **ptr, URI_PTR *uri_ptr)
855 {
856 HTTPINSPECT_CONF *ServerConf = Session->server_conf;
857 const u_char **start_sp;
858 const u_char **end_sp;
859
860 /*
861 ** Horizontal tab is only accepted by apache web servers, not IIS.
862 ** Some IIS exploits contain a tab (0x09) in the URI, so we don't want
863 ** to treat it as a URI delimiter and cut off the URI.
864 */
865 if ( **ptr == '\t' && !ServerConf->tab_uri_delimiter )
866 {
867 (*ptr)++;
868 return HI_SUCCESS;
869 }
870
871 /*
872 ** Reset the identifier, because we've just seen another space. We
873 ** should only see the identifier immediately after a space followed
874 ** by a delimiter.
875 */
876 if(uri_ptr->ident)
877 {
878 if(ServerConf->non_strict)
879 {
880 /*
881 ** In non-strict mode it is ok to see spaces after the
882 ** "identifier", so we just increment the ptr and return.
883 */
884 (*ptr)++;
885 return HI_SUCCESS;
886 }
887 else
888 {
889 /*
890 ** This means that we've already seen a space and a version
891 ** identifier, and now that we've seen another space, we know
892 ** that this can't be the URI so we just bail out with no
893 ** URI.
894 */
895 return NO_URI;
896 }
897 }
898
899 uri_ptr->ident = NULL;
900
901 /*
902 ** We only check for one here, because both should be set if one
903 ** is.
904 */
905 if(uri_ptr->first_sp_end)
906 {
907 /*
908 ** If the second space has been set, then this means that we have
909 ** seen a third space, which we shouldn't see in the URI so we
910 ** are now done and know there is no URI in this packet.
911 */
912 if(uri_ptr->second_sp_end)
913 {
914 return NO_URI;
915 }
916
917 /*
918 ** Treat whitespace differently at the end of the URI than we did
919 ** at the beginning. Ignore and return if special characters are
920 ** not defined as whitespace after the URI.
921 */
922 if(ServerConf->whitespace[**ptr]
923 && !(ServerConf->whitespace[**ptr] & HI_UI_CONFIG_WS_AFTER_URI))
924 {
925 (*ptr)++;
926 return HI_SUCCESS;
927 }
928
929 /*
930 ** Since we've seen the second space, we need to update the uri ptr
931 ** to the end of the first space, since the URI cannot be before the
932 ** first space.
933 */
934 uri_ptr->uri = uri_ptr->first_sp_end;
935
936 uri_ptr->second_sp_start = *ptr;
937 uri_ptr->second_sp_end = NULL;
938
939 start_sp = &uri_ptr->second_sp_start;
940 end_sp = &uri_ptr->second_sp_end;
941 }
942 else
943 {
944 /*
945 ** This means that there is whitespace at the beginning of the line
946 ** and we unset the URI so we can set it later if need be.
947 **
948 ** This is mainly so we handle data that is all spaces correctly.
949 **
950 ** In the normal case where we've seen text and then the first space,
951 ** we leave the uri ptr pointing at the beginning of the data, and
952 ** set the uri end after we've determined where to put it.
953 */
954 if(start == *ptr)
955 uri_ptr->uri = NULL;
956
957
958 uri_ptr->first_sp_start = *ptr;
959 uri_ptr->first_sp_end = NULL;
960
961 start_sp = &uri_ptr->first_sp_start;
962 end_sp = &uri_ptr->first_sp_end;
963 }
964
965 while(hi_util_in_bounds(start, end, *ptr))
966 {
967 /*
968 ** Check for whitespace
969 */
970 if(**ptr == ' ')
971 {
972 (*ptr)++;
973 continue;
974 }
975 else if(ServerConf->whitespace[**ptr])
976 {
977 if(ServerConf->apache_whitespace.on)
978 {
979 if(hi_eo_generate_event(Session,
980 ServerConf->apache_whitespace.alert))
981 {
982 hi_eo_client_event_log(Session, HI_EO_CLIENT_APACHE_WS,
983 NULL, NULL);
984 }
985 }
986 (*ptr)++;
987 continue;
988 }
989 else
990 {
991 /*
992 ** This sets the sp_end for whatever space delimiter we are on,
993 ** whether that is the first space or the second space.
994 */
995 *end_sp = *ptr;
996
997 if(!IsHttpVersion(ptr, end))
998 {
999 /*
1000 ** This is the default method and what we've been doing
1001 ** since the start of development.
1002 */
1003 if(uri_ptr->second_sp_start)
1004 {
1005 /*
1006 ** There is no HTTP version indentifier at the beginning
1007 ** of the second space, and this means that there is no
1008 ** URI.
1009 */
1010 if(ServerConf->non_strict)
1011 {
1012 /*
1013 ** In non-strict mode, we must assume the URI is
1014 ** between the first and second space, so now
1015 ** that we've seen the second space that's the
1016 ** identifier.
1017 */
1018 uri_ptr->ident = *end_sp;
1019 uri_ptr->uri_end = *start_sp;
1020
1021 return HI_SUCCESS;
1022 }
1023 else
1024 {
1025 /*
1026 ** Since we are in strict mode here, it means that
1027 ** we haven't seen a valid identifier, so there was
1028 ** no URI.
1029 */
1030
1031 return NO_URI;
1032 }
1033 }
1034
1035 /*
1036 ** RESET NECESSARY URI_PTRs HERE. This is the place where
1037 ** the uri is updated. It can only happen once, so do it
1038 ** right here.
1039 **
1040 ** When we get here it means that we have found the end of
1041 ** the FIRST whitespace, and that there was no delimiter,
1042 ** so we reset the uri pointers and other related
1043 ** pointers.
1044 */
1045 uri_ptr->uri = *end_sp;
1046 uri_ptr->uri_end = end;
1047 uri_ptr->norm = NULL;
1048 uri_ptr->last_dir = NULL;
1049 uri_ptr->param = NULL;
1050 uri_ptr->proxy = NULL;
1051 }
1052 else
1053 {
1054 /*
1055 ** Means we found the HTTP version identifier and we reset
1056 ** the uri_end pointer to point to the beginning of the
1057 ** whitespace detected.
1058 **
1059 ** This works for both "uri_is_here HTTP/1.0" and
1060 ** "METHOD uri_is_here HTTP/1.0", so it works when the
1061 ** identifier is after either the first or the second
1062 ** whitespace.
1063 */
1064 uri_ptr->ident = *end_sp;
1065 uri_ptr->uri_end = *start_sp;
1066 }
1067
1068 /*
1069 ** We found a non-whitespace char
1070 */
1071 return HI_SUCCESS;
1072 }
1073 }
1074
1075 /*
1076 ** This is the case where we've seen text and found a whitespace until
1077 ** the end of the buffer. In that case, we set the uri_end to the
1078 ** beginning of the whitespace.
1079 */
1080 uri_ptr->uri_end = *start_sp;
1081
1082 return HI_OUT_OF_BOUNDS;
1083 }
1084
1085 /*
1086 ** NAME
1087 ** SetPercentNorm::
1088 */
1089 /**
1090 ** Check for percent normalization in the URI buffer.
1091 **
1092 ** We don't do much here besides check the configuration, set the pointer,
1093 ** and continue processing.
1094 **
1095 ** @param ServerConf pointer to the server configuration
1096 ** @param start pointer to the start of payload
1097 ** @param end pointer to the end of the payload
1098 ** @param ptr pointer to the pointer of the current index
1099 ** @param uri_ptr pointer to the URI_PTR construct
1100 **
1101 ** @return integer
1102 **
1103 ** @retval HI_SUCCESS function successful
1104 */
1105 int SetPercentNorm(HI_SESSION *Session, const u_char *start,
1106 const u_char *end, const u_char **ptr, URI_PTR *uri_ptr)
1107 {
1108 HTTPINSPECT_CONF *ServerConf = Session->server_conf;
1109
1110 if(!uri_ptr->norm && !uri_ptr->ident)
1111 {
1112 if(ServerConf->ascii.on)
1113 {
1114 uri_ptr->norm = *ptr;
1115 }
1116 }
1117
1118 (*ptr)++;
1119
1120 return HI_SUCCESS;
1121 }
1122
1123 /*
1124 ** NAME
1125 ** CheckLongDir::
1126 */
1127 /**
1128 ** We check the directory length against the global config.
1129 **
1130 ** @param Session pointer to the current session
1131 ** @param uri_ptr pointer to the URI state
1132 ** @param ptr pointer to the current index in buffer
1133 **
1134 ** @return integer
1135 **
1136 ** @retval HI_SUCCESS
1137 */
1138 static inline int CheckLongDir(HI_SESSION *Session, URI_PTR *uri_ptr,
1139 const u_char *ptr)
1140 {
1141 int iDirLen;
1142
1143 /*
1144 ** Check for oversize directory
1145 */
1146 if(Session->server_conf->long_dir &&
1147 uri_ptr->last_dir && !uri_ptr->param)
1148 {
1149 iDirLen = ptr - uri_ptr->last_dir;
1150
1151 if(iDirLen > Session->server_conf->long_dir &&
1152 hi_eo_generate_event(Session, HI_EO_CLIENT_OVERSIZE_DIR))
1153 {
1154 hi_eo_client_event_log(Session, HI_EO_CLIENT_OVERSIZE_DIR,
1155 NULL, NULL);
1156 }
1157 }
1158
1159 return HI_SUCCESS;
1160
1161 }
1162
1163 /*
1164 ** NAME
1165 ** SetSlashNorm::
1166 */
1167 /**
1168 ** Check for any directory traversal or multi-slash normalization.
1169 **
1170 ** @param ServerConf pointer to the server configuration
1171 ** @param start pointer to the start of payload
1172 ** @param end pointer to the end of the payload
1173 ** @param ptr pointer to the pointer of the current index
1174 ** @param uri_ptr pointer to the URI_PTR construct
1175 **
1176 ** @return integer
1177 **
1178 ** @retval HI_SUCCESS function successful
1179 ** @retval HI_OUT_OF_BOUNDS reached the end of the buffer
1180 */
1181 int SetSlashNorm(HI_SESSION *Session, const u_char *start,
1182 const u_char *end, const u_char **ptr, URI_PTR *uri_ptr)
1183 {
1184 HTTPINSPECT_CONF *ServerConf = Session->server_conf;
1185
1186 CheckLongDir(Session, uri_ptr, *ptr);
1187 if( proxy_start)
1188 {
1189 // This is the first dir after http://
1190 if(!uri_ptr->ident && !uri_ptr->last_dir)
1191 proxy_end = *ptr;
1192 }
1193 uri_ptr->last_dir = *ptr;
1194
1195 if(!uri_ptr->norm && !uri_ptr->ident)
1196 {
1197
1198 uri_ptr->norm = *ptr;
1199
1200 (*ptr)++;
1201
1202 if(!hi_util_in_bounds(start,end, *ptr))
1203 {
1204 /*
1205 ** This is the case where there is a slash as the last char
1206 ** and we don't want to normalize that since there really
1207 ** is nothing to normalize.
1208 */
1209 uri_ptr->norm = NULL;
1210 return HI_OUT_OF_BOUNDS;
1211 }
1212
1213 /*
1214 ** Check for directory traversals
1215 */
1216 if(ServerConf->directory.on)
1217 {
1218 if(**ptr == '.')
1219 {
1220 (*ptr)++;
1221 if(!hi_util_in_bounds(start, end, *ptr))
1222 {
1223 uri_ptr->norm = NULL;
1224 return HI_OUT_OF_BOUNDS;
1225 }
1226
1227 if(**ptr == '.' || ** ptr == '/')
1228 {
1229 return HI_SUCCESS;
1230 }
1231 }
1232 }
1233
1234 /*
1235 ** Check for multiple slash normalization
1236 */
1237 if(ServerConf->multiple_slash.on)
1238 {
1239 if(**ptr == '/')
1240 {
1241 return HI_SUCCESS;
1242 }
1243 }
1244
1245 uri_ptr->norm = NULL;
1246 return HI_SUCCESS;
1247 }
1248
1249 (*ptr)++;
1250
1251 return HI_SUCCESS;
1252 }
1253
1254 /*
1255 ** NAME
1256 ** SetBackSlashNorm::
1257 */
1258 /**
1259 ** Check for backslashes and if we need to normalize.
1260 **
1261 ** This really just checks the configuration option, and sets the norm
1262 ** variable if applicable.
1263 **
1264 ** @param ServerConf pointer to the server configuration
1265 ** @param start pointer to the start of payload
1266 ** @param end pointer to the end of the payload
1267 ** @param ptr pointer to the pointer of the current index
1268 ** @param uri_ptr pointer to the URI_PTR construct
1269 **
1270 ** @return integer
1271 **
1272 ** @retval HI_SUCCESS function successful
1273 */
1274 int SetBackSlashNorm(HI_SESSION *Session, const u_char *start,
1275 const u_char *end, const u_char **ptr, URI_PTR *uri_ptr)
1276 {
1277 HTTPINSPECT_CONF *ServerConf = Session->server_conf;
1278
1279 if(!uri_ptr->norm && !uri_ptr->ident)
1280 {
1281 if(ServerConf->iis_backslash.on)
1282 {
1283 uri_ptr->norm = *ptr;
1284 }
1285 }
1286
1287 (*ptr)++;
1288
1289 return HI_SUCCESS;
1290 }
1291
1292 /*
1293 * ** NAME
1294 * ** SetPlusNorm::
1295 * */
1296 /**
1297 * ** Check for "+" and if we need to normalize.
1298 * **
1299 * **
1300 * ** @param ServerConf pointer to the server configuration
1301 * ** @param start pointer to the start of payload
1302 * ** @param end pointer to the end of the payload
1303 * ** @param ptr pointer to the pointer of the current index
1304 * ** @param uri_ptr pointer to the URI_PTR construct
1305 * **
1306 * ** @return integer
1307 * **
1308 * ** @retval HI_SUCCESS function successful
1309 * */
1310
1311
1312 int SetPlusNorm(HI_SESSION *Session, const u_char *start,
1313 const u_char *end, const u_char **ptr, URI_PTR *uri_ptr)
1314 {
1315 if(!uri_ptr->norm && !uri_ptr->ident)
1316 {
1317 uri_ptr->norm = *ptr;
1318 }
1319
1320 (*ptr)++;
1321
1322 return HI_SUCCESS;
1323 }
1324
1325 /*
1326 ** NAME
1327 ** SetBinaryNorm::
1328 */
1329 /**
1330 ** Look for non-ASCII chars in the URI.
1331 **
1332 ** We look for these chars in the URI and set the normalization variable
1333 ** if it's not already set. I think we really only need this for IIS
1334 ** servers, but we may want to know if it's in the URI too.
1335 **
1336 ** @param ServerConf pointer to the server configuration
1337 ** @param start pointer to the start of payload
1338 ** @param end pointer to the end of the payload
1339 ** @param ptr pointer to the pointer of the current index
1340 ** @param uri_ptr pointer to the URI_PTR construct
1341 **
1342 ** @return integer
1343 **
1344 ** @retval HI_SUCCESS function successful
1345 */
1346 int SetBinaryNorm(HI_SESSION *Session, const u_char *start,
1347 const u_char *end, const u_char **ptr, URI_PTR *uri_ptr)
1348 {
1349 if(!uri_ptr->norm && !uri_ptr->ident)
1350 {
1351 uri_ptr->norm = *ptr;
1352 }
1353
1354 (*ptr)++;
1355
1356 return HI_SUCCESS;
1357 }
1358
1359 /*
1360 ** NAME
1361 ** SetParamField::
1362 */
1363 /**
1364 ** This function sets the parameter field as the first '?'. The big thing
1365 ** is that we set the param value, so we don't false positive long dir
1366 ** events when it's really just a long parameter field.
1367 **
1368 ** @param ServerConf pointer to the server configuration
1369 ** @param start pointer to the start of payload
1370 ** @param end pointer to the end of the payload
1371 ** @param ptr pointer to the pointer of the current index
1372 ** @param uri_ptr pointer to the URI_PTR construct
1373 **
1374 ** @return integer
1375 **
1376 ** @retval HI_SUCCESS function successful
1377 */
1378 int SetParamField(HI_SESSION *Session, const u_char *start,
1379 const u_char *end, const u_char **ptr, URI_PTR *uri_ptr)
1380 {
1381 if(!uri_ptr->ident)
1382 {
1383 uri_ptr->param = *ptr;
1384 }
1385
1386 (*ptr)++;
1387
1388 return HI_SUCCESS;
1389 }
1390 /*
1391 ** NAME
1392 ** SetProxy::
1393 */
1394 /**
1395 ** This function checks for an absolute URI in the URI.
1396 **
1397 ** @param ServerConf pointer to the server configuration
1398 ** @param start pointer to the start of payload
1399 ** @param end pointer to the end of the payload
1400 ** @param ptr pointer to the pointer of the current index
1401 ** @param uri_ptr pointer to the URI_PTR construct
1402 **
1403 ** @return integer
1404 **
1405 ** @retval HI_SUCCESS function successful
1406 */
1407 int SetProxy(HI_SESSION *Session, const u_char *start,
1408 const u_char *end, const u_char **ptr, URI_PTR *uri_ptr)
1409 {
1410 HTTPINSPECT_CONF *ServerConf = Session->server_conf;
1411
1412 if(!uri_ptr->ident && !uri_ptr->last_dir)
1413 {
1414 if(hi_util_in_bounds(start, end, ((*ptr)+2)))
1415 {
1416 if(*((*ptr)+1) == '/' && *((*ptr)+2) == '/')
1417 {
1418 if(Session->global_conf->proxy_alert && !ServerConf->allow_proxy)
1419 uri_ptr->proxy = *ptr;
1420 //If we found :// check to see if it is preceeded by http. If so, this is a proxy
1421 proxy_start = (u_char *)SnortStrcasestr((const char *)uri_ptr->uri, (*ptr - uri_ptr->uri), "http");
1422 proxy_end = end;
1423 (*ptr) = (*ptr) + 3;
1424 return HI_SUCCESS;
1425 }
1426 }
1427 }
1428
1429 (*ptr)++;
1430
1431 return HI_SUCCESS;
1432 }
1433
1434 /*
1435 ** NAME
1436 ** SetClientVars::
1437 */
1438 /**
1439 ** This is where we set the HI_CLIENT values that we found during URI
1440 ** discovery. This also covers checking these values for errors.
1441 **
1442 ** @param Client pointer to HI_CLIENT structure
1443 ** @param uri_ptr pointer to the uri data
1444 **
1445 ** @return integer
1446 **
1447 ** @retval HI_NONFATAL_ERR problem with the uri values.
1448 ** @retval HI_SUCCESS values set successfully
1449 */
1450 static int SetClientVars(HI_CLIENT *Client, URI_PTR *uri_ptr, u_int dsize)
1451 {
1452 /*
1453 ** We got here either because we found the delimiter or we are
1454 ** out of bounds.
1455 */
1456
1457 /*
1458 if(uri_ptr->first_sp_start)
1459 printf("** first_start = %c\n", *uri_ptr->first_sp_start);
1460 if(uri_ptr->first_sp_end)
1461 printf("** first_end = %c\n", *uri_ptr->first_sp_end);
1462 if(uri_ptr->second_sp_start)
1463 printf("** second_start = %c\n", *uri_ptr->second_sp_start);
1464 if(uri_ptr->second_sp_end)
1465 printf("** second_end = %c\n", *uri_ptr->second_sp_end);
1466 if(uri_ptr->delimiter)
1467 printf("** delimiter = %c\n", *uri_ptr->delimiter);
1468
1469 if(uri_ptr->uri)
1470 printf("** uri = %c\n", *uri_ptr->uri);
1471 if(uri_ptr->norm)
1472 printf("** norm = %.2x\n", *uri_ptr->norm);
1473 */
1474
1475 /*
1476 ** This means that there was only spaces or delimiters within the
1477 ** complete URI. In this case, there is no valid URI so we just
1478 ** return such.
1479 */
1480 if(uri_ptr->uri == NULL)
1481 {
1482 return HI_NONFATAL_ERR;
1483 }
1484
1485 /*
1486 ** This is where we set the Session variables before moving into more
1487 ** HttpInspect processing. If we don't get to this point, then we don't
1488 ** need to set these variables since we would have aborted with a
1489 ** NONFATAL_ERR.
1490 */
1491 Client->request.uri = uri_ptr->uri;
1492 Client->request.uri_size = uri_ptr->uri_end - uri_ptr->uri;
1493 Client->request.uri_norm = uri_ptr->norm;
1494
1495 /*
1496 ** LAST RESORT:
1497 **
1498 ** This is one of the last checks we do to make sure that we didn't
1499 ** mess up or anything.
1500 */
1501 if(Client->request.uri_size > dsize)
1502 {
1503 /*
1504 ** Bad stuff, let's just bail.
1505 */
1506 return HI_NONFATAL_ERR;
1507 }
1508
1509 /*
1510 printf("** Norm = %s\n", Client->request.uri_norm ? "YES" : "NO");
1511 printf("** URI: |%.*s| size = %u\n", Client->request.uri_size,
1512 Client->request.uri, Client->request.uri_size);
1513 */
1514
1515 return HI_SUCCESS;
1516 }
1517
1518 static inline int hi_client_extract_post(
1519 HI_SESSION *Session, HTTPINSPECT_CONF *ServerConf,
1520 const u_char *ptr, const u_char *end, URI_PTR *result,
1521 int content_length, bool is_chunked, HttpSessionData *hsd)
1522 {
1523 const u_char *start = ptr;
1524 const u_char *post_end = end;
1525
1526 Session->norm_flags &= HI_BODY;
1527
1528 /* Limit search depth */
1529 if (is_chunked)
1530 {
1531 if ( (ServerConf->chunk_length || ServerConf->small_chunk_length.size)
1532 && (CheckChunkEncoding(Session, start, end, &post_end, NULL, 0,
1533 0, NULL, NULL, hsd, HI_SI_CLIENT_MODE) == 1) )
1534 {
1535 result->uri = start;
1536 result->uri_end = post_end;
1537 return POST_END;
1538 }
1539 else
1540 {
1541 return HI_NONFATAL_ERR;
1542 }
1543 }
1544 else if(content_length > 0)
1545 {
1546 if ((post_end - ptr ) > content_length)
1547 {
1548 post_end = ptr + content_length;
1549 }
1550 }
1551 else
1552 {
1553 return HI_NONFATAL_ERR;
1554 }
1555
1556 result->uri = start;
1557 result->uri_end = post_end;
1558
1559 return POST_END;
1560 }
1561
1562
1563 static inline int HTTP_CopyExtraDataToSession(const uint8_t *start, int length, int command_type, HTTP_LOG_STATE *log_state)
1564 {
1565 uint8_t *alt_buf;
1566 uint32_t alt_size;
1567 uint32_t *alt_len;
1568 int ret;
1569
1570 if (length <= 0)
1571 return -1;
1572
1573
1574 switch (command_type)
1575 {
1576 case COPY_URI:
1577 alt_buf = log_state->uri_extracted;
1578 alt_size = MAX_URI_EXTRACTED;
1579 alt_len = &(log_state->uri_bytes);
1580 break;
1581
1582 case COPY_HOSTNAME:
1583 alt_buf = log_state->hostname_extracted;
1584 alt_size = MAX_HOSTNAME;
1585 alt_len = &(log_state->hostname_bytes);
1586 break;
1587
1588 default:
1589 return -1;
1590 }
1591
1592 if(length > (int) alt_size)
1593 length = alt_size;
1594
1595 *alt_len = 0;
1596
1597 ret = SafeMemcpy(alt_buf, start, length, alt_buf, alt_buf + alt_size);
1598
1599 if (ret != SAFEMEM_SUCCESS)
1600 {
1601 return -1;
1602 }
1603
1604 *alt_len += length;
1605
1606 return 0;
1607 }
1608
1609 static inline void HTTP_CopyUri(HTTPINSPECT_CONF *ServerConf, const u_char *start, const u_char *end, HttpSessionData *hsd, int stream_ins, void* ssnptr)
1610 {
1611 int iRet = 0;
1612 const u_char *cur_ptr;
1613
1614 cur_ptr = start;
1615
1616 #if defined(FEAT_OPEN_APPID)
1617 if((ServerConf->log_uri || ServerConf->appid_enabled) && !stream_ins && hsd)
1618 #else
1619 if(ServerConf->log_uri && !stream_ins && hsd)
1620 #endif /* defined(FEAT_OPEN_APPID) */
1621 {
1622 SkipBlankSpace(start,end,&cur_ptr);
1623
1624 start = cur_ptr;
1625 if(!SetLogBuffers(hsd, ssnptr))
1626 {
1627 iRet = HTTP_CopyExtraDataToSession((uint8_t *)start, (end - start), COPY_URI, hsd->log_state);
1628 if(!iRet)
1629 hsd->log_flags |= HTTP_LOG_URI;
1630 }
1631 }
1632 }
1633
1634
1635 static inline int unfold_http_uri(HTTPINSPECT_CONF *ServerConf, const u_char *end, URI_PTR *uri_ptr, HttpSessionData *hsd, int stream_ins, void* ssnptr)
1636 {
1637 uint8_t unfold_buf[DECODE_BLEN];
1638 uint32_t unfold_size =0;
1639 const u_char *p;
1640 int folded = 0;
1641 const char *tmp = NULL;
1642 int iRet = -1;
1643
1644 p = uri_ptr->uri;
1645
1646
1647 sf_unfold_header(p, (end - p), unfold_buf, sizeof(unfold_buf), &unfold_size, 0, &folded);
1648
1649 if( !folded)
1650 {
1651 HTTP_CopyUri(ServerConf, uri_ptr->uri , uri_ptr->uri_end, hsd, stream_ins, ssnptr);
1652 return iRet;
1653 }
1654
1655 tmp = SnortStrnPbrk((const char *)unfold_buf, unfold_size, " \t");
1656
1657 if (tmp != NULL)
1658 {
1659 unfold_size = ((uint8_t *)tmp - unfold_buf);
1660 iRet = 0;
1661 }
1662
1663 p = p + unfold_size;
1664 uri_ptr->uri_end = p;
1665
1666 HTTP_CopyUri(ServerConf, unfold_buf, unfold_buf + unfold_size, hsd, stream_ins, ssnptr);
1667
1668 return iRet;
1669 }
1670
1671
1672 static inline int hi_client_extract_uri(
1673 HI_SESSION *Session, HTTPINSPECT_CONF *ServerConf,
1674 HI_CLIENT * Client, const u_char *start, const u_char *end,
1675 const u_char *ptr, URI_PTR *uri_ptr, HttpSessionData *hsd, int stream_ins, void* ssnptr)
1676 {
1677 int iRet = HI_SUCCESS;
1678 const u_char *tmp;
1679 int uri_copied = 0;
1680
1681 Session->norm_flags &= ~HI_BODY;
1682
1683
1684 /*
1685 ** This loop compares each char to an array of functions
1686 ** (one for each char) and calling that function if there is one.
1687 **
1688 ** If there is no function, then we just increment the char ptr and
1689 ** continue processing.
1690 **
1691 ** If there is a function, we call that function and process. It's
1692 ** important to note that the function that is called is responsible
1693 ** for incrementing the ptr to the next char to be inspected. The
1694 ** loop does not increment the pointer when a function is called to
1695 ** allow the maximum flexibility to the functions.
1696 */
1697
1698 while(hi_util_in_bounds(start, end, ptr))
1699 {
1700 if(!ServerConf->extended_ascii_uri)
1701 {
1702 /* isascii returns non-zero if it is ascii */
1703 if (isascii((int)*ptr) == 0)
1704 {
1705 /* Possible post data or something else strange... */
1706 iRet = URI_END;
1707 /* Find the end of the URI in this case*/
1708 tmp = (const u_char *)SnortStrnPbrk((const char *)ptr, (uri_ptr->uri_end - ptr), " \r\n\t");
1709 if(tmp != NULL)
1710 uri_ptr->uri_end = tmp;
1711
1712 if(!uri_copied)
1713 {
1714 HTTP_CopyUri(ServerConf, uri_ptr->uri , uri_ptr->uri_end, hsd, stream_ins, ssnptr);
1715 }
1716 break;
1717 }
1718 }
1719
1720 if(lookup_table[*ptr] || ServerConf->whitespace[*ptr])
1721 {
1722 if(lookup_table[*ptr])
1723 {
1724 iRet = (lookup_table[*ptr])(Session, start, end,
1725 &ptr, uri_ptr);
1726 }
1727 else
1728 {
1729 iRet = NextNonWhiteSpace(Session, start, end, &ptr, uri_ptr);
1730 }
1731
1732 if(iRet)
1733 {
1734 if(iRet == URI_END)
1735 {
1736 if((*(uri_ptr->uri_end) == '\n') || (*(uri_ptr->uri_end) == '\r') )
1737 {
1738 uri_copied = 1;
1739 if(!unfold_http_uri(ServerConf, end, uri_ptr, hsd, stream_ins, ssnptr ))
1740 {
1741 SkipCRLF(start,end, &ptr);
1742 continue;
1743 }
1744 }
1745 else if(!uri_copied)
1746 {
1747 HTTP_CopyUri(ServerConf, uri_ptr->uri , uri_ptr->uri_end, hsd, stream_ins, ssnptr);
1748 }
1749 /*
1750 ** You found a URI, let's break and check it out.
1751 */
1752 break;
1753 }
1754 else if(iRet == HI_OUT_OF_BOUNDS)
1755 {
1756 /*
1757 ** Means you've reached the end of the buffer. THIS
1758 ** DOESN'T MEAN YOU HAVEN'T FOUND A URI.
1759 */
1760 break;
1761 }
1762 else /* NO_URI */
1763 {
1764 /*
1765 ** Check for chunk encoding, because the delimiter can
1766 ** also be a space, which would look like a pipeline request
1767 ** to us if we don't do this first.
1768 */
1769 if(Session->server_conf->chunk_length || Session->server_conf->small_chunk_length.size)
1770 {
1771 (void)CheckChunkEncoding(Session, start, end, NULL, NULL, 0,
1772 0, NULL, NULL, hsd, HI_SI_CLIENT_MODE);
1773 }
1774
1775 /*
1776 ** We only inspect the packet for another pipeline
1777 ** request if there wasn't a previous pipeline request.
1778 ** The reason that we do this is because
1779 */
1780 if(!Client->request.pipeline_req)
1781 {
1782 /*
1783 ** Just because there was no URI in the first part
1784 ** the packet, doesn't mean that this isn't a
1785 ** pipelined request that has been segmented.
1786 */
1787 if(!ServerConf->no_pipeline)
1788 {
1789 Client->request.pipeline_req = FindPipelineReq(Session, ptr, end);
1790 if(Client->request.pipeline_req)
1791 {
1792 return HI_SUCCESS;
1793 }
1794 }
1795 }
1796
1797 return HI_NONFATAL_ERR;
1798 }
1799 }
1800 else
1801 {
1802 /*
1803 ** This means that we found the next non-whitespace char
1804 ** and since we are already pointed there, so we just
1805 ** continue.
1806 */
1807 continue;
1808 }
1809 }
1810
1811 ptr++;
1812 }
1813 /* No uri in this request. We shouldn't process this request */
1814 if(uri_ptr->uri == uri_ptr->uri_end)
1815 return HI_NONFATAL_ERR;
1816 return iRet;
1817 }
1818
1819 const u_char *extract_http_cookie(const u_char *p, const u_char *end, HEADER_PTR *header_ptr,
1820 HEADER_FIELD_PTR *header_field_ptr)
1821 {
1822 const u_char *crlf;
1823 const u_char *start;
1824 if (header_ptr->cookie.cookie)
1825 {
1826 /* unusal, multiple cookies... alloc new cookie pointer */
1827 COOKIE_PTR *extra_cookie = calloc(1, sizeof(COOKIE_PTR));
1828 hi_stats.mem_used += sizeof(COOKIE_PTR);
1829 if (!extra_cookie)
1830 {
1831 /* Failure to allocate, stop where we are... */
1832 header_ptr->header.uri_end = p;
1833 return p;
1834 }
1835 header_field_ptr->cookie->next = extra_cookie;
1836 header_field_ptr->cookie = extra_cookie;
1837 /* extra_cookie->next = NULL; */ /* removed, since calloc NULLs this. */
1838 }
1839 else
1840 {
1841 header_field_ptr->cookie = &header_ptr->cookie;
1842 }
1843
1844 start = p;
1845 /* skip spaces before : */
1846 SkipBlankSpace(start,end,&p);
1847 if(hi_util_in_bounds(start, end, p) && *p == ':')
1848 {
1849 p++;
1850 SkipBlankSpace(start,end,&p);
1851 }
1852
1853 header_field_ptr->cookie->cookie = p;
1854
1855 {
1856 crlf = (u_char *)SnortStrnStr((const char *)p, end - p, "\n");
1857
1858 /* find a \n */
1859 if (crlf) /* && hi_util_in_bounds(start, end, crlf+1)) bounds is checked in SnortStrnStr */
1860 {
1861 if(*(crlf -1) == '\r')
1862 header_field_ptr->cookie->cookie_end = crlf - 1;
1863 else
1864 header_field_ptr->cookie->cookie_end = crlf;
1865
1866 p = crlf;
1867 }
1868 else
1869 {
1870 header_ptr->header.uri_end = header_field_ptr->cookie->cookie_end = end;
1871 return end;
1872 }
1873 }
1874 return p;
1875 }
1876
1877 Transaction* createNode_tList(sfaddr_t *tmp, uint8_t req_id)
1878 {
1879 Transaction *tList_node = (Transaction*)SnortAlloc(sizeof(Transaction));
1880 hi_stats.mem_used += sizeof(Transaction);
1881 tList_node->true_ip = tmp;
1882 tList_node->tID = req_id;
1883 tList_node->next = NULL;
1884 return tList_node;
1885 }
1886
1887 void insertNode_tList(HttpSessionData* hsd, sfaddr_t *tmp)
1888 {
1889 Transaction *tList_node = createNode_tList(tmp,hsd->http_req_id);
1890 if( hsd->tList_start == NULL && hsd->tList_end == NULL )
1891 {
1892 hsd->tList_start = tList_node;
1893 hsd->tList_end = tList_node;
1894 }
1895 else if ( (hsd->tList_end != NULL) && ( hsd->tList_end->tID != hsd->http_req_id ) )
1896 {
1897 hsd->tList_end->next = tList_node;
1898 hsd->tList_end = tList_node;
1899 }
1900 else
1901 freeTransactionNode(tList_node);
1902 }
1903
1904 const u_char *extract_http_xff(HI_SESSION *Session, const u_char *p, const u_char *start,
1905 const u_char *end, HI_CLIENT_HDR_ARGS *hdrs_args)
1906 {
1907 int num_spaces = 0;
1908 SFIP_RET status;
1909 sfaddr_t *tmp;
1910 char *ipAddr = NULL;
1911 uint8_t unfold_buf[DECODE_BLEN];
1912 uint32_t unfold_size =0;
1913 const u_char *start_ptr, *end_ptr, *cur_ptr;
1914 const u_char *port;
1915 HEADER_PTR *header_ptr;
1916
1917 header_ptr = hdrs_args->hdr_ptr;
1918
1919 if( (hdrs_args->true_clnt_xff & (HDRS_BOTH | XFF_HEADERS)) == HDRS_BOTH)
1920 {
1921 if(hi_eo_generate_event(Session, HI_EO_CLIENT_BOTH_TRUEIP_XFF_HDRS))
1922 {
1923 hi_eo_client_event_log(Session, HI_EO_CLIENT_BOTH_TRUEIP_XFF_HDRS, NULL, NULL);
1924 }
1925
1926 }
1927
1928 SkipBlankSpace(start,end,&p);
1929
1930 if(hi_util_in_bounds(start, end, p) && *p == ':')
1931 {
1932 p++;
1933 CheckSkipAlertMultipleColon(Session, start, end, &p, HI_SI_CLIENT_MODE);
1934
1935 if(hi_util_in_bounds(start, end, p))
1936 sf_unfold_header(p, end-p, unfold_buf, sizeof(unfold_buf), &unfold_size, 0 , &num_spaces);
1937
1938 if(!unfold_size)
1939 {
1940 header_ptr->header.uri_end = end;
1941 return end;
1942 }
1943
1944 if(num_spaces >= Session->server_conf->max_spaces)
1945 {
1946 if(hi_eo_generate_event(Session, Session->server_conf->max_spaces))
1947 {
1948 hi_eo_client_event_log(Session, HI_EO_CLIENT_EXCEEDS_SPACES, NULL, NULL);
1949 }
1950
1951 }
1952
1953 p = p + unfold_size;
1954
1955 start_ptr = unfold_buf;
1956 cur_ptr = unfold_buf;
1957 end_ptr = unfold_buf + unfold_size;
1958 SkipBlankSpace(start_ptr,end_ptr,&cur_ptr);
1959
1960 start_ptr = cur_ptr;
1961 while( cur_ptr < end_ptr )
1962 {
1963 if( *cur_ptr == ' ' || *cur_ptr == '\t' ||
1964 *cur_ptr == ',' )
1965 break;
1966 cur_ptr++;
1967 }
1968
1969 if(cur_ptr - start_ptr)
1970 {
1971 ipAddr = SnortStrndup((const char *)start_ptr, cur_ptr - start_ptr );
1972 }
1973 if(ipAddr)
1974 {
1975 if( (tmp = sfaddr_alloc(ipAddr, &status)) == NULL )
1976 {
1977 port = (u_char *)SnortStrnStr((const char *)start_ptr, (cur_ptr - start_ptr), ":");
1978 if(port)
1979 {
1980 free(ipAddr);
1981 ipAddr = SnortStrndup((const char *)start_ptr, port - start_ptr );
1982 if( !ipAddr)
1983 {
1984 return p;
1985 }
1986 if( (tmp = sfaddr_alloc(ipAddr, &status)) == NULL )
1987 {
1988 if((status != SFIP_ARG_ERR) && (status !=SFIP_ALLOC_ERR))
1989 {
1990 if(hi_eo_generate_event(Session, HI_EO_CLIENT_INVALID_TRUEIP))
1991 {
1992 hi_eo_client_event_log(Session, HI_EO_CLIENT_INVALID_TRUEIP, NULL, NULL);
1993 }
1994 free(ipAddr);
1995 return p;
1996 }
1997 }
1998 }
1999 else if((status != SFIP_ARG_ERR) && (status !=SFIP_ALLOC_ERR))
2000 {
2001 if(hi_eo_generate_event(Session, HI_EO_CLIENT_INVALID_TRUEIP))
2002 {
2003 hi_eo_client_event_log(Session, HI_EO_CLIENT_INVALID_TRUEIP, NULL, NULL);
2004 }
2005 free(ipAddr);
2006 return p;
2007 }
2008 }
2009 /* At this point we have a new/valid IP from the header being processed.
2010 If we are using custom xff headers, check the precedence ranking. */
2011 if( (hdrs_args->true_clnt_xff & XFF_HEADERS) != 0 )
2012 {
2013 /* Have we located any others? */
2014 if( (hdrs_args->top_precedence > 0) &&
2015 (hdrs_args->new_precedence >= hdrs_args->top_precedence) )
2016 {
2017 sfaddr_free( tmp );
2018 free( ipAddr );
2019 return( p );
2020 }
2021
2022 hdrs_args->top_precedence = hdrs_args->new_precedence;
2023
2024 /* if we find the top precedence, no need to continue
2025 looking so clear the XFF_HEADERS_ACTIVE flag. */
2026 if( hdrs_args->top_precedence == XFF_TOP_PRECEDENCE )
2027 hdrs_args->true_clnt_xff &= (~XFF_HEADERS_ACTIVE);
2028 }
2029
2030 /*** If Count reaches to Max limit, we are not store XFF data for further requests in the session.
2031 */
2032 if( ( hdrs_args->sd->tList_count != XFF_MAX_PIPELINE_REQ ) && (hdrs_args->sd->tList_count != 0 ) )
2033 {
2034 /* Check if true-IP for this request is added to the List or not. If not, add this new IP to the List.
2035 If already added true-IP , then check new Ip and current IP is same or not.*/
2036 if ( (hdrs_args->sd->tList_end != NULL) && ( hdrs_args->sd->tList_end->tID == hdrs_args->sd->http_req_id ) )
2037 {
2038 /* If we have already added a true_ip to the List for the currect request,
2039 see if the current IP differs from other XFF Headers IP.
2040 If so , replace it and post an alert saying multiple true IPs in same session.
2041 */
2042 if (!IP_EQUALITY(hdrs_args->sd->tList_end->true_ip, tmp))
2043 {
2044 if (hdrs_args->top_precedence)
2045 {
2046 /* If we've precedence configuration, then add new IP to the List */
2047 sfaddr_free(hdrs_args->sd->tList_end->true_ip);
2048 hdrs_args->sd->tList_end->true_ip = tmp;
2049
2050 }
2051 else if ((hdrs_args->prev_true_clnt_xff & TRUE_CLIENT_IP_HDR) && (hdrs_args->true_clnt_xff & XFF_HDR) )
2052 {
2053 /* when no precedence configured, First X-Forwarded-For IP should print though True-Client-IP present in GET request */
2054 sfaddr_free(hdrs_args->sd->tList_end->true_ip);
2055 hdrs_args->sd->tList_end->true_ip = tmp;
2056 }
2057 else
2058 {
2059 sfaddr_free(tmp);
2060 }
2061
2062 // alert
2063 if( ((hdrs_args->true_clnt_xff & XFF_HEADERS) == 0) &&
2064 hi_eo_generate_event(Session, HI_EO_CLIENT_MULTIPLE_TRUEIP_IN_SESSION))
2065 hi_eo_client_event_log(Session, HI_EO_CLIENT_MULTIPLE_TRUEIP_IN_SESSION, NULL, NULL);
2066 }
2067 else
2068 sfaddr_free(tmp);
2069 }
2070 else
2071 insertNode_tList(hdrs_args->sd, tmp);
2072 }
2073 else
2074 sfaddr_free(tmp);
2075
2076 free(ipAddr);
2077 }
2078
2079 }
2080 else
2081 {
2082 header_ptr->header.uri_end = end;
2083 return end;
2084 }
2085 hdrs_args->prev_true_clnt_xff = hdrs_args->true_clnt_xff;
2086 return p;
2087
2088 }
2089
2090 #if defined(FEAT_OPEN_APPID)
2091 static const u_char *extract_http_client_header(HI_SESSION *Session, const u_char *p, const u_char *start,
2092 const u_char *end, HEADER_PTR *header_ptr, HEADER_LOCATION *headerLoc)
2093 {
2094 int num_spaces = 0;
2095 uint8_t unfold_buf[DECODE_BLEN];
2096 uint32_t unfold_size =0;
2097 const u_char *end_ptr, *cur_ptr;
2098
2099 SkipBlankSpace(start,end,&p);
2100
2101 if(hi_util_in_bounds(start, end, p) && *p == ':')
2102 {
2103 p++;
2104 CheckSkipAlertMultipleColon(Session, start, end, &p, HI_SI_CLIENT_MODE);
2105
2106 if(hi_util_in_bounds(start, end, p))
2107 sf_unfold_header(p, end-p, unfold_buf, sizeof(unfold_buf), &unfold_size, 0 , &num_spaces);
2108
2109 if(!unfold_size)
2110 {
2111 header_ptr->header.uri_end = end;
2112 return end;
2113 }
2114
2115 if(num_spaces >= Session->server_conf->max_spaces)
2116 {
2117 if(hi_eo_generate_event(Session, Session->server_conf->max_spaces))
2118 {
2119 hi_eo_client_event_log(Session, HI_EO_CLIENT_EXCEEDS_SPACES, NULL, NULL);
2120 }
2121 }
2122
2123 p = p + unfold_size;
2124
2125 cur_ptr = unfold_buf;
2126 end_ptr = unfold_buf + unfold_size;
2127 SkipBlankSpace(unfold_buf,end_ptr,&cur_ptr);
2128
2129 {
2130 unsigned field_strlen = (unsigned)(end_ptr - cur_ptr);
2131 if (field_strlen)
2132 {
2133 headerLoc->start = (u_char *)strndup((const char *)cur_ptr, field_strlen);
2134 if (NULL == headerLoc->start)
2135 {
2136 /* treat this out-of-memory error as a parse failure */
2137 header_ptr->header.uri_end = end;
2138 return end;
2139 }
2140 /* now that we have the memory, fill in len. */
2141 headerLoc->len = field_strlen;
2142 }
2143 }
2144 }
2145 else
2146 {
2147 header_ptr->header.uri_end = end;
2148 return end;
2149 }
2150
2151 return p;
2152
2153 }
2154
2155 #endif /* defined(FEAT_OPEN_APPID) */
2156
2157 const u_char *extract_http_hostname(HI_SESSION *Session, const u_char *p, const u_char *start,
2158 const u_char *end, HEADER_PTR *header_ptr, HttpSessionData *hsd)
2159 {
2160 int num_spaces = 0;
2161 uint8_t unfold_buf[DECODE_BLEN];
2162 uint32_t unfold_size =0;
2163 const u_char *start_ptr, *end_ptr, *cur_ptr;
2164 int iRet=0;
2165
2166
2167 SkipBlankSpace(start,end,&p);
2168
2169 if(hi_util_in_bounds(start, end, p) && *p == ':')
2170 {
2171 p++;
2172 CheckSkipAlertMultipleColon(Session, start, end, &p, HI_SI_CLIENT_MODE);
2173
2174 if(hi_util_in_bounds(start, end, p))
2175 sf_unfold_header(p, end-p, unfold_buf, sizeof(unfold_buf), &unfold_size, 0, &num_spaces);
2176
2177 if(!unfold_size)
2178 {
2179 header_ptr->header.uri_end = end;
2180 return end;
2181 }
2182
2183 if(num_spaces >= Session->server_conf->max_spaces)
2184 {
2185 //alert
2186 if(hi_eo_generate_event(Session, Session->server_conf->max_spaces))
2187 {
2188 hi_eo_client_event_log(Session, HI_EO_CLIENT_EXCEEDS_SPACES, NULL, NULL);
2189 }
2190 }
2191 p = p + unfold_size;
2192
2193 start_ptr = unfold_buf;
2194 cur_ptr = unfold_buf;
2195 end_ptr = unfold_buf + unfold_size;
2196 SkipBlankSpace(start_ptr,end_ptr,&cur_ptr);
2197
2198 start_ptr = cur_ptr;
2199
2200 if((end_ptr - start_ptr) >= MAX_HOSTNAME)
2201 {
2202 if(hi_eo_generate_event(Session, HI_EO_CLIENT_LONG_HOSTNAME))
2203 {
2204 hi_eo_client_event_log(Session, HI_EO_CLIENT_LONG_HOSTNAME, NULL, NULL);
2205 }
2206 }
2207
2208 iRet = HTTP_CopyExtraDataToSession((uint8_t *)start_ptr, (end_ptr - start_ptr), COPY_HOSTNAME, hsd->log_state);
2209 if(!iRet)
2210 {
2211 hsd->log_flags |= HTTP_LOG_HOSTNAME;
2212 }
2213 }
2214 else
2215 {
2216 header_ptr->header.uri_end = end;
2217 return end;
2218 }
2219
2220 return p;
2221 }
2222
2223 /* extract_http_range will extract "0-" and flag it as full
2224 * content, when the unit is bytes. Otherwise flag error or
2225 * partial content accordingly. Syntax as follows,
2226 * Range: <units>=<ranges separated with ,>
2227 */
2228 static const u_char *extract_http_range(HI_SESSION *Session,
2229 const u_char *p, const u_char *start, const u_char *end,
2230 HEADER_PTR *header_ptr)
2231 {
2232 u_char *crlf = NULL;
2233 const u_char *unit_start = NULL;
2234 const u_char *unit_end = NULL;
2235
2236 SkipBlankSpace(start,end,&p);
2237 if (hi_util_in_bounds(start, end, p) && *p == ':')
2238 {
2239 p++;
2240 CheckSkipAlertMultipleColon(Session, start, end, &p, HI_SI_CLIENT_MODE);
2241 while (hi_util_in_bounds(start, end, p) && ( *p == ' ' || *p == '\t' || *p == '\n'))
2242 {
2243 p++;
2244 }
2245
2246 if (hi_util_in_bounds(start, end, p))
2247 {
2248 /* extract units and look for '=' token */
2249 unit_start = p;
2250 while (hi_util_in_bounds(start, end, p) && ( *p != '='))
2251 {
2252 p++;
2253 }
2254
2255 if (*p != '=')
2256 {
2257 if (hi_eo_generate_event(Session, HI_EO_CLIENT_INVALID_RANGE_UNIT_FMT))
2258 {
2259 hi_eo_client_event_log(Session, HI_EO_CLIENT_INVALID_RANGE_UNIT_FMT, NULL, NULL);
2260 }
2261 header_ptr->range_flag = RANGE_WITH_REQ_ERROR;
2262 return end;
2263 }
2264
2265 unit_end = (p - 1);
2266 p++;
2267 SkipBlankSpace(start,end,&p);
2268
2269 while (hi_util_in_bounds(start, end, p) && ( *p == ','))
2270 {
2271 p++;
2272 }
2273 SkipBlankSpace(start,end,&p);
2274
2275 if (hi_util_in_bounds(start, end, p))
2276 {
2277 /* Look for "0-" and unit as bytes, then set it as full content */
2278 if (*p == '0')
2279 {
2280 p++;
2281 if (hi_util_in_bounds(start, end, p))
2282 {
2283 if (*p == '-')
2284 {
2285 p++;
2286 if (hi_util_in_bounds(start, end, p) && ( *p == '\r' || *p == '\n'))
2287 {
2288 if (((unit_end - unit_start) >= 5) &&
2289 (!strncasecmp((const char *)unit_start, RANGE_UNIT_BYTE, 5)))
2290 {
2291 header_ptr->range_flag = HTTP_RANGE_WITH_FULL_CONTENT_REQ;
2292 }
2293 else
2294 {
2295 header_ptr->range_flag = RANGE_WITH_PARTIAL_CONTENT_REQ;
2296 }
2297
2298 crlf = (u_char *)SnortStrnStr((const char *)p, end - p, "\n");
2299 if (crlf)
2300 {
2301 p = crlf;
2302 return p;
2303 }
2304 else
2305 {
2306 header_ptr->header.uri_end = end;
2307 return end;
2308 }
2309 }
2310 }
2311 }
2312 }
2313
2314 crlf = (u_char *)SnortStrnStr((const char *)p, end - p, "\n");
2315 if (crlf)
2316 {
2317 p = crlf;
2318 header_ptr->range_flag = RANGE_WITH_PARTIAL_CONTENT_REQ;
2319 return p;
2320 }
2321 else
2322 {
2323 header_ptr->header.uri_end = end;
2324 header_ptr->range_flag = RANGE_WITH_REQ_ERROR;
2325 return end;
2326 }
2327 }
2328 }
2329 }
2330
2331 header_ptr->range_flag = RANGE_WITH_REQ_ERROR;
2332 crlf = (u_char *)SnortStrnStr((const char *)p, end - p, "\n");
2333 if (crlf)
2334 {
2335 p = crlf;
2336 return p;
2337 }
2338 else
2339 {
2340 header_ptr->header.uri_end = end;
2341 return end;
2342 }
2343 }
2344
2345 const u_char *extract_http_content_length(HI_SESSION *Session,
2346 HTTPINSPECT_CONF *ServerConf, const u_char *p, const u_char *start,
2347 const u_char *end, HEADER_PTR *header_ptr, HEADER_FIELD_PTR *header_field_ptr, int iInspectMode)
2348 {
2349 int num_spaces = 0;
2350 const u_char *crlf;
2351 int space_present = 0;
2352 if (header_ptr->content_len.cont_len_start)
2353 {
2354 if(iInspectMode == HI_SI_SERVER_MODE)
2355 {
2356 if(hi_eo_generate_event(Session, HI_EO_SERVER_MULTIPLE_CONTLEN))
2357 {
2358 hi_eo_server_event_log(Session, HI_EO_SERVER_MULTIPLE_CONTLEN, NULL, NULL);
2359 }
2360 }
2361 else if(iInspectMode == HI_SI_CLIENT_MODE)
2362 {
2363 if(hi_eo_generate_event(Session, HI_EO_CLIENT_MULTIPLE_CONTLEN))
2364 {
2365 hi_eo_client_event_log(Session, HI_EO_CLIENT_MULTIPLE_CONTLEN, NULL, NULL);
2366 }
2367 }
2368 header_ptr->header.uri_end = p;
2369 return p;
2370 }
2371 else
2372 {
2373 header_field_ptr->content_len = &header_ptr->content_len;
2374 p = p + 14;
2375 }
2376 /* Move past all the blank spaces. Only tabs and spaces are allowed here */
2377 SkipBlankSpace(start,end,&p);
2378
2379 if(hi_util_in_bounds(start, end, p) && *p == ':')
2380 {
2381 p++;
2382 CheckSkipAlertMultipleColon(Session, start, end, &p, iInspectMode);
2383
2384 if ( hi_util_in_bounds(start, end, p) )
2385 {
2386 if ( ServerConf->profile == HI_APACHE || ServerConf->profile == HI_ALL)
2387 {
2388 SkipWhiteSpace(start,end,&p);
2389 }
2390 else
2391 {
2392 SkipBlankAndNewLine(start,end,&p);
2393 }
2394 if( hi_util_in_bounds(start, end, p))
2395 {
2396 if ( *p == '\n' )
2397 {
2398 while(hi_util_in_bounds(start, end, p))
2399 {
2400 if ( *p == '\n')
2401 {
2402 p++;
2403 while( hi_util_in_bounds(start, end, p) && ( *p == ' ' || *p == '\t'))
2404 {
2405 space_present = 1;
2406 p++;
2407 num_spaces++;
2408 }
2409 if ( space_present )
2410 {
2411 if(num_spaces >= Session->server_conf->max_spaces)
2412 {
2413 if(hi_eo_generate_event(Session, Session->server_conf->max_spaces))
2414 {
2415 hi_eo_client_event_log(Session, HI_EO_CLIENT_EXCEEDS_SPACES, NULL, NULL);
2416 }
2417 }
2418 if ( isdigit((int)*p))
2419 break;
2420 else if(isspace((int)*p) &&
2421 (ServerConf->profile == HI_APACHE || ServerConf->profile == HI_ALL) )
2422 {
2423 SkipWhiteSpace(start,end,&p);
2424 }
2425 else
2426 {
2427 header_field_ptr->content_len->cont_len_start =
2428 header_field_ptr->content_len->cont_len_end = NULL;
2429 header_field_ptr->content_len->len = 0;
2430 return p;
2431 }
2432 }
2433 else
2434 {
2435 header_field_ptr->content_len->cont_len_start =
2436 header_field_ptr->content_len->cont_len_end = NULL;
2437 header_field_ptr->content_len->len = 0;
2438 return p;
2439 }
2440 }
2441 else
2442 break;
2443 }
2444 }
2445 else if(!isdigit((int)*p))
2446 {
2447 header_field_ptr->content_len->cont_len_start =
2448 header_field_ptr->content_len->cont_len_end = NULL;
2449 header_field_ptr->content_len->len = 0;
2450 return p;
2451 }
2452 if(isdigit((int)*p))
2453 {
2454 header_field_ptr->content_len->cont_len_start = p;
2455 p++;
2456 while(hi_util_in_bounds(start, end, p))
2457 {
2458 if(isdigit((int)*p))
2459 {
2460 p++;
2461 continue;
2462 }
2463 else if((*p == '\n')) /* digit followed by \n */
2464 {
2465 header_field_ptr->content_len->cont_len_end = p;
2466 break;
2467 }
2468 else if( (!isdigit((int)*p)) && (!isspace((int)*p))) /* alphabet after digit*/
2469 {
2470 header_field_ptr->content_len->cont_len_start =
2471 header_field_ptr->content_len->cont_len_end = NULL;
2472 header_field_ptr->content_len->len = 0;
2473
2474 crlf = (u_char *)SnortStrnStr((const char *)p, end - p, "\n");
2475 if (crlf)
2476 {
2477 return p;
2478 }
2479 else
2480 {
2481 header_ptr->header.uri_end = end;
2482 return end;
2483 }
2484 }
2485 else
2486 {
2487 if (ServerConf->profile == HI_APACHE || ServerConf->profile == HI_ALL)
2488 {
2489 SkipWhiteSpace(start,end,&p);
2490 }
2491 else
2492 {
2493 SkipBlankAndNewLine(start,end,&p);
2494 }
2495 if ( *p == '\n' )
2496 {
2497 header_field_ptr->content_len->cont_len_end = p;
2498 break;
2499 }
2500 else /*either a "digit digit" or "digit other character" */
2501 {
2502 header_field_ptr->content_len->cont_len_start =
2503 header_field_ptr->content_len->cont_len_end = NULL;
2504 header_field_ptr->content_len->len = 0;
2505 crlf = (u_char *)SnortStrnStr((const char *)p, end - p, "\n");
2506 if (crlf)
2507 {
2508 p = crlf;
2509 return p;
2510 }
2511 else
2512 {
2513 header_ptr->header.uri_end = end;
2514 return end;
2515 }
2516 }
2517 }
2518 }
2519 }
2520 else
2521 {
2522 header_field_ptr->content_len->cont_len_start =
2523 header_field_ptr->content_len->cont_len_end = NULL;
2524 header_field_ptr->content_len->len = 0;
2525 return p;
2526 }
2527 }
2528 }
2529 }
2530 else
2531 {
2532 if(hi_util_in_bounds(start, end, p))
2533 {
2534 crlf = (u_char *)SnortStrnStr((const char *)p, end - p, "\n");
2535 if(crlf)
2536 {
2537 p = crlf;
2538 }
2539 else
2540 {
2541 header_ptr->header.uri_end = end ;
2542 return end;
2543 }
2544 }
2545 }
2546 if ( header_field_ptr->content_len->cont_len_start &&
2547 header_field_ptr->content_len->cont_len_end )
2548 {
2549 char *pcEnd;
2550 uint64_t len;
2551 len = (uint64_t)SnortStrtol((char *)header_field_ptr->content_len->cont_len_start, &pcEnd, 10);
2552
2553 if ( (errno == ERANGE)
2554 || ((char *)header_field_ptr->content_len->cont_len_start == pcEnd)
2555 || (len > 0xFFFFFFFF) )
2556 {
2557 header_field_ptr->content_len->len = 0;
2558 }
2559 else
2560 header_field_ptr->content_len->len = (uint32_t)len;
2561 }
2562 if(!p || !hi_util_in_bounds(start, end, p))
2563 p = end;
2564
2565 return p;
2566 }
2567
2568 static inline bool IsXFFFieldName( HI_CLIENT_HDR_ARGS *hdrs_args,
2569 u_char **pp, const u_char *end,
2570 uint8_t **Field_Names, uint8_t *Field_Length )
2571 {
2572 int i;
2573 int len;
2574 uint8_t *header_ptr;
2575 uint8_t *field_ptr;
2576
2577 i = 0; // index into the list of XFF field names
2578 field_ptr = NULL; // pointer into the active Field_Name entry
2579 header_ptr = *pp; // pointer into the header, will not step past 'end'
2580 len = 0; // len of the matched name entry
2581
2582 while( true )
2583 {
2584 /* If we run off the end of the active table, or table is truncated then
2585 we can stop. We didn't locate a match. */
2586 if( (i >= (HTTP_MAX_XFF_FIELDS)) || (Field_Names[i] == NULL) )
2587 break;
2588
2589 if( field_ptr == NULL ) // didn't start to match any entry
2590 {
2591 /* If the length doesn't permit a match, move on. */
2592 if( (end - *pp) < Field_Length[i] )
2593 {
2594 i += 1;
2595 continue;
2596 }
2597
2598 if( toupper(*header_ptr) == *Field_Names[i] ) // does the first char match?
2599 {
2600 /* set our working pointer to the field name */
2601 field_ptr = (Field_Names[i] + 1);
2602 header_ptr += 1;
2603 len = 1; // We matched one character
2604 continue;
2605 }
2606 i += 1;
2607 }
2608 else
2609 {
2610 /* If we are still matching and we get to the end
2611 of the field name, then we've located a name match */
2612 if( *field_ptr == 0 ) // End of the field name
2613 {
2614 *pp += len; // Step input pointer over what we found
2615 hdrs_args->new_precedence = (i+1); // Precedence started with one
2616 return( true );
2617 }
2618 else
2619 {
2620 /* check for another matching character */
2621 if( toupper(*header_ptr) == *field_ptr )
2622 {
2623 header_ptr += 1;
2624 field_ptr += 1;
2625 len += 1;
2626 }
2627 else
2628 {
2629 header_ptr = *pp; // Back to the start for the name
2630 field_ptr = NULL; // No longer a match
2631 len = 0;
2632 i += 1;
2633 }
2634 }
2635 }
2636 }
2637
2638 return( false );
2639 }
2640
2641 static inline const u_char *extractHeaderFieldValues(HI_SESSION *Session,
2642 HTTPINSPECT_CONF *ServerConf, const u_char *p, const u_char *offset,
2643 const u_char *start, const u_char *end, HI_CLIENT_HDR_ARGS *hdrs_args, void* ssnptr)
2644 {
2645 HttpSessionData *hsd;
2646
2647 hsd = hdrs_args->sd;
2648 if (((p - offset) == 0) && (ServerConf->enable_xff != 0) &&
2649 ((hdrs_args->true_clnt_xff & XFF_HEADERS_ACTIVE) != 0) && (hsd) &&
2650 IsXFFFieldName(hdrs_args, (u_char **)&p, (const u_char *)end,
2651 ServerConf->xff_headers, ServerConf->xff_header_lengths))
2652 {
2653 p = extract_http_xff(Session, p, start, end, hdrs_args);
2654 }
2655 else if (((p - offset) == 0) && ((*p == 'C') || (*p == 'c')))
2656 {
2657 /* Search for 'Cookie' at beginning, starting from current *p */
2658 if ( ServerConf->enable_cookie &&
2659 IsHeaderFieldName(p, end, HEADER_NAME__COOKIE, HEADER_LENGTH__COOKIE))
2660 {
2661 p = extract_http_cookie((p+ HEADER_LENGTH__COOKIE), end, hdrs_args->hdr_ptr, hdrs_args->hdr_field_ptr);
2662 }
2663 else if ( IsHeaderFieldName(p, end, HEADER_NAME__CONTENT_LENGTH, HEADER_LENGTH__CONTENT_LENGTH) )
2664 {
2665 p = extract_http_content_length(Session, ServerConf, p, start,
2666 end, hdrs_args->hdr_ptr, hdrs_args->hdr_field_ptr,HI_SI_CLIENT_MODE);
2667 }
2668 else if ( IsHeaderFieldName(p, end, HEADER_NAME__CONTENT_TYPE, HEADER_LENGTH__CONTENT_TYPE) )
2669 {
2670 Session->client.request.content_type = p;
2671 }
2672 else if ( IsHeaderFieldName(p, end, HEADER_NAME__CONTENT_DISP, HEADER_LENGTH__CONTENT_DISP) )
2673 {
2674 Session->client.request.content_disp = p;
2675 }
2676 }
2677 else if (((p - offset) == 0) && ((*p == 'x') || (*p == 'X') || (*p == 't') || (*p == 'T')))
2678 {
2679 //* The default/legacy behavior with two builtin XFF field names */
2680 if ( (ServerConf->enable_xff) && hsd && ((hdrs_args->true_clnt_xff & XFF_HEADERS) == 0) )
2681 {
2682 if(IsHeaderFieldName(p, end, HEADER_NAME__XFF, HEADER_LENGTH__XFF))
2683 {
2684 hdrs_args->true_clnt_xff |= XFF_HDR;
2685 p = p + HEADER_LENGTH__XFF;
2686 p = extract_http_xff(Session, p, start, end, hdrs_args);
2687 }
2688 else if(IsHeaderFieldName(p, end, HEADER_NAME__TRUE_IP, HEADER_LENGTH__TRUE_IP))
2689 {
2690 hdrs_args->true_clnt_xff |= TRUE_CLIENT_IP_HDR;
2691 p = p + HEADER_LENGTH__TRUE_IP;
2692 p = extract_http_xff(Session, p, start, end, hdrs_args);
2693 }
2694 }
2695 else if ( IsHeaderFieldName(p, end, HEADER_NAME__TRANSFER_ENCODING,
2696 HEADER_LENGTH__TRANSFER_ENCODING) && hsd)
2697 {
2698 if (!hi_paf_disable_te(ssnptr, true))
2699 {
2700 p = p + HEADER_LENGTH__TRANSFER_ENCODING;
2701 p = extract_http_transfer_encoding(Session, hsd, p, start, end, hdrs_args->hdr_ptr, HI_SI_CLIENT_MODE);
2702 }
2703 }
2704 }
2705 #if defined(FEAT_OPEN_APPID)
2706 else if(((p - offset) == 0) && ((*p == 'U') || (*p == 'u')))
2707 {
2708 if ((ServerConf->appid_enabled))
2709 {
2710 if(IsHeaderFieldName(p, end, HEADER_NAME__USER_AGENT, HEADER_LENGTH__USER_AGENT))
2711 {
2712 p = p + HEADER_LENGTH__USER_AGENT;
2713 p = extract_http_client_header(Session, p, start, end, hdrs_args->hdr_ptr, &hdrs_args->hdr_ptr->userAgent);
2714 }
2715 }
2716 }
2717 else if(((p - offset) == 0) && ((*p == 'R') || (*p == 'r')))
2718 {
2719 if ((ServerConf->appid_enabled))
2720 {
2721 if(IsHeaderFieldName(p, end, HEADER_NAME__REFERER, HEADER_LENGTH__REFERER))
2722 {
2723 p = p + HEADER_LENGTH__REFERER;
2724 p = extract_http_client_header(Session, p, start, end, hdrs_args->hdr_ptr, &hdrs_args->hdr_ptr->referer);
2725 }
2726 }
2727 if (IsHeaderFieldName(p, end, HEADER_NAME__RANGE, HEADER_LENGTH__RANGE))
2728 {
2729 p = p + HEADER_LENGTH__RANGE;
2730 p = extract_http_range(Session, p, start, end, hdrs_args->hdr_ptr);
2731 }
2732 }
2733 else if(((p - offset) == 0) && ((*p == 'V') || (*p == 'v')))
2734 {
2735 if ((ServerConf->appid_enabled))
2736 {
2737 if(IsHeaderFieldName(p, end, HEADER_NAME__VIA, HEADER_LENGTH__VIA))
2738 {
2739 p = p + HEADER_LENGTH__VIA;
2740 p = extract_http_client_header(Session, p, start, end, hdrs_args->hdr_ptr, &hdrs_args->hdr_ptr->via);
2741 }
2742 }
2743 }
2744 #else
2745 else if (((p - offset) == 0) && ((*p == 'R') || (*p == 'r')))
2746 {
2747 if (IsHeaderFieldName(p, end, HEADER_NAME__RANGE, HEADER_LENGTH__RANGE))
2748 {
2749 p = p + HEADER_LENGTH__RANGE;
2750 p = extract_http_range(Session, p, start, end, hdrs_args->hdr_ptr);
2751 }
2752 }
2753 #endif /* defined(FEAT_OPEN_APPID) */
2754 else if(((p - offset) == 0) && ((*p == 'H') || (*p == 'h')))
2755 {
2756 if(IsHeaderFieldName(p, end, HEADER_NAME__HOSTNAME, HEADER_LENGTH__HOSTNAME))
2757 {
2758 /* Alert when there are multiple host headers in one request */
2759 if(hdrs_args->hst_name_hdr)
2760 {
2761 if(hi_eo_generate_event(Session, HI_EO_CLIENT_MULTIPLE_HOST_HDRS))
2762 {
2763 hi_eo_client_event_log(Session, HI_EO_CLIENT_MULTIPLE_HOST_HDRS, NULL, NULL);
2764 }
2765 return p;
2766 }
2767 else
2768 {
2769 hdrs_args->hst_name_hdr = 1;
2770 #if defined(FEAT_OPEN_APPID)
2771 if ( hsd && (ServerConf->log_hostname || ServerConf->appid_enabled))
2772 #else
2773 if ( hsd && !(hdrs_args->strm_ins) && (ServerConf->log_hostname))
2774 #endif /* defined(FEAT_OPEN_APPID) */
2775 {
2776 if(!SetLogBuffers(hsd, ssnptr))
2777 {
2778 p = p + HEADER_LENGTH__HOSTNAME;
2779 p = extract_http_hostname(Session, p, start, end, hdrs_args->hdr_ptr, hsd);
2780 }
2781 }
2782 }
2783 }
2784 }
2785 return p;
2786 }
2787
2788
2789 /*
2790 ** NAME
2791 ** hi_client_extract_header::
2792 */
2793 /**
2794 ** Catch multiple requests per packet, by returning pointer to after the
2795 ** end of the request header if there is another request.
2796 **
2797 ** There are 4 types of "valid" delimiters that we look for. They are:
2798 ** "\r\n\r\n"
2799 ** "\r\n\n"
2800 ** "\n\r\n"
2801 ** "\n\n"
2802 ** The only patterns that we really only need to look for are:
2803 ** "\n\r\n"
2804 ** "\n\n"
2805 ** The reason being that these two patterns are suffixes of the other
2806 ** patterns. So once we find those, we are all good.
2807 **
2808 ** @param Session pointer to the session
2809 ** @param start pointer to the start of text
2810 ** @param end pointer to the end of text
2811 **
2812 ** @return pointer
2813 **
2814 ** @retval NULL Did not find pipeline request
2815 ** @retval !NULL Found another possible request.
2816 */
2817 static inline const u_char *hi_client_extract_header(
2818 HI_SESSION *Session, HTTPINSPECT_CONF *ServerConf,
2819 HEADER_PTR *header_ptr, const u_char *start,
2820 const u_char *end, HttpSessionData *hsd, int stream_ins, void* ssnptr)
2821 {
2822 int iRet = HI_SUCCESS;
2823 const u_char *p;
2824 const u_char *offset;
2825 const u_char *crlf;
2826 URI_PTR version_string;
2827 HEADER_FIELD_PTR header_field_ptr ;
2828 HI_CLIENT_HDR_ARGS hdrs_args;
2829 int header_count = 0;
2830 int num_spaces = 0;
2831
2832 if(!start || !end)
2833 return NULL;
2834
2835 p = start;
2836
2837 /*
2838 ** We say end - 6 because we need at least six bytes to verify that
2839 ** there is an end to the URI and still a request afterwards. To be
2840 ** exact, we should only subtract 1, but we are not interested in a
2841 ** 1 byte method, uri, etc.
2842 **
2843 ** a.k.a there needs to be data after the initial request to inspect
2844 ** to make it worth our while.
2845 */
2846 if (p > (end - 6 ))
2847 {
2848 header_ptr->header.uri = NULL;
2849 return p;
2850 }
2851 header_ptr->content_len.len = 0;
2852 header_ptr->is_chunked = false;
2853
2854 header_ptr->header.uri = start;
2855 header_ptr->header.uri_end = end;
2856 hdrs_args.hdr_ptr = header_ptr;
2857 hdrs_args.hdr_field_ptr = &header_field_ptr;
2858 hdrs_args.sd = hsd;
2859 hdrs_args.strm_ins = stream_ins;
2860 hdrs_args.hst_name_hdr = 0;
2861 hdrs_args.true_clnt_xff = (ServerConf->xff_headers[0] != NULL) ? XFF_INIT : 0;
2862 hdrs_args.top_precedence = 0;
2863
2864 SkipBlankSpace(start,end,&p);
2865
2866 /* This is to skip past the HTTP/1.0 (or 1.1) version string */
2867 if (IsHttpVersion(&p, end))
2868 {
2869 memset(&version_string, 0, sizeof(URI_PTR));
2870 version_string.uri = p;
2871
2872 while (hi_util_in_bounds(start, end, p))
2873 {
2874 if(lookup_table[*p] || ServerConf->whitespace[*p])
2875 {
2876 if(lookup_table[*p])
2877 {
2878 iRet = (lookup_table[*p])(Session, start, end, &p, &version_string);
2879 }
2880 else
2881 {
2882 iRet = NextNonWhiteSpace(Session, start, end, &p, &version_string);
2883 }
2884
2885 if(iRet == URI_END)
2886 {
2887 if (*p == '\n')
2888 {
2889 p++;
2890 if (hi_util_in_bounds(start, end, p))
2891 {
2892 version_string.uri_end = p;
2893 }
2894 else
2895 {
2896 return p;
2897 }
2898
2899
2900 if(hi_eo_generate_event(Session, Session->server_conf->max_spaces))
2901 {
2902 num_spaces = SkipBlankSpace(start,end,&p);
2903 if(num_spaces >= Session->server_conf->max_spaces)
2904 {
2905 //alert
2906 hi_eo_client_event_log(Session, HI_EO_CLIENT_EXCEEDS_SPACES, NULL, NULL);
2907 }
2908 }
2909 }
2910 break;
2911 }
2912 else if(iRet == HI_OUT_OF_BOUNDS)
2913 {
2914 return p;
2915 }
2916 }
2917 p++;
2918 }
2919 if (iRet == URI_END)
2920 {
2921 header_ptr->header.uri = version_string.uri_end + 1;
2922 offset = (u_char *)p;
2923 }
2924 else
2925 {
2926 return p;
2927 }
2928 }
2929 else
2930 {
2931 if(hi_eo_generate_event(Session, HI_EO_CLIENT_UNESCAPED_SPACE_URI))
2932 {
2933 hi_eo_client_event_log(Session, HI_EO_CLIENT_UNESCAPED_SPACE_URI,
2934 NULL, NULL);
2935 }
2936 if(p < end)
2937 {
2938 crlf = (u_char *)SnortStrnStr((const char *)p, end - p, "\n");
2939 if(crlf)
2940 {
2941 p = crlf;
2942 }
2943 else
2944 return p;
2945 }
2946 else
2947 {
2948 return p;
2949 }
2950 }
2951
2952 /******* If xff is enabled , then only we are storing original client IP data */
2953 if( ServerConf->enable_xff )
2954 {
2955 if( ScPafEnabled() )
2956 {
2957 if (hsd->http_req_id == XFF_MAX_PIPELINE_REQ )
2958 hsd->http_req_id = 0;
2959
2960 hsd->http_req_id++;
2961 hsd->is_response = 0;
2962
2963 if( hsd->tList_count != XFF_MAX_PIPELINE_REQ )
2964 hsd->tList_count++;
2965 }
2966 }
2967
2968 offset = (u_char*)p;
2969
2970 header_ptr->header.uri = p;
2971
2972 while (hi_util_in_bounds(start, end, p))
2973 {
2974 if(*p == '\n')
2975 {
2976 header_count++;
2977
2978 if(hi_eo_generate_event(Session, Session->server_conf->max_hdr_len)
2979 && ((p - offset) >= Session->server_conf->max_hdr_len))
2980 {
2981 hi_eo_client_event_log(Session, HI_EO_CLIENT_LONG_HDR, NULL, NULL);
2982 }
2983
2984 if (Session->server_conf->max_headers &&
2985 (header_count > Session->server_conf->max_headers))
2986 {
2987 hi_eo_client_event_log(Session, HI_EO_CLIENT_MAX_HEADERS, NULL, NULL);
2988 }
2989
2990 p++;
2991
2992 if(hi_eo_generate_event(Session, Session->server_conf->max_spaces))
2993 {
2994 num_spaces = SkipBlankSpace(start,end,&p);
2995 if(num_spaces >= Session->server_conf->max_spaces)
2996 {
2997 //alert
2998 hi_eo_client_event_log(Session, HI_EO_CLIENT_EXCEEDS_SPACES, NULL, NULL);
2999 }
3000 }
3001
3002 offset = (u_char*)p;
3003
3004 if (!hi_util_in_bounds(start, end, p))
3005 {
3006 header_ptr->header.uri_end = p;
3007 return p;
3008 }
3009
3010 hdrs_args.hdr_ptr = header_ptr;
3011 hdrs_args.hdr_field_ptr = &header_field_ptr;
3012
3013 /* As performance ugly as this may be, need to bounds check p in each of the
3014 * if blocks below to prevent read beyond end of buffer */
3015 if (*p < 0x0E)
3016 {
3017 if(*p == '\r')
3018 {
3019 p++;
3020
3021 if (!hi_util_in_bounds(start, end, p))
3022 {
3023 header_ptr->header.uri_end = p;
3024 return p;
3025 }
3026 else if(*p == '\n')
3027 {
3028 p++;
3029 header_ptr->header.uri_end = p;
3030 return p;
3031 }
3032 }
3033 else if(*p == '\n')
3034 {
3035 p++;
3036 header_ptr->header.uri_end = p;
3037 return p;
3038 }
3039 }
3040 else if ( (p = extractHeaderFieldValues(Session, ServerConf, p, offset, start, end, &hdrs_args, ssnptr)) == end)
3041 {
3042 return end;
3043 }
3044
3045 }
3046 else if( (p == header_ptr->header.uri) &&
3047 (p = extractHeaderFieldValues(Session, ServerConf, p, offset, start, end, &hdrs_args, ssnptr)) == end)
3048 {
3049 return end;
3050 }
3051 if ( *p == '\n') continue;
3052 p++;
3053 }
3054
3055 /* Never observed an end-of-field. Maybe it's not there, but the header is long anyway: */
3056 if(hi_eo_generate_event(Session, Session->server_conf->max_hdr_len)
3057 && ((p - start) >= Session->server_conf->max_hdr_len))
3058 {
3059 hi_eo_client_event_log(Session, HI_EO_CLIENT_LONG_HDR, NULL, NULL);
3060 }
3061
3062 header_ptr->header.uri_end = p;
3063 return p;
3064 }
3065 #define CLR_POST(Client) \
3066 do { \
3067 Client->request.post_raw = NULL;\
3068 Client->request.post_raw_size = 0;\
3069 Client->request.post_norm = NULL; \
3070 } while(0);
3071
3072 #define CLR_HEADER(Client) \
3073 do { \
3074 Client->request.header_raw = NULL;\
3075 Client->request.header_raw_size = 0;\
3076 Client->request.header_norm = NULL; \
3077 Client->request.header_norm_size = 0 ;\
3078 Client->request.cookie.cookie = NULL;\
3079 Client->request.cookie.cookie_end = NULL;\
3080 if(Client->request.cookie.next) { \
3081 COOKIE_PTR *cookie = Client->request.cookie.next; \
3082 do { \
3083 Client->request.cookie.next = Client->request.cookie.next->next; \
3084 free(cookie); \
3085 cookie = Client->request.cookie.next; \
3086 } while(cookie); \
3087 }\
3088 Client->request.cookie.next = NULL;\
3089 Client->request.cookie_norm = NULL;\
3090 Client->request.cookie_norm_size = 0;\
3091 } while(0);
3092
3093 #define CLR_METHOD(Client) \
3094 do { \
3095 Client->request.method_raw = NULL;\
3096 Client->request.method_size = 0; \
3097 Client->request.method = 0 ;\
3098 } while(0);
3099
3100 /*
3101 ** NAME
3102 ** StatelessInspection::
3103 */
3104 /**
3105 ** Find the URI and determine whether the URI needs to be normalized.
3106 **
3107 ** This is a big step in stateless inspection, because we need to reliably
3108 ** find the URI and when possible filter out non-URIs. We do this using a
3109 ** simple state machine that is based on characters found in the data
3110 ** buffer.
3111 **
3112 ** Another important aspect of the stateless inspection is the ability to
3113 ** track and inspect pipelined requests. It is VERY IMPORTANT to reset the
3114 ** pipeline_req pointer, since we don't memset the whole structure. This
3115 ** pointer is reset in the hi_si_session_inspection() function. Check there
3116 ** for more details.
3117 **
3118 ** Normalization is detected when we are looking at the packet for the URI.
3119 ** We look for the following issues:
3120 ** - ////
3121 ** - /../
3122 ** - /./
3123 ** - non-ascii charss
3124 ** - %
3125 ** - \
3126 ** When these things are seen we point to the first occurence in the URI, or
3127 ** where we have to start normalizing. If the URI is updated to a new
3128 ** pointer, then the normalization pointer is reset and we start over.
3129 ** Using this method should cut down the memcpy()s per URI, since most
3130 ** URIs are not normalized.
3131 **
3132 ** If this function returns HI_NONFATAL_ERR, we return out of mode_inspection
3133 ** with an error and abort HttpInspect processing, and continue on with
3134 ** any other processing we do. The Session parameters that we use here are
3135 ** reset in the next time that we do session_inspection, so we don't do
3136 ** any initialization here.
3137 **
3138 ** @param Session pointer to the HTTP session
3139 ** @param data pointer to the start of the packet payload
3140 ** @param dsize size of the payload
3141 **
3142 ** @return integer
3143 **
3144 ** @retval HI_INVALID_ARG invalid argument
3145 ** @retval HI_NONFATAL_ERR no URI detected
3146 ** @retval HI_SUCCESS URI detected and Session pointers updated
3147 */
3148
3149 int StatelessInspection(Packet *p, HI_SESSION *Session, HttpSessionData *hsd, int stream_ins)
3150 {
3151 HTTPINSPECT_CONF *ServerConf;
3152 HTTPINSPECT_CONF *ClientConf;
3153 HI_CLIENT *Client;
3154 URI_PTR method_ptr;
3155 URI_PTR uri_ptr;
3156 URI_PTR post_ptr;
3157 HEADER_PTR header_ptr;
3158 HTTP_CMD_CONF *CmdConf = NULL;
3159 const u_char *start;
3160 const u_char *end;
3161 const u_char *ptr, *mthd;
3162 const u_char *method_end = NULL;
3163 int method_len;
3164 int iRet=0;
3165 char sans_uri = 0;
3166 const unsigned char *data = p->data;
3167 int dsize = p->dsize;
3168 bool http_post_hdr_flush = false;
3169
3170 if(stream_api->get_preproc_flags(p->ssnptr) & PP_HTTPINSPECT_PAF_FLUSH_POST_HDR)
3171 http_post_hdr_flush = true;
3172
3173 if ( ScPafEnabled() )
3174 {
3175 if ( stream_ins && (p->packet_flags & PKT_STREAM_INSERT) )
3176 return HI_INVALID_ARG;
3177 }
3178
3179 ServerConf = Session->server_conf;
3180 if(!ServerConf)
3181 {
3182 return HI_INVALID_ARG;
3183 }
3184
3185 ClientConf = Session->client_conf;
3186 if(!ClientConf)
3187 {
3188 return HI_INVALID_ARG;
3189 }
3190
3191 Client = &Session->client;
3192
3193 memset(&uri_ptr, 0x00, sizeof(URI_PTR));
3194 memset(&post_ptr, 0x00, sizeof(URI_PTR));
3195 memset(&header_ptr, 0x00, sizeof(HEADER_PTR));
3196 memset(&method_ptr, 0x00, sizeof(URI_PTR));
3197
3198 /*
3199 ** We set the starting boundary depending on whether this request is
3200 ** a normal request or a pipeline request. The end boundary is always
3201 ** the same whether it is a pipeline request or other.
3202 */
3203 if(Client->request.pipeline_req)
3204 {
3205 start = Client->request.pipeline_req;
3206 p->packet_flags |= PKT_ALLOW_MULTIPLE_DETECT;
3207 }
3208 else
3209 {
3210 start = data;
3211 }
3212
3213 Client->request.pipeline_req = NULL;
3214
3215 end = data + dsize;
3216 ptr = start;
3217
3218 /*
3219 ** Apache and IIS strike again . . . Thanks Kanatoko
3220 ** - Ignore CRLFs at the beginning of the request.
3221 */
3222 while(hi_util_in_bounds(start, end, ptr))
3223 {
3224 if(*ptr < 0x21)
3225 {
3226 if(*ptr < 0x0E && *ptr > 0x08)
3227 {
3228 ptr++;
3229 continue;
3230 }
3231 else
3232 {
3233 if(*ptr == 0x20)
3234 {
3235 ptr++;
3236 continue;
3237 }
3238 }
3239 }
3240
3241 break;
3242 }
3243
3244 mthd = method_ptr.uri = ptr;
3245
3246 while(hi_util_in_bounds(start, end, mthd))
3247 {
3248 if (ServerConf->whitespace[*mthd] || (lookup_table[*mthd] == NextNonWhiteSpace))
3249 {
3250 method_end = mthd++;
3251 break;
3252 }
3253 if ( !ScPafEnabled() )
3254 {
3255 /* isascii returns non-zero if it is ascii */
3256 if (isascii((int)*mthd) == 0)
3257 {
3258 /* Possible post data or something else strange... */
3259 method_end = mthd++;
3260 break;
3261 }
3262 }
3263 mthd++;
3264 }
3265 if (method_end)
3266 {
3267 method_ptr.uri_end = method_end;
3268 }
3269 else
3270 {
3271 method_ptr.uri_end = end;
3272 }
3273 method_len = method_ptr.uri_end - method_ptr.uri;
3274
3275 /* Need slightly special handling for POST requests
3276 * Since we don't normalize on the request method itself,
3277 * just do a strcmp here and skip the characters below. */
3278 if(method_len == 4 && !strncasecmp("POST", (const char *)method_ptr.uri, 4))
3279 {
3280 if(!http_post_hdr_flush)
3281 hi_stats.post++;
3282 Client->request.method = HI_POST_METHOD;
3283 }
3284 else if(method_len == 3 && !strncasecmp("GET", (const char *)method_ptr.uri, 3))
3285 {
3286 hi_stats.get++;
3287 Client->request.method = HI_GET_METHOD;
3288 }
3289 else if(method_len > 0 && method_len <= MAX_METHOD_LEN )
3290 {
3291 CmdConf = http_cmd_lookup_find(ServerConf->cmd_lookup, (const char *)method_ptr.uri,
3292 method_len, &iRet);
3293
3294 if(iRet == -1 || (CmdConf == NULL))
3295 {
3296 if(!stream_ins && hi_eo_generate_event(Session, HI_EO_CLIENT_UNKNOWN_METHOD))
3297 {
3298 hi_eo_client_event_log(Session, HI_EO_CLIENT_UNKNOWN_METHOD, NULL, NULL);
3299 }
3300
3301 Client->request.method = HI_UNKNOWN_METHOD;
3302 }
3303 }
3304 else
3305 {
3306 if( ScPafEnabled() )
3307 {
3308 /* Might have gotten non-ascii characters, hence no method, but if
3309 * PAF is in use, checking "!stream_ins" equates to PacketHasStartOfPDU()
3310 * so we know we're looking for a method and not guessing that we're in
3311 * the body or somewhere else because we found a non-ascii character */
3312 if (!stream_ins && hi_eo_generate_event(Session, HI_EO_CLIENT_UNKNOWN_METHOD))
3313 hi_eo_client_event_log(Session, HI_EO_CLIENT_UNKNOWN_METHOD, NULL, NULL);
3314 Client->request.method = HI_UNKNOWN_METHOD;
3315 }
3316 else
3317 {
3318 if (!stream_ins && hi_eo_generate_event(Session, HI_EO_CLIENT_UNKNOWN_METHOD))
3319 hi_eo_client_event_log(Session, HI_EO_CLIENT_UNKNOWN_METHOD, NULL, NULL);
3320 sans_uri = 1;
3321 Client->request.method = HI_UNKNOWN_METHOD;
3322 }
3323 }
3324 /* If the Http method is set to UNKNOWN and its not a valid http packet
3325 *(i.e. packet has junk characters ) then we return without populating
3326 * the URI buffers for inspection */
3327
3328 if ((Client->request.method == HI_UNKNOWN_METHOD ) && ScPafEnabled() && !(hi_paf_valid_http(p->ssnptr)))
3329 return HI_INVALID_ARG;
3330
3331 if (!sans_uri )
3332 {
3333 uri_ptr.uri = method_ptr.uri_end;
3334 uri_ptr.uri_end = end;
3335
3336 /* This will set up the URI pointers - effectively extracting
3337 * the URI. */
3338 iRet = hi_client_extract_uri(
3339 Session, ServerConf, Client, start, end, uri_ptr.uri, &uri_ptr, hsd, stream_ins, p->ssnptr);
3340 }
3341
3342 /* Check if the URI exceeds the max header field length */
3343 /* Only check if we succesfully observed a GET or POST method, otherwise,
3344 * this may very well be a POST body */
3345 if(iRet == URI_END &&
3346 hi_eo_generate_event(Session, ServerConf->max_hdr_len) &&
3347 ((uri_ptr.uri_end - uri_ptr.uri) >= ServerConf->max_hdr_len))
3348 {
3349 hi_eo_client_event_log(Session, HI_EO_CLIENT_LONG_HDR, NULL, NULL);
3350 }
3351
3352 #if defined(FEAT_OPEN_APPID)
3353 if(iRet == URI_END &&
3354 (!(ServerConf->uri_only) || ServerConf->appid_enabled))
3355 #else
3356 if(iRet == URI_END &&
3357 !(ServerConf->uri_only))
3358 #endif /* defined(FEAT_OPEN_APPID) */
3359 {
3360 Client->request.method_raw = method_ptr.uri;
3361 Client->request.method_size = method_ptr.uri_end - method_ptr.uri;
3362 ///XXX
3363 ///Copy out the header into its own buffer...,
3364 /// set ptr to end of header.
3365 //
3366 // uri_ptr.end points to end of URI & HTTP version identifier.
3367 if (hi_util_in_bounds(start, end, uri_ptr.uri_end + 1))
3368 {
3369 header_ptr.range_flag = HTTP_RANGE_NONE;
3370 ptr = hi_client_extract_header(Session, ServerConf, &header_ptr, uri_ptr.uri_end+1, end, hsd, stream_ins, p->ssnptr);
3371 if (header_ptr.range_flag != HTTP_RANGE_NONE)
3372 {
3373 Client->request.range_flag = header_ptr.range_flag;
3374 }
3375 else
3376 {
3377 Client->request.range_flag = HTTP_RANGE_NONE;
3378 }
3379 }
3380
3381 if (header_ptr.header.uri)
3382 {
3383 Client->request.header_raw = header_ptr.header.uri;
3384 Client->request.header_raw_size = header_ptr.header.uri_end - header_ptr.header.uri;
3385 if(!Client->request.header_raw_size)
3386 {
3387 CLR_HEADER(Client);
3388 }
3389 else
3390 {
3391 if(!http_post_hdr_flush)
3392 hi_stats.req_headers++;
3393 Client->request.header_norm = header_ptr.header.uri;
3394 if (header_ptr.cookie.cookie)
3395 {
3396 if(!http_post_hdr_flush)
3397 hi_stats.req_cookies++;
3398 Client->request.cookie.cookie = header_ptr.cookie.cookie;
3399 Client->request.cookie.cookie_end = header_ptr.cookie.cookie_end;
3400 Client->request.cookie.next = header_ptr.cookie.next;
3401 Client->request.cookie_norm = header_ptr.cookie.cookie;
3402 }
3403 else
3404 {
3405 Client->request.cookie.cookie = NULL;
3406 Client->request.cookie.cookie_end = NULL;
3407 Client->request.cookie.next = NULL;
3408 Client->request.cookie_norm = NULL;
3409 }
3410 }
3411 }
3412 else
3413 {
3414 CLR_HEADER(Client);
3415 }
3416
3417 /* Got a Content-Length or it's a POST request which may be chunked */
3418 if (header_ptr.content_len.cont_len_start || header_ptr.is_chunked)
3419 {
3420 /* Need to skip over header and get to the body.
3421 * The unaptly named FindPipelineReq will do that. */
3422 ptr = FindPipelineReq(Session, uri_ptr.delimiter, end);
3423 //ptr = FindPipelineReq(Session, ptr, end);
3424 if(ptr)
3425 {
3426 post_ptr.uri = ptr;
3427 post_ptr.uri_end = end;
3428 if((POST_END == hi_client_extract_post(
3429 Session, ServerConf, ptr, end, &post_ptr,
3430 header_ptr.content_len.len, header_ptr.is_chunked, hsd )))
3431 {
3432 if(!http_post_hdr_flush)
3433 hi_stats.post_params++;
3434 Client->request.post_raw = post_ptr.uri;
3435 Client->request.post_raw_size = post_ptr.uri_end - post_ptr.uri;
3436 Client->request.post_norm = post_ptr.norm;
3437 ptr = post_ptr.uri_end;
3438 }
3439 else
3440 {
3441 CLR_POST(Client);
3442 }
3443
3444 if ( ptr < end )
3445 Client->request.pipeline_req = ptr;
3446
3447 if(Client->request.post_raw && (ServerConf->post_extract_size > -1))
3448 {
3449 if(ServerConf->post_extract_size && ((int)Client->request.post_raw_size > ServerConf->post_extract_size))
3450 {
3451 Client->request.post_raw_size = (unsigned int)ServerConf->post_extract_size;
3452 }
3453 }
3454 else
3455 {
3456 CLR_POST(Client);
3457 }
3458 }
3459 else
3460 {
3461 CLR_POST(Client);
3462 ptr = uri_ptr.delimiter;
3463 }
3464 }
3465 else
3466 {
3467 ptr = uri_ptr.delimiter;
3468 }
3469 }
3470 else
3471 {
3472 CLR_HEADER(Client);
3473 CLR_POST(Client);
3474 if (!(Client->request.method & HI_UNKNOWN_METHOD) && method_ptr.uri)
3475 {
3476 Client->request.method_raw = method_ptr.uri;
3477 Client->request.method_size = method_ptr.uri_end - method_ptr.uri;
3478 }
3479 else
3480 {
3481 CLR_METHOD(Client);
3482 return HI_NONFATAL_ERR;
3483 }
3484 ptr = uri_ptr.delimiter;
3485 }
3486 #if defined(FEAT_OPEN_APPID)
3487 //copy over extracted headers for appId
3488 if ((ServerConf->appid_enabled))
3489 {
3490 HttpParsedHeaders headers;
3491 memset(&headers, 0, sizeof(headers));
3492 if (hsd->log_state)
3493 {
3494 if (hsd->log_state->hostname_extracted)
3495 {
3496 headers.host.start = hsd->log_state->hostname_extracted;
3497 headers.host.len = hsd->log_state->hostname_bytes;
3498 }
3499 if (hsd->log_state->uri_extracted)
3500 {
3501 headers.url.start = hsd->log_state->uri_extracted;
3502 headers.url.len = hsd->log_state->uri_bytes;
3503 }
3504 }
3505 if (Client->request.method_raw)
3506 {
3507 headers.method.start = Client->request.method_raw;
3508 headers.method.len = Client->request.method_size;
3509 }
3510
3511 headers.userAgent = header_ptr.userAgent;
3512 headers.referer = header_ptr.referer;
3513 headers.via = header_ptr.via;
3514
3515 /*callback into appId with header values extracted. */
3516 CallHttpHeaderProcessors(p, &headers);
3517
3518 free((void *)headers.userAgent.start);
3519 free((void *)headers.referer.start);
3520 free((void *)headers.via.start);
3521 }
3522
3523 #endif /* defined(FEAT_OPEN_APPID) */
3524
3525 /*
3526 ** Find the next pipeline request, if one is there. If we don't find
3527 ** a pipeline request, then we return NULL here, so this is always
3528 ** set to the correct value.
3529 */
3530 if(!ServerConf->no_pipeline)
3531 {
3532 if(post_ptr.uri)
3533 {
3534 Client->request.pipeline_req =
3535 FindPipelineReq(Session, post_ptr.delimiter, end);
3536 }
3537 else if(!Client->request.pipeline_req && uri_ptr.uri)
3538 {
3539 Client->request.pipeline_req =
3540 FindPipelineReq(Session, ptr, end);
3541 }
3542 }
3543 else
3544 {
3545 Client->request.pipeline_req = NULL;
3546 }
3547
3548 /*
3549 ** We set the HI_CLIENT variables from the URI_PTR structure. We also
3550 ** do error checking for the values in this routine as well.
3551 */
3552 iRet = SetClientVars(Client, &uri_ptr, dsize);
3553 if (iRet)
3554 {
3555 CLR_HEADER(Client);
3556 CLR_POST(Client);
3557 CLR_METHOD(Client);
3558 return iRet;
3559 }
3560 /*
3561 ** One last check for an oversize directory. This gets the long
3562 ** directory when there is a beginning slash and no other slashes
3563 ** until the end of the packet.
3564 **
3565 ** We do this check after we set the variables, just in case there
3566 ** was some errors while setting the variables. This could save some
3567 ** false positives on a bad URI setting.
3568 */
3569 if(uri_ptr.uri_end)
3570 CheckLongDir(Session, &uri_ptr, uri_ptr.uri_end);
3571
3572 /*
3573 ** Check for absolute URI and alert for proxy comm if necessary
3574 **
3575 ** NOTE:
3576 ** Also check ClientConf for proxy configuration so we don't
3577 ** alert on outbound requests from legitimate proxies.
3578 */
3579 if(uri_ptr.proxy && Session->global_conf->proxy_alert &&
3580 (!ServerConf->allow_proxy && !ClientConf->allow_proxy))
3581 {
3582 if(hi_eo_generate_event(Session, HI_EO_CLIENT_PROXY_USE))
3583 {
3584 hi_eo_client_event_log(Session, HI_EO_CLIENT_PROXY_USE,
3585 NULL, NULL);
3586 }
3587 }
3588
3589 return HI_SUCCESS;
3590 }
3591
3592 int hi_client_inspection(Packet *p, void *S, HttpSessionData *hsd, int stream_ins)
3593 {
3594 HI_SESSION *Session;
3595 int iRet;
3596
3597 if(!S || !(p->data) || (p->dsize < 1))
3598 return HI_INVALID_ARG;
3599
3600 Session = (HI_SESSION *)S;
3601
3602 if(!Session->global_conf)
3603 return HI_INVALID_ARG;
3604
3605 iRet = StatelessInspection(p, Session, hsd, stream_ins);
3606 if (iRet)
3607 return iRet;
3608
3609 return HI_SUCCESS;
3610 }
3611
3612 /*
3613 ** NAME
3614 ** hi_client_init::
3615 */
3616 /**
3617 ** Initializes arrays and search algorithms depending on the type of
3618 ** inspection that we are doing.
3619 **
3620 ** @param GlobalConf pointer to the global configuration
3621 **
3622 ** @return integer
3623 **
3624 ** @retval HI_SUCCESS function successful.
3625 */
3626 int hi_client_init(HTTPINSPECT_GLOBAL_CONF *GlobalConf)
3627 {
3628 int iCtr;
3629
3630 memset(lookup_table, 0x00, sizeof(lookup_table));
3631
3632 /*
3633 ** Set up the non-ASCII register for processing.
3634 */
3635 for(iCtr = 0x80; iCtr <= 0xff; iCtr++)
3636 lookup_table[iCtr] = SetBinaryNorm;
3637 lookup_table[0x00] = SetBinaryNorm;
3638
3639 lookup_table[' '] = NextNonWhiteSpace;
3640 lookup_table['\r'] = find_rfc_delimiter;
3641 lookup_table['\n'] = find_non_rfc_delimiter;
3642
3643 /*
3644 ** ASCII encoding
3645 */
3646 lookup_table['%'] = SetPercentNorm;
3647
3648 /*
3649 ** Looking for multiple slashes
3650 */
3651 lookup_table['/'] = SetSlashNorm;
3652
3653 /*
3654 ** Looking for backslashs
3655 */
3656 lookup_table['\\'] = SetBackSlashNorm;
3657
3658 lookup_table['+'] = SetPlusNorm;
3659
3660 /*
3661 ** Look up parameter field, so we don't alert on long directory
3662 ** strings, when the next slash in the parameter field.
3663 */
3664 lookup_table['?'] = SetParamField;
3665
3666 /*
3667 ** Look for absolute URI and proxy communication.
3668 */
3669 lookup_table[':'] = SetProxy;
3670
3671 return HI_SUCCESS;
3672 }
3673
3674
3675
3676 /**
3677 ** This was just an initial testing program for these functions.
3678 */
3679 #ifdef TEST_ME
3680
3681 #include <sys/socket.h>
3682 #include <netinet/in.h>
3683 #include <arpa/inet.h>
3684
3685 int main(int argc, char **argv)
3686 {
3687 HTTPINSPECT_GLOBAL_CONF GlobalConf;
3688 HI_SESSION *Session;
3689 HI_SI_INPUT SiInput;
3690 int iInspectMode = 0;
3691 int iRet;
3692 char data[] = "Hdslkfjaslfkj HTTP/00000.111111";
3693
3694 if((iRet = hi_ui_config_init_global_conf(&GlobalConf)))
3695 {
3696 printf("** error during global init.\n");
3697 return iRet;
3698 }
3699
3700 if((iRet = hi_ui_config_default(&GlobalConf)))
3701 {
3702 printf("** error config default.\n");
3703 return iRet;
3704 }
3705
3706 hi_ui_config_print_config(&GlobalConf);
3707
3708 if((iRet = hi_client_init(&GlobalConf)))
3709 {
3710 printf("** error client init\n");
3711 return iRet;
3712 }
3713
3714 SiInput.sip = inet_addr("1.1.1.1");
3715 SiInput.sip = inet_addr("1.1.1.2");
3716 SiInput.dport = 80;
3717 SiInput.sport = 7880;
3718
3719 if((iRet = hi_si_session_inspection(&GlobalConf, &Session, &SiInput,
3720 &iInspectMode)))
3721 {
3722 printf("** error session inspection\n");
3723 return iRet;
3724 }
3725
3726 printf("** iInspectMode = %d\n", iInspectMode);
3727 if((iRet = hi_mi_mode_inspection(Session, iInspectMode, data,
3728 strlen(data))))
3729 {
3730 printf("** error mode_inspection\n");
3731 return iRet;
3732 }
3733
3734 return 0;
3735 }
3736 #endif
3737
3738