Ticket #1528: 1528.4.patch

File 1528.4.patch, 9.8 kB (added by glen, 4 months ago)

test4 -- do not handle "all" in chained proxies

  • src/mod_extforward.c

    old new  
    2020/** 
    2121 * mod_extforward.c for lighttpd, by comman.kang <at> gmail <dot> com 
    2222 *                  extended, modified by Lionel Elie Mamane (LEM), lionel <at> mamane <dot> lu 
     23 *                  support chained proxies by glen@delfi.ee, #1528 
    2324 * 
    2425 * Config example: 
    2526 * 
     
    3334 *       Note that "all" has precedence over specific entries, 
    3435 *       so "all except" setups will not work. 
    3536 * 
     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 * 
    3641 * Note: The effect of this module is variable on $HTTP["remotip"] directives and 
    3742 *       other module's remote ip dependent actions. 
    3843 *  Things done by modules before we change the remoteip or after we reset it will match on the proxy's IP. 
     
    225230                char *base, *curr; 
    226231                /* state variable, 0 means not in string, 1 means in string */ 
    227232                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++) { 
    230234                        if (in_str) { 
    231                                 if ( (*curr > '9' || *curr < '0') && *curr != '.' && *curr != ':' ) { 
     235                                if ((*curr > '9' || *curr < '0') && *curr != '.' && *curr != ':') { 
    232236                                        /* 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); 
    234238                                        /* change state to not in string */ 
    235239                                        in_str = 0; 
    236240                                } 
    237241                        } else { 
    238                                 if (*curr >= '0' && *curr <= '9') 
    239                                 { 
     242                                if (*curr >= '0' && *curr <= '9') { 
    240243                                        /* found leading char of an IP address, move base pointer and change state */ 
    241244                                        base = curr; 
    242245                                        in_str = 1; 
     
    244247                        } 
    245248                } 
    246249                /* 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); 
    250252                } 
    251253        } 
    252254        return result; 
     
    255257#define IP_TRUSTED 1 
    256258#define IP_UNTRUSTED 0 
    257259/* 
    258    check whether ip is trusted, return 1 for trusted , 0 for untrusted 
    259 */ 
     260 * check whether ip is trusted, return 1 for trusted , 0 for untrusted 
     261 */ 
    260262static int is_proxy_trusted(const char *ipstr, plugin_data *p) 
    261263{ 
    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 
    263266        if (allds) { 
    264                 if (strcasecmp(allds->value->ptr,"trust") == 0) 
     267                if (strcasecmp(allds->value->ptr, "trust") == 0) { 
    265268                        return IP_TRUSTED; 
    266                 else 
     269                } else { 
    267270                        return IP_UNTRUSTED; 
     271                } 
    268272        } 
    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; 
    270275} 
    271276 
     277/* 
     278 * Return char *ip of last address of proxy that is not trusted. 
     279 * Do not accept "all" keyword here. 
     280 */ 
     281static 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 
    272296struct addrinfo *ipstr_to_sockaddr(const char *host) 
    273297{ 
    274298   struct addrinfo hints, *res0; 
     
    316340        struct addrinfo *addrlist = NULL; 
    317341#endif 
    318342        const char *dst_addr_str = NULL; 
    319         int i; 
    320343        array *forward_array = NULL; 
    321         char *real_remote_addr = NULL; 
     344        const char *real_remote_addr = NULL; 
    322345#ifdef HAVE_IPV6 
    323346#endif 
    324347 
     
    342365                return HANDLER_GO_ON; 
    343366        } 
    344367 
    345         /* if the remote ip itself is not trusted , then do nothing */ 
    346368#ifdef HAVE_IPV6 
    347369        dst_addr_str = inet_ntop(con->dst_addr.plain.sa_family, 
    348370                      con->dst_addr.plain.sa_family == AF_INET6 ? 
     
    353375#else 
    354376        dst_addr_str = inet_ntoa(con->dst_addr.ipv4.sin_addr); 
    355377#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)) { 
    357381                if (con->conf.log_request_handling) { 
    358382                        log_error_write(srv, __FILE__, __LINE__, "s", 
    359383                                        "remote address is NOT a trusted proxy, skipping"); 
     
    362386                return HANDLER_GO_ON; 
    363387        } 
    364388 
     389        /* build forward_array from forwarded data_string */ 
    365390        forward_array = extract_forward_array(forwarded->value); 
     391        real_remote_addr = last_not_in_array(forward_array, p); 
    366392 
    367         /* Testing shows that multiple headers and multiple values in one header 
    368            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  
    380393        if (real_remote_addr != NULL) { /* parsed */ 
    381394                sock_addr sock; 
    382395                struct addrinfo *addrs_left; 
    383396                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"); 
    385398 
    386                 if (forwarded_proto && !strcmp(forwarded_proto->value->ptr, "https")) 
     399                if (forwarded_proto && !strcmp(forwarded_proto->value->ptr, "https")) { 
    387400                        srv_sock->is_proxy_ssl = 1; 
    388                 else 
     401                } else { 
    389402                        srv_sock->is_proxy_ssl = 0; 
     403                } 
    390404 
    391405                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); 
    394407                } 
    395408#ifdef HAVE_IPV6 
    396409                addrlist = ipstr_to_sockaddr(real_remote_addr); 
    397410                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) { 
    400412                        sock.plain.sa_family = addrs_left->ai_family; 
    401                         if ( sock.plain.sa_family == AF_INET ) { 
     413                        if (sock.plain.sa_family == AF_INET) { 
    402414                                sock.ipv4.sin_addr = ((struct sockaddr_in*)addrs_left->ai_addr)->sin_addr; 
    403415                                break; 
    404                         } else if ( sock.plain.sa_family == AF_INET6 ) { 
     416                        } else if (sock.plain.sa_family == AF_INET6) { 
    405417                                sock.ipv6.sin6_addr = ((struct sockaddr_in6*)addrs_left->ai_addr)->sin6_addr; 
    406418                                break; 
    407419                        } 
     
    436448                if (addrlist != NULL ) freeaddrinfo(addrlist); 
    437449#endif 
    438450        } 
    439       array_free(forward_array); 
     451      array_free(forward_array); 
    440452 
    441453        /* not found */ 
    442454        return HANDLER_GO_ON; 
  • tests/mod-extforward.conf

    old new  
    11debug.log-request-handling   = "enable" 
    2 debug.log-response-header   = "enable" 
    3 debug.log-request-header   = "enable" 
     2debug.log-response-header   = "disable" 
     3debug.log-request-header   = "disable" 
    44 
    55server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/" 
    66server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid" 
     
    2727 
    2828extforward.forwarder = ( 
    2929        "127.0.0.1" => "trust", 
     30        "127.0.30.1" => "trust", 
    3031) 
  • tests/mod-extforward.t

    old new  
    88 
    99use strict; 
    1010use IO::Socket; 
    11 use Test::More tests => 2
     11use Test::More tests => 5
    1212use LightyTest; 
    1313 
    1414my $tf = LightyTest->new(); 
     
    1818 
    1919ok($tf->start_proc == 0, "Starting lighttpd") or die(); 
    2020 
    21 ## check if If-Modified-Since, If-None-Match works 
    22  
    2321$t->{REQUEST} = ( <<EOF 
    2422GET /ip.pl HTTP/1.0 
    2523Host: www.example.org 
     
    2725EOF 
    2826); 
    2927$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'); 
     28ok($tf->handle_http($t) == 0, 'expect 127.0.10.1, from single ip'); 
    3129 
    3230$t->{REQUEST} = ( <<EOF 
    3331GET /ip.pl HTTP/1.0 
     
    3634EOF 
    3735); 
    3836$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'); 
     37ok($tf->handle_http($t) == 0, 'expect 127.0.20.1, from two ips'); 
    4038 
     39$t->{REQUEST} = ( <<EOF 
     40GET /ip.pl HTTP/1.0 
     41Host: www.example.org 
     42X-Forwarded-For: 127.0.10.1, 127.0.20.1, 127.0.30.1 
     43EOF 
     44); 
     45$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '127.0.20.1' } ]; 
     46ok($tf->handle_http($t) == 0, 'expect 127.0.20.1, from chained proxies'); 
     47 
    4148ok($tf->stop_proc == 0, "Stopping lighttpd"); 
  • tests/docroot/www/ip.pl

    old new  
    22print "Content-Type: text/html\r\n\r\n"; 
    33print $ENV{'REMOTE_ADDR'}; 
    44 
     5if ($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 
    5130; 
  • NEWS

    old new  
    2020  * HTTPS env var should be "on" when using mod_extforward and the X-Forwarded-Proto header is set. (#1499) 
    2121  * generate ETag and Last-Modified headers for mod_ssi based on newest modified include (#1491) 
    2222  * support letterhomes in mod_userdir (#1473) 
     23  * support chained proxies in mod_extforward (#1528) 
    2324 
    2425- 1.4.18 - 2007-09-09 
    2526