Skip to contentSkip to conversation

enhance compatibility with HTTP/1.1 proxies

PATCH In review Frank Behrens 4 participants 7 messages Oct 27, 2008 – Nov 20, 2008

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 enhance compatibility with HTTP/1.1 proxies

May I propose the following patch to enhance openvpn's compatibility with HTTP/1.1 proxies?
See
http://tools.ietf.org/html/rfc2616#section-14.23
and
http://tools.ietf.org/html/rfc2817#section-5.2

proxy.c renamed from proxy.c.orig +6 -0
@@ -348,6 +348,12 @@
   if (!send_line_crlf (sd, buf))
     goto error;
 
+  /* send Host: header */
+  openvpn_snprintf (buf, sizeof(buf), "Host: %s:%d",
+		    host, port);
+  if (!send_line_crlf (sd, buf))
+    goto error;
+
   /* send User-Agent string if provided */
   if (p->options.user_agent)
     {

Regards,
Frank

Signature · 2 lines
Frank Behrens, Osterwieck, Germany
PGP-key 0x5B7C47ED on public servers available.
#1 lore raw
Quoted 11 lines · Frank Behrens

May I propose the following patch to enhance openvpn's compatibility with HTTP/1.1 proxies? See
http://tools.ietf.org/html/rfc2616#section-14.23
and
http://tools.ietf.org/html/rfc2817#section-5.2

proxy.c renamed from proxy.c.orig +0 -0
@@ -348,6 +348,12 @@
   if (!send_line_crlf (sd, buf))
     goto error;

proxy.c line 359

Quoted 10 lines
proxy.c renamed from proxy.c.orig +6 -0
 
+  /* send Host: header */
+  openvpn_snprintf (buf, sizeof(buf), "Host: %s:%d",
+		    host, port);
+  if (!send_line_crlf (sd, buf))
+    goto error;
+
   /* send User-Agent string if provided */
   if (p->options.user_agent)
     {

Shouldn't you check p->options.http_version and make sure it's >= 1.1 before sending the Host header?

James

#2 lore raw
Quoted 25 lines · James Yonan
Quoted 11 lines · Frank Behrens

May I propose the following patch to enhance openvpn's compatibility with HTTP/1.1 proxies? See
http://tools.ietf.org/html/rfc2616#section-14.23
and
http://tools.ietf.org/html/rfc2817#section-5.2

proxy.c 2008-10-27 13:30:48.000000000 +0100 renamed from proxy.c.orig 2008-10-06 09:22:20.000000000 +0200 +0 -0
@@ -348,6 +348,12 @@
   if (!send_line_crlf (sd, buf))
     goto error;

proxy.c 2008-10-27 13:30:48.000000000 +0100 line 359

Quoted 10 lines
proxy.c 2008-10-27 13:30:48.000000000 +0100 renamed from proxy.c.orig 2008-10-06 09:22:20.000000000 +0200 +6 -0
 
+  /* send Host: header */
+  openvpn_snprintf (buf, sizeof(buf), "Host: %s:%d",
+            host, port);
+  if (!send_line_crlf (sd, buf))
+    goto error;
+
   /* send User-Agent string if provided */
   if (p->options.user_agent)
     {

Shouldn't you check p->options.http_version and make sure it's >= 1.1 before sending the Host header?

Quoted 1 line

James

Cuurently I can not imagine a server/proxy, that does not understand the Host header? see also http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.6.1.1

But to be on the safe side we can make this check. I would check for http_version != "1.0". Currently I'm not able to send a revised patch, if desired I can make this until weekend.

Thanks for your attention!
Frank

#3 lore raw
In reply to James Yonan

James Yonan <[email protected]...> wrote on 4 Nov 2008 12:16:

Quoted 2 lines

Shouldn't you check p->options.http_version and make sure it's >= 1.1 before sending the Host header?

Here is a revised patch, that works for me and implements your suggestion:

proxy.c renamed from proxy.c.orig +8 -0
@@ -348,6 +348,14 @@ establish_http_proxy_passthru (struct ht
   if (!send_line_crlf (sd, buf))
     goto error;
 
+  /* send Host: header for HTTP version above 1.0 */
+  if (strcmp(p->options.http_version, "1.0") != 0) {
+    openvpn_snprintf (buf, sizeof(buf), "Host: %s:%d",
+		      host, port);
+    if (!send_line_crlf (sd, buf))
+      goto error;
+  }
+
   /* send User-Agent string if provided */
   if (p->options.user_agent)
     {
#4 lore raw
Quoted 6 lines · Frank Behrens

James Yonan <[email protected]...> wrote on 4 Nov 2008 12:16:

Quoted 2 lines

Shouldn't you check p->options.http_version and make sure it's >= 1.1 before sending the Host header?

Here is a revised patch, that works for me and implements your suggestion:

Sorry Frank,

I have to object. It does not implement James's suggestion as you claim, but random guesswork - inadequate for security software and prone to breaking at later updates.

proxy.c establish_http_proxy_passthru (struct ht · line 352

Quoted 8 lines
proxy.c renamed from proxy.c.orig +2 -0
@@ -348,6 +348,14 @@ establish_http_proxy_passthru (struct ht
   if (!send_line_crlf (sd, buf))
     goto error;
 
+  /* send Host: header for HTTP version above 1.0 */
+  if (strcmp(p->options.http_version, "1.0") != 0) {

This doesn't check for ">= 1.1", but "!= 1.0".
What if I use 0.9, or garbage, or nothing?
Oops, you lose -- in either case.

Even if it's a user option and it's their own fault for misconfiguring.

At the very very least, it'll go along these lines (untested and without reading how http_version is obtained and if additional checks are sensible!). Note this may fail with HTTP/2.X or newer, since new major versions are free to interpret existing headers in a different way, but since that's neither existent nor implement, let's not care today, but let's not throw obstacles for later use...

    int rc,
    unsigned int major, minor;

    rc = sscanf(p->options.http_version, "%u.%u", &major, &minor);
    if (rc == 2) {
      switch (major) {
        case 1:
          if (minor >= 1) {
              /* HTTP/1.1 or newer, use Host: header */
          } else {
              /* HTTP/1.0 or HTTP/0.9 */
          }
          break;
        default:
          /* unsupported, complain and terminate */
      }
    }

You may want to accept only 1.0 and 1.1 rather than 1.0 and 1.n for n >= 1
- but there should only ever be A SINGLE PLACE to enforce that.

Else you'll have a hell of work once you start implementing HTTP/1.2 later on...

Signature · 1 line
Matthias Andree
#5 lore raw

Hi Matthias!

Matthias Andree <[email protected]...> wrote on 12 Nov 2008 14:36:

Quoted 6 lines · Frank Behrens
Quoted 4 lines

James Yonan <[email protected]...> wrote on 4 Nov 2008 12:16:

Quoted 2 lines

Shouldn't you check p->options.http_version and make sure it's >= 1.1 before sending the Host header?

Quoted 6 lines
Quoted 2 lines

Here is a revised patch, that works for me and implements your suggestion:

Sorry Frank,

I have to object. It does not implement James's suggestion as you claim,

Ok, this was a mistake. I implemented the solution I proposed on this list in my mail from 05 Nov 2008
(<[email protected]...>).

Quoted 2 lines

but random guesswork - inadequate for security software and prone to breaking at later updates.

I would not say "random guesswork".

Quoted 6 lines
Quoted 6 lines
proxy.c renamed from proxy.c.orig +0 -0
@@ -348,6 +348,14 @@ establish_http_proxy_passthru (struct ht
   if (!send_line_crlf (sd, buf))
     goto error;
 
Quoted 6 lines

proxy.c establish_http_proxy_passthru (struct ht · line 352

Quoted 2 lines
proxy.c renamed from proxy.c.orig +2 -0
+  /* send Host: header for HTTP version above 1.0 */
+  if (strcmp(p->options.http_version, "1.0") != 0) {

This doesn't check for ">= 1.1", but "!= 1.0".
What if I use 0.9, or garbage, or nothing?
Oops, you lose -- in either case.

What have we currently? Only HTTP/1.0 and HTTP/1.1.
0.9 does not matter, it defines GET only, has not headers is not able to proxy HTTPS connections. So my solution handles backward compatibility without problems. The remaining question is how to handle future upward compatibility. You never know, what you will get. So we can either:
- disable all future protocol version the user may configure or
- hope that the protocol is upwards compatible.

I decided to implement the 2nd solution, because the other parts are already implemented this way. The user may already use arbitrary protocol versions.

Quoted 5 lines

You may want to accept only 1.0 and 1.1 rather than 1.0 and 1.n for n >= 1
- but there should only ever be A SINGLE PLACE to enforce that.

Else you'll have a hell of work once you start implementing HTTP/1.2 later on...

But then this check must no be done for the Host: header, but for the complete proxy support. I see your objections, but "my" additional header does not introduce an additional security problem, all other proxy setup code is already version independent. May be "CONNECT HTTP/2.0" will directly connect to the NSA/BND/(insert your favorite agency here)? ;-)

Frank

Signature · 2 lines
Frank Behrens, Osterwieck, Germany
PGP-key 0x5B7C47ED on public servers available.
#6 lore raw
Quoted 37 lines · Frank Behrens

Hi Matthias!

Matthias Andree <[email protected]...> wrote on 12 Nov 2008 14:36:

Quoted 8 lines · Frank Behrens
Quoted 4 lines

James Yonan <[email protected]...> wrote on 4 Nov 2008 12:16:

Quoted 1 line

Shouldn't you check p->options.http_version and make sure it's >= 1.1 before sending the Host header?

Here is a revised patch, that works for me and implements your suggestion:

Sorry Frank,

I have to object. It does not implement James's suggestion as you claim,

Ok, this was a mistake. I implemented the solution I proposed on this list in my mail from 05 Nov 2008 (<[email protected]...>).

Quoted 2 lines

but random guesswork - inadequate for security software and prone to breaking at later updates.

I would not say "random guesswork".

Quoted 11 lines

proxy.c establish_http_proxy_passthru (struct ht · line 352

Quoted 8 lines
proxy.c renamed from proxy.c.orig +2 -0
@@ -348,6 +348,14 @@ establish_http_proxy_passthru (struct ht
   if (!send_line_crlf (sd, buf))
     goto error;
 
+  /* send Host: header for HTTP version above 1.0 */
+  if (strcmp(p->options.http_version, "1.0") != 0) {

This doesn't check for ">= 1.1", but "!= 1.0".
What if I use 0.9, or garbage, or nothing?
Oops, you lose -- in either case.

What have we currently? Only HTTP/1.0 and HTTP/1.1. 0.9 does not matter, it defines GET only, has not headers is not able to proxy HTTPS connections. So my solution handles backward compatibility without problems. The remaining question is how to handle future upward compatibility. You never know, what you will get. So we can either:
- disable all future protocol version the user may configure or
- hope that the protocol is upwards compatible.

I decided to implement the 2nd solution, because the other parts are already implemented this way. The user may already use arbitrary protocol versions.

Quoted 8 lines
Quoted 5 lines

You may want to accept only 1.0 and 1.1 rather than 1.0 and 1.n for n >= 1
- but there should only ever be A SINGLE PLACE to enforce that.

Else you'll have a hell of work once you start implementing HTTP/1.2 later on...

But then this check must no be done for the Host: header, but for the complete proxy support. I see your objections, but "my" additional header does not introduce an additional security problem, all other proxy setup code is already version independent. May be "CONNECT HTTP/2.0" will directly connect to the NSA/BND/(insert your favorite agency here)? ;-)

I'd say that if you have a routine which handles HTTP/1.x, you should be pretty safe. At the moment 0.9, 1.0 and 1.1 is what's in use. 0.9 I would not care about now, as that one is underspecified and proper RFC is completely missing (afaik). If I'm not mistaken, 0.9 is the version used by clients not supporting all 1.0 features. I think a work on a HTTP/2.0 protocol did also start but nobody has brought that to life. (you might find some references which is about 10 years old or so)

So make sure 1.0 and 1.1 is handled properly, and you're safe. I'd say that 1.2+ can at the moment be handled as 1.1, as the protocols usually is backwards compatible. And I would rather reject 2.0 and 0.9 protocols, as they most probably should be considered undocumented at the moment.

kind regards,

David Sommerseth