Forum

Reverse Proxy HTTP Header incorrect

Kjetil
14 November 2013, 18:48
Hi,

I'm using Hiawatha as a reverse proxy/front end for an internal webserver. With Hiawatha running on a non-standard port.
The basic setup is Hiawatha on port 8080, forwarding traffic to a different system on another port.

What I see is that in the HTTP header the "Host:" field becomes incorrect.
A '\0'-termination is inserted between the IP address and the port instead of a ":" (in violation of HTTP/1.0 4.2 and HTTP/1.1 14.23)

The most likely culprit is session.c:remove_port_from_hostname() which remove the ":" hostname-port separator inplace.
Thus when rproxy.c:send_request_to_webserver() sends the HTTP headers to the target web server, it uses the original
header field length, and manages to output both the IP and the port, but now with a '\0' instead of ':'

Regards,
Kjetil

Hiawatha version: 9.3
Operating System: Linux
Hugo Leisink
14 November 2013, 19:12
I've tried many configurations, but I can't reproduce your problem. Can you be more specific? Perhaps show me your configuration and logfile samples?
Kjetil
14 November 2013, 19:24
Hi,

For my test setup I have netcat listening on port 8081 on 192.168.0.1.

When I access Hiawatha with http://127.0.0.1:8080/proxy I get the following header out of netcat:
GET /proxy HTTP/1.1
X-Hiawatha-RProxy-ID: ffd5f7a4bf
Host: 127.0.0.18080
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:23.0) Gecko/20100101 Firefox/23.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
X-Forwarded-For: 127.0.0.1

Note the missing character between 127.0.0.1 and 8080 in the "Host:" field.
I have verified with wireshark that there is a character present there and it is a '\0'.
Probably missing in the output of netcat as it is a non-printable.

Here the configuration file I used:
# GENERAL SETTINGS
#
# ServerId = us
ConnectionsTotal = 250
ConnectionsPerIP = 25
SystemLogfile = /home/user/temp/system.log
GarbageLogfile = /home/user/temp/garbage.log


# BINDING SETTINGS
# A binding is where a client can connect to.
#
Binding {
Port = 8080
# Interface = 127.0.0.1
MaxKeepAlive = 30
TimeForRequest = 1
}

WorkDirectory = /home/user/temp

# DEFAULT WEBSITE
# It is wise to use your IP address as the hostname of the default website
# and give it a blank webpage. By doing so, automated webscanners won't find
# your possible vulnerable website.
#
Hostname = 127.0.0.1
WebsiteRoot = /home/user/www
StartFile = index.html

AccessLogfile = /home/user/temp/access.log
ErrorLogfile = /home/user/temp/error.log
#ErrorHandler = 404:/error.cgi

ReverseProxy proxy* http://192.168.0.1:8081 360
Hugo Leisink
14 November 2013, 20:17
Got it. Please download this version [www.hiawatha-webserver.org] and try again. Please note that this is not the official 9.3.1 release yet. It probably will be soon, but not yet.
Kjetil
15 November 2013, 12:18
Hi,

Thanks for your quick fix for this issue!

I do see that the host port is now completely gone from the request header sent to the internal web server. I don't know if this is intended behavior for reverse proxies. I guess the proxy port is off little or no interest for the target web server.

I do believe that I have encountered another issue with the reverse proxy implementation.
I think the connection type is not detected correctly on the connection between Hiawatha proxy and the proxy target web server. Thus if the target web server is a HTTP/1.0
server or a HTTP/1.1 server that does not support permanent connections (Sends "Connection: close" in the HTTP response header). The proxy_request():keep_alive flag is not set correctly, and the connection is not closed by Hiawatha.

The culprit is the parsing of the HTTP response header in proxy_request() (lines 1557,1559) which requires a CRLF-sequence after the version type
("HTTP/1.0\r\n","HTTP/1.1\r\n")
This would be the correct for a HTTP request header, but not for the response.

HTTP/1.0 6.1 and HTTP/1.1 6.1 specifies that the first line in a HTTP response should be on the format:
Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
And no extra CRLF sequences are allowed on this line, except from the final one.

I guess a more correct check would be "HTTP/1.0 " and "HTTP/1.1 "

Hugo Leisink
17 November 2013, 20:59
It is correct that the host port is gone. The Host header should only contain the hostname. The port number is irrelevant for a webserver.

Can you describe how to reproduce the connection problem for the reverse proxy? I tried several things, but reproduce it myself.
The parsing of the header (lines 1557, 1559) is correct. Every HTTP header line should end with CRLF, even in the response.
Kjetil
17 November 2013, 21:53
I recreated this issue with the follow test setup:

busybox httpd running at port 8081 (The simplest HTTP/1.0 server I can think off)
Hiawatha running on port 8080 proxying traffic to the busybox httpd server.

And if you apply the following patch:
diff -urN hiawatha-9.3.1/src/target.c hiawatha-9.3.1-mod/src/target.c
--- hiawatha-9.3.1/src/target.c 2013-11-14 20:15:57.000000000 +0100
+++ hiawatha-9.3.1-mod/src/target.c 2013-11-17 21:51:33.000000000 +0100
@@ -1339,6 +1339,7 @@
bool header_read = false, keep_reading = true, keep_alive, chunked = false;
struct pollfd poll_data;
time_t deadline;
+ int unknown_header = 0;
#ifdef ENABLE_CACHE
t_cached_object *cached_object;
char *cache_buffer = NULL;
@@ -1568,6 +1569,9 @@
*eol = '\r';
}
}
+ } else {
+ printf("Unable to detect HTTP Version (%s)\n",buffer);
+ unknown_header = 1;
}

content_read = bytes_in_buffer - (end_of_header + 4 - buffer);
@@ -1634,6 +1638,10 @@
}
#endif

+ if ( keep_alive == true && unknown_header == 1 ) {
+ printf("\nUnknown header and keeping connection alive.. Will cause socket timeouts\n");
+ }
+
if (keep_alive == false) {
/* Close connection to webserver

You should get some debug messages showing the HTTP response header that it can't recognize:
Unable to detect HTTP Version (HTTP/1.0 200 OK
Content-type: application/octet-stream
Date: Sun, 17 Nov 2013 20:52:14 GMT
Connection: close
Accept-Ranges: bytes
Last-Modified: Sun, 17 Nov 2013 20:35:50 GMT
Content-length: 6
)
Hugo Leisink
17 November 2013, 22:50
Thanks, am now able to reproduce it. Will take a look at it tomorrow. Going to sleep now.
Hugo Leisink
18 November 2013, 12:16
I've updated the beta package. Please redownload and try again.
Kjetil
18 November 2013, 14:08
Hi again.

Thanks a lot for your support! I can see that the connections are shutdown cleanly between Hiawatha and the internal web server.
And no hanging sockets between requests.
This topic has been closed.