"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