Ticket #1528: 1528.4.patch
| File 1528.4.patch, 9.8 kB (added by glen, 4 months ago) |
|---|
-
src/mod_extforward.c
old new 20 20 /** 21 21 * mod_extforward.c for lighttpd, by comman.kang <at> gmail <dot> com 22 22 * extended, modified by Lionel Elie Mamane (LEM), lionel <at> mamane <dot> lu 23 * support chained proxies by glen@delfi.ee, #1528 23 24 * 24 25 * Config example: 25 26 * … … 33 34 * Note that "all" has precedence over specific entries, 34 35 * so "all except" setups will not work. 35 36 * 37 * In case you have chained proxies, you can add all their IP's to the 38 * config. However "all" has effect only on connecting IP, as the 39 * X-Forwarded-For header can not be trusted. 40 * 36 41 * Note: The effect of this module is variable on $HTTP["remotip"] directives and 37 42 * other module's remote ip dependent actions. 38 43 * Things done by modules before we change the remoteip or after we reset it will match on the proxy's IP. … … 225 230 char *base, *curr; 226 231 /* state variable, 0 means not in string, 1 means in string */ 227 232 int in_str = 0; 228 for (base = pbuffer->ptr, curr = pbuffer->ptr; *curr; curr++) 229 { 233 for (base = pbuffer->ptr, curr = pbuffer->ptr; *curr; curr++) { 230 234 if (in_str) { 231 if ( (*curr > '9' || *curr < '0') && *curr != '.' && *curr != ':') {235 if ((*curr > '9' || *curr < '0') && *curr != '.' && *curr != ':') { 232 236 /* found an separator , insert value into result array */ 233 put_string_into_array_len(result, base, curr -base);237 put_string_into_array_len(result, base, curr - base); 234 238 /* change state to not in string */ 235 239 in_str = 0; 236 240 } 237 241 } else { 238 if (*curr >= '0' && *curr <= '9') 239 { 242 if (*curr >= '0' && *curr <= '9') { 240 243 /* found leading char of an IP address, move base pointer and change state */ 241 244 base = curr; 242 245 in_str = 1; … … 244 247 } 245 248 } 246 249 /* if breaking out while in str, we got to the end of string, so add it */ 247 if (in_str) 248 { 249 put_string_into_array_len(result, base, curr-base); 250 if (in_str) { 251 put_string_into_array_len(result, base, curr - base); 250 252 } 251 253 } 252 254 return result; … … 255 257 #define IP_TRUSTED 1 256 258 #define IP_UNTRUSTED 0 257 259 /* 258 check whether ip is trusted, return 1 for trusted , 0 for untrusted259 */260 * check whether ip is trusted, return 1 for trusted , 0 for untrusted 261 */ 260 262 static int is_proxy_trusted(const char *ipstr, plugin_data *p) 261 263 { 262 data_string* allds = (data_string *) array_get_element(p->conf.forwarder,"all"); 264 data_string* allds = (data_string *)array_get_element(p->conf.forwarder, "all"); 265 263 266 if (allds) { 264 if (strcasecmp(allds->value->ptr, "trust") == 0)267 if (strcasecmp(allds->value->ptr, "trust") == 0) { 265 268 return IP_TRUSTED; 266 else269 } else { 267 270 return IP_UNTRUSTED; 271 } 268 272 } 269 return (data_string *)array_get_element(p->conf.forwarder,ipstr) ? IP_TRUSTED : IP_UNTRUSTED ; 273 274 return (data_string *)array_get_element(p->conf.forwarder, ipstr) ? IP_TRUSTED : IP_UNTRUSTED; 270 275 } 271 276 277 /* 278 * Return char *ip of last address of proxy that is not trusted. 279 * Do not accept "all" keyword here. 280 */ 281 static const char *last_not_in_array(array *a, plugin_data *p) 282 { 283 array *forwarder = p->conf.forwarder; 284 285 for (int i = a->used - 1; i >= 0; i--) { 286 data_string *ds = (data_string *)a->data[i]; 287 const char *ip = ds->value->ptr; 288 289 if (!array_get_element(forwarder, ip)) { 290 return ip; 291 } 292 } 293 return NULL; 294 } 295 272 296 struct addrinfo *ipstr_to_sockaddr(const char *host) 273 297 { 274 298 struct addrinfo hints, *res0; … … 316 340 struct addrinfo *addrlist = NULL; 317 341 #endif 318 342 const char *dst_addr_str = NULL; 319 int i;320 343 array *forward_array = NULL; 321 c har *real_remote_addr = NULL;344 const char *real_remote_addr = NULL; 322 345 #ifdef HAVE_IPV6 323 346 #endif 324 347 … … 342 365 return HANDLER_GO_ON; 343 366 } 344 367 345 /* if the remote ip itself is not trusted , then do nothing */346 368 #ifdef HAVE_IPV6 347 369 dst_addr_str = inet_ntop(con->dst_addr.plain.sa_family, 348 370 con->dst_addr.plain.sa_family == AF_INET6 ? … … 353 375 #else 354 376 dst_addr_str = inet_ntoa(con->dst_addr.ipv4.sin_addr); 355 377 #endif 356 if (IP_UNTRUSTED == is_proxy_trusted (dst_addr_str, p) ) { 378 379 /* if the remote ip itself is not trusted, then do nothing */ 380 if (IP_UNTRUSTED == is_proxy_trusted(dst_addr_str, p)) { 357 381 if (con->conf.log_request_handling) { 358 382 log_error_write(srv, __FILE__, __LINE__, "s", 359 383 "remote address is NOT a trusted proxy, skipping"); … … 362 386 return HANDLER_GO_ON; 363 387 } 364 388 389 /* build forward_array from forwarded data_string */ 365 390 forward_array = extract_forward_array(forwarded->value); 391 real_remote_addr = last_not_in_array(forward_array, p); 366 392 367 /* Testing shows that multiple headers and multiple values in one header368 come in _reverse_ order. So the first one we get is the last one in the request. */369 for (i = forward_array->used - 1; i >= 0; i--) {370 data_string *ds = (data_string *) forward_array->data[i];371 if (ds) {372 real_remote_addr = ds->value->ptr;373 break;374 } else {375 /* bug ? bailing out here */376 break;377 }378 }379 380 393 if (real_remote_addr != NULL) { /* parsed */ 381 394 sock_addr sock; 382 395 struct addrinfo *addrs_left; 383 396 server_socket *srv_sock = con->srv_socket; 384 data_string *forwarded_proto = (data_string *) array_get_element(con->request.headers,"X-Forwarded-Proto");397 data_string *forwarded_proto = (data_string *)array_get_element(con->request.headers, "X-Forwarded-Proto"); 385 398 386 if (forwarded_proto && !strcmp(forwarded_proto->value->ptr, "https")) 399 if (forwarded_proto && !strcmp(forwarded_proto->value->ptr, "https")) { 387 400 srv_sock->is_proxy_ssl = 1; 388 else401 } else { 389 402 srv_sock->is_proxy_ssl = 0; 403 } 390 404 391 405 if (con->conf.log_request_handling) { 392 log_error_write(srv, __FILE__, __LINE__, "ss", 393 "using address:", real_remote_addr); 406 log_error_write(srv, __FILE__, __LINE__, "ss", "using address:", real_remote_addr); 394 407 } 395 408 #ifdef HAVE_IPV6 396 409 addrlist = ipstr_to_sockaddr(real_remote_addr); 397 410 sock.plain.sa_family = AF_UNSPEC; 398 for (addrs_left = addrlist; addrs_left != NULL; 399 addrs_left = addrs_left -> ai_next) { 411 for (addrs_left = addrlist; addrs_left != NULL; addrs_left = addrs_left -> ai_next) { 400 412 sock.plain.sa_family = addrs_left->ai_family; 401 if ( sock.plain.sa_family == AF_INET) {413 if (sock.plain.sa_family == AF_INET) { 402 414 sock.ipv4.sin_addr = ((struct sockaddr_in*)addrs_left->ai_addr)->sin_addr; 403 415 break; 404 } else if ( sock.plain.sa_family == AF_INET6) {416 } else if (sock.plain.sa_family == AF_INET6) { 405 417 sock.ipv6.sin6_addr = ((struct sockaddr_in6*)addrs_left->ai_addr)->sin6_addr; 406 418 break; 407 419 } … … 436 448 if (addrlist != NULL ) freeaddrinfo(addrlist); 437 449 #endif 438 450 } 439 array_free(forward_array);451 array_free(forward_array); 440 452 441 453 /* not found */ 442 454 return HANDLER_GO_ON; -
tests/mod-extforward.conf
old new 1 1 debug.log-request-handling = "enable" 2 debug.log-response-header = " enable"3 debug.log-request-header = " enable"2 debug.log-response-header = "disable" 3 debug.log-request-header = "disable" 4 4 5 5 server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/" 6 6 server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid" … … 27 27 28 28 extforward.forwarder = ( 29 29 "127.0.0.1" => "trust", 30 "127.0.30.1" => "trust", 30 31 ) -
tests/mod-extforward.t
old new 8 8 9 9 use strict; 10 10 use IO::Socket; 11 use Test::More tests => 2;11 use Test::More tests => 5; 12 12 use LightyTest; 13 13 14 14 my $tf = LightyTest->new(); … … 18 18 19 19 ok($tf->start_proc == 0, "Starting lighttpd") or die(); 20 20 21 ## check if If-Modified-Since, If-None-Match works22 23 21 $t->{REQUEST} = ( <<EOF 24 22 GET /ip.pl HTTP/1.0 25 23 Host: www.example.org … … 27 25 EOF 28 26 ); 29 27 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '127.0.10.1' } ]; 30 ok($tf->handle_http($t) == 0, 'expect 127.0.10.1 ');28 ok($tf->handle_http($t) == 0, 'expect 127.0.10.1, from single ip'); 31 29 32 30 $t->{REQUEST} = ( <<EOF 33 31 GET /ip.pl HTTP/1.0 … … 36 34 EOF 37 35 ); 38 36 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '127.0.20.1' } ]; 39 ok($tf->handle_http($t) == 0, 'expect 127.0.20.1 ');37 ok($tf->handle_http($t) == 0, 'expect 127.0.20.1, from two ips'); 40 38 39 $t->{REQUEST} = ( <<EOF 40 GET /ip.pl HTTP/1.0 41 Host: www.example.org 42 X-Forwarded-For: 127.0.10.1, 127.0.20.1, 127.0.30.1 43 EOF 44 ); 45 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '127.0.20.1' } ]; 46 ok($tf->handle_http($t) == 0, 'expect 127.0.20.1, from chained proxies'); 47 41 48 ok($tf->stop_proc == 0, "Stopping lighttpd"); -
tests/docroot/www/ip.pl
old new 2 2 print "Content-Type: text/html\r\n\r\n"; 3 3 print $ENV{'REMOTE_ADDR'}; 4 4 5 if ($ENV{'QUERY_STRING'} eq 'info') { 6 print "\nF:",$ENV{'HTTP_X_FORWARDED_FOR'},"\n"; 7 8 while (my($key, $value) = each %ENV) { 9 printf "%s => %s\n", $key, $value; 10 } 11 } 12 5 13 0; -
NEWS
old new 20 20 * HTTPS env var should be "on" when using mod_extforward and the X-Forwarded-Proto header is set. (#1499) 21 21 * generate ETag and Last-Modified headers for mod_ssi based on newest modified include (#1491) 22 22 * support letterhomes in mod_userdir (#1473) 23 * support chained proxies in mod_extforward (#1528) 23 24 24 25 - 1.4.18 - 2007-09-09 25 26

