]>
Commit | Line | Data |
---|---|---|
21a4552f ER |
1 | --- lighttpd-1.4.13/configure.in~ 2006-12-12 19:59:48.956431896 +0200 |
2 | +++ lighttpd-1.4.13/configure.in 2006-12-12 20:00:40.387576647 +0200 | |
b58467d6 ER |
3 | @@ -538,7 +538,7 @@ |
4 | AC_OUTPUT | |
5 | ||
6 | ||
21a4552f ER |
7 | -do_build="mod_cgi mod_fastcgi mod_proxy mod_evhost mod_simple_vhost mod_access mod_alias mod_setenv mod_usertrack mod_auth mod_status mod_accesslog mod_rrdtool mod_secdownload mod_expire mod_compress mod_dirlisting mod_indexfiles mod_userdir mod_webdav mod_staticfile mod_scgi mod_flv_streaming" |
8 | +do_build="mod_cgi mod_fastcgi mod_extforward mod_proxy mod_evhost mod_simple_vhost mod_access mod_alias mod_setenv mod_usertrack mod_auth mod_status mod_accesslog mod_rrdtool mod_secdownload mod_expire mod_compress mod_dirlisting mod_indexfiles mod_userdir mod_webdav mod_staticfile mod_scgi mod_flv_streaming" | |
b58467d6 ER |
9 | |
10 | plugins="mod_rewrite mod_redirect mod_ssi mod_trigger_b4_dl" | |
11 | features="regex-conditionals" | |
b58467d6 ER |
12 | --- lighttpd-1.4.11/src/Makefile.am 2006-03-07 13:20:20.000000000 +0100 |
13 | +++ lighttpd-1.4.11.extforward/src/Makefile.am 2006-05-26 19:17:55.028343433 +0200 | |
14 | @@ -193,6 +193,11 @@ | |
15 | mod_fastcgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined | |
16 | mod_fastcgi_la_LIBADD = $(common_libadd) | |
17 | ||
18 | +lib_LTLIBRARIES += mod_extforward.la | |
19 | +mod_extforward_la_SOURCES = mod_extforward.c | |
20 | +mod_extforward_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined | |
21 | +mod_extforward_la_LIBADD = $(common_libadd) | |
22 | + | |
23 | lib_LTLIBRARIES += mod_access.la | |
24 | mod_access_la_SOURCES = mod_access.c | |
25 | mod_access_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined | |
b58467d6 ER |
26 | --- lighttpd-1.4.11/src/mod_extforward.c 1970-01-01 01:00:00.000000000 +0100 |
27 | +++ lighttpd-1.4.11.extforward/src/mod_extforward.c 2006-05-26 23:54:32.050640213 +0200 | |
28 | @@ -0,0 +1,490 @@ | |
29 | +#include <ctype.h> | |
30 | +#include <stdlib.h> | |
31 | +#include <string.h> | |
32 | +#include <stdio.h> | |
33 | +#include <netinet/in.h> | |
34 | + | |
35 | +#include "base.h" | |
36 | +#include "log.h" | |
37 | +#include "buffer.h" | |
38 | + | |
39 | +#include "plugin.h" | |
40 | + | |
41 | +#include "inet_ntop_cache.h" | |
42 | +#ifdef HAVE_CONFIG_H | |
43 | +#include "config.h" | |
44 | +#endif | |
45 | + | |
46 | +/** | |
47 | + * mod_extforward.c for lighttpd, by comman.kang <at> gmail <dot> com | |
48 | + * extended, modified by Lionel Elie Mamane (LEM), lionel <at> mamane <dot> lu | |
49 | + * | |
50 | + * Config example: | |
51 | + * | |
52 | + * Trust proxy 10.0.0.232 and 10.0.0.232 | |
53 | + * extforward.forwarder = ( "10.0.0.232" => "trust", | |
54 | + * "10.0.0.233" => "trust" ) | |
55 | + * | |
56 | + * Trust all proxies (NOT RECOMMENDED!) | |
57 | + * extforward.forwarder = ( "all" => "trust") | |
58 | + * | |
59 | + * Note that "all" has precedence over specific entries, | |
60 | + * so "all except" setups will not work. | |
61 | + * | |
62 | + * Note: The effect of this module is variable on $HTTP["remotip"] directives and | |
63 | + * other module's remote ip dependent actions. | |
64 | + * Things done by modules before we change the remoteip or after we reset it will match on the proxy's IP. | |
65 | + * Things done in between these two moments will match on the real client's IP. | |
66 | + * The moment things are done by a module depends on in which hook it does things and within the same hook | |
67 | + * on whether they are before/after us in the module loading order | |
68 | + * (order in the server.modules directive in the config file). | |
69 | + * | |
70 | + * Tested behaviours: | |
71 | + * | |
72 | + * mod_access: Will match on the real client. | |
73 | + * | |
74 | + * mod_accesslog: | |
75 | + * In order to see the "real" ip address in access log , | |
76 | + * you'll have to load mod_extforward after mod_accesslog. | |
77 | + * like this: | |
78 | + * | |
79 | + * server.modules = ( | |
80 | + * ..... | |
81 | + * mod_accesslog, | |
82 | + * mod_extforward | |
83 | + * ) | |
84 | + * | |
85 | + * Known issues: | |
86 | + * seems causing segfault with mod_ssl and $HTTP{"socket"} directives | |
87 | + * LEM 2006.05.26: Fixed segfault $SERVER["socket"] directive. Untested with SSL. | |
88 | + * | |
89 | + * ChangeLog: | |
90 | + * 2005.12.19 Initial Version | |
91 | + * 2005.12.19 fixed conflict with conditional directives | |
92 | + * 2006.05.26 LEM: IPv6 support | |
93 | + * 2006.05.26 LEM: Fix a segfault with $SERVER["socket"] directive. | |
94 | + * 2006.05.26 LEM: Run at uri_raw time, as we don't need to see the URI | |
95 | + * In this manner, we run before mod_access and $HTTP["remoteip"] directives work! | |
96 | + * 2006.05.26 LEM: Clean config_cond cache of tests whose result we probably change. | |
97 | + */ | |
98 | + | |
99 | + | |
100 | +/* plugin config for all request/connections */ | |
101 | + | |
102 | +typedef struct { | |
103 | + array *forwarder; | |
104 | +} plugin_config; | |
105 | + | |
106 | +typedef struct { | |
107 | + PLUGIN_DATA; | |
108 | + | |
109 | + plugin_config **config_storage; | |
110 | + | |
111 | + plugin_config conf; | |
112 | +} plugin_data; | |
113 | + | |
114 | + | |
115 | +/* context , used for restore remote ip */ | |
116 | + | |
117 | +typedef struct { | |
118 | + sock_addr saved_remote_addr; | |
119 | + buffer *saved_remote_addr_buf; | |
120 | +} handler_ctx; | |
121 | + | |
122 | + | |
123 | +static handler_ctx * handler_ctx_init(sock_addr oldaddr, buffer *oldaddr_buf) { | |
124 | + handler_ctx * hctx; | |
125 | + hctx = calloc(1, sizeof(*hctx)); | |
126 | + hctx->saved_remote_addr = oldaddr; | |
127 | + hctx->saved_remote_addr_buf = oldaddr_buf; | |
128 | + return hctx; | |
129 | +} | |
130 | + | |
131 | +static void handler_ctx_free(handler_ctx *hctx) { | |
132 | + free(hctx); | |
133 | +} | |
134 | + | |
135 | +/* init the plugin data */ | |
136 | +INIT_FUNC(mod_extforward_init) { | |
137 | + plugin_data *p; | |
138 | + p = calloc(1, sizeof(*p)); | |
139 | + return p; | |
140 | +} | |
141 | + | |
142 | +/* destroy the plugin data */ | |
143 | +FREE_FUNC(mod_extforward_free) { | |
144 | + plugin_data *p = p_d; | |
145 | + | |
146 | + UNUSED(srv); | |
147 | + | |
148 | + if (!p) return HANDLER_GO_ON; | |
149 | + | |
150 | + if (p->config_storage) { | |
151 | + size_t i; | |
152 | + | |
153 | + for (i = 0; i < srv->config_context->used; i++) { | |
154 | + plugin_config *s = p->config_storage[i]; | |
155 | + | |
156 | + if (!s) continue; | |
157 | + | |
158 | + array_free(s->forwarder); | |
159 | + | |
160 | + free(s); | |
161 | + } | |
162 | + free(p->config_storage); | |
163 | + } | |
164 | + | |
165 | + | |
166 | + free(p); | |
167 | + | |
168 | + return HANDLER_GO_ON; | |
169 | +} | |
170 | + | |
171 | +/* handle plugin config and check values */ | |
172 | + | |
173 | +SETDEFAULTS_FUNC(mod_extforward_set_defaults) { | |
174 | + plugin_data *p = p_d; | |
175 | + size_t i = 0; | |
176 | + | |
177 | + config_values_t cv[] = { | |
178 | + { "extforward.forwarder", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ | |
179 | + { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } | |
180 | + }; | |
181 | + | |
182 | + if (!p) return HANDLER_ERROR; | |
183 | + | |
184 | + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); | |
185 | + | |
186 | + for (i = 0; i < srv->config_context->used; i++) { | |
187 | + plugin_config *s; | |
188 | + | |
189 | + s = calloc(1, sizeof(plugin_config)); | |
190 | + s->forwarder = array_init(); | |
191 | + | |
192 | + cv[0].destination = s->forwarder; | |
193 | + | |
194 | + p->config_storage[i] = s; | |
195 | + | |
196 | + if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) { | |
197 | + return HANDLER_ERROR; | |
198 | + } | |
199 | + } | |
200 | + | |
201 | + return HANDLER_GO_ON; | |
202 | +} | |
203 | + | |
204 | +#define PATCH(x) \ | |
205 | + p->conf.x = s->x; | |
206 | +static int mod_extforward_patch_connection(server *srv, connection *con, plugin_data *p) { | |
207 | + size_t i, j; | |
208 | + plugin_config *s = p->config_storage[0]; | |
209 | + | |
210 | + PATCH(forwarder); | |
211 | + | |
212 | + /* LEM: The purpose of this seems to match extforward configuration | |
213 | + stanzas that are not in the global context, but in some sub-context. | |
214 | + I fear this will break contexts of the form HTTP['remote'] = . | |
215 | + (in the form that they do not work with the real remote, but matching on | |
216 | + the proxy instead). | |
217 | + | |
218 | + I'm not sure this this is all thread-safe. Is the p we are passed different | |
219 | + for each connection or is it global? | |
220 | + | |
221 | + mod_fastcgi does the same, so it must be safe. | |
222 | + */ | |
223 | + /* skip the first, the global context */ | |
224 | + for (i = 1; i < srv->config_context->used; i++) { | |
225 | + data_config *dc = (data_config *)srv->config_context->data[i]; | |
226 | + s = p->config_storage[i]; | |
227 | + | |
228 | + /* condition didn't match */ | |
229 | + if (!config_check_cond(srv, con, dc)) continue; | |
230 | + | |
231 | + /* merge config */ | |
232 | + for (j = 0; j < dc->value->used; j++) { | |
233 | + data_unset *du = dc->value->data[j]; | |
234 | + | |
235 | + if (buffer_is_equal_string(du->key, CONST_STR_LEN("extforward.forwarder"))) { | |
236 | + PATCH(forwarder); | |
237 | + } | |
238 | + } | |
239 | + } | |
240 | + | |
241 | + return 0; | |
242 | +} | |
243 | +#undef PATCH | |
244 | + | |
245 | + | |
246 | +static void put_string_into_array_len(array *ary, const char *str, int len) | |
247 | +{ | |
248 | + data_string *tempdata; | |
249 | + if (len == 0) | |
250 | + return; | |
251 | + tempdata = data_string_init(); | |
252 | + buffer_copy_string_len(tempdata->value,str,len); | |
253 | + array_insert_unique(ary,(data_unset *)tempdata); | |
254 | +} | |
255 | +/* | |
256 | + extract a forward array from the environment | |
257 | +*/ | |
258 | +static array *extract_forward_array(buffer *pbuffer) | |
259 | +{ | |
260 | + array *result = array_init(); | |
261 | + if (pbuffer->used > 0) { | |
262 | + char *base, *curr; | |
263 | + /* state variable, 0 means not in string, 1 means in string */ | |
264 | + int in_str = 0; | |
265 | + for (base = pbuffer->ptr, curr = pbuffer->ptr; *curr; curr++) | |
266 | + { | |
267 | + if (in_str) { | |
268 | + if ( (*curr > '9' || *curr < '0') && *curr != '.' && *curr != ':' ) { | |
269 | + /* found an separator , insert value into result array */ | |
270 | + put_string_into_array_len(result, base, curr-base); | |
271 | + /* change state to not in string */ | |
272 | + in_str = 0; | |
273 | + } | |
274 | + } else { | |
275 | + if (*curr >= '0' && *curr <= '9') | |
276 | + { | |
277 | + /* found leading char of an IP address, move base pointer and change state */ | |
278 | + base = curr; | |
279 | + in_str = 1; | |
280 | + } | |
281 | + } | |
282 | + } | |
283 | + /* if breaking out while in str, we got to the end of string, so add it */ | |
284 | + if (in_str) | |
285 | + { | |
286 | + put_string_into_array_len(result, base, curr-base); | |
287 | + } | |
288 | + } | |
289 | + return result; | |
290 | +} | |
291 | + | |
292 | +#define IP_TRUSTED 1 | |
293 | +#define IP_UNTRUSTED 0 | |
294 | +/* | |
295 | + check whether ip is trusted, return 1 for trusted , 0 for untrusted | |
296 | +*/ | |
297 | +static int is_proxy_trusted(const char *ipstr, plugin_data *p) | |
298 | +{ | |
299 | + data_string* allds = (data_string *) array_get_element(p->conf.forwarder,"all"); | |
300 | + if (allds) { | |
301 | + if (strcasecmp(allds->value->ptr,"trust") == 0) | |
302 | + return IP_TRUSTED; | |
303 | + else | |
304 | + return IP_UNTRUSTED; | |
305 | + } | |
306 | + return (data_string *)array_get_element(p->conf.forwarder,ipstr) ? IP_TRUSTED : IP_UNTRUSTED ; | |
307 | +} | |
308 | + | |
309 | +struct addrinfo *ipstr_to_sockaddr(const char *host) | |
310 | +{ | |
311 | + struct addrinfo hints, *res0; | |
312 | + int result; | |
313 | + memset(&hints, 0, sizeof(hints)); | |
314 | + hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; | |
315 | + | |
316 | + result = getaddrinfo(host, NULL, &hints, &res0); | |
317 | + if ( result != 0 ) | |
318 | + { | |
319 | + fprintf(stderr,"could not resolve hostname %s because %s\n", host,gai_strerror(result)); | |
320 | + if (result == EAI_SYSTEM) | |
321 | + perror("The system error is "); | |
322 | + return NULL; | |
323 | + } | |
324 | + else | |
325 | + if (res0==0) | |
326 | + fprintf(stderr, "Problem in resolving hostname %s: succeeded, but no information returned\n", host); | |
327 | + | |
328 | + return res0; | |
329 | +} | |
330 | + | |
331 | + | |
332 | +static void clean_cond_cache(server *srv, connection *con) | |
333 | +{ | |
334 | + size_t i; | |
335 | + | |
336 | + for (i = 0; i < srv->config_context->used; i++) { | |
337 | + data_config *dc = (data_config *)srv->config_context->data[i]; | |
338 | + | |
339 | + if (dc->comp == COMP_HTTP_REMOTEIP) | |
340 | + { | |
341 | + con->cond_cache[i].result = COND_RESULT_UNSET; | |
342 | + con->cond_cache[i].patterncount = 0; | |
343 | + } | |
344 | + } | |
345 | +} | |
346 | + | |
347 | +URIHANDLER_FUNC(mod_extforward_uri_handler) { | |
348 | + plugin_data *p = p_d; | |
349 | + data_string *forwarded = NULL; | |
350 | +#ifdef HAVE_IPV6 | |
351 | + char b2[INET6_ADDRSTRLEN + 1]; | |
352 | +#endif | |
353 | + const char *s; | |
354 | + UNUSED(srv); | |
355 | + mod_extforward_patch_connection(srv, con, p); | |
356 | + | |
357 | +/* log_error_write(srv, __FILE__, __LINE__,"s","mod_extforward_uri_handler called\n"); */ | |
358 | + | |
359 | + /* if the remote ip itself is not trusted , then do nothing */ | |
360 | +#ifdef HAVE_IPV6 | |
361 | + s = inet_ntop(con->dst_addr.plain.sa_family, | |
362 | + con->dst_addr.plain.sa_family == AF_INET6 ? | |
363 | + &(con->dst_addr.ipv6.sin6_addr) : | |
364 | + &(con->dst_addr.ipv4.sin_addr), | |
365 | + b2, | |
366 | + (sizeof b2) - 1); | |
367 | +#else | |
368 | + s = inet_ntoa(con->dst_addr.ipv4.sin_addr); | |
369 | +#endif | |
370 | + if (IP_UNTRUSTED == is_proxy_trusted (s, p) ) | |
371 | + return HANDLER_GO_ON; | |
372 | + | |
373 | + /* log_error_write(srv, __FILE__, __LINE__,"s","remote address is trusted proxy, go on\n");*/ | |
374 | + if (con->request.headers && | |
375 | + ((forwarded = (data_string *) array_get_element(con->request.headers,"X-Forwarded-For")) || | |
376 | + (forwarded = (data_string *) array_get_element(con->request.headers, "Forwarded-For")))) | |
377 | + { | |
378 | + /* log_error_write(srv, __FILE__, __LINE__,"s","found forwarded header\n");*/ | |
379 | + /* found forwarded for header */ | |
380 | + int i; | |
381 | + array *forward_array = extract_forward_array(forwarded->value); | |
382 | + char *real_remote_addr = NULL; | |
383 | +#ifdef HAVE_IPV6 | |
384 | + struct addrinfo *addrlist = NULL; | |
385 | +#endif | |
386 | + /* Testing shows that multiple headers and multiple values in one header | |
387 | + come in _reverse_ order. So the first one we get is the last one in the request. */ | |
388 | + for (i = forward_array->used - 1; i >= 0; i--) | |
389 | + { | |
390 | + data_string *ds = (data_string *) forward_array->data[i]; | |
391 | + if (ds) { | |
392 | +/* log_error_write(srv, __FILE__, __LINE__,"ss","forward",ds->value->ptr); */ | |
393 | + real_remote_addr = ds->value->ptr; | |
394 | + break; | |
395 | + /* LEM: What the hell is this about? | |
396 | + We test whether the forwarded for IP is trusted? | |
397 | + This looks like an ugly hack to handle multiple Forwarded-For's | |
398 | + and avoid those set to our proxies, or something like that. | |
399 | + My testing shows that reverse proxies add a new X-Forwarded-For header, | |
400 | + and we should thus take the last one, which is the first one we see. | |
401 | + | |
402 | + The net result of the old code is that we use the first untrusted IP, | |
403 | + or if all are trusted, the last trusted IP. | |
404 | + That's crazy. So I've disabled this. | |
405 | + */ | |
406 | + /* check whether it is trusted */ | |
407 | +/* if (IP_UNTRUSTED == is_proxy_trusted(ds->value->ptr,p) ) */ | |
408 | +/* break; */ | |
409 | +/* log_error_write(srv, __FILE__, __LINE__,"ss",ds->value->ptr," is trusted."); */ | |
410 | + | |
411 | + } | |
412 | + else { | |
413 | + /* bug ? bailing out here */ | |
414 | + break; | |
415 | + } | |
416 | + } | |
417 | + if (real_remote_addr != NULL) /* parsed */ | |
418 | + { | |
419 | + sock_addr s; | |
420 | + struct addrinfo *addrs_left; | |
421 | +/* log_error_write(srv, __FILE__, __LINE__,"ss","use forward",real_remote_addr); */ | |
422 | +#ifdef HAVE_IPV6 | |
423 | + addrlist = ipstr_to_sockaddr(real_remote_addr); | |
424 | + s.plain.sa_family = AF_UNSPEC; | |
425 | + for (addrs_left = addrlist; addrs_left != NULL; | |
426 | + addrs_left = addrs_left -> ai_next) | |
427 | + { | |
428 | + s.plain.sa_family = addrs_left->ai_family; | |
429 | + if ( s.plain.sa_family == AF_INET ) | |
430 | + { | |
431 | + s.ipv4.sin_addr = ((struct sockaddr_in*)addrs_left->ai_addr)->sin_addr; | |
432 | + break; | |
433 | + } | |
434 | + else if ( s.plain.sa_family == AF_INET6 ) | |
435 | + { | |
436 | + s.ipv6.sin6_addr = ((struct sockaddr_in6*)addrs_left->ai_addr)->sin6_addr; | |
437 | + break; | |
438 | + } | |
439 | + } | |
440 | +#else | |
441 | + s.ipv4.sin_addr.s_addr = inet_addr(real_remote_addr); | |
442 | + s.plain.sa_family = (s.ipv4.sin_addr.s_addr == 0xFFFFFFFF) ? AF_UNSPEC : AF_INET; | |
443 | +#endif | |
444 | + if (s.plain.sa_family != AF_UNSPEC) | |
445 | + { | |
446 | + /* we found the remote address, modify current connection and save the old address */ | |
447 | + if (con->plugin_ctx[p->id]) { | |
448 | + log_error_write(srv, __FILE__, __LINE__,"patching an already patched connection!"); | |
449 | + handler_ctx_free(con->plugin_ctx[p->id]); | |
450 | + con->plugin_ctx[p->id] = NULL; | |
451 | + } | |
452 | + /* save old address */ | |
453 | + con->plugin_ctx[p->id] = handler_ctx_init(con->dst_addr, con->dst_addr_buf); | |
454 | + /* patch connection address */ | |
455 | + con->dst_addr = s; | |
456 | + con->dst_addr_buf = buffer_init(); | |
457 | + buffer_copy_string(con->dst_addr_buf, real_remote_addr); | |
458 | +/* log_error_write(srv, __FILE__, __LINE__,"ss","Set dst_addr_buf to ", real_remote_addr); */ | |
459 | + /* Now, clean the conf_cond cache, because we may have changed the results of tests */ | |
460 | + clean_cond_cache(srv, con); | |
461 | + } | |
462 | +#ifdef HAVE_IPV6 | |
463 | + if (addrlist != NULL ) freeaddrinfo(addrlist); | |
464 | +#endif | |
465 | + } | |
466 | + array_free(forward_array); | |
467 | + } | |
468 | + | |
469 | + /* not found */ | |
470 | + return HANDLER_GO_ON; | |
471 | +} | |
472 | + | |
473 | +CONNECTION_FUNC(mod_extforward_restore) { | |
474 | + plugin_data *p = p_d; | |
475 | + UNUSED(srv); | |
476 | + | |
477 | + /* LEM: This seems completely unuseful, as we are not using | |
478 | + p->conf in this function. Furthermore, it brings a | |
479 | + segfault if one of the conditional configuration | |
480 | + blocks is "SERVER['socket'] == foo", because the | |
481 | + socket is not known yet in the srv/con structure. | |
482 | + */ | |
483 | + /* mod_extforward_patch_connection(srv, con, p); */ | |
484 | + | |
485 | + /* restore this connection's remote ip */ | |
486 | + if (con->plugin_ctx[p->id]) { | |
487 | + handler_ctx *hctx = con->plugin_ctx[p->id]; | |
488 | + con->dst_addr = hctx->saved_remote_addr; | |
489 | + buffer_free(con->dst_addr_buf); | |
490 | + con->dst_addr_buf = hctx->saved_remote_addr_buf; | |
491 | +/* log_error_write(srv, __FILE__, __LINE__,"s","LEM: Reset dst_addr_buf"); */ | |
492 | + handler_ctx_free(hctx); | |
493 | + con->plugin_ctx[p->id] = NULL; | |
494 | + /* Now, clean the conf_cond cache, because we may have changed the results of tests */ | |
495 | + clean_cond_cache(srv, con); | |
496 | + } | |
497 | + return HANDLER_GO_ON; | |
498 | +} | |
499 | + | |
500 | + | |
501 | +/* this function is called at dlopen() time and inits the callbacks */ | |
502 | + | |
503 | +int mod_extforward_plugin_init(plugin *p) { | |
504 | + p->version = LIGHTTPD_VERSION_ID; | |
505 | + p->name = buffer_init_string("extforward"); | |
506 | + | |
507 | + p->init = mod_extforward_init; | |
508 | + p->handle_uri_raw = mod_extforward_uri_handler; | |
509 | + p->handle_request_done = mod_extforward_restore; | |
510 | + p->connection_reset = mod_extforward_restore; | |
511 | + p->set_defaults = mod_extforward_set_defaults; | |
512 | + p->cleanup = mod_extforward_free; | |
513 | + | |
514 | + p->data = NULL; | |
515 | + | |
516 | + return 0; | |
517 | +} | |
518 | + |