예제 #1
0
htp_status_t htp_tx_finalize(htp_tx_t *tx) {
    if (tx == NULL) return HTP_ERROR;

    if (!htp_tx_is_complete(tx)) return HTP_OK;

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

    // In streaming processing, we destroy the transaction because it will not be needed any more.
    if (tx->connp->cfg->tx_auto_destroy) {
        htp_tx_destroy(tx);
    }

    return HTP_OK;
}
예제 #2
0
/**
 * Destroys a connection, as well as all the transactions it contains. It is
 * not possible to destroy a connection structure yet leave any of its
 * transactions intact. This is because transactions need its connection and
 * connection structures hold little data anyway. The opposite is true, though
 * it is possible to delete a transaction but leave its connection alive.
 *
 * @param conn
 */
void htp_conn_destroy(htp_conn_t *conn) {
    if (conn == NULL) return;
    
    // Destroy individual transactions. Do note that iterating
    // using the iterator does not work here because some of the
    // list element may be NULL (and with the iterator it is impossible
    // to distinguish a NULL element from the end of the list).
    if (conn->transactions != NULL) {
        size_t i;
        for (i = 0; i < list_size(conn->transactions); i++) {
            htp_tx_t *tx = (htp_tx_t *)list_get(conn->transactions, i);
            if (tx != NULL) {
                htp_tx_destroy(tx);
            }
        }

        list_destroy(conn->transactions);
    }

    // Destroy individual messages
    if (conn->messages != NULL) {
        htp_log_t *l = NULL;
        list_iterator_reset(conn->messages);
        while ((l = list_iterator_next(conn->messages)) != NULL) {
            free((void *)l->msg);
            free(l);
        }

        list_destroy(conn->messages);
    }

    if (conn->local_addr != NULL) {
        free(conn->local_addr);
    }

    if (conn->remote_addr != NULL) {
        free(conn->remote_addr);
    }
   
    // Finally, destroy the connection
    // structure itself.
    free(conn);
}
예제 #3
0
htp_status_t htp_connp_RES_FINALIZE(htp_connp_t *connp) {
    int rc = htp_tx_state_response_complete(connp->out_tx);
    if (rc != HTP_OK) return rc;

    // 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.
    if ((connp->in_status == HTP_STREAM_DATA_OTHER) && (connp->in_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 (connp->out_data_other_at_tx_end) {
        // We do. Let's yield then.
        connp->out_data_other_at_tx_end = 0;
        return HTP_DATA_OTHER;
    }

    // In streaming processing, we destroy the transaction
    // because it will not be needed any more.
    if (connp->cfg->tx_auto_destroy) {
        htp_tx_destroy(connp->out_tx);
    }

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

    connp->out_state = htp_connp_RES_IDLE;

    return HTP_OK;
}
예제 #4
0
/**
 * The response idle state will initialize response processing, as well as
 * finalize each transactions after we are done with it.
 *
 * @param connp
 * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed.
 */
int htp_connp_RES_IDLE(htp_connp_t * connp) {
    // If we're here and an outgoing transaction object exists that
    // means we've just completed parsing a response. We need
    // to run the final hook in a transaction and start over.
    if (connp->out_tx != NULL) {
        // Shut down the decompressor, if we've used one
        if (connp->out_decompressor != NULL) {
            connp->out_decompressor->destroy(connp->out_decompressor);
            connp->out_decompressor = NULL;
        }

        connp->out_tx->progress = TX_PROGRESS_DONE;

        // Run the last RESPONSE_BODY_DATA HOOK, but
        // only if there was a response body
        if (connp->out_tx->response_transfer_coding != -1) {
            htp_tx_data_t d;
            d.data = NULL;
            d.tx = connp->out_tx;
            htp_res_run_hook_body_data(connp, &d);
        }

        // Run hook RESPONSE
        int rc = hook_run_all(connp->cfg->hook_response, connp);
        if (rc != HTP_OK) {
            htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0,
                "Response callback returned error (%d)", rc);
            return HTP_ERROR;
        }

        if (connp->cfg->tx_auto_destroy) {
            htp_tx_destroy(connp->out_tx);
        }

        // 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.
        if ((connp->in_status == STREAM_STATE_DATA_OTHER) && (connp->in_tx == connp->out_tx)) {
            connp->out_tx = NULL;
            return HTP_DATA_OTHER;
        }

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

    // We want to start parsing the next response (and change
    // the state from IDLE) only if there's at least one
    // byte of data available. Otherwise we could be creating
    // new structures even if there's no more data on the
    // connection.
    OUT_TEST_NEXT_BYTE_OR_RETURN(connp);

    // Parsing a new response

    // Find the next outgoing transaction
    connp->out_tx = list_get(connp->conn->transactions, connp->out_next_tx_index);
    if (connp->out_tx == NULL) {
        htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0,
            "Unable to match response to request");
        return HTP_ERROR;
    }

    // We've used one transaction
    connp->out_next_tx_index++;

    // TODO Detect state mismatch

    connp->out_content_length = -1;
    connp->out_body_data_left = -1;
    connp->out_header_line_index = -1;
    connp->out_header_line_counter = 0;

    // Change state into response line parsing, except if we're following
    // a short HTTP/0.9 request, because such requests to not have a
    // response line and headers.
    if (connp->out_tx->protocol_is_simple) {
        connp->out_tx->response_transfer_coding = IDENTITY;
        connp->out_state = htp_connp_RES_BODY_IDENTITY;
        connp->out_tx->progress = TX_PROGRESS_RES_BODY;
    } else {

        connp->out_state = htp_connp_RES_LINE;
        connp->out_tx->progress = TX_PROGRESS_RES_LINE;
    }

    return HTP_OK;
}