Exemplo n.º 1
0
static INLINE int hi_server_extract_status_code(HI_SESSION *Session, const u_char *start, const u_char *ptr, 
        const u_char *end, URI_PTR *result)
{
    int iRet = HI_SUCCESS;
    SkipBlankSpace(start,end,&ptr);

    result->uri = ptr;

    while(  hi_util_in_bounds(start, end, ptr) )
    {
        if(isdigit((int)*ptr))
        {
            SkipDigits(start, end, &ptr);
            if (  hi_util_in_bounds(start, end, ptr) )
            {
                if(isspace((int)*ptr))
                {
                    result->uri_end = ptr;
                    iRet = STAT_END;
                    return iRet;
                }
                else
                {
                    iRet = HI_NONFATAL_ERR;
                    return iRet;
                }

            }
            else
            {
                iRet = HI_OUT_OF_BOUNDS;
                return iRet;
            }

        }
        else
        {

            if(hi_eo_generate_event(Session, HI_EO_SERVER_INVALID_STATCODE))
            {
                hi_eo_server_event_log(Session, HI_EO_SERVER_INVALID_STATCODE, NULL, NULL);
            }
            ptr++;
        }
    }

    iRet = HI_OUT_OF_BOUNDS;

    return iRet;
}
Exemplo n.º 2
0
static INLINE int hi_server_extract_status_msg( const u_char *start, const u_char *ptr, 
        const u_char *end, URI_PTR *result)
{
    int iRet = HI_SUCCESS;
    SkipBlankSpace(start,end,&ptr);

    if (  hi_util_in_bounds(start, end, ptr) )
    {
        const u_char *crlf = (u_char *)SnortStrnStr((const char *)ptr, end - ptr, "\n");
        result->uri = ptr;
        if (crlf)
        {
            if(crlf[-1] == '\r')
                result->uri_end = crlf - 1;
            else
                result->uri_end = crlf;
            ptr = crlf;
        }
        else
        {
            result->uri_end =end;
        }

        if(result->uri < result->uri_end)
            iRet = STAT_END;
        else
            iRet = HI_OUT_OF_BOUNDS;
    }
    else
        iRet = HI_OUT_OF_BOUNDS;

    return iRet;
}
Exemplo n.º 3
0
static INLINE const u_char *MovePastDelims(const u_char *start, const u_char *end,const u_char *ptr)
{

    while(hi_util_in_bounds(start, end, ptr))
    {
       if(*ptr < 0x21)
        {
            if(*ptr < 0x0E && *ptr > 0x08)
            {
                ptr++;
                continue;
            }
            else
            {
                if(*ptr == 0x20)
                {
                    ptr++;
                    continue;
                                                                                                                                                                    }
            }
        }

        break;
    }

    return ptr;
}
Exemplo n.º 4
0
/**
**  This routine is for getting bytes in the U decode.
**
**  This checks the current bounds and checking for the double decoding.
**  This routine differs from the other Get routines because it returns
**  other values than just END_OF_BUFFER and the char.
**
**  We also return DOUBLE_ENCODING if there is a % and double decoding
**  is turned on.
**
**  When using this function it is important to note that it increments
**  the buffer before checking the bounds.  So, if you call this function
**  in a loop and don't check for END_OF_BUFFER being returned, then
**  you are going to overwrite the buffer.  If I put the check in, you
**  would just be in an never-ending loop.  So just use this correctly.
**
**  @param ServerConf  the server configuration
**  @param start       the start of the URI
**  @param end         the end of the URI
**  @param ptr         the current pointer into the URI
**
**  @return integer
**
**  @retval END_OF_BUFFER    the end of the buffer has been reached.
**  @retval DOUBLE_ENCODING  a percent was found and double decoding is on
**  @retval <= 0xff          an ASCII char
*/
static int GetPtr(HI_SESSION *Session, const u_char *start,
                  const u_char *end, const u_char **ptr, URI_NORM_STATE *norm_state, uint16_t *encodeType)
{
    HTTPINSPECT_CONF *ServerConf = Session->server_conf;

    (*ptr)++;

    if(!hi_util_in_bounds(start, end, *ptr))
        return END_OF_BUFFER;

    if(ServerConf->double_decoding.on && **ptr == '%')
    {
        *encodeType |= HTTP_ENCODE_TYPE__DOUBLE_ENCODE ;
        return DOUBLE_ENCODING;
    }

    return (int)**ptr;
}
Exemplo n.º 5
0
/**
**  Check for standard RFC HTTP delimiter.
**
**  If we find the delimiter, we return that URI_PTR structures should
**  be checked, which bails us out of the loop.  If there isn't a RFC
**  delimiter, then we bail with a no URI.  Otherwise, we check for out
**  of bounds.
**
**  @param ServerConf pointer to the server configuration
**  @param start      pointer to the start of payload
**  @param end        pointer to the end of the payload
**  @param ptr        pointer to the pointer of the current index
**  @param uri_ptr    pointer to the URI_PTR construct
**  
**  @return integer
**  
**  @retval HI_OUT_OF_BOUNDS 
**  @retval URI_END end of the URI is found, check URI_PTR.
**  @retval NO_URI  malformed delimiter, no URI.
*/
static int find_rfc_delimiter(HI_SESSION *Session, u_char *start, 
        u_char *end, u_char **ptr, URI_PTR *uri_ptr)
{
    if(*ptr == start || !uri_ptr->uri)
        return NO_URI;

    /*
    **  This is important to catch the defunct way of getting URIs without
    **  specifying "HTTP/major.minor\r\n\r\n".  This is a quick way for
    **  us to tell if we are in that state.
    **
    **  We check for a legal identifier to deal with the case of
    **  "some_of_the_uri_in segmented packet \r\n" in the defunct case.
    **  Since we find a "valid" (still defunct) delimiter, we account for
    **  it here, so that we don't set the uri_end to the delimiter.
    **
    **  NOTE:
    **  We now assume that the defunct method is in effect and if there is
    **  a valid identifier, then we don't update the uri_end because it's
    **  already been set when the identifier was validated.
    */

    (*ptr)++;
    if(!hi_util_in_bounds(start, end, *ptr))
    {
        return HI_OUT_OF_BOUNDS;
    }
        
    if(**ptr == '\n')
    {
        uri_ptr->delimiter = (*ptr)-1;

        if(!uri_ptr->ident)
            uri_ptr->uri_end = uri_ptr->delimiter;
        
        return URI_END;
    }

    return NO_URI;
}
Exemplo n.º 6
0
/**
**  This function checks for an absolute URI in the URI.
**  
**  @param ServerConf pointer to the server configuration
**  @param start      pointer to the start of payload
**  @param end        pointer to the end of the payload
**  @param ptr        pointer to the pointer of the current index
**  @param uri_ptr    pointer to the URI_PTR construct  
**  
**  @return integer
**  
**  @retval HI_SUCCESS       function successful
*/
static int SetProxy(HI_SESSION *Session, u_char *start,
        u_char *end, u_char **ptr, URI_PTR *uri_ptr)
{
    HTTPINSPECT_CONF *ServerConf = Session->server_conf;

    if(!uri_ptr->ident && !uri_ptr->last_dir)
    {
        if(Session->global_conf->proxy_alert && !ServerConf->allow_proxy)
        {
            if(hi_util_in_bounds(start, end, ((*ptr)+2)))
            {
                if(*((*ptr)+1) == '/' && *((*ptr)+1) == '/')
                {
                    uri_ptr->proxy = *ptr;
                }
            }
        }
    }

    (*ptr)++;

    return HI_SUCCESS;
}
Exemplo n.º 7
0
/**
**  Wrapper for PercentDecode() and handles the return values from
**  PercentDecode().
**
**  This really decodes the chars for UnicodeDecode().  If the char is
**  a percent then we process stuff, otherwise we just increment the
**  pointer and return.
**
**  @param ServerConf  the server configuration
**  @param start       the start of the URI
**  @param end         the end of the URI
**  @param ptr         the current pointer into the URI
**  @param bare_byte   value for a non-ASCII char or a decoded non-ASCII char
**
**  @return integer
**
**  @retval END_OF_BUFFER   End of the buffer has been reached before decode.
**  @retval NON_ASCII_CHAR  End of buffer during decoding, return decoded char.
**  @retval char            return the valid decoded/undecoded char
**
**  @see PercentDecode()
**  @see GetByte()
*/
static int GetChar(HI_SESSION *Session, const u_char *start,
                   const u_char *end, const u_char **ptr, int *bare_byte,
                   URI_NORM_STATE *norm_state, uint16_t *encodeType)
{
    HTTPINSPECT_CONF *ServerConf = Session->server_conf;
    int iNorm;

    if(!hi_util_in_bounds(start, end, *ptr))
        return END_OF_BUFFER;

    iNorm = (int)(**ptr);

    if(**ptr == '%' && ServerConf->ascii.on)
    {
        /*
        **  We go into percent encoding.
        */
        iNorm = PercentDecode(Session, start, end, ptr, norm_state, encodeType);

        /*
        **  If during the course of PercentDecode() we run into the end
        **  of the buffer, then we return early (WITHOUT INCREMENTING ptr)
        **  with a NON_ASCII_CHAR.
        */
        if(iNorm == END_OF_BUFFER)
            return NON_ASCII_CHAR;

        *bare_byte = 0;
    }
    else
    {
        if(ServerConf->bare_byte.on && (u_char)iNorm > 0x7f)
        {
            *encodeType |= HTTP_ENCODE_TYPE__BARE_BYTE;
            if(hi_eo_generate_event(Session, ServerConf->bare_byte.alert) &&
               !norm_state->param)
            {
                hi_eo_client_event_log(Session, HI_EO_CLIENT_BARE_BYTE,
                                       NULL, NULL);
            }

            /*
            **  Set the bare_byte flag
            */
            *bare_byte = 0;
        }
        else
        {
            /*
            **  Set the bare_byte flag negative.
            */
            *bare_byte = 1;
        }
    }

    /*
    **  Increment the buffer.
    */
    (*ptr)++;

    return iNorm;
}
Exemplo n.º 8
0
/**
**  Normalize the URI into the URI normalize buffer.
**
**  This is the routine that users call to normalize the URI.  It iterates
**  through the URI buffer decoding the next character and is then checked
**  for any directory problems before writing the decoded character into the
**  normalizing buffer.
**
**  We return the length of the normalized URI buffer in the variable,
**  uribuf_size.  This value is passed in as the max size of the normalization
**  buffer, which we then set in iMaxUriBufSize for later reference.
**
**  If there was some sort of problem during normalizing we set the normalized
**  URI buffer size to 0 and return HI_NONFATAL_ERR.
**
**  @param ServerConf   the pointer to the server configuration
**  @param uribuf       the pointer to the normalize uri buffer
**  @param uribuf_size  the size of the normalize buffer
**  @param uri          the pointer to the unnormalized uri buffer
**  @param uri_size     the size of the unnormalized uri buffer
**
**  @return integer
**
**  @retval HI_NONFATAL_ERR there was a problem during normalizing, the
**                          uribuf_size is also set to 0
**  @retval HI_SUCCESS      Normalizing the URI was successful
*/
int hi_norm_uri(HI_SESSION *Session, u_char *uribuf, int *uribuf_size,
                const u_char *uri, int uri_size, uint16_t *encodeType)
{
    HTTPINSPECT_CONF *ServerConf;
    int iChar;
    int iRet;
    int iMaxUriBufSize;
    URI_NORM_STATE norm_state;
    u_char *ub_ptr;
    const u_char *ptr;
    const u_char *start;
    const u_char *end;
    u_char *ub_start;
    u_char *ub_end;

    ServerConf = Session->server_conf;

    iMaxUriBufSize = *uribuf_size;

    start = uri;
    end   = uri + uri_size;
    ub_start = uribuf;
    ub_end   = uribuf + iMaxUriBufSize;

    ub_ptr = uribuf;
    ptr    = uri;

    /*
    **  Initialize the URI directory normalization state
    */
    norm_state.dir_count = 0;
    norm_state.param     = NULL;

    while(hi_util_in_bounds(ub_start, ub_end, ub_ptr))
    {
        byte_decoded = false;

        iChar = GetDecodedByte(Session, start, end, &ptr, &norm_state, encodeType);
        if(iChar == END_OF_BUFFER)
            break;

        /*
        **  Look for user-defined Non-Rfc chars.  If we find them
        **  then log an alert.
        */
        if(ServerConf->non_rfc_chars[(u_char)iChar])
        {
            if(hi_eo_generate_event(Session, HI_EO_CLIENT_NON_RFC_CHAR) &&
               !norm_state.param)
            {
                hi_eo_client_event_log(Session, HI_EO_CLIENT_NON_RFC_CHAR,
                                       NULL, NULL);
            }
        }

        iRet = InspectUriChar(Session, iChar, &norm_state, start, end, &ptr,
                              ub_start, ub_end, &ub_ptr, encodeType);
        if (iRet)
        {
            if(iRet == END_OF_BUFFER)
                break;

            /*
            **  This is the default case when we don't want anything to do with
            **  the char besides writing the value into the buffer.
            */
            *ub_ptr = (u_char)iChar;
            ub_ptr++;
        }
    }

    /*
    **  Now that we are done, let's make sure that we didn't just have a
    **  single large directory, with the rest in the next packet.
    */
    CheckLongDir(Session, &norm_state, ub_ptr);

    /*
    **  This means that we got to the end of the URI, so we set the length,
    **  check it, and move on.
    */
    *uribuf_size = ub_ptr - ub_start;

    if(*uribuf_size > uri_size || *uribuf_size < 1)
        return HI_NONFATAL_ERR;

    return HI_SUCCESS;
}
Exemplo n.º 9
0
/**
**  This function inspects the normalized chars for any other processing
**  that we need to do, such as directory traversals.
**
**  The main things that we check for here are '/' and '?'.  There reason
**  for '/' is that we do directory traversals.  If it's a slash, we call
**  the routine that will normalize mutli-slashes, self-referential dirs,
**  and dir traversals.  We do all that processing here and call the
**  appropriate functions.
**
**  The '?' is so we can mark the parameter field, and check for oversize
**  directories one last time.  Once the parameter field is set, we don't
**  do any more oversize directory checks since we aren't in the url
**  any more.
**
**  @param Session      pointer to the current session
**  @param iChar        the char to inspect
**  @param norm_state   the normalization state
**  @param start        the start of the URI buffer
**  @param end          the end of the URI buffer
**  @param ptr          the address of the pointer index into the URI buffer
**  @param ub_start     the start of the norm buffer
**  @param ub_end       the end of the norm buffer
**  @param ub_ptr       the address of the pointer index into the norm buffer
**
**  @return integer
**
**  @retval END_OF_BUFFER    we've reached the end of the URI or norm buffer
**  @retval HI_NONFATAL_ERR  no special char, so just write the char and
**                           increment the ub_ptr.
**  @retval HI_SUCCESS       normalized the special char and already
**                           incremented the buffers.
*/
static inline int InspectUriChar(HI_SESSION *Session, int iChar,
                                 URI_NORM_STATE *norm_state,
                                 const u_char *start, const u_char *end, const u_char **ptr,
                                 u_char *ub_start, u_char *ub_end,
                                 u_char **ub_ptr, uint16_t *encodeType)
{
    HTTPINSPECT_CONF *ServerConf = Session->server_conf;
    int iDir;

    /*
    **  Let's add absolute URI/proxy support everyone.
    */
    if(!norm_state->dir_count && (u_char)iChar == ':' &&
       hi_util_in_bounds(start, end, ((*ptr)+2)))
    {
        if(**ptr == '/' && *((*ptr)+1) == '/')
        {
            /*
            **  We've found absolute vodka.
            */
            if(!hi_util_in_bounds(ub_start, ub_end, ((*ub_ptr)+2)))
                return END_OF_BUFFER;

            /*
            **  Write the :
            */
            **ub_ptr = (u_char)iChar;
            (*ub_ptr)++;

            /*
            **  This increments us past the first slash, so at the next
            **  slash we will track a directory.
            **
            **  The reason we do this is so that an attacker can't trick
            **  us into normalizing a directory away that ended in a :.
            **  For instance, if we got a URL that was separated in by a
            **  packet boundary like this, and we were looking for the
            **  URL real_dir:/file.html:
            **    real_dir://obfuscate_dir/../file.html
            **  we would normalize it with proxy support to:
            **    /file.html
            **  because we never tracked the :// as a valid directory.  So
            **  even though this isn't the best solution, it is the best
            **  we can do given that we are working with stateless
            **  inspection.
            */
            (*ptr)++;

            return HI_SUCCESS;
        }
    }

    /*
    **  Now that we have the "true" byte, we check this byte for other
    **  types of normalization:
    **    -  directory traversals
    **    -  multiple slashes
    */
    if((u_char)iChar == '/')
    {
        /*
        **  First thing we do is check for a long directory.
        */
        CheckLongDir(Session, norm_state, *ub_ptr);

        iDir = DirNorm(Session, start, end, ptr, norm_state, encodeType);

        if(iDir == DIR_TRAV)
        {
            /*
            **  This is the case where we have a directory traversal.
            **
            **  The DirTrav function will reset the ub_ptr to the previous
            **  slash.  After that, we just continue through the loop because
            **  DirNorm has already set ptr to the slash, so we can just
            **  continue on.
            */
            DirTrav(Session,norm_state, ub_start, ub_ptr);
        }
        else
        {
            /*
            **  This is the case where we didn't have a directory traversal,
            **  and we are now just writing the char after the '/'.
            **
            **  We call DirSet, because all this function does is write a
            **  '/' into the buffer and increment the ub_ptr.  We then
            **  check the return code and return END_OF_BUFFER if
            **  needed.
            */
            DirSet(norm_state, ub_ptr);
            if(iDir == END_OF_BUFFER)
                return END_OF_BUFFER;

            /*
            **  We check the bounds before we write the next byte
            */
            if(!hi_util_in_bounds(ub_start, ub_end, *ub_ptr))
                return END_OF_BUFFER;

            /*
            **  Set the char to what we got in DirNorm()
            */
            /*
            **  Look for user-defined Non-Rfc chars.  If we find them
            **  then log an alert.
            */
            if(ServerConf->non_rfc_chars[(u_char)iDir])
            {
                if(hi_eo_generate_event(Session, HI_EO_CLIENT_NON_RFC_CHAR) &&
                   !norm_state->param)
                {
                    hi_eo_client_event_log(Session, HI_EO_CLIENT_NON_RFC_CHAR,
                                           NULL, NULL);
                }
            }

            **ub_ptr = (u_char)iDir;
            (*ub_ptr)++;
        }

        return HI_SUCCESS;
    }

    if((!byte_decoded && (u_char)iChar == '?'))
    {
        /*
        **  We assume that this is the beginning of the parameter field,
        **  and check for a long directory following.  Event though seeing
        **  a question mark does not guarantee the parameter field, thanks
        **  IIS.
        */
        CheckLongDir(Session, norm_state, *ub_ptr);
        norm_state->param = *ub_ptr;
    }

    /*
    **  This is neither char, so we just bail and let the loop finish
    **  for us.
    */
    return HI_NONFATAL_ERR;
}
Exemplo n.º 10
0
/**
**  Check for any directory traversal or multi-slash normalization.
**  
**  @param ServerConf pointer to the server configuration
**  @param start      pointer to the start of payload
**  @param end        pointer to the end of the payload
**  @param ptr        pointer to the pointer of the current index
**  @param uri_ptr    pointer to the URI_PTR construct  
**  
**  @return integer
**  
**  @retval HI_SUCCESS       function successful
**  @retval HI_OUT_OF_BOUNDS reached the end of the buffer
*/
static int SetSlashNorm(HI_SESSION *Session, u_char *start,
        u_char *end, u_char **ptr, URI_PTR *uri_ptr)
{
    HTTPINSPECT_CONF *ServerConf = Session->server_conf;

    CheckLongDir(Session, uri_ptr, *ptr);
    uri_ptr->last_dir = *ptr;

    if(!uri_ptr->norm && !uri_ptr->ident)
    {

        uri_ptr->norm = *ptr;

        (*ptr)++;

        if(!hi_util_in_bounds(start,end, *ptr))
        {
            /*
            **  This is the case where there is a slash as the last char
            **  and we don't want to normalize that since there really
            **  is nothing to normalize.
            */
            uri_ptr->norm = NULL;
            return HI_OUT_OF_BOUNDS;
        }

        /*
        **  Check for directory traversals
        */
        if(ServerConf->directory.on)
        {
            if(**ptr == '.')
            {
                (*ptr)++;
                if(!hi_util_in_bounds(start, end, *ptr))
                {
                    uri_ptr->norm = NULL;
                    return HI_OUT_OF_BOUNDS;
                }

                if(**ptr == '.' || ** ptr == '/')
                {
                    return HI_SUCCESS;
                }
            }
        }

        /*
        **  Check for multiple slash normalization
        */
        if(ServerConf->multiple_slash.on)
        {
            if(**ptr == '/')
            {
                return HI_SUCCESS;
            }
        }

        uri_ptr->norm = NULL;
        return HI_SUCCESS;
    }

    (*ptr)++;

    return HI_SUCCESS;
}
Exemplo n.º 11
0
/**
**  Update the URI_PTR fields spaces, find the next non-white space char,
**  and validate the HTTP version identifier after the spaces.
**  
**  This is the main part of the URI algorithm.  This verifies that there
**  isn't too many spaces in the data to be a URI, it checks that after the
**  second space that there is an HTTP identifier or otherwise it's no good.
**  Also, if we've found an identifier after the first whitespace, and
**  find another whitespace, there is no URI.
**  
**  The uri and uri_end pointers are updated in this function depending
**  on what space we are at, and if the space was followed by the HTTP
**  identifier.  (NOTE:  the HTTP delimiter is no longer "HTTP/", but
**  can also be "\r\n", "\n", or "\r".  This is the defunct method, and
**  we deal with it in the IsHttpVersion and delimiter functions.)
**  
**  @param ServerConf pointer to the server configuration
**  @param start      pointer to the start of payload
**  @param end        pointer to the end of the payload
**  @param ptr        pointer to the pointer of the current index
**  @param uri_ptr    pointer to the URI_PTR construct  
**  
**  @return integer
**  
**  @retval HI_SUCCESS       found the next non-whitespace
**  @retval HI_OUT_OF_BOUNDS whitespace to the end of the buffer
**  @retval URI_END          delimiter found, end of URI
**  @retval NO_URI
*/
static int NextNonWhiteSpace(HI_SESSION *Session, u_char *start, 
        u_char *end, u_char **ptr, URI_PTR *uri_ptr)
{
    HTTPINSPECT_CONF *ServerConf = Session->server_conf;
    u_char **start_sp;
    u_char **end_sp;

    /*
    **  Reset the identifier, because we've just seen another space.  We
    **  should only see the identifier immediately after a space followed
    **  by a delimiter.
    */
    if(uri_ptr->ident)
    {
        if(ServerConf->non_strict)
        {
            /*
            **  In non-strict mode it is ok to see spaces after the
            **  "identifier", so we just increment the ptr and return.
            */
            (*ptr)++;
            return HI_SUCCESS;
        }
        else
        {
            /*
            **  This means that we've already seen a space and a version
            **  identifier, and now that we've seen another space, we know
            **  that this can't be the URI so we just bail out with no
            **  URI.
            */
            return NO_URI;
        }
    }

    uri_ptr->ident = NULL;

    /*
    **  We only check for one here, because both should be set if one
    **  is.
    */
    if(uri_ptr->first_sp_end)
    {
        /*
        **  If the second space has been set, then this means that we have   
        **  seen a third space, which we shouldn't see in the URI so we
        **  are now done and know there is no URI in this packet.
        */
        if(uri_ptr->second_sp_end)
        {
            return NO_URI;
        }

        /*
        **  Since we've seen the second space, we need to update the uri ptr
        **  to the end of the first space, since the URI cannot be before the
        **  first space.
        */
        uri_ptr->uri = uri_ptr->first_sp_end;

        uri_ptr->second_sp_start = *ptr;
        uri_ptr->second_sp_end = NULL;

        start_sp = &uri_ptr->second_sp_start;
        end_sp = &uri_ptr->second_sp_end;
    }
    else
    {
        /*
        **  This means that there is whitespace at the beginning of the line
        **  and we unset the URI so we can set it later if need be.
        **
        **  This is mainly so we handle data that is all spaces correctly.
        **  
        **  In the normal case where we've seen text and then the first space,
        **  we leave the uri ptr pointing at the beginning of the data, and
        **  set the uri end after we've determined where to put it.
        */
        if(start == *ptr)
            uri_ptr->uri = NULL;


        uri_ptr->first_sp_start = *ptr;
        uri_ptr->first_sp_end = NULL;

        start_sp = &uri_ptr->first_sp_start;
        end_sp = &uri_ptr->first_sp_end;
    }

    while(hi_util_in_bounds(start, end, *ptr))
    {
        /*
        **  Check for whitespace
        */
        if(**ptr == ' ')
        {
            (*ptr)++;
            continue;
        }
        else if((**ptr == '\t'))
        {
            if(ServerConf->apache_whitespace.on)
            {
                if(hi_eo_generate_event(Session, 
                                        ServerConf->apache_whitespace.alert))
                {
                    hi_eo_client_event_log(Session, HI_EO_CLIENT_APACHE_WS,
                                           NULL, NULL);
                }

                (*ptr)++;
                continue;
            }
            else
            {
                return NO_URI;
            }
        }
        else
        {
            /*
            **  This sets the sp_end for whatever space delimiter we are on,
            **  whether that is the first space or the second space.
            */
            *end_sp = *ptr;

            if(!IsHttpVersion(ptr, end))
            {
                /*
                **  This is the default method and what we've been doing
                **  since the start of development.
                */
                if(uri_ptr->second_sp_start)
                {
                    /*
                    **  There is no HTTP version indentifier at the beginning
                    **  of the second space, and this means that there is no
                    **  URI.
                    */
                    if(ServerConf->non_strict)
                    {
                        /*
                        **  In non-strict mode, we must assume the URI is
                        **  between the first and second space, so now
                        **  that we've seen the second space that's the
                        **  identifier.
                        */
                        uri_ptr->ident  = *end_sp;
                        uri_ptr->uri_end = *start_sp;
                    
                        return HI_SUCCESS;
                    }
                    else
                    {
                        /*
                        **  Since we are in strict mode here, it means that
                        **  we haven't seen a valid identifier, so there was
                        **  no URI.
                        */
                        return NO_URI;
                    }
                }

                /*
                **  RESET NECESSARY URI_PTRs HERE.  This is the place where
                **  the uri is updated.  It can only happen once, so do it
                **  right here.
                **
                **  When we get here it means that we have found the end of
                **  the FIRST whitespace, and that there was no delimiter,
                **  so we reset the uri pointers and other related 
                **  pointers.
                */
                uri_ptr->uri      = *end_sp;
                uri_ptr->uri_end  = end;
                uri_ptr->norm     = NULL;
                uri_ptr->last_dir = NULL;
                uri_ptr->param    = NULL;
                uri_ptr->proxy    = NULL;
            }
            else
            {
                /*
                **  Means we found the HTTP version identifier and we reset
                **  the uri_end pointer to point to the beginning of the
                **  whitespace detected.
                **
                **  This works for both "uri_is_here HTTP/1.0" and
                **  "METHOD uri_is_here HTTP/1.0", so it works when the
                **  identifier is after either the first or the second
                **  whitespace.
                */
                uri_ptr->ident   = *end_sp;
                uri_ptr->uri_end = *start_sp;
            }

            /*
            **  We found a non-whitespace char
            */
            return HI_SUCCESS;
        }
    }

    /*
    **  This is the case where we've seen text and found a whitespace until
    **  the end of the buffer.  In that case, we set the uri_end to the
    **  beginning of the whitespace.
    */
    uri_ptr->uri_end = *start_sp;

    return HI_OUT_OF_BOUNDS;
}
Exemplo n.º 12
0
/**
**  Find the URI and determine whether the URI needs to be normalized.
**  
**  This is a big step in stateless inspection, because we need to reliably
**  find the URI and when possible filter out non-URIs.  We do this using a
**  simple state machine that is based on characters found in the data
**  buffer.
**  
**  Another important aspect of the stateless inspection is the ability to
**  track and inspect pipelined requests.  It is VERY IMPORTANT to reset the
**  pipeline_req pointer, since we don't memset the whole structure.  This
**  pointer is reset in the hi_si_session_inspection() function.  Check there
**  for more details.
**  
**  Normalization is detected when we are looking at the packet for the URI.
**  We look for the following issues:
**      - ////
**      - /../
**      - /./
**      - non-ascii charss
**      - %
**      - \
**  When these things are seen we point to the first occurence in the URI, or
**  where we have to start normalizing.  If the URI is updated to a new
**  pointer, then the normalization pointer is reset and we start over.
**  Using this method should cut down the memcpy()s per URI, since most
**  URIs are not normalized.
**  
**  If this function returns HI_NONFATAL_ERR, we return out of mode_inspection
**  with an error and abort HttpInspect processing, and continue on with
**  any other processing we do.  The Session parameters that we use here are
**  reset in the next time that we do session_inspection, so we don't do
**  any initialization here.
**  
**  @param Session pointer to the HTTP session
**  @param data    pointer to the start of the packet payload
**  @param dsize   size of the payload
**  
**  @return integer
**  
**  @retval HI_INVALID_ARG  invalid argument
**  @retval HI_NONFATAL_ERR no URI detected
**  @retval HI_SUCCESS      URI detected and Session pointers updated
*/
static int StatelessInspection(HI_SESSION *Session, unsigned char *data,
        int dsize)
{
    HTTPINSPECT_CONF *ServerConf;
    HTTPINSPECT_CONF *ClientConf;
    HI_CLIENT *Client;
    URI_PTR uri_ptr;
    u_char *start;
    u_char *end;
    u_char *ptr;
    int iRet;

    if(!Session || !data || dsize < 1)
    {
        return HI_INVALID_ARG;
    }

    ServerConf = Session->server_conf;
    if(!ServerConf)
    {
        return HI_INVALID_ARG;
    }

    ClientConf = Session->client_conf;
    if(!ClientConf)
    {
        return HI_INVALID_ARG;
    }

    Client = &Session->client;

    memset(&uri_ptr, 0x00, sizeof(URI_PTR));

    /*
    **  We set the starting boundary depending on whether this request is
    **  a normal request or a pipeline request.  The end boundary is always
    **  the same whether it is a pipeline request or other.
    */
    if(Client->request.pipeline_req)
    {
        start = Client->request.pipeline_req;
    }
    else
    {
        start = data;
    }

    end   = data + dsize;

    ptr = start;

    /*
    **  Apache and IIS strike again . . . Thanks Kanatoko
    **    - Ignore CRLFs at the beginning of the request.
    */
    while(hi_util_in_bounds(start, end, ptr))
    {
        if(*ptr < 0x21)
        {
            if(*ptr < 0x0E && *ptr > 0x08)
            {
                ptr++;
                continue;
            }
            else
            {
                if(*ptr == 0x20)
                {
                    ptr++;
                    continue;
                }
            }
        }
        
        break;
    }

    uri_ptr.uri = ptr;
    uri_ptr.uri_end = end;

    /*
    **  This loop compares each char to an array of functions
    **  (one for each char) and calling that function if there is one.
    **  
    **  If there is no function, then we just increment the char ptr and
    **  continue processing.
    **
    **  If there is a function, we call that function and process.  It's
    **  important to note that the function that is called is responsible
    **  for incrementing the ptr to the next char to be inspected.  The
    **  loop does not increment the pointer when a function is called to
    **  allow the maximum flexibility to the functions.
    */
    while(hi_util_in_bounds(start, end, ptr))
    {
        if(lookup_table[*ptr])
        {
            if((iRet = (lookup_table[*ptr])(Session, start, end,
                            &ptr, &uri_ptr)))
            {
                if(iRet == URI_END)
                {
                    /*
                    **  You found a URI, let's break and check it out.
                    */
                    break;
                }
                else if(iRet == HI_OUT_OF_BOUNDS)
                {
                    /*
                    **  Means you've reached the end of the buffer.  THIS
                    **  DOESN'T MEAN YOU HAVEN'T FOUND A URI.
                    */
                    break;
                }
                else /* NO_URI */
                {
                    /*
                    **  Check for chunk encoding, because the delimiter can
                    **  also be a space, which would look like a pipeline request
                    **  to us if we don't do this first.
                    */
                    if(Session->server_conf->chunk_length)
                            CheckChunkEncoding(Session, start, end);

                    /*
                    **  We only inspect the packet for another pipeline
                    **  request if there wasn't a previous pipeline request.
                    **  The reason that we do this is because 
                    */  
                    if(!Client->request.pipeline_req)
                    {
                        /*
                        **  Just because there was no URI in the first part
                        **  the packet, doesn't mean that this isn't a
                        **  pipelined request that has been segmented.
                        */
                        if(!ServerConf->no_pipeline)
                        {
                            if((Client->request.pipeline_req =
                                FindPipelineReq(ptr, end)))
                            {
                                return HI_SUCCESS;
                            }
                        }
                    }

                    return HI_NONFATAL_ERR;
                }
            }
            else
            {
                /*
                **  This means that we found the next non-whitespace char
                **  and since we are already pointed there, so we just
                **  continue.
                */
                continue;
            }
        }

        ptr++;
    }

    /*
    **  If there is a pipelined request in this packet, we should always
    **  see the first space followed by text (which is the URI).  Without
    **  that first space, then we never get to the URI, so we should just
    **  return, since there is nothing else to inspect.
    */
    if(Client->request.pipeline_req)
    {
        if(uri_ptr.uri != uri_ptr.first_sp_end)
        {
            if(Session->server_conf->chunk_length)
                CheckChunkEncoding(Session, start, end);

            return HI_NONFATAL_ERR;
        }
    }

    /*
    **  We set the HI_CLIENT variables from the URI_PTR structure.  We also
    **  do error checking for the values in this routine as well.
    */
    if((iRet = SetClientVars(Client, &uri_ptr, dsize)))
    {
        return iRet;
    }

    /*
    **  One last check for an oversize directory.  This gets the long
    **  directory when there is a beginning slash and no other slashes
    **  until the end of the packet.
    **
    **  We do this check after we set the variables, just in case there
    **  was some errors while setting the variables.  This could save some
    **  false positives on a bad URI setting.
    */
    CheckLongDir(Session, &uri_ptr, ptr);

    /*
    **  Check for absolute URI and alert for proxy comm if necessary
    **
    **  NOTE:
    **    Also check ClientConf for proxy configuration so we don't
    **    alert on outbound requests from legitimate proxies.
    */
    if(uri_ptr.proxy && Session->global_conf->proxy_alert &&
       (!ServerConf->allow_proxy && !ClientConf->allow_proxy))
    {
        if(hi_eo_generate_event(Session, HI_EO_CLIENT_PROXY_USE))
        {
            hi_eo_client_event_log(Session, HI_EO_CLIENT_PROXY_USE, 
                    NULL, NULL);
        }
    }

    /*
    **  Find the next pipeline request, if one is there.  If we don't find
    **  a pipeline request, then we return NULL here, so this is always
    **  set to the correct value.
    */
    if(!ServerConf->no_pipeline)
    {
        Client->request.pipeline_req = FindPipelineReq(uri_ptr.delimiter, end);
    }
    else
    {
        Client->request.pipeline_req = NULL;
    }

    if(Session->server_conf->chunk_length)
        CheckChunkEncoding(Session, uri_ptr.delimiter, end);

    return HI_SUCCESS;
}
Exemplo n.º 13
0
/**
**  This routine checks for chunk encoding anomalies in an HTTP client request
**  packet.
**  
**  We convert potential chunk lengths and test them against the user-defined
**  max chunk length.  We log events on any chunk lengths that are over this
**  defined chunk lengths.
**  
**  Chunks are skipped to save time when the chunk is contained in the packet.
**  
**  We assume coming into this function that we are pointed at the beginning
**  of what may be a chunk length.  That's why the iCheckChunk var is set
**  to 1.
**  
**  @param Session pointer to the Session construct
**  @param start   pointer to where to beginning of buffer
**  @param end     pointer to the end of buffer
**  
**  @return integer
**  
**  @retval HI_SUCCESS      function successful
**  @retval HI_INVALID_ARG  invalid argument
*/
static int CheckChunkEncoding(HI_SESSION *Session, u_char *start, u_char *end)
{
    u_int  iChunkLen   = 0;
    int    iChunkChars = 0;
    int    iCheckChunk = 1;
    u_char *ptr;
    u_char *jump_ptr;

    if(!start || !end)
        return HI_INVALID_ARG;

    ptr = start;

    while(hi_util_in_bounds(start, end, ptr))
    {
        if(*ptr == '\n' || *ptr == ' ' || *ptr == '\t')
        {
            if(iCheckChunk && iChunkLen != 0)
            {
                if(Session->server_conf->chunk_length < iChunkLen &&
                   hi_eo_generate_event(Session, HI_EO_CLIENT_LARGE_CHUNK))
                {
                    hi_eo_client_event_log(Session, HI_EO_CLIENT_LARGE_CHUNK,
                                           NULL, NULL);
                }

                jump_ptr = ptr + iChunkLen;

                if(jump_ptr <= ptr)
                {
                    break;
                }

                if(hi_util_in_bounds(start, end, jump_ptr))
                {
                    ptr = jump_ptr;
                }
                else
                {
                    /*
                    **  Chunk too large for packet, so we bail
                    */
                    break;
                }
            }

            /*
            **  If we've already evaluated the chunk, or we have a valid delimiter
            **  for handling new chunks, we reset and starting evaluating possible
            **  chunk lengths.
            */
            if(iCheckChunk || *ptr == '\n')
            {
                iCheckChunk = 1;
                iChunkLen   = 0;
                iChunkChars = 0;
            }

            ptr++;
            continue;
        }

        if(iCheckChunk)
        {
            if(hex_lookup[*ptr] == INVALID_HEX_VAL)
            {
                if(*ptr == '\r')
                {
                    ptr++;

                    if(!hi_util_in_bounds(start, end, ptr))
                        break;

                    if(*ptr == '\n')
                        continue;
                }
                else if(*ptr == ';')
                {
                    /*
                    **  This is where we skip through the chunk name=value
                    **  field.
                    */
                    ptr++;

                    while(hi_util_in_bounds(start, end, ptr))
                    {
                        if(*ptr == '\n')
                            break;

                        ptr++;
                    }

                    continue;
                }

                iCheckChunk = 0;
                iChunkLen   = 0;
                iChunkChars = 0;
            }
            else
            {
                if(iChunkChars >= 8)
                {
                    iCheckChunk = 0;
                    iChunkLen   = 0;
                    iChunkChars = 0;
                }
                else
                {
                    iChunkLen <<= 4;
                    iChunkLen |= (unsigned int)hex_lookup[*ptr];

                    iChunkChars++;
                }
            }
        }

        ptr++;
    }

    return HI_SUCCESS;
}
Exemplo n.º 14
0
static INLINE const u_char *hi_server_extract_header(
        HI_SESSION *Session, HTTPINSPECT_CONF *ServerConf, 
            HEADER_PTR *header_ptr, const u_char *start, 
            const u_char *end, int parse_cont_encoding,
            HttpSessionData *hsd)
{
    const u_char *p;
    const u_char *offset;
    HEADER_FIELD_PTR header_field_ptr ;

    if(!start || !end)
        return NULL;

    p = start;

    offset = (u_char*)p;

    header_ptr->header.uri = p;
    header_ptr->header.uri_end = end;
    header_ptr->content_encoding.compress_fmt = 0;
    header_ptr->content_len.len = 0;

    while (hi_util_in_bounds(start, end, p))
    {
        if(*p == '\n')
        {
            p++;

            offset = (u_char*)p;

            if (!hi_util_in_bounds(start, end, p))
            {
                header_ptr->header.uri_end = p;
                return p;
            }

            if (*p < 0x0E)
            {
                if(*p == '\r')
                {
                    p++;

                    if(hi_util_in_bounds(start, end, p) && (*p == '\n'))
                    {
                        p++;
                        header_ptr->header.uri_end = p;
                        return p;
                    }
                }
                else if(*p == '\n')
                {
                    p++;
                    header_ptr->header.uri_end = p;
                    return p;
                }
            }
            else if ( (p = extractHttpRespHeaderFieldValues(ServerConf, p, offset, 
                            start, end, header_ptr, &header_field_ptr, 
                            parse_cont_encoding, hsd, Session)) == end)
            {
                return end;
            }

        }
        else if( (p == header_ptr->header.uri) && 
                (p = extractHttpRespHeaderFieldValues(ServerConf, p, offset, 
                          start, end, header_ptr, &header_field_ptr,
                          parse_cont_encoding, hsd, Session)) == end)
        {
            return end;
        }
        if ( *p == '\n') continue;
        p++;
    }

    header_ptr->header.uri_end = p;
    return p;
}
Exemplo n.º 15
0
static INLINE const u_char *extract_http_content_encoding(HTTPINSPECT_CONF *ServerConf, 
        const u_char *p, const u_char *start, const u_char *end, HEADER_PTR *header_ptr, 
        HEADER_FIELD_PTR *header_field_ptr)
{
    const u_char *crlf;
    int space_present = 0;
    if (header_ptr->content_encoding.cont_encoding_start)
    {
        header_ptr->header.uri_end = p;
        header_ptr->content_encoding.compress_fmt = 0;
        return p;
    }
    else
    {
        header_field_ptr->content_encoding = &header_ptr->content_encoding;
        p = p + HTTPRESP_HEADER_LENGTH__CONTENT_ENCODING;
    }
    SkipBlankSpace(start,end,&p);
    if(hi_util_in_bounds(start, end, p) && *p == ':')
    {
        p++;
        if (  hi_util_in_bounds(start, end, p) )
        {
            if ( ServerConf->profile == HI_APACHE || ServerConf->profile == HI_ALL)
            {
                SkipWhiteSpace(start,end,&p);
            }
            else
            {
                SkipBlankAndNewLine(start,end,&p);
            }
            if( hi_util_in_bounds(start, end, p))
            {
                if ( *p == '\n' )
                {
                    while(hi_util_in_bounds(start, end, p))
                    {
                        if ( *p == '\n')
                        {
                            p++;
                            while( hi_util_in_bounds(start, end, p) && ( *p == ' ' || *p == '\t'))
                            {
                                space_present = 1;
                                p++;
                            }
                            if ( space_present )
                            {
                                if ( isalpha((int)*p))
                                    break;
                                else if(isspace((int)*p) && (ServerConf->profile == HI_APACHE || ServerConf->profile == HI_ALL) )
                                {
                                    SkipWhiteSpace(start,end,&p);
                                }
                                else
                                {
                                    header_field_ptr->content_encoding->cont_encoding_start=
                                        header_field_ptr->content_encoding->cont_encoding_end = NULL;
                                    header_field_ptr->content_encoding->compress_fmt = 0;
                                    return p;
                                }
                            }
                            else
                            {
                                header_field_ptr->content_encoding->cont_encoding_start=
                                    header_field_ptr->content_encoding->cont_encoding_end = NULL;
                                header_field_ptr->content_encoding->compress_fmt = 0;
                                return p;
                            }
                        }
                        else
                            break;
                    }
                }
                else if(isalpha((int)*p))
                {
                    header_field_ptr->content_encoding->cont_encoding_start = p;
                    while(hi_util_in_bounds(start, end, p) && *p!='\n' )
                    {
                        if(IsHeaderFieldName(p, end, HTTPRESP_HEADER_NAME__GZIP, HTTPRESP_HEADER_LENGTH__GZIP) ||
                                IsHeaderFieldName(p, end, HTTPRESP_HEADER_NAME__XGZIP, HTTPRESP_HEADER_LENGTH__XGZIP))
                        {
                            header_field_ptr->content_encoding->compress_fmt |= HTTP_RESP_COMPRESS_TYPE__GZIP;
                            p = p + HTTPRESP_HEADER_LENGTH__GZIP;
                            continue;
                        }
                        else if(IsHeaderFieldName(p, end, HTTPRESP_HEADER_NAME__DEFLATE, HTTPRESP_HEADER_LENGTH__DEFLATE))
                        {
                            header_field_ptr->content_encoding->compress_fmt |= HTTP_RESP_COMPRESS_TYPE__DEFLATE;
                            p = p + HTTPRESP_HEADER_LENGTH__DEFLATE;
                            continue;
                        }
                        else
                            p++;
                    }

                    /*crlf = (u_char *)SnortStrnStr((const char *)p, end - p, "\n");
                    if(crlf)
                    {
                        p = crlf;
                    }
                    else
                    {
                        header_ptr->header.uri_end = end ;
                        return end;
                    }*/
                }
                else
                {
                    header_field_ptr->content_encoding->cont_encoding_start=
                        header_field_ptr->content_encoding->cont_encoding_end = NULL;
                    header_field_ptr->content_encoding->compress_fmt = 0;
                    return p;
                }
            }
        }
    }
    else
    {
        if(hi_util_in_bounds(start, end, p))
        {
            crlf = (u_char *)SnortStrnStr((const char *)p, end - p, "\n");
            if(crlf)
            {
                p = crlf;
            }
            else
            {
                header_ptr->header.uri_end = end ;
                return end;
            }
        }
    }
    if(!p || !hi_util_in_bounds(start, end, p))
        p = end;

    return p;
}
Exemplo n.º 16
0
int HttpResponseInspection(HI_SESSION *Session, Packet *p, const unsigned char *data,
        int dsize, HttpSessionData *sd)
{
    HTTPINSPECT_CONF *ServerConf;
    URI_PTR stat_code_ptr;
    URI_PTR stat_msg_ptr;
    HEADER_PTR header_ptr;
    URI_PTR body_ptr;
    HI_SERVER *Server;

    const u_char *start;
    const u_char *end;
    const u_char *ptr;
    int len;
    int iRet = 0;
    int resp_header_size = 0;
    /* Refers to the stream reassembled packets when reassembly is turned on.
     * Refers to all packets when reassembly is turned off.
     */
    int not_stream_insert = 1;
#ifdef ZLIB
    int parse_cont_encoding = 1;
    int status;
#endif
    int expected_pkt = 0;
    int alt_dsize;
    uint32_t seq_num = 0;

    if (!Session || !p || !data || (dsize == 0))
        return HI_INVALID_ARG;

    ServerConf = Session->server_conf;
    if(!ServerConf)
        return HI_INVALID_ARG;


    Server = &(Session->server);
    clearHttpRespBuffer(Server);

    seq_num = GET_PKT_SEQ(p);

    if ( (sd != NULL) )
    {
        /* If the previously inspected packet in this session identified as a body
         * and if the packets are stream inserted wait for reassembled */
        if (sd->resp_state.inspect_reassembled)
        {
            if(p->packet_flags & PKT_STREAM_INSERT)
            {
#ifdef ZLIB
                parse_cont_encoding = 0;
#endif
                not_stream_insert = 0;
            }
        }
        /* If this packet is the next expected packet to be inspected and is out of sequence
         * clear out the resp state*/
#ifdef ZLIB
        if(( sd->decomp_state && sd->decomp_state->decompress_data) && parse_cont_encoding)
        {
            if( sd->resp_state.next_seq &&
                    (seq_num == sd->resp_state.next_seq) )
            {
                sd->resp_state.next_seq = seq_num + p->dsize;
                expected_pkt = 1;
            }
            else
            {
                ResetGzipState(sd->decomp_state);
                ResetRespState(&(sd->resp_state));
            }
        }
        else
#endif
        if(sd->resp_state.inspect_body && not_stream_insert)
        {
            /* If the server flow depth is 0 then we need to check if the packet
             * is in sequence
             */
            if(!ServerConf->server_flow_depth)
            {
                if( sd->resp_state.next_seq &&
                        (seq_num == sd->resp_state.next_seq) )
                {
                    sd->resp_state.next_seq = seq_num + p->dsize;
                    expected_pkt = 1;
                }
                else
                {
#ifdef ZLIB
                    ResetGzipState(sd->decomp_state);
#endif
                    ResetRespState(&(sd->resp_state));
                }
            }
            else 
            {
                /*Check if the sequence number of the packet is within the allowed
                 * flow_depth
                 */
                if( (sd->resp_state.is_max_seq) && 
                        SEQ_LT(seq_num, (sd->resp_state.max_seq)))
                {
                    expected_pkt = 1;
                }
                else
                {
#ifdef ZLIB
                    ResetGzipState(sd->decomp_state);
#endif
                    ResetRespState(&(sd->resp_state));
                }
            }

        }
    }


    memset(&stat_code_ptr, 0x00, sizeof(URI_PTR));
    memset(&stat_msg_ptr, 0x00, sizeof(URI_PTR));
    memset(&header_ptr, 0x00, sizeof(HEADER_PTR));
    memset(&body_ptr, 0x00, sizeof(URI_PTR));

    start = data;
    end = data + dsize;
    ptr = start;

    /* moving past the CRLF */

    while(hi_util_in_bounds(start, end, ptr))
    {
        if(*ptr < 0x21)
        {
            if(*ptr < 0x0E && *ptr > 0x08)
            {
                ptr++;
                continue;
            }
            else
            {
                if(*ptr == 0x20)
                {
                    ptr++;
                    continue;
                }
            }
        }

        break;
    }

    /*after doing this we need to basically check for version, status code and status message*/

    len = end - ptr;
    if ( len > 4 )
    {
        if(!IsHttpVersion(&ptr, end))
        { 
            if(expected_pkt)
            {
                ptr = start;
                p->packet_flags |= PKT_HTTP_DECODE;
            }
            else
            {
                p->packet_flags |= PKT_HTTP_DECODE;
                ApplyFlowDepth(ServerConf, p, sd, resp_header_size, 0, seq_num);
                if ( not_stream_insert && (sd != NULL))
                {
#ifdef ZLIB
                    ResetGzipState(sd->decomp_state);
#endif
                    ResetRespState(&(sd->resp_state));
                }
                CLR_SERVER_HEADER(Server);
                return HI_SUCCESS;
            }
        }
        else
        {
            p->packet_flags |= PKT_HTTP_DECODE;
            /* This is a next expected packet to be decompressed but the packet is a
             * valid HTTP response. So the gzip decompression ends here */
            if(expected_pkt)
            {
                expected_pkt = 0;
#ifdef ZLIB
                ResetGzipState(sd->decomp_state);
#endif
                ResetRespState(&(sd->resp_state));
            }
            while(hi_util_in_bounds(start, end, ptr))
            {
                if (isspace((int)*ptr))
                    break;
                ptr++;
            }

        }
    }
    else if (!expected_pkt)
    {
        return HI_SUCCESS;
    }

    /*If this is the next expected packet to be decompressed, send this packet 
     * decompression */

    if (expected_pkt)
    {
        if (hi_util_in_bounds(start, end, ptr))
        {
            iRet = hi_server_inspect_body(Session, sd, ptr, end, &body_ptr);
        }
    }
    else
    {
        iRet = hi_server_extract_status_code(Session, start,ptr,end , &stat_code_ptr);

        if ( iRet == STAT_END )
        {
            Server->response.status_code = stat_code_ptr.uri;
            Server->response.status_code_size = stat_code_ptr.uri_end - stat_code_ptr.uri;
            if ( (int)Server->response.status_code_size <= 0)
            {
                CLR_SERVER_STAT(Server);
            }
            else
            {
                iRet = hi_server_extract_status_msg(start, stat_code_ptr.uri_end , 
                        end, &stat_msg_ptr);
    
                if ( stat_msg_ptr.uri )
                {
                    Server->response.status_msg = stat_msg_ptr.uri;
                    Server->response.status_msg_size = stat_msg_ptr.uri_end - stat_msg_ptr.uri;
                    if ((int)Server->response.status_msg_size <= 0)
                    {
                        CLR_SERVER_STAT(Server);
                    }
                    else
                    {
#ifdef ZLIB
                        ptr =  hi_server_extract_header(Session, ServerConf, &header_ptr,
                                            stat_msg_ptr.uri_end , end, parse_cont_encoding, sd );
#else
                        /* We dont need the content-encoding header when zlib is not enabled */
                        ptr =  hi_server_extract_header(Session, ServerConf, &header_ptr,
                                    stat_msg_ptr.uri_end , end, 0, sd );
#endif
                    }
                }
                else
                {
                    CLR_SERVER_STAT(Server);
                }
            }
     
            if (header_ptr.header.uri)
            {
                Server->response.header_raw = header_ptr.header.uri;
                Server->response.header_raw_size = 
                    header_ptr.header.uri_end - header_ptr.header.uri;
                if(!Server->response.header_raw_size)
                {
                    CLR_SERVER_HEADER(Server);
                }
                else
                {
                    resp_header_size = (header_ptr.header.uri_end - p->data);
                    hi_stats.resp_headers++;
                    Server->response.header_norm = header_ptr.header.uri;
                    if (header_ptr.cookie.cookie)
                    {
                        hi_stats.resp_cookies++;
                        Server->response.cookie.cookie = header_ptr.cookie.cookie;
                        Server->response.cookie.cookie_end = header_ptr.cookie.cookie_end;
                        Server->response.cookie.next = header_ptr.cookie.next;
                    }
                    else
                    {
                        Server->response.cookie.cookie = NULL;
                        Server->response.cookie.cookie_end = NULL;
                        Server->response.cookie.next = NULL;
                    }
                    if (sd != NULL)
                    {
#ifdef ZLIB
                        if( header_ptr.content_encoding.compress_fmt )
                        {
                            hi_stats.gzip_pkts++;

                            /* We've got gzip data - grab buffer from mempool and attach
                             * to session data if server is configured to do so */
                            if (sd->decomp_state == NULL)
                                SetGzipBuffers(sd, Session);

                            if (sd->decomp_state != NULL)
                            {
                                sd->decomp_state->decompress_data = 1;
                                sd->decomp_state->compress_fmt =
                                                            header_ptr.content_encoding.compress_fmt;
                            }

                        }
                        else
#endif
                        {
                            sd->resp_state.inspect_body = 1;
                        }

                        sd->resp_state.last_pkt_contlen = header_ptr.content_len.len;
                        if(ServerConf->server_flow_depth == -1)
                            sd->resp_state.is_max_seq = 0;
                        else
                        {
                            sd->resp_state.is_max_seq = 1;
                            sd->resp_state.max_seq = seq_num +
                                        (header_ptr.header.uri_end - start)+ ServerConf->server_flow_depth;
                        }

                        if (p->packet_flags & PKT_STREAM_INSERT)
                        {
                            if(header_ptr.content_len.cont_len_start && ((end - (header_ptr.header.uri_end)) >= header_ptr.content_len.len))
                            {
                                /* change this when the api is fixed to flush correctly */
                                //stream_api->response_flush_stream(p);
                                expected_pkt = 1;
                            }
                            else
                                sd->resp_state.inspect_reassembled = 1;

                        }
                        else
                        {
                            if(p->packet_flags & PKT_REBUILT_STREAM)
                                sd->resp_state.inspect_reassembled = 1;

                            expected_pkt = 1;
                        }
                        if(expected_pkt)
                        {
                            sd->resp_state.next_seq = seq_num + p->dsize;

                            if(hi_util_in_bounds(start, end, header_ptr.header.uri_end))
                            {
                                iRet = hi_server_inspect_body(Session, sd, header_ptr.header.uri_end,
                                                                end, &body_ptr);
                            }
                        }
                    }
                }
            }
            else
            {
                CLR_SERVER_HEADER(Server);

            }
        }
        else
        {
            CLR_SERVER_STAT(Server);
        }
    }

    if( body_ptr.uri )
    {
        Server->response.body = body_ptr.uri;
        Server->response.body_size = body_ptr.uri_end - body_ptr.uri;
        if( Server->response.body_size > 0)
        {
            if ( Server->response.body_size < sizeof(DecodeBuffer.data) )
            {
                alt_dsize = Server->response.body_size;
            }
            else
            {
                alt_dsize = sizeof(DecodeBuffer.data);
            }
#ifdef ZLIB
            if(sd->decomp_state && sd->decomp_state->decompress_data)
            {
                status = SafeMemcpy(DecodeBuffer.data, Server->response.body,
                                            alt_dsize, DecodeBuffer.data, DecodeBuffer.data + sizeof(DecodeBuffer.data));
                if( status != SAFEMEM_SUCCESS  )
                    return HI_MEM_ALLOC_FAIL;
                p->data_flags |= DATA_FLAGS_GZIP;
                SetAltDecode(p, alt_dsize);
                SetDetectLimit(p, alt_dsize);
            }
            else
#endif
            {
                if(sd->resp_state.last_pkt_chunked)
                {
                    p->data_flags |= DATA_FLAGS_RESP_BODY;
                    SetAltDecode(p, alt_dsize);
                    SetDetectLimit(p, alt_dsize);
                }
                else
                {
                    p->data_flags |= DATA_FLAGS_RESP_BODY;
                    p->packet_flags |= PKT_HTTP_RESP_BODY;
                    SetDetectLimit(p, (alt_dsize + resp_header_size));
                }
            }

            if (get_decode_utf_state_charset(&(sd->utf_state)) != CHARSET_DEFAULT)
            {
                if ( Server->response.body_size < sizeof(DecodeBuffer.data) )
                {
                    alt_dsize = Server->response.body_size;
                }           
                else
                {
                    alt_dsize = sizeof(DecodeBuffer.data);
                }
                SetDetectLimit(p, alt_dsize);
                SetAltDecode(p, alt_dsize);
            }
        }
        
    }
    else
    {
        /* There is no body to the HTTP response.
         * In this case we need to inspect the entire HTTP response header.
         */
        ApplyFlowDepth(ServerConf, p, sd, resp_header_size, 1, seq_num);
    }

    return HI_SUCCESS;
}