Esempio n. 1
0
static INLINE int hi_server_decompress(HI_SESSION *Session, HttpSessionData *sd, const u_char *ptr, 
        const u_char *end, URI_PTR *result)
{
    const u_char *start = ptr;
    int rawbuf_size = end - ptr;
    int iRet = HI_SUCCESS;
    int zRet = HI_FATAL_ERR;
    int compr_depth, decompr_depth;
    int compr_bytes_read, decompr_bytes_read;
    int compr_avail, decompr_avail;
    int total_bytes_read = 0;
    int chunk_size = 0;
    int chunk_read = 0;

    u_char *compr_buffer;
    u_char *decompr_buffer;
    compr_depth = sd->decomp_state->compr_depth;
    decompr_depth = sd->decomp_state->decompr_depth;
    compr_bytes_read = sd->decomp_state->compr_bytes_read;
    decompr_bytes_read = sd->decomp_state->decompr_bytes_read;
    compr_buffer = sd->decomp_state->compr_buffer;
    decompr_buffer = sd->decomp_state->decompr_buffer;

    if(Session->server_conf->unlimited_decompress)
    {
        compr_avail = compr_depth;
        decompr_avail = decompr_depth;
    }
    else
    {
        compr_avail = compr_depth-compr_bytes_read;
        decompr_avail = decompr_depth - decompr_bytes_read;
    }

    /* Apply the server flow depth
     * If the server flow depth is set then we need to decompress only upto the 
     * server flow depth
     */
    switch ( Session->server_conf->server_flow_depth)
    {
        case -1:
            decompr_avail=0;
            break;
        case 0:
            break;
        default:
            if(sd->resp_state.flow_depth_read < Session->server_conf->server_flow_depth)
            {
                if(decompr_avail > (Session->server_conf->server_flow_depth - sd->resp_state.flow_depth_read))
                    decompr_avail = Session->server_conf->server_flow_depth - sd->resp_state.flow_depth_read;
            }
            else
            {
                decompr_avail = 0;
            }
            break;
    }

    if(compr_avail <=0 || decompr_avail <=0 ||
            (!compr_buffer) || (!decompr_buffer))
    {
        ResetGzipState(sd->decomp_state);
        ResetRespState(&(sd->resp_state));
        return iRet;
    }


    if(rawbuf_size < compr_avail)
    {
        compr_avail = rawbuf_size;
    }

    if(!(sd->resp_state.last_pkt_contlen))
    {
        if(CheckChunkEncoding(Session, start, end, NULL, compr_buffer, compr_avail, 
                    sd->resp_state.last_chunk_size, &chunk_size, &chunk_read ) == 1)
        {
            sd->resp_state.last_chunk_size = chunk_size;
            compr_avail = chunk_read;
            zRet = uncompress_gzip(decompr_buffer,decompr_avail,compr_buffer, compr_avail, sd, &total_bytes_read,
                                    sd->decomp_state->compress_fmt);
        }
        else
        {
            /* No Content-Length or Transfer-Encoding : chunked */
            if(hi_eo_generate_event(Session, HI_EO_SERVER_NO_CONTLEN))
            {
                hi_eo_server_event_log(Session, HI_EO_SERVER_NO_CONTLEN, NULL, NULL);
            }

            memcpy(compr_buffer, ptr, compr_avail);
            zRet = uncompress_gzip(decompr_buffer,decompr_avail,compr_buffer, compr_avail, sd, 
                    &total_bytes_read, sd->decomp_state->compress_fmt);
        }
    }
    else
    {
        memcpy(compr_buffer, ptr, compr_avail);
        zRet = uncompress_gzip(decompr_buffer,decompr_avail,compr_buffer, compr_avail, sd, 
                &total_bytes_read, sd->decomp_state->compress_fmt);
    }
    
    sd->decomp_state->compr_bytes_read += compr_avail;
    hi_stats.compr_bytes_read += compr_avail;

    if((zRet == HI_SUCCESS) || (zRet == HI_NONFATAL_ERR))
    {
        if(decompr_buffer)
        {
            result->uri = decompr_buffer;
            if ( total_bytes_read < decompr_avail )
            {
                result->uri_end = decompr_buffer + total_bytes_read;
                sd->decomp_state->decompr_bytes_read += total_bytes_read;
                sd->resp_state.flow_depth_read += total_bytes_read;
                hi_stats.decompr_bytes_read += total_bytes_read;
            }
            else
            {
                result->uri_end = decompr_buffer + decompr_avail;
                sd->decomp_state->decompr_bytes_read += decompr_avail;
                sd->resp_state.flow_depth_read += decompr_avail;
                hi_stats.decompr_bytes_read += decompr_avail;
            }
        }
    }
    else
    {
        ResetGzipState(sd->decomp_state);
        ResetRespState(&(sd->resp_state));
    }

    return iRet;


}
Esempio n. 2
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;
}
Esempio n. 3
0
static INLINE int hi_server_extract_body(
                        HI_SESSION *Session, HttpSessionData *sd,
                        const u_char *ptr, const u_char *end, URI_PTR *result)
{
    HTTPINSPECT_CONF *ServerConf;
    const u_char *start = ptr;
    int iRet = HI_SUCCESS;
    const u_char *post_end = end; 
    int chunk_size = 0;
    int chunk_read = 0;
    int bytes_to_read = 0;
    ServerConf = Session->server_conf;

    switch(ServerConf->server_flow_depth)
    {
        case -1: 
            result->uri = result->uri_end = NULL;
            return iRet;
        case 0:
            break;
        default:
            if(sd->resp_state.flow_depth_read < ServerConf->server_flow_depth)
            {
                bytes_to_read = ServerConf->server_flow_depth - sd->resp_state.flow_depth_read;
                if((end-ptr) > bytes_to_read )
                {
                    end = ptr + bytes_to_read;
                }
                sd->resp_state.flow_depth_read +=bytes_to_read;
            }
            else
            {
                result->uri = result->uri_end = NULL;
                return iRet;
            }
    }

/*    if( ServerConf->server_flow_depth && ((end - ptr) > ServerConf->server_flow_depth) )
    {
        end = ptr + ServerConf->server_flow_depth;
    }*/

    if (!(sd->resp_state.last_pkt_contlen))
    {
        if( ServerConf->chunk_length )
        {
            if(CheckChunkEncoding(Session, start, end, &post_end, (u_char *)DecodeBuffer.data, sizeof(DecodeBuffer.data),
                                    sd->resp_state.last_chunk_size, &chunk_size, &chunk_read ) == 1)
            {
                sd->resp_state.last_chunk_size = chunk_size;
                sd->resp_state.last_pkt_chunked = 1;
                result->uri = (u_char *)DecodeBuffer.data;
                result->uri_end = result->uri + chunk_read;
                return iRet;
            }
            else
            {
                if(!(sd->resp_state.last_pkt_chunked))
                {
                    if(hi_eo_generate_event(Session, HI_EO_SERVER_NO_CONTLEN))
                    {
                        hi_eo_server_event_log(Session, HI_EO_SERVER_NO_CONTLEN, NULL, NULL);
                    }
                }
                else
                {
                    sd->resp_state.last_pkt_chunked = 0;
                    sd->resp_state.last_chunk_size = 0;
                }
                result->uri = start;
                result->uri_end = end;
            }
        }
        else
        {
            result->uri = start;
            result->uri_end = end;
            return iRet;
        }
    }

    result->uri = start;
    result->uri_end = end;

    return STAT_END;
}