Exemple #1
0
/**
 * Processes an identity response body of known length.
 *
 * @param[in] connp
 * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed.
 */
htp_status_t htp_connp_RES_BODY_IDENTITY_CL_KNOWN(htp_connp_t *connp) {
    size_t bytes_to_consume;   
        
    // Determine how many bytes we can consume.
    if (connp->out_current_len - connp->out_current_read_offset >= connp->out_body_data_left) {
        bytes_to_consume = connp->out_body_data_left;
    } else {
        bytes_to_consume = connp->out_current_len - connp->out_current_read_offset;
    }       
    
    if (bytes_to_consume == 0) return HTP_DATA;    

    // Consume the data.
    htp_status_t rc = htp_tx_res_process_body_data_ex(connp->out_tx, connp->out_current_data + connp->out_current_read_offset, bytes_to_consume);
    if (rc != HTP_OK) return rc;

    // Adjust the counters.
    connp->out_current_read_offset += bytes_to_consume;
    connp->out_current_consume_offset += bytes_to_consume;
    connp->out_stream_offset += bytes_to_consume;
    connp->out_body_data_left -= bytes_to_consume;

    // Have we seen the entire response body?    
    if (connp->out_body_data_left == 0) {
        connp->out_state = htp_connp_RES_FINALIZE;
        return HTP_OK;
    }

    return HTP_DATA;
}
Exemple #2
0
/**
 * Processes a chunk of data.
 *
 * @param[in] connp
 * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed.
 */
htp_status_t htp_connp_RES_BODY_CHUNKED_DATA(htp_connp_t *connp) {
    size_t bytes_to_consume;

    // Determine how many bytes we can consume.
    if (connp->out_current_len - connp->out_current_read_offset >= connp->out_chunked_length) {
        bytes_to_consume = connp->out_chunked_length;
    } else {
        bytes_to_consume = connp->out_current_len - connp->out_current_read_offset;
    }

    if (bytes_to_consume == 0) return HTP_DATA;

    // Consume the data.
    htp_status_t rc = htp_tx_res_process_body_data_ex(connp->out_tx, connp->out_current_data + connp->out_current_read_offset, bytes_to_consume);
    if (rc != HTP_OK) return rc;

    // Adjust the counters.
    connp->out_current_read_offset += bytes_to_consume;
    connp->out_current_consume_offset += bytes_to_consume;
    connp->out_stream_offset += bytes_to_consume;
    connp->out_chunked_length -= bytes_to_consume;

    // Have we seen the entire chunk?
    if (connp->out_chunked_length == 0) {
        connp->out_state = htp_connp_RES_BODY_CHUNKED_DATA_END;
        return HTP_OK;
    }

    return HTP_DATA;
}
htp_status_t htp_tx_state_response_complete_ex(htp_tx_t *tx, int hybrid_mode) {
    if (tx == NULL) return HTP_ERROR;

    if (tx->response_progress != HTP_RESPONSE_COMPLETE) {
        tx->response_progress = HTP_RESPONSE_COMPLETE;

        // Run the last RESPONSE_BODY_DATA HOOK, but only if there was a response body present.
        if (tx->response_transfer_coding != HTP_CODING_NO_BODY) {
            htp_tx_res_process_body_data_ex(tx, NULL, 0);
        }

        // Run hook RESPONSE_COMPLETE.
        htp_status_t rc = htp_hook_run_all(tx->connp->cfg->hook_response_complete, tx);
        if (rc != HTP_OK) return rc;
    }

    if (!hybrid_mode) {
        // Check if the inbound parser is waiting on us. If it is, that means that
        // there might be request data that the inbound parser hasn't consumed yet.
        // If we don't stop parsing we might encounter a response without a request,
        // which is why we want to return straight away before processing any data.
        //
        // This situation will occur any time the parser needs to see the server
        // respond to a particular situation before it can decide how to proceed. For
        // example, when a CONNECT is sent, different paths are used when it is accepted
        // and when it is not accepted.
        //
        // It is not enough to check only in_status here. Because of pipelining, it's possible
        // that many inbound transactions have been processed, and that the parser is
        // waiting on a response that we have not seen yet.
        if ((tx->connp->in_status == HTP_STREAM_DATA_OTHER) && (tx->connp->in_tx == tx->connp->out_tx)) {
            return HTP_DATA_OTHER;
        }

        // Do we have a signal to yield to inbound processing at
        // the end of the next transaction?
        if (tx->connp->out_data_other_at_tx_end) {
            // We do. Let's yield then.
            tx->connp->out_data_other_at_tx_end = 0;
            return HTP_DATA_OTHER;
        }
    }

    // Make a copy of the connection parser pointer, so that
    // we don't have to reference it via tx, which may be destroyed later.
    htp_connp_t *connp = tx->connp;

    // Finalize the transaction. This may call may destroy the transaction, if auto-destroy is enabled.
    htp_status_t rc = htp_tx_finalize(tx);
    if (rc != HTP_OK) return rc;

    // Disconnect transaction from the parser.
    connp->out_tx = NULL;

    connp->out_state = htp_connp_RES_IDLE;

    return HTP_OK;
}
Exemple #4
0
/**
 * Processes identity response body of unknown length. In this case, we assume the
 * response body consumes all data until the end of the stream.
 *
 * @param[in] connp
 * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed.
 */
