ngx_int_t ngx_http_modsecurity_rewrite_handler(ngx_http_request_t *r)
{
    ngx_http_modsecurity_ctx_t *ctx = NULL;
    ngx_http_modsecurity_loc_conf_t *cf;

    cf = ngx_http_get_module_loc_conf(r, ngx_http_modsecurity);
    if (cf == NULL || cf->enable != 1)
    {
        dd("ModSecurity not enabled... returning");
        return NGX_DECLINED;
    }

    if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_POST) {
        dd("ModSecurity is not ready to deal with anything different from " \
            "POST or GET");
        return NGX_DECLINED;
    }

    dd("catching a new _rewrite_ pahase handler");

    ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity);

    dd("recovering ctx: %p", ctx);

    if (ctx == NULL)
    {
        int ret = 0;

        ngx_connection_t *connection = r->connection;
        /** 
         * FIXME: We may want to use struct sockaddr instead of addr_text.
         *
         */
        ngx_str_t addr_text = connection->addr_text;

        ctx = ngx_http_modsecurity_create_ctx(r);

        dd("ctx was NULL, creating new context: %p", ctx);

        if (ctx == NULL)
        {
            dd("ctx still null; Nothing we can do, returning an error.");

            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        /**
         * FIXME: Check if it is possible to hook on nginx on a earlier phase.
         *
         * At this point we are doing an late connection process. Maybe
         * we have to hook into NGX_HTTP_FIND_CONFIG_PHASE, it seems to be the
         * erliest phase that nginx allow us to attach those kind of hooks.
         *
         */
        int client_port = htons(((struct sockaddr_in *) connection->sockaddr)->sin_port);
        int server_port = htons(((struct sockaddr_in *) connection->listening->sockaddr)->sin_port);
        const char *client_addr = ngx_str_to_char(addr_text, r->pool);
        const char *server_addr = inet_ntoa(((struct sockaddr_in *) connection->sockaddr)->sin_addr);
        ret = msc_process_connection(ctx->modsec_transaction,
            client_addr, client_port,
            server_addr, server_port);
        if (ret != 1){
            dd("Was not able to exract connection information.");
        }
        /**
         *
         * FIXME: Check how we can finalize a request without crash nginx.
         *
         * I don't think nginx is expecting to finalize a request at that
         * point as it seems that it clean the ngx_http_request_t information
         * and try to use it later. 
         *
         */
        ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r);
        if (ret > 0)
        {
            return ret;
        }

        const char *http_version;
        switch (r->http_version) {
            case NGX_HTTP_VERSION_9 :
                http_version = "0.9";
                break;
            case NGX_HTTP_VERSION_10 :
                http_version = "1.0";
                break;
            case NGX_HTTP_VERSION_11 :
                http_version = "1.1";
                break;
            case NGX_HTTP_VERSION_20 :
                http_version = "2.0";
                break;
            default :
                http_version = "1.0";
                break;
        }

        msc_process_uri(ctx->modsec_transaction, ngx_str_to_char(r->unparsed_uri, r->pool),
            ngx_str_to_char(r->method_name, r->pool), http_version
        );
        ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r);
        if (ret > 0)
        {
            return ret;
        }

        /**
         * Since headers are already in place, lets send it to ModSecurity
         * 
         */
        ngx_list_part_t *part = &r->headers_in.headers.part;
        ngx_table_elt_t *data = part->elts;
        ngx_uint_t i = 0;
        for (i = 0 ;; i++) {
            if (i >= part->nelts) {
                if (part->next == NULL) {
                    break;
                }

                part = part->next;
                data = part->elts;
                i = 0;
            }

            /**
             * By using u_char (utf8_t) I believe nginx is hoping to deal
             * with utf8 strings.
             * Casting those into to unsigned char * in order to pass
             * it to ModSecurity, it will handle with those later.
             * 
             */

            msc_add_n_request_header(ctx->modsec_transaction,
                (const unsigned char *) data[i].key.data,
                data[i].key.len,
                (const unsigned char *) data[i].value.data,
                data[i].value.len);
        }

        /**
         * Since ModSecurity already knew about all headers, i guess it is safe
         * to process this information.
         */

        msc_process_request_headers(ctx->modsec_transaction);
        ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r);
        if (ret > 0)
        {
            return ret;
        }
    }


    return NGX_DECLINED;
}
Esempio n. 2
0
/*
** [ENTRY POINT] does : this function called by nginx from the request handler
*/
static ngx_int_t
ngx_http_modsecurity_handler(ngx_http_request_t *r)
{
    ngx_http_modsecurity_loc_conf_t *cf;
    ngx_http_modsecurity_ctx_t      *ctx;
    ngx_int_t                        rc;

    cf = ngx_http_get_module_loc_conf(r, ngx_http_modsecurity);

    /* Process only main request */
    if (r != r->main || !cf->enable) {
        return NGX_DECLINED;
    }

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "modSecurity: handler");

    /* create / retrive request ctx */
    if (r->internal) {
        
        ctx = ngx_http_get_module_pool_ctx(r, ngx_http_modsecurity);

        if (ctx) {
            /* we have already processed the request headers */
            ngx_http_set_ctx(r, ctx, ngx_http_modsecurity);
            return NGX_DECLINED;
        }

        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "modSecurity: request pool ctx empty");
    }

    ctx = ngx_http_modsecurity_create_ctx(r);
    if (ctx == NULL) {

        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    ngx_http_set_ctx(r, ctx, ngx_http_modsecurity);

    if (ngx_http_set_pool_ctx(r, ctx, ngx_http_modsecurity) != NGX_OK) {
        return NGX_ERROR;
    }

    /* load request to request rec */
    if (ngx_http_modsecurity_load_request(r) != NGX_OK
        || ngx_http_modsecurity_load_headers_in(r) != NGX_OK) {

        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    /* processing request headers */
    rc = ngx_http_modsecurity_status(r, modsecProcessRequestHeaders(ctx->req));

    if (rc != NGX_DECLINED) {
        return rc;
    }

    if (modsecContextState(ctx->req) == MODSEC_DISABLED) {
        return NGX_DECLINED;
    }

    if (r->method == NGX_HTTP_POST 
            && modsecIsRequestBodyAccessEnabled(ctx->req) ) {

        /* read POST request body, should we process PUT? */
        rc = ngx_http_read_client_request_body(r, ngx_http_modsecurity_body_handler);
        if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
            return rc;
        }

        return NGX_DONE;
    }
    
    /* other method */
    return ngx_http_modsecurity_status(r, modsecProcessRequestBody(ctx->req));
}