static ngx_inline ngx_int_t ngx_http_modsecurity_load_headers_in(ngx_http_request_t *r) { ngx_http_modsecurity_ctx_t *ctx; const char *lang; request_rec *req; ngx_list_part_t *part; ngx_table_elt_t *h; ngx_uint_t i; ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity); req = ctx->req; part = &r->headers_in.headers.part; h = part->elts; for (i = 0; ; i++) { if (i >= part->nelts) { if (part->next == NULL) break; part = part->next; h = part->elts; i = 0; } apr_table_setn(req->headers_in, (char *)h[i].key.data, (char *)h[i].value.data); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: load headers in: \"%V: %V\"", &h[i].key, &h[i].value); } req->clength = r->headers_in.content_length_n; req->range = apr_table_get(req->headers_in, "Range"); req->content_type = apr_table_get(req->headers_in, "Content-Type"); req->content_encoding = apr_table_get(req->headers_in, "Content-Encoding"); lang = apr_table_get(ctx->req->headers_in, "Content-Languages"); if(lang != NULL) { ctx->req->content_languages = apr_array_make(ctx->req->pool, 1, sizeof(const char *)); *(const char **)apr_array_push(ctx->req->content_languages) = lang; } req->ap_auth_type = (char *)apr_table_get(req->headers_in, "Authorization"); req->user = (char *)ngx_pstrdup0(r->pool, &r->headers_in.user); ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: load headers in done"); return NGX_OK; }
static ngx_inline ngx_int_t ngx_http_modsecurity_load_headers_out(ngx_http_request_t *r) { ngx_http_modsecurity_ctx_t *ctx; char *data; request_rec *req; u_char *content_type; ngx_uint_t content_type_len; ngx_http_variable_value_t *vv; ngx_list_part_t *part; ngx_table_elt_t *h; ngx_uint_t i; char *key, *value; u_char *buf = NULL; size_t size = 0; ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity); req = ctx->req; req->status = r->headers_out.status; req->status_line = (char *)ngx_pstrdup0(r->pool, &r->headers_out.status_line); if (r->headers_out.charset.len) { content_type_len = r->headers_out.content_type.len + r->headers_out.charset.len + ngx_strlen("; charset=") + 1; content_type = ngx_palloc(r->pool, content_type_len); if (content_type == NULL) { return NGX_ERROR; } ngx_snprintf(content_type, content_type_len, "%V; charset=%V%Z", &r->headers_out.content_type, &r->headers_out.charset); r->headers_out.content_type.data = content_type; r->headers_out.content_type.len = content_type_len; } /* deep copy */ part = &r->headers_out.headers.part; h = part->elts; for (i = 0; ; i++) { if (i >= part->nelts) { if (part->next == NULL) break; part = part->next; h = part->elts; i = 0; } size += h[i].key.len + h[i].value.len + 2; buf = ngx_palloc(r->pool, size); if (buf == NULL) { return NGX_ERROR; } key = (char *)buf; buf = ngx_cpymem(buf, h[i].key.data, h[i].key.len); *buf++ = '\0'; value = (char *)buf; buf = ngx_cpymem(buf, h[i].value.data, h[i].value.len); *buf++ = '\0'; apr_table_addn(req->headers_out, key, value); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: load headers out: \"%V: %V\"", &h[i].key, &h[i].value); } for (i = 0; special_headers_out[i].name; i++) { vv = ngx_http_get_variable(r, &special_headers_out[i].variable_name, ngx_hash_key(special_headers_out[i].variable_name.data, special_headers_out[i].variable_name.len)); if (vv && !vv->not_found) { data = ngx_palloc(r->pool, vv->len + 1); if (data == NULL) { return NGX_ERROR; } ngx_memcpy(data,vv->data, vv->len); data[vv->len] = '\0'; apr_table_setn(req->headers_out, special_headers_out[i].name, data); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: load headers out: \"%s: %s\"", special_headers_out[i].name, data); } } req->content_type = apr_table_get(ctx->req->headers_out, "Content-Type"); req->content_encoding = apr_table_get(ctx->req->headers_out, "Content-Encoding"); data = (char *)apr_table_get(ctx->req->headers_out, "Content-Languages"); if(data != NULL) { ctx->req->content_languages = apr_array_make(ctx->req->pool, 1, sizeof(const char *)); *(const char **)apr_array_push(ctx->req->content_languages) = data; } /* req->chunked = r->chunked; may be useless */ req->clength = r->headers_out.content_length_n; req->mtime = apr_time_make(r->headers_out.last_modified_time, 0); ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: load headers out done"); return NGX_OK; }
static ngx_inline ngx_int_t ngx_http_modsecurity_load_request(ngx_http_request_t *r) { ngx_http_modsecurity_ctx_t *ctx; request_rec *req; ngx_str_t str; size_t root; ngx_str_t path; ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity); req = ctx->req; /* request line */ req->method = (char *)ngx_pstrdup0(r->pool, &r->method_name); /* TODO: how to use ap_method_number_of ? * req->method_number = ap_method_number_of(req->method); */ req->method_number = ngx_http_modsecurity_method_number(r->method); /* ngx_http_map_uri_to_path() allocates memory for terminating '\0' */ if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) { return NGX_ERROR; } req->filename = (char *) path.data; req->path_info = req->filename; req->args = (char *)ngx_pstrdup0(r->pool, &r->args); req->proto_num = r->http_major *1000 + r->http_minor; req->protocol = (char *)ngx_pstrdup0(r->pool, &r->http_protocol); req->request_time = apr_time_make(r->start_sec, r->start_msec); req->the_request = (char *)ngx_pstrdup0(r->pool, &r->request_line); req->unparsed_uri = (char *)ngx_pstrdup0(r->pool, &r->unparsed_uri); req->uri = (char *)ngx_pstrdup0(r->pool, &r->uri); req->parsed_uri.scheme = "http"; #if (NGX_HTTP_SSL) if (r->connection->ssl) { req->parsed_uri.scheme = "https"; } #endif req->parsed_uri.path = (char *)ngx_pstrdup0(r->pool, &r->uri); req->parsed_uri.is_initialized = 1; str.data = r->port_start; str.len = r->port_end - r->port_start; req->parsed_uri.port = ngx_atoi(str.data, str.len); req->parsed_uri.port_str = (char *)ngx_pstrdup0(r->pool, &str); req->parsed_uri.query = r->args.len ? req->args : NULL; req->parsed_uri.dns_looked_up = 0; req->parsed_uri.dns_resolved = 0; // req->parsed_uri.password = (char *)ngx_pstrdup0(r->pool, &r->headers_in.passwd); // req->parsed_uri.user = (char *)ngx_pstrdup0(r->pool, &r->headers_in.user); req->parsed_uri.fragment = (char *)ngx_pstrdup0(r->pool, &r->exten); req->hostname = (char *)ngx_pstrdup0(r->pool, (ngx_str_t *)&ngx_cycle->hostname); req->header_only = r->header_only ? r->header_only : (r->method == NGX_HTTP_HEAD); return NGX_OK; }
static ngx_http_modsecurity_ctx_t * ngx_http_modsecurity_create_ctx(ngx_http_request_t *r) { ngx_http_modsecurity_loc_conf_t *cf; ngx_pool_cleanup_t *cln; ngx_http_modsecurity_ctx_t *ctx; apr_sockaddr_t *asa; struct sockaddr_in *sin; char *txid; unsigned char salt[TXID_SIZE]; int i; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6; #endif ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_modsecurity_ctx_t)); if (ctx == NULL) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "modSecurity: ctx memory allocation error"); return NULL; } cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_modsecurity_ctx_t)); if (cln == NULL) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "modSecurity: ctx memory allocation error"); return NULL; } cln->handler = ngx_http_modsecurity_cleanup; cln->data = ctx; ctx->r = r; if (r->connection->requests == 0 || ctx->connection == NULL) { /* TODO: set server_rec, why igonre return value? */ ctx->connection = modsecNewConnection(); /* fill apr_sockaddr_t */ asa = ngx_palloc(r->pool, sizeof(apr_sockaddr_t)); asa->pool = ctx->connection->pool; asa->hostname = (char *)ngx_pstrdup0(r->pool, &r->connection->addr_text); asa->servname = asa->hostname; asa->next = NULL; asa->salen = r->connection->socklen; ngx_memcpy(&asa->sa, r->connection->sockaddr, asa->salen); asa->family = ((struct sockaddr *)&asa->sa)->sa_family; switch ( asa->family) { #if (NGX_HAVE_INET6) case AF_INET6: sin6 = (struct sockaddr_in6 *)&asa->sa; asa->ipaddr_ptr = &sin6->sin6_addr; asa->ipaddr_len = sizeof(sin6->sin6_addr); asa->port = ntohs(sin6->sin6_port); asa->addr_str_len = NGX_INET6_ADDRSTRLEN + 1; break; #endif default: /* AF_INET */ sin = (struct sockaddr_in *) &asa->sa; asa->ipaddr_ptr = &sin->sin_addr; asa->ipaddr_len = sizeof(sin->sin_addr); asa->port = ntohs(sin->sin_port); asa->addr_str_len = NGX_INET_ADDRSTRLEN + 1; break; } #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER < 3 ctx->connection->remote_addr = asa; ctx->connection->remote_ip = asa->hostname; #else ctx->connection->client_addr = asa; ctx->connection->client_ip = asa->hostname; #endif ctx->connection->remote_host = NULL; modsecProcessConnection(ctx->connection); } cf = ngx_http_get_module_loc_conf(r, ngx_http_modsecurity); ctx->req = modsecNewRequest(ctx->connection, cf->config); apr_table_setn(ctx->req->notes, NOTE_NGINX_REQUEST_CTX, (const char *) ctx); apr_generate_random_bytes(salt, TXID_SIZE); txid = apr_pcalloc (ctx->req->pool, TXID_SIZE); apr_base64_encode (txid, (const char*)salt, TXID_SIZE); for(i=0;i<TXID_SIZE;i++) { if((salt[i] >= 0x30) && (salt[i] <= 0x39)) {} else if((salt[i] >= 0x40) && (salt[i] <= 0x5A)) {} else if((salt[i] >= 0x61) && (salt[i] <= 0x7A)) {} else { if((i%2)==0) salt[i] = 0x41; else salt[i] = 0x63; } } salt[TXID_SIZE-1] = '\0'; apr_table_setn(ctx->req->subprocess_env, "UNIQUE_ID", apr_psprintf(ctx->req->pool, "%s", salt)); ctx->brigade = apr_brigade_create(ctx->req->pool, ctx->req->connection->bucket_alloc); if (ctx->brigade == NULL) { return NULL; } return ctx; }
static ngx_inline ngx_int_t ngx_http_modsecurity_save_request_body(ngx_http_request_t *r) { ngx_http_modsecurity_ctx_t *ctx; apr_off_t content_length; ngx_buf_t *buf; ngx_http_core_srv_conf_t *cscf; size_t size; ngx_http_connection_t *hc; ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity); apr_brigade_length(ctx->brigade, 0, &content_length); if (r->header_in->end - r->header_in->last >= content_length) { /* use r->header_in */ if (ngx_buf_size(r->header_in)) { /* move to the end */ ngx_memmove(r->header_in->pos + content_length, r->header_in->pos, ngx_buf_size(r->header_in)); } if (apr_brigade_flatten(ctx->brigade, (char *)r->header_in->pos, (apr_size_t *)&content_length) != APR_SUCCESS) { return NGX_ERROR; } apr_brigade_cleanup(ctx->brigade); r->header_in->last += content_length; return NGX_OK; } if (ngx_buf_size(r->header_in)) { /* * ngx_http_set_keepalive will reuse r->header_in if * (r->header_in != c->buffer && r->header_in.last != r->header_in.end), * so we need this code block. * see ngx_http_set_keepalive, ngx_http_alloc_large_header_buffer */ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); size = ngx_max(cscf->large_client_header_buffers.size, (size_t)content_length + ngx_buf_size(r->header_in)); hc = r->http_connection; #if defined(nginx_version) && nginx_version >= 1011011 if (hc->free && size == cscf->large_client_header_buffers.size) { buf = hc->free->buf; #else if (hc->nfree && size == cscf->large_client_header_buffers.size) { buf = hc->free[--hc->nfree]; #endif ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: use http free large header buffer: %p %uz", buf->pos, buf->end - buf->last); } else if (hc->nbusy < cscf->large_client_header_buffers.num) { if (hc->busy == NULL) { hc->busy = ngx_palloc(r->connection->pool, cscf->large_client_header_buffers.num * sizeof(ngx_buf_t *)); } if (hc->busy == NULL) { return NGX_ERROR; } else { buf = ngx_create_temp_buf(r->connection->pool, size); } } else { /* TODO: how to deal this case ? */ return NGX_ERROR; } } else { buf = ngx_create_temp_buf(r->pool, (size_t) content_length); } if (buf == NULL) { return NGX_ERROR; } if (apr_brigade_flatten(ctx->brigade, (char *)buf->pos, (apr_size_t *)&content_length) != APR_SUCCESS) { return NGX_ERROR; } apr_brigade_cleanup(ctx->brigade); buf->last += content_length; ngx_memcpy(buf->last, r->header_in->pos, ngx_buf_size(r->header_in)); buf->last += ngx_buf_size(r->header_in); r->header_in = buf; return NGX_OK; } static ngx_inline ngx_int_t ngx_http_modsecurity_load_headers_out(ngx_http_request_t *r) { ngx_http_modsecurity_ctx_t *ctx; char *data; request_rec *req; ngx_http_variable_value_t *vv; ngx_list_part_t *part; ngx_table_elt_t *h; ngx_uint_t i; char *key, *value; u_char *buf = NULL; size_t size = 0; ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity); req = ctx->req; req->status = r->headers_out.status; req->status_line = (char *)ngx_pstrdup0(r->pool, &r->headers_out.status_line); /* deep copy */ part = &r->headers_out.headers.part; h = part->elts; for (i = 0; ; i++) { if (i >= part->nelts) { if (part->next == NULL) break; part = part->next; h = part->elts; i = 0; } size += h[i].key.len + h[i].value.len + 2; buf = ngx_palloc(r->pool, size); if (buf == NULL) { return NGX_ERROR; } key = (char *)buf; buf = ngx_cpymem(buf, h[i].key.data, h[i].key.len); *buf++ = '\0'; value = (char *)buf; buf = ngx_cpymem(buf, h[i].value.data, h[i].value.len); *buf++ = '\0'; apr_table_addn(req->headers_out, key, value); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: load headers out: \"%V: %V\"", &h[i].key, &h[i].value); } for (i = 0; special_headers_out[i].name; i++) { vv = ngx_http_get_variable(r, &special_headers_out[i].variable_name, ngx_hash_key(special_headers_out[i].variable_name.data, special_headers_out[i].variable_name.len)); if (vv && !vv->not_found) { data = ngx_palloc(r->pool, vv->len + 1); if (data == NULL) { return NGX_ERROR; } ngx_memcpy(data,vv->data, vv->len); data[vv->len] = '\0'; apr_table_setn(req->headers_out, special_headers_out[i].name, data); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: load headers out: \"%s: %s\"", special_headers_out[i].name, data); } } req->content_type = apr_table_get(ctx->req->headers_out, "Content-Type"); req->content_encoding = apr_table_get(ctx->req->headers_out, "Content-Encoding"); data = (char *)apr_table_get(ctx->req->headers_out, "Content-Languages"); if(data != NULL) { ctx->req->content_languages = apr_array_make(ctx->req->pool, 1, sizeof(const char *)); *(const char **)apr_array_push(ctx->req->content_languages) = data; } /* req->chunked = r->chunked; may be useless */ req->clength = r->headers_out.content_length_n; req->mtime = apr_time_make(r->headers_out.last_modified_time, 0); ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: load headers out done"); return NGX_OK; }
static ngx_inline ngx_int_t ngx_http_modsecurity_load_request(ngx_http_request_t *r) { ngx_http_modsecurity_ctx_t *ctx; request_rec *req; size_t root; ngx_str_t path; ngx_uint_t port; struct sockaddr_in *sin; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6; #endif ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity); req = ctx->req; /* request line */ req->method = (char *)ngx_pstrdup0(r->pool, &r->method_name); /* TODO: how to use ap_method_number_of ? * req->method_number = ap_method_number_of(req->method); */ req->method_number = ngx_http_modsecurity_method_number(r->method); /* ngx_http_map_uri_to_path() allocates memory for terminating '\0' */ if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) { return NGX_ERROR; } req->filename = (char *) path.data; req->path_info = req->filename; req->args = (char *)ngx_pstrdup0(r->pool, &r->args); req->proto_num = r->http_major *1000 + r->http_minor; req->protocol = (char *)ngx_pstrdup0(r->pool, &r->http_protocol); req->request_time = apr_time_make(r->start_sec, r->start_msec); req->the_request = (char *)ngx_pstrdup0(r->pool, &r->request_line); req->unparsed_uri = (char *)ngx_pstrdup0(r->pool, &r->unparsed_uri); req->uri = (char *)ngx_pstrdup0(r->pool, &r->uri); req->parsed_uri.scheme = "http"; #if (NGX_HTTP_SSL) if (r->connection->ssl) { req->parsed_uri.scheme = "https"; } #endif req->parsed_uri.path = (char *)ngx_pstrdup0(r->pool, &r->uri); req->parsed_uri.is_initialized = 1; switch (r->connection->local_sockaddr->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: sin6 = (struct sockaddr_in6 *) r->connection->local_sockaddr; port = ntohs(sin6->sin6_port); break; #endif #if (NGX_HAVE_UNIX_DOMAIN) case AF_UNIX: port = 0; break; #endif default: /* AF_INET */ sin = (struct sockaddr_in *) r->connection->local_sockaddr; port = ntohs(sin->sin_port); break; } req->parsed_uri.port = port; req->parsed_uri.port_str = ngx_pnalloc(r->pool, sizeof("65535")); (void) ngx_sprintf((u_char *)req->parsed_uri.port_str, "%ui%c", port, '\0'); req->parsed_uri.query = r->args.len ? req->args : NULL; req->parsed_uri.dns_looked_up = 0; req->parsed_uri.dns_resolved = 0; // req->parsed_uri.password = (char *)ngx_pstrdup0(r->pool, &r->headers_in.passwd); // req->parsed_uri.user = (char *)ngx_pstrdup0(r->pool, &r->headers_in.user); req->parsed_uri.fragment = (char *)ngx_pstrdup0(r->pool, &r->exten); req->hostname = (char *)ngx_pstrdup0(r->pool, (ngx_str_t *)&ngx_cycle->hostname); req->header_only = r->header_only ? r->header_only : (r->method == NGX_HTTP_HEAD); return NGX_OK; }