htp_status_t htp_connp_RES_BODY_IDENTITY_STREAM_CLOSE(htp_connp_t *connp) {        
    // Consume all data from the input buffer.
    size_t bytes_to_consume = connp->out_current_len - connp->out_current_read_offset;

    if (bytes_to_consume != 0) {
        htp_status_t rc = htp_tx_res_process_body_data_ex(connp->out_tx, connp->out_current_data + connp->out_current_read_offset, bytes_to_consume);
        if (rc != HTP_OK) return rc;

        // Adjust the counters.
        connp->out_current_read_offset += bytes_to_consume;
        connp->out_current_consume_offset += bytes_to_consume;
        connp->out_stream_offset += bytes_to_consume;        
    }

    // Have we seen the entire response body?
    if (connp->out_status == HTP_STREAM_CLOSED) {
        connp->out_state = htp_connp_RES_FINALIZE;
        return HTP_OK;
    }
   
    return HTP_DATA;
}
Exemple #5
0
/**
 * Parses response line.
 *
 * @param[in] connp
 * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed.
 */
htp_status_t htp_connp_RES_LINE(htp_connp_t *connp) {
    for (;;) {
        // Don't try to get more data if the stream is closed. If we do, we'll return, asking for more data.
        if (connp->out_status != HTP_STREAM_CLOSED) {
            // Get one byte
            OUT_COPY_BYTE_OR_RETURN(connp);
        }

        // Have we reached the end of the line? We treat stream closure as end of line in
        // order to handle the case when the first line of the response is actually response body
        // (and we wish it processed as such).
        if ((connp->out_next_byte == LF)||(connp->out_status == HTP_STREAM_CLOSED)) {
            unsigned char *data;
            size_t len;

            if (htp_connp_res_consolidate_data(connp, &data, &len) != HTP_OK) {
                return HTP_ERROR;
            }

            #ifdef HTP_DEBUG
            fprint_raw_data(stderr, __FUNCTION__, data, len);
            #endif

            // Is this a line that should be ignored?
            if (htp_connp_is_line_ignorable(connp, data, len)) {
                // We have an empty/whitespace line, which we'll note, ignore and move on
                connp->out_tx->response_ignored_lines++;

                // TODO How many lines are we willing to accept?

                // Start again
                htp_connp_res_clear_buffer(connp);

                return HTP_OK;
            }

            // Deallocate previous response line allocations, which we would have on a 100 response.

            if (connp->out_tx->response_line != NULL) {
                bstr_free(connp->out_tx->response_line);
                connp->out_tx->response_line = NULL;
            }

            if (connp->out_tx->response_protocol != NULL) {
                bstr_free(connp->out_tx->response_protocol);
                connp->out_tx->response_protocol = NULL;
            }

            if (connp->out_tx->response_status != NULL) {
                bstr_free(connp->out_tx->response_status);
                connp->out_tx->response_status = NULL;
            }

            if (connp->out_tx->response_message != NULL) {
                bstr_free(connp->out_tx->response_message);
                connp->out_tx->response_message = NULL;
            }

            // Process response line.           

            int chomp_result = htp_chomp(data, &len);

            connp->out_tx->response_line = bstr_dup_mem(data, len);
            if (connp->out_tx->response_line == NULL) return HTP_ERROR;

            if (connp->cfg->parse_response_line(connp) != HTP_OK) return HTP_ERROR;

            // If the response line is invalid, determine if it _looks_ like
            // a response line. If it does not look like a line, process the
            // data as a response body because that is what browsers do.
           
            if (htp_treat_response_line_as_body(connp->out_tx)) {
                connp->out_tx->response_content_encoding_processing = HTP_COMPRESSION_NONE;

                htp_status_t rc = htp_tx_res_process_body_data_ex(connp->out_tx, data, len + chomp_result);
                if (rc != HTP_OK) return rc;

                // Continue to process response body. Because we don't have
                // any headers to parse, we assume the body continues until
                // the end of the stream.
                connp->out_tx->response_transfer_coding = HTP_CODING_IDENTITY;
                connp->out_tx->response_progress = HTP_RESPONSE_BODY;
                connp->out_state = htp_connp_RES_BODY_IDENTITY_STREAM_CLOSE;               
                connp->out_body_data_left = -1;

                return HTP_OK;
            }

            htp_status_t rc = htp_tx_state_response_line(connp->out_tx);
            if (rc != HTP_OK) return rc;

            htp_connp_res_clear_buffer(connp);

            // Move on to the next phase.
            connp->out_state = htp_connp_RES_HEADERS;
            connp->out_tx->response_progress = HTP_RESPONSE_HEADERS;

            return HTP_OK;
        }
    }

    return HTP_ERROR;
}
htp_status_t htp_tx_res_process_body_data(htp_tx_t *tx, const void *data, size_t len) {
    if ((tx == NULL) || (data == NULL)) return HTP_ERROR;
    if (len == 0) return HTP_OK;
    return htp_tx_res_process_body_data_ex(tx, data, len);
}