Mercurial > hg > nginx-quic
annotate src/http/modules/ngx_http_referer_module.c @ 4664:356c91151658 stable-1.2
Merge of r4618: rewrite escaping fix (ticket #162).
The following code resulted in incorrect escaping of uri and possible
segfault:
location / {
rewrite ^(.*) $1?c=$1;
return 200 "$uri";
}
If there were arguments in a rewrite's replacement string, and length was
actually calculated (due to duplicate captures as in the example above,
or variables present), the is_args flag was set and incorrectly copied
after length calculation. This resulted in escaping applied to the uri part
of the replacement, resulting in incorrect escaping. Additionally, buffer
was allocated without escaping expected, thus this also resulted in buffer
overrun and possible segfault.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 04 Jun 2012 11:07:19 +0000 |
parents | d620f497c50f |
children | 8f74cf107137 |
rev | line source |
---|---|
577 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4412 | 4 * Copyright (C) Nginx, Inc. |
577 | 5 */ |
6 | |
7 | |
8 #include <ngx_config.h> | |
9 #include <ngx_core.h> | |
10 #include <ngx_http.h> | |
11 | |
12 | |
595 | 13 #define NGX_HTTP_REFERER_NO_URI_PART ((void *) 4) |
14 | |
1785 | 15 #if !(NGX_PCRE) |
1388 | 16 |
17 #define ngx_regex_t void | |
18 | |
19 #endif | |
20 | |
21 | |
577 | 22 typedef struct { |
1253
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
23 ngx_hash_combined_t hash; |
577 | 24 |
1388 | 25 #if (NGX_PCRE) |
26 ngx_array_t *regex; | |
27 #endif | |
28 | |
593 | 29 ngx_flag_t no_referer; |
30 ngx_flag_t blocked_referer; | |
577 | 31 |
593 | 32 ngx_hash_keys_arrays_t *keys; |
3939
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
33 |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
34 ngx_uint_t referer_hash_max_size; |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
35 ngx_uint_t referer_hash_bucket_size; |
577 | 36 } ngx_http_referer_conf_t; |
37 | |
38 | |
39 static void * ngx_http_referer_create_conf(ngx_conf_t *cf); | |
40 static char * ngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent, | |
41 void *child); | |
42 static char *ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, | |
43 void *conf); | |
593 | 44 static char *ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys, |
595 | 45 ngx_str_t *value, ngx_str_t *uri); |
1388 | 46 static char *ngx_http_add_regex_referer(ngx_conf_t *cf, |
47 ngx_http_referer_conf_t *rlcf, ngx_str_t *name, ngx_regex_t *regex); | |
593 | 48 static int ngx_libc_cdecl ngx_http_cmp_referer_wildcards(const void *one, |
49 const void *two); | |
577 | 50 |
51 | |
52 static ngx_command_t ngx_http_referer_commands[] = { | |
53 | |
54 { ngx_string("valid_referers"), | |
55 NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, | |
56 ngx_http_valid_referers, | |
57 NGX_HTTP_LOC_CONF_OFFSET, | |
58 0, | |
59 NULL }, | |
60 | |
3939
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
61 { ngx_string("referer_hash_max_size"), |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
62 NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
63 ngx_conf_set_num_slot, |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
64 NGX_HTTP_LOC_CONF_OFFSET, |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
65 offsetof(ngx_http_referer_conf_t, referer_hash_max_size), |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
66 NULL }, |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
67 |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
68 { ngx_string("referer_hash_bucket_size"), |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
69 NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
70 ngx_conf_set_num_slot, |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
71 NGX_HTTP_LOC_CONF_OFFSET, |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
72 offsetof(ngx_http_referer_conf_t, referer_hash_bucket_size), |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
73 NULL }, |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
74 |
577 | 75 ngx_null_command |
76 }; | |
77 | |
78 | |
79 static ngx_http_module_t ngx_http_referer_module_ctx = { | |
80 NULL, /* preconfiguration */ | |
81 NULL, /* postconfiguration */ | |
82 | |
83 NULL, /* create main configuration */ | |
84 NULL, /* init main configuration */ | |
85 | |
86 NULL, /* create server configuration */ | |
87 NULL, /* merge server configuration */ | |
88 | |
89 ngx_http_referer_create_conf, /* create location configuration */ | |
90 ngx_http_referer_merge_conf /* merge location configuration */ | |
91 }; | |
92 | |
93 | |
94 ngx_module_t ngx_http_referer_module = { | |
95 NGX_MODULE_V1, | |
96 &ngx_http_referer_module_ctx, /* module context */ | |
97 ngx_http_referer_commands, /* module directives */ | |
98 NGX_HTTP_MODULE, /* module type */ | |
99 NULL, /* init master */ | |
100 NULL, /* init module */ | |
101 NULL, /* init process */ | |
102 NULL, /* init thread */ | |
103 NULL, /* exit thread */ | |
104 NULL, /* exit process */ | |
105 NULL, /* exit master */ | |
106 NGX_MODULE_V1_PADDING | |
107 }; | |
108 | |
109 | |
110 static ngx_int_t | |
111 ngx_http_referer_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, | |
112 uintptr_t data) | |
113 { | |
1388 | 114 u_char *p, *ref, *last; |
115 size_t len; | |
116 ngx_str_t *uri; | |
117 ngx_uint_t i, key; | |
118 ngx_http_referer_conf_t *rlcf; | |
119 u_char buf[256]; | |
577 | 120 |
593 | 121 rlcf = ngx_http_get_module_loc_conf(r, ngx_http_referer_module); |
577 | 122 |
1253
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
123 if (rlcf->hash.hash.buckets == NULL |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
124 && rlcf->hash.wc_head == NULL |
1388 | 125 && rlcf->hash.wc_tail == NULL |
126 #if (NGX_PCRE) | |
127 && rlcf->regex == NULL | |
128 #endif | |
129 ) | |
1253
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
130 { |
595 | 131 goto valid; |
577 | 132 } |
133 | |
134 if (r->headers_in.referer == NULL) { | |
593 | 135 if (rlcf->no_referer) { |
595 | 136 goto valid; |
137 } | |
577 | 138 |
595 | 139 goto invalid; |
577 | 140 } |
141 | |
142 len = r->headers_in.referer->value.len; | |
143 ref = r->headers_in.referer->value.data; | |
144 | |
3459 | 145 if (len >= sizeof("http://i.ru") - 1) { |
146 last = ref + len; | |
147 | |
148 if (ngx_strncasecmp(ref, (u_char *) "http://", 7) == 0) { | |
149 ref += 7; | |
150 goto valid_scheme; | |
151 | |
152 } else if (ngx_strncasecmp(ref, (u_char *) "https://", 8) == 0) { | |
153 ref += 8; | |
154 goto valid_scheme; | |
595 | 155 } |
577 | 156 } |
157 | |
3459 | 158 if (rlcf->blocked_referer) { |
159 goto valid; | |
160 } | |
161 | |
162 goto invalid; | |
163 | |
164 valid_scheme: | |
165 | |
595 | 166 i = 0; |
167 key = 0; | |
577 | 168 |
595 | 169 for (p = ref; p < last; p++) { |
593 | 170 if (*p == '/' || *p == ':') { |
171 break; | |
577 | 172 } |
595 | 173 |
174 buf[i] = ngx_tolower(*p); | |
175 key = ngx_hash(key, buf[i++]); | |
176 | |
177 if (i == 256) { | |
178 goto invalid; | |
179 } | |
593 | 180 } |
577 | 181 |
1388 | 182 uri = ngx_hash_find_combined(&rlcf->hash, key, buf, p - ref); |
577 | 183 |
1253
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
184 if (uri) { |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
185 goto uri; |
577 | 186 } |
187 | |
1388 | 188 #if (NGX_PCRE) |
189 | |
190 if (rlcf->regex) { | |
1785 | 191 ngx_int_t rc; |
192 ngx_str_t referer; | |
1388 | 193 |
194 referer.len = len - 7; | |
195 referer.data = ref; | |
196 | |
1785 | 197 rc = ngx_regex_exec_array(rlcf->regex, &referer, r->connection->log); |
1388 | 198 |
1785 | 199 if (rc == NGX_OK) { |
1388 | 200 goto valid; |
201 } | |
1785 | 202 |
203 if (rc == NGX_ERROR) { | |
204 return rc; | |
205 } | |
206 | |
207 /* NGX_DECLINED */ | |
1388 | 208 } |
209 | |
210 #endif | |
211 | |
595 | 212 invalid: |
213 | |
577 | 214 *v = ngx_http_variable_true_value; |
215 | |
216 return NGX_OK; | |
595 | 217 |
218 uri: | |
219 | |
220 for ( /* void */ ; p < last; p++) { | |
221 if (*p == '/') { | |
222 break; | |
223 } | |
224 } | |
225 | |
226 len = last - p; | |
227 | |
228 if (uri == NGX_HTTP_REFERER_NO_URI_PART) { | |
229 goto valid; | |
230 } | |
231 | |
232 if (len < uri->len || ngx_strncmp(uri->data, p, uri->len) != 0) { | |
233 goto invalid; | |
234 } | |
235 | |
236 valid: | |
237 | |
238 *v = ngx_http_variable_null_value; | |
239 | |
240 return NGX_OK; | |
577 | 241 } |
242 | |
243 | |
244 static void * | |
245 ngx_http_referer_create_conf(ngx_conf_t *cf) | |
246 { | |
247 ngx_http_referer_conf_t *conf; | |
248 | |
593 | 249 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_referer_conf_t)); |
577 | 250 if (conf == NULL) { |
2912
c7d57b539248
return NULL instead of NGX_CONF_ERROR on a create conf failure
Igor Sysoev <igor@sysoev.ru>
parents:
1800
diff
changeset
|
251 return NULL; |
577 | 252 } |
253 | |
1782
db07cb9d1cbc
regex valid_referers were not inherited
Igor Sysoev <igor@sysoev.ru>
parents:
1704
diff
changeset
|
254 #if (NGX_PCRE) |
db07cb9d1cbc
regex valid_referers were not inherited
Igor Sysoev <igor@sysoev.ru>
parents:
1704
diff
changeset
|
255 conf->regex = NGX_CONF_UNSET_PTR; |
db07cb9d1cbc
regex valid_referers were not inherited
Igor Sysoev <igor@sysoev.ru>
parents:
1704
diff
changeset
|
256 #endif |
db07cb9d1cbc
regex valid_referers were not inherited
Igor Sysoev <igor@sysoev.ru>
parents:
1704
diff
changeset
|
257 |
577 | 258 conf->no_referer = NGX_CONF_UNSET; |
259 conf->blocked_referer = NGX_CONF_UNSET; | |
3939
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
260 conf->referer_hash_max_size = NGX_CONF_UNSET_UINT; |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
261 conf->referer_hash_bucket_size = NGX_CONF_UNSET_UINT; |
577 | 262 |
263 return conf; | |
264 } | |
265 | |
266 | |
267 static char * | |
268 ngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent, void *child) | |
269 { | |
270 ngx_http_referer_conf_t *prev = parent; | |
271 ngx_http_referer_conf_t *conf = child; | |
272 | |
593 | 273 ngx_hash_init_t hash; |
274 | |
275 if (conf->keys == NULL) { | |
276 conf->hash = prev->hash; | |
277 | |
1800 | 278 #if (NGX_PCRE) |
1782
db07cb9d1cbc
regex valid_referers were not inherited
Igor Sysoev <igor@sysoev.ru>
parents:
1704
diff
changeset
|
279 ngx_conf_merge_ptr_value(conf->regex, prev->regex, NULL); |
1800 | 280 #endif |
577 | 281 ngx_conf_merge_value(conf->no_referer, prev->no_referer, 0); |
282 ngx_conf_merge_value(conf->blocked_referer, prev->blocked_referer, 0); | |
3939
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
283 ngx_conf_merge_uint_value(conf->referer_hash_max_size, |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
284 prev->referer_hash_max_size, 2048); |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
285 ngx_conf_merge_uint_value(conf->referer_hash_bucket_size, |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
286 prev->referer_hash_bucket_size, 64); |
593 | 287 |
288 return NGX_CONF_OK; | |
289 } | |
290 | |
603 | 291 if ((conf->no_referer == 1 || conf->blocked_referer == 1) |
1253
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
292 && conf->keys->keys.nelts == 0 |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
293 && conf->keys->dns_wc_head.nelts == 0 |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
294 && conf->keys->dns_wc_tail.nelts == 0) |
603 | 295 { |
296 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, | |
297 "the \"none\" or \"blocked\" referers are specified " | |
298 "in the \"valid_referers\" directive " | |
299 "without any valid referer"); | |
300 return NGX_CONF_ERROR; | |
301 } | |
302 | |
3939
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
303 ngx_conf_merge_uint_value(conf->referer_hash_max_size, |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
304 prev->referer_hash_max_size, 2048); |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
305 ngx_conf_merge_uint_value(conf->referer_hash_bucket_size, |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
306 prev->referer_hash_bucket_size, 64); |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
307 conf->referer_hash_bucket_size = ngx_align(conf->referer_hash_bucket_size, |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
308 ngx_cacheline_size); |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
309 |
593 | 310 hash.key = ngx_hash_key_lc; |
3939
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
311 hash.max_size = conf->referer_hash_max_size; |
3cbbe86a7a95
referer_hash_max_size and referer_hash_bucket_size directives
Igor Sysoev <igor@sysoev.ru>
parents:
3516
diff
changeset
|
312 hash.bucket_size = conf->referer_hash_bucket_size; |
4008
debb2f235aa3
Fix names of the referer hash size directives introduced in r3940.
Igor Sysoev <igor@sysoev.ru>
parents:
3939
diff
changeset
|
313 hash.name = "referer_hash"; |
593 | 314 hash.pool = cf->pool; |
315 | |
316 if (conf->keys->keys.nelts) { | |
1253
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
317 hash.hash = &conf->hash.hash; |
593 | 318 hash.temp_pool = NULL; |
319 | |
320 if (ngx_hash_init(&hash, conf->keys->keys.elts, conf->keys->keys.nelts) | |
321 != NGX_OK) | |
322 { | |
323 return NGX_CONF_ERROR; | |
324 } | |
325 } | |
326 | |
1253
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
327 if (conf->keys->dns_wc_head.nelts) { |
593 | 328 |
1253
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
329 ngx_qsort(conf->keys->dns_wc_head.elts, |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
330 (size_t) conf->keys->dns_wc_head.nelts, |
593 | 331 sizeof(ngx_hash_key_t), |
332 ngx_http_cmp_referer_wildcards); | |
333 | |
334 hash.hash = NULL; | |
335 hash.temp_pool = cf->temp_pool; | |
336 | |
1253
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
337 if (ngx_hash_wildcard_init(&hash, conf->keys->dns_wc_head.elts, |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
338 conf->keys->dns_wc_head.nelts) |
593 | 339 != NGX_OK) |
340 { | |
341 return NGX_CONF_ERROR; | |
342 } | |
343 | |
1253
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
344 conf->hash.wc_head = (ngx_hash_wildcard_t *) hash.hash; |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
345 } |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
346 |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
347 if (conf->keys->dns_wc_tail.nelts) { |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
348 |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
349 ngx_qsort(conf->keys->dns_wc_tail.elts, |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
350 (size_t) conf->keys->dns_wc_tail.nelts, |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
351 sizeof(ngx_hash_key_t), |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
352 ngx_http_cmp_referer_wildcards); |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
353 |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
354 hash.hash = NULL; |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
355 hash.temp_pool = cf->temp_pool; |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
356 |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
357 if (ngx_hash_wildcard_init(&hash, conf->keys->dns_wc_tail.elts, |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
358 conf->keys->dns_wc_tail.nelts) |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
359 != NGX_OK) |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
360 { |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
361 return NGX_CONF_ERROR; |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
362 } |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
363 |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
364 conf->hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash; |
577 | 365 } |
366 | |
1800 | 367 #if (NGX_PCRE) |
1782
db07cb9d1cbc
regex valid_referers were not inherited
Igor Sysoev <igor@sysoev.ru>
parents:
1704
diff
changeset
|
368 ngx_conf_merge_ptr_value(conf->regex, prev->regex, NULL); |
1800 | 369 #endif |
1782
db07cb9d1cbc
regex valid_referers were not inherited
Igor Sysoev <igor@sysoev.ru>
parents:
1704
diff
changeset
|
370 |
577 | 371 if (conf->no_referer == NGX_CONF_UNSET) { |
372 conf->no_referer = 0; | |
373 } | |
374 | |
375 if (conf->blocked_referer == NGX_CONF_UNSET) { | |
376 conf->blocked_referer = 0; | |
377 } | |
378 | |
611 | 379 conf->keys = NULL; |
380 | |
577 | 381 return NGX_CONF_OK; |
382 } | |
383 | |
384 | |
385 static char * | |
386 ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
387 { | |
593 | 388 ngx_http_referer_conf_t *rlcf = conf; |
577 | 389 |
593 | 390 u_char *p; |
595 | 391 ngx_str_t *value, uri, name; |
593 | 392 ngx_uint_t i, n; |
577 | 393 ngx_http_variable_t *var; |
394 ngx_http_server_name_t *sn; | |
395 ngx_http_core_srv_conf_t *cscf; | |
396 | |
3516
dd1570b6f237
ngx_str_set() and ngx_str_null()
Igor Sysoev <igor@sysoev.ru>
parents:
3459
diff
changeset
|
397 ngx_str_set(&name, "invalid_referer"); |
577 | 398 |
583 | 399 var = ngx_http_add_variable(cf, &name, |
1565 | 400 NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOHASH); |
577 | 401 if (var == NULL) { |
402 return NGX_CONF_ERROR; | |
403 } | |
404 | |
637 | 405 var->get_handler = ngx_http_referer_variable; |
577 | 406 |
593 | 407 if (rlcf->keys == NULL) { |
408 rlcf->keys = ngx_pcalloc(cf->temp_pool, sizeof(ngx_hash_keys_arrays_t)); | |
409 if (rlcf->keys == NULL) { | |
410 return NGX_CONF_ERROR; | |
411 } | |
577 | 412 |
593 | 413 rlcf->keys->pool = cf->pool; |
414 rlcf->keys->temp_pool = cf->pool; | |
415 | |
416 if (ngx_hash_keys_array_init(rlcf->keys, NGX_HASH_SMALL) != NGX_OK) { | |
577 | 417 return NGX_CONF_ERROR; |
418 } | |
419 } | |
420 | |
421 value = cf->args->elts; | |
422 | |
423 for (i = 1; i < cf->args->nelts; i++) { | |
424 if (value[i].len == 0) { | |
425 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
426 "invalid referer \"%V\"", &value[i]); | |
427 return NGX_CONF_ERROR; | |
428 } | |
429 | |
430 if (ngx_strcmp(value[i].data, "none") == 0) { | |
593 | 431 rlcf->no_referer = 1; |
577 | 432 continue; |
433 } | |
434 | |
435 if (ngx_strcmp(value[i].data, "blocked") == 0) { | |
593 | 436 rlcf->blocked_referer = 1; |
577 | 437 continue; |
438 } | |
439 | |
3516
dd1570b6f237
ngx_str_set() and ngx_str_null()
Igor Sysoev <igor@sysoev.ru>
parents:
3459
diff
changeset
|
440 ngx_str_null(&uri); |
595 | 441 |
577 | 442 if (ngx_strcmp(value[i].data, "server_names") == 0) { |
593 | 443 |
444 cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module); | |
577 | 445 |
593 | 446 sn = cscf->server_names.elts; |
447 for (n = 0; n < cscf->server_names.nelts; n++) { | |
1388 | 448 |
449 #if (NGX_PCRE) | |
450 if (sn[n].regex) { | |
451 | |
452 if (ngx_http_add_regex_referer(cf, rlcf, &sn[n].name, | |
3325 | 453 sn[n].regex->regex) |
1388 | 454 != NGX_OK) |
455 { | |
456 return NGX_CONF_ERROR; | |
457 } | |
458 | |
459 continue; | |
460 } | |
461 #endif | |
462 | |
595 | 463 if (ngx_http_add_referer(cf, rlcf->keys, &sn[n].name, &uri) |
464 != NGX_OK) | |
465 { | |
593 | 466 return NGX_CONF_ERROR; |
467 } | |
468 } | |
577 | 469 |
470 continue; | |
471 } | |
472 | |
1388 | 473 if (value[i].data[0] == '~') { |
474 if (ngx_http_add_regex_referer(cf, rlcf, &value[i], NULL) != NGX_OK) | |
475 { | |
476 return NGX_CONF_ERROR; | |
477 } | |
478 | |
479 continue; | |
480 } | |
481 | |
1242 | 482 p = (u_char *) ngx_strchr(value[i].data, '/'); |
577 | 483 |
593 | 484 if (p) { |
595 | 485 uri.len = (value[i].data + value[i].len) - p; |
486 uri.data = p; | |
593 | 487 value[i].len = p - value[i].data; |
577 | 488 } |
489 | |
595 | 490 if (ngx_http_add_referer(cf, rlcf->keys, &value[i], &uri) != NGX_OK) { |
577 | 491 return NGX_CONF_ERROR; |
492 } | |
493 } | |
494 | |
495 return NGX_CONF_OK; | |
496 } | |
593 | 497 |
498 | |
499 static char * | |
500 ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys, | |
595 | 501 ngx_str_t *value, ngx_str_t *uri) |
593 | 502 { |
1253
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
503 ngx_int_t rc; |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
504 ngx_str_t *u; |
593 | 505 |
595 | 506 if (uri->len == 0) { |
507 u = NGX_HTTP_REFERER_NO_URI_PART; | |
508 | |
509 } else { | |
510 u = ngx_palloc(cf->pool, sizeof(ngx_str_t)); | |
511 if (u == NULL) { | |
512 return NGX_CONF_ERROR; | |
513 } | |
514 | |
515 *u = *uri; | |
516 } | |
517 | |
1253
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
518 rc = ngx_hash_add_key(keys, value, u, NGX_HASH_WILDCARD_KEY); |
593 | 519 |
520 if (rc == NGX_OK) { | |
521 return NGX_CONF_OK; | |
522 } | |
523 | |
1253
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
524 if (rc == NGX_DECLINED) { |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
525 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
526 "invalid hostname or wildcard \"%V\"", value); |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
527 } |
8ef04207c84f
the "www.example.*" wildcard hash support
Igor Sysoev <igor@sysoev.ru>
parents:
1242
diff
changeset
|
528 |
593 | 529 if (rc == NGX_BUSY) { |
530 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
531 "conflicting parameter \"%V\"", value); | |
532 } | |
533 | |
534 return NGX_CONF_ERROR; | |
535 } | |
536 | |
537 | |
1388 | 538 static char * |
539 ngx_http_add_regex_referer(ngx_conf_t *cf, ngx_http_referer_conf_t *rlcf, | |
540 ngx_str_t *name, ngx_regex_t *regex) | |
541 { | |
542 #if (NGX_PCRE) | |
3325 | 543 ngx_regex_elt_t *re; |
544 ngx_regex_compile_t rc; | |
545 u_char errstr[NGX_MAX_CONF_ERRSTR]; | |
1388 | 546 |
3122
3e994ac670dc
test space between "~" and regex in server_name and invalid_referers
Igor Sysoev <igor@sysoev.ru>
parents:
3116
diff
changeset
|
547 if (name->len == 1) { |
3e994ac670dc
test space between "~" and regex in server_name and invalid_referers
Igor Sysoev <igor@sysoev.ru>
parents:
3116
diff
changeset
|
548 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty regex in \"%V\"", name); |
3e994ac670dc
test space between "~" and regex in server_name and invalid_referers
Igor Sysoev <igor@sysoev.ru>
parents:
3116
diff
changeset
|
549 return NGX_CONF_ERROR; |
3e994ac670dc
test space between "~" and regex in server_name and invalid_referers
Igor Sysoev <igor@sysoev.ru>
parents:
3116
diff
changeset
|
550 } |
3e994ac670dc
test space between "~" and regex in server_name and invalid_referers
Igor Sysoev <igor@sysoev.ru>
parents:
3116
diff
changeset
|
551 |
1782
db07cb9d1cbc
regex valid_referers were not inherited
Igor Sysoev <igor@sysoev.ru>
parents:
1704
diff
changeset
|
552 if (rlcf->regex == NGX_CONF_UNSET_PTR) { |
1785 | 553 rlcf->regex = ngx_array_create(cf->pool, 2, sizeof(ngx_regex_elt_t)); |
1388 | 554 if (rlcf->regex == NULL) { |
555 return NGX_CONF_ERROR; | |
556 } | |
557 } | |
558 | |
1785 | 559 re = ngx_array_push(rlcf->regex); |
560 if (re == NULL) { | |
1388 | 561 return NGX_CONF_ERROR; |
562 } | |
563 | |
564 if (regex) { | |
1785 | 565 re->regex = regex; |
566 re->name = name->data; | |
1388 | 567 |
568 return NGX_CONF_OK; | |
569 } | |
570 | |
571 name->len--; | |
572 name->data++; | |
573 | |
3325 | 574 ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); |
1388 | 575 |
3325 | 576 rc.pattern = *name; |
577 rc.pool = cf->pool; | |
578 rc.options = NGX_REGEX_CASELESS; | |
579 rc.err.len = NGX_MAX_CONF_ERRSTR; | |
580 rc.err.data = errstr; | |
581 | |
582 if (ngx_regex_compile(&rc) != NGX_OK) { | |
583 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err); | |
1388 | 584 return NGX_CONF_ERROR; |
585 } | |
586 | |
3325 | 587 re->regex = rc.regex; |
1785 | 588 re->name = name->data; |
1388 | 589 |
590 return NGX_CONF_OK; | |
591 | |
592 #else | |
593 | |
594 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
595 "the using of the regex \"%V\" requires PCRE library", | |
596 name); | |
597 | |
598 return NGX_CONF_ERROR; | |
599 | |
600 #endif | |
601 } | |
602 | |
603 | |
593 | 604 static int ngx_libc_cdecl |
605 ngx_http_cmp_referer_wildcards(const void *one, const void *two) | |
606 { | |
607 ngx_hash_key_t *first, *second; | |
608 | |
609 first = (ngx_hash_key_t *) one; | |
610 second = (ngx_hash_key_t *) two; | |
611 | |
3116
98e288c6dac3
If .domain.com, .sub.domain.com, and .domain-some.com were defined,
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
612 return ngx_dns_strcmp(first->key.data, second->key.data); |
593 | 613 } |