--- pen.c.orig 2007-09-12 08:26:31.000000000 +0200 +++ pen.c 2007-09-18 12:44:58.000000000 +0200 @@ -1775,6 +1775,15 @@ { int upfd = -1, clino = -1, index = -1, n, pd; unsigned int cli = cli_addr->sin_addr.s_addr; + unsigned int http_cli; // http client address... + struct sockaddr_in http_cli_addr; // and the sockaddr of it + unsigned int real_cli = cli; // the client that will really be used (default is tcp client)... + struct sockaddr_in *real_cli_addr = cli_addr; // and the sockaddr for it + char http_prefetch_buffer[BUFFER_MAX]; // buffer for http request + char *http_forward_header; // client address found in X-Forwarded-For header + char *saveptr; // save pointer for strtok_r + int rc = 0; // read count for http_prefetch_buffer + #ifdef HAVE_SSL SSL *ssl = NULL; @@ -1792,25 +1801,53 @@ } #endif - pd = match_acl(client_acl, cli); + if (http) { + if (debuglevel>1) { + debug("add_client is using prefetch buffer (http mode)"); + } + rc = read(downfd, http_prefetch_buffer, BUFFER_MAX); + if (rc != -1) { + if (pen_strcasestr(http_prefetch_buffer, "\nX-Forwarded-For:")) { + if (debuglevel>1) debug ("Found X-Forwarded-For header"); + http_forward_header = strtok_r(pen_strcasestr(http_prefetch_buffer, "\nX-Forwarded-For:"), " \n", &saveptr); + if (http_forward_header) { + http_forward_header = strtok_r(NULL, " \n", &saveptr); + if (http_forward_header) { + debug("Using X-Forwarded-For client addr: %s", http_forward_header); + if (inet_aton(http_forward_header, &http_cli_addr.sin_addr)) { + http_cli = http_cli_addr.sin_addr.s_addr; + real_cli = http_cli; + real_cli_addr = &http_cli_addr; + } else { + error("X-Forwarded-For field value seems strange: <%s>", http_forward_header); + } + } else error("Couldn't parse X-Forwarded-For header"); + } else error("Couldn't parse X-Forwarded-For header"); + } + } else error("Couldn't read from socket descriptor: %d", downfd); + } + + + pd = match_acl(client_acl, real_cli); if (!pd) { if (debuglevel) debug("add_client: denied by acl"); if (abuse_server != -1) { - upfd = try_server(abuse_server, 0, cli); + upfd = try_server(abuse_server, 0, real_cli_addr); if (upfd != -1) goto Success; } goto Failure; } + if (roundrobin) { if (debuglevel) debug("Bypassing client tracking"); } else { - clino = lookup_client(cli_addr->sin_addr); + clino = lookup_client(real_cli_addr->sin_addr); if (debuglevel) debug("lookup_client returns %d", clino); if (clino != -1) { index = clients[clino].cno; if (index != emerg_server && index != abuse_server) { - upfd = try_server(index, 1, cli); + upfd = try_server(index, 1, real_cli); if (upfd != -1) goto Success; } } @@ -1818,13 +1855,13 @@ if (weight) { index = server_by_weight(); if (index != -1) { - upfd = try_server(index, 0, cli); + upfd = try_server(index, 0, real_cli); if (upfd != -1) goto Success; } } if (hash) { index = cli % nservers; - upfd = try_server(index, 0, cli); + upfd = try_server(index, 0, real_cli); if (upfd != -1) goto Success; } @@ -1832,7 +1869,7 @@ index = current; do { index = (index + 1) % nservers; - if ((upfd = try_server(index, 0, cli)) != -1) goto Success; + if ((upfd = try_server(index, 0, real_cli)) != -1) goto Success; } while (index != current); } /* if we get here, we're dead */ @@ -1840,7 +1877,7 @@ if (!emergency) debug("Using emergency server"); emergency=1; - if ((upfd = try_server(emerg_server, 0, cli)) != -1) goto Success2; + if ((upfd = try_server(emerg_server, 0, real_cli)) != -1) goto Success2; } debug("Couldn't find a server for client"); Failure: @@ -1850,12 +1887,18 @@ Success: emergency=0; Success2: - n = store_client(clino, cli_addr->sin_addr, index); + n = store_client(clino, real_cli_addr->sin_addr, index); + #ifdef HAVE_SSL store_conn(downfd, ssl, upfd, n, index); #else store_conn(downfd, upfd, n, index); #endif + + if ((http) && (rc>0)) { + write(upfd, http_prefetch_buffer, rc); + } + return; }