Bug 1394: PPv2 header modifed
authorTodd Lyons <tlyons@exim.org>
Mon, 12 May 2014 23:15:07 +0000 (16:15 -0700)
committerTodd Lyons <tlyons@exim.org>
Tue, 13 May 2014 18:21:51 +0000 (11:21 -0700)
The HAProxy dev team adjusted the layout of the 16 byte header to allow
  it to be used for SSL connections.  Had to adjust PPv2 handling code
  and perl proxy emulation script.
Added link to this HAProxy commit in the documentation.

doc/doc-txt/experimental-spec.txt
src/src/smtp_in.c
src/src/string.c
src/util/proxy_protocol_client.pl

index 018bfddb92496796f53be1ee56b3f598768c1ec7..d8c26bf931063dd131dc3ab37170bd1052d62c24 100644 (file)
@@ -1025,6 +1025,8 @@ Proxy Protocol Support
 Exim now has Experimental "Proxy Protocol" support.  It was built on
 specifications from:
 http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt
+Above URL revised May 2014 to change version 2 spec:
+http://git.1wt.eu/web?p=haproxy.git;a=commitdiff;h=afb768340c9d7e50d8e
 
 The purpose of this function is so that an application load balancer,
 such as HAProxy, can sit in front of several Exim servers and Exim
index aad778eefc4360176396b34dcded05092e43b961..b7e60bfab37faf4387cbef844c9fa50861db479c 100644 (file)
@@ -623,10 +623,9 @@ union {
   } v1;
   struct {
     uschar sig[12];
-    uschar ver;
-    uschar cmd;
-    uschar fam;
-    uschar len;
+    uint8_t ver_cmd;
+    uint8_t fam;
+    uint16_t len;
     union {
       struct { /* TCP/UDP over IPv4, len = 12 */
         uint32_t src_addr;
@@ -657,7 +656,7 @@ struct sockaddr_in6 tmpaddr6;
 
 int get_ok = 0;
 int size, ret, fd;
-const char v2sig[13] = "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A\x02";
+const char v2sig[12] = "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A";
 uschar *iptype;  /* To display debug info */
 struct timeval tv;
 socklen_t vslen = 0;
@@ -693,16 +692,32 @@ if (ret == -1)
   }
 
 if (ret >= 16 &&
-    memcmp(&hdr.v2, v2sig, 13) == 0)
+    memcmp(&hdr.v2, v2sig, 12) == 0)
   {
+  uint8_t ver, cmd;
+
+  /* May 2014: haproxy combined the version and command into one byte to
+     allow two full bytes for the length field in order to proxy SSL
+     connections.  SSL Proxy is not supported in this version of Exim, but
+     must still seperate values here. */
+  ver = (hdr.v2.ver_cmd & 0xf0) >> 4;
+  cmd = (hdr.v2.ver_cmd & 0x0f);
+
+  if (ver != 0x02)
+    {
+    DEBUG(D_receive) debug_printf("Invalid Proxy Protocol version: %d\n", ver);
+    goto proxyfail;
+    }
   DEBUG(D_receive) debug_printf("Detected PROXYv2 header\n");
+  /* The v2 header will always be 16 bytes per the spec. */
   size = 16 + hdr.v2.len;
   if (ret < size)
     {
-    DEBUG(D_receive) debug_printf("Truncated or too large PROXYv2 header\n");
+    DEBUG(D_receive) debug_printf("Truncated or too large PROXYv2 header (%d/%d)\n",
+                                  ret, size);
     goto proxyfail;
     }
-  switch (hdr.v2.cmd)
+  switch (cmd)
     {
     case 0x01: /* PROXY command */
       switch (hdr.v2.fam)
@@ -772,8 +787,7 @@ if (ret >= 16 &&
       break;
     default:
       DEBUG(D_receive)
-        debug_printf("Unsupported PROXYv2 command: 0x%02x\n",
-                     hdr.v2.cmd);
+        debug_printf("Unsupported PROXYv2 command: 0x%x\n", cmd);
       goto proxyfail;
     }
   }
index 914390255f43f59e55a919f00a3fb3d0d55d8689..0f657dccaebb16499a5e40f57ce656fb2977a1b7 100644 (file)
@@ -304,7 +304,7 @@ if (nonprintcount == 0) return s;
 /* Get a new block of store guaranteed big enough to hold the
 expanded string. */
 
-ss = store_get(length + nonprintcount * 4 + 1);
+ss = store_get(length + nonprintcount * 3 + 1);
 
 /* Copy everying, escaping non printers. */
 
index 7cfc13ddcf88c28f2d3004250b3c7f9325af8846..feae3ca90f8762aa833323c18e9679b2c0663bcc 100644 (file)
@@ -82,10 +82,10 @@ sub generate_preamble {
   if (!$opts{version} || $opts{version} == 2) {
     @preamble = (
       "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A", # 12 byte v2 header
-      "\x02",                                             # declares v2
-      "\x01",                                             # connection is proxied
+      "\x21",                                             # top 4 bits declares v2
+                                                          # bottom 4 bits is command
       $opts{6} ? "\x21" : "\x11",                         # inet6/4 and TCP (stream)
-      $opts{6} ? "\x24" : "\x0b",                         # 36 bytes / 12 bytes
+      $opts{6} ? "\x00\x24" : "\x00\x0b",                 # 36 bytes / 12 bytes
       $source_ip,
       $dest_ip,
       $source_port,