@@ -45,19 +45,248 @@ ngx_http_modsecurity_request_read(ngx_http_request_t *r)
4545ngx_int_t
4646ngx_http_modsecurity_access_handler (ngx_http_request_t * r )
4747{
48- #if 1
48+
4949 ngx_pool_t * old_pool ;
5050 ngx_http_modsecurity_ctx_t * ctx ;
5151 ngx_http_modsecurity_conf_t * mcf ;
5252
53- dd ("catching a new _access_ phase handler" );
54-
5553 mcf = ngx_http_get_module_loc_conf (r , ngx_http_modsecurity_module );
56- if (mcf == NULL || mcf -> enable != 1 )
57- {
54+ if (mcf == NULL || mcf -> enable != 1 ) {
5855 dd ("ModSecurity not enabled... returning" );
5956 return NGX_DECLINED ;
6057 }
58+
59+ /*
60+ if (r->method != NGX_HTTP_GET &&
61+ r->method != NGX_HTTP_POST && r->method != NGX_HTTP_HEAD) {
62+ dd("ModSecurity is not ready to deal with anything different from " \
63+ "POST, GET or HEAD");
64+ return NGX_DECLINED;
65+ }
66+ */
67+
68+ dd ("catching a new _rewrite_ phase handler" );
69+
70+ ctx = ngx_http_modsecurity_get_module_ctx (r );
71+
72+ dd ("recovering ctx: %p" , ctx );
73+
74+ if (ctx == NULL )
75+ {
76+ int ret = 0 ;
77+
78+ ngx_connection_t * connection = r -> connection ;
79+ /**
80+ * FIXME: We may want to use struct sockaddr instead of addr_text.
81+ *
82+ */
83+ ngx_str_t addr_text = connection -> addr_text ;
84+
85+ ctx = ngx_http_modsecurity_create_ctx (r );
86+
87+ dd ("ctx was NULL, creating new context: %p" , ctx );
88+
89+ if (ctx == NULL ) {
90+ dd ("ctx still null; Nothing we can do, returning an error." );
91+ return NGX_HTTP_INTERNAL_SERVER_ERROR ;
92+ }
93+
94+ /**
95+ * FIXME: Check if it is possible to hook on nginx on a earlier phase.
96+ *
97+ * At this point we are doing an late connection process. Maybe
98+ * we have to hook into NGX_HTTP_FIND_CONFIG_PHASE, it seems to be the
99+ * erliest phase that nginx allow us to attach those kind of hooks.
100+ *
101+ */
102+ int client_port = ngx_inet_get_port (connection -> sockaddr );
103+ int server_port = ngx_inet_get_port (connection -> local_sockaddr );
104+
105+ const char * client_addr = ngx_str_to_char (addr_text , r -> pool );
106+ if (client_addr == (char * )-1 ) {
107+ return NGX_HTTP_INTERNAL_SERVER_ERROR ;
108+ }
109+
110+ #if defined(MODSECURITY_CHECK_VERSION )
111+ #if MODSECURITY_VERSION_NUM >= 30130100
112+ ngx_str_t hostname ;
113+ hostname .len = 0 ;
114+ // first check if Nginx received a Host header and it's usable
115+ // (i.e. not empty)
116+ // if yes, we can use that
117+ if (r -> headers_in .server .len > 0 ) {
118+ hostname .len = r -> headers_in .server .len ;
119+ hostname .data = r -> headers_in .server .data ;
120+ }
121+ else {
122+ // otherwise we try to use the server config, namely the
123+ // server_name $SERVER_NAME
124+ // directive
125+ // for eg. in default config, server_name is "_"
126+ // possible all requests without a Host header will be
127+ // handled by this server block
128+ ngx_http_core_srv_conf_t * cscf ;
129+ cscf = ngx_http_get_module_srv_conf (r , ngx_http_core_module );
130+ if (cscf -> server_name .len > 0 ) {
131+ hostname .len = cscf -> server_name .len ;
132+ hostname .data = cscf -> server_name .data ;
133+ }
134+ }
135+ if (hostname .len > 0 ) {
136+ const char * host_name = ngx_str_to_char (hostname , r -> pool );
137+ if (host_name == (char * )-1 || host_name == NULL ) {
138+ return NGX_HTTP_INTERNAL_SERVER_ERROR ;
139+ }
140+ else {
141+ // set the hostname in the transaction
142+ // this function is only available in ModSecurity 3.0.13 and later
143+ msc_set_request_hostname (ctx -> modsec_transaction , (const unsigned char * )host_name );
144+ }
145+ }
146+ #endif
147+ #endif
148+
149+ ngx_str_t s ;
150+ u_char addr [NGX_SOCKADDR_STRLEN ];
151+ s .len = NGX_SOCKADDR_STRLEN ;
152+ s .data = addr ;
153+ if (ngx_connection_local_sockaddr (r -> connection , & s , 0 ) != NGX_OK ) {
154+ return NGX_HTTP_INTERNAL_SERVER_ERROR ;
155+ }
156+
157+ const char * server_addr = ngx_str_to_char (s , r -> pool );
158+ if (server_addr == (char * )-1 ) {
159+ return NGX_HTTP_INTERNAL_SERVER_ERROR ;
160+ }
161+
162+ old_pool = ngx_http_modsecurity_pcre_malloc_init (r -> pool );
163+ ret = msc_process_connection (ctx -> modsec_transaction ,
164+ client_addr , client_port ,
165+ server_addr , server_port );
166+ ngx_http_modsecurity_pcre_malloc_done (old_pool );
167+ if (ret != 1 ){
168+ dd ("Was not able to extract connection information." );
169+ }
170+ /**
171+ *
172+ * FIXME: Check how we can finalize a request without crash nginx.
173+ *
174+ * I don't think nginx is expecting to finalize a request at that
175+ * point as it seems that it clean the ngx_http_request_t information
176+ * and try to use it later.
177+ *
178+ */
179+ dd ("Processing intervention with the connection information filled in" );
180+ ret = ngx_http_modsecurity_process_intervention (ctx -> modsec_transaction , r , 1 );
181+ if (ret > 0 ) {
182+ ctx -> intervention_triggered = 1 ;
183+ return ret ;
184+ }
185+
186+ const char * http_version ;
187+ switch (r -> http_version ) {
188+ case NGX_HTTP_VERSION_9 :
189+ http_version = "0.9" ;
190+ break ;
191+ case NGX_HTTP_VERSION_10 :
192+ http_version = "1.0" ;
193+ break ;
194+ case NGX_HTTP_VERSION_11 :
195+ http_version = "1.1" ;
196+ break ;
197+ #if defined(nginx_version ) && nginx_version >= 1009005
198+ case NGX_HTTP_VERSION_20 :
199+ http_version = "2.0" ;
200+ break ;
201+ #endif
202+ default :
203+ http_version = ngx_str_to_char (r -> http_protocol , r -> pool );
204+ if (http_version == (char * )-1 ) {
205+ return NGX_HTTP_INTERNAL_SERVER_ERROR ;
206+ }
207+ if ((http_version != NULL ) && (strlen (http_version ) > 5 ) && (!strncmp ("HTTP/" , http_version , 5 ))) {
208+ http_version += 5 ;
209+ } else {
210+ http_version = "1.0" ;
211+ }
212+ break ;
213+ }
214+
215+ const char * n_uri = ngx_str_to_char (r -> unparsed_uri , r -> pool );
216+ const char * n_method = ngx_str_to_char (r -> method_name , r -> pool );
217+ if (n_uri == (char * )-1 || n_method == (char * )-1 ) {
218+ return NGX_HTTP_INTERNAL_SERVER_ERROR ;
219+ }
220+ if (n_uri == NULL ) {
221+ dd ("uri is of length zero" );
222+ return NGX_HTTP_INTERNAL_SERVER_ERROR ;
223+ }
224+ old_pool = ngx_http_modsecurity_pcre_malloc_init (r -> pool );
225+ msc_process_uri (ctx -> modsec_transaction , n_uri , n_method , http_version );
226+ ngx_http_modsecurity_pcre_malloc_done (old_pool );
227+
228+ dd ("Processing intervention with the transaction information filled in (uri, method and version)" );
229+ ret = ngx_http_modsecurity_process_intervention (ctx -> modsec_transaction , r , 1 );
230+ if (ret > 0 ) {
231+ ctx -> intervention_triggered = 1 ;
232+ return ret ;
233+ }
234+
235+ /**
236+ * Since incoming request headers are already in place, lets send it to ModSecurity
237+ *
238+ */
239+ ngx_list_part_t * part = & r -> headers_in .headers .part ;
240+ ngx_table_elt_t * data = part -> elts ;
241+ ngx_uint_t i = 0 ;
242+ for (i = 0 ; /* void */ ; i ++ ) {
243+ if (i >= part -> nelts ) {
244+ if (part -> next == NULL ) {
245+ break ;
246+ }
247+
248+ part = part -> next ;
249+ data = part -> elts ;
250+ i = 0 ;
251+ }
252+
253+ /**
254+ * By using u_char (utf8_t) I believe nginx is hoping to deal
255+ * with utf8 strings.
256+ * Casting those into to unsigned char * in order to pass
257+ * it to ModSecurity, it will handle with those later.
258+ *
259+ */
260+
261+ dd ("Adding request header: %.*s with value %.*s" , (int )data [i ].key .len , data [i ].key .data , (int ) data [i ].value .len , data [i ].value .data );
262+ msc_add_n_request_header (ctx -> modsec_transaction ,
263+ (const unsigned char * ) data [i ].key .data ,
264+ data [i ].key .len ,
265+ (const unsigned char * ) data [i ].value .data ,
266+ data [i ].value .len );
267+ }
268+
269+ /**
270+ * Since ModSecurity already knew about all headers, i guess it is safe
271+ * to process this information.
272+ */
273+
274+ old_pool = ngx_http_modsecurity_pcre_malloc_init (r -> pool );
275+ msc_process_request_headers (ctx -> modsec_transaction );
276+ ngx_http_modsecurity_pcre_malloc_done (old_pool );
277+ dd ("Processing intervention with the request headers information filled in" );
278+ ret = ngx_http_modsecurity_process_intervention (ctx -> modsec_transaction , r , 1 );
279+ if (r -> error_page ) {
280+ return NGX_DECLINED ;
281+ }
282+ if (ret > 0 ) {
283+ ctx -> intervention_triggered = 1 ;
284+ return ret ;
285+ }
286+ }
287+
288+ #if 1
289+
61290 /*
62291 * FIXME:
63292 * In order to perform some tests, let's accept everything.
0 commit comments