[MINOR] permit renaming of x-forwarded-for header

Because I needed it in my situation - here's a quick patch to
allow changing of the "x-forwarded-for" header by using a suboption to
"option forwardfor".

Suboption "header XYZ" will set the header from "x-forwarded-for" to "XYZ".

Default is still "x-forwarded-for" if the header value isn't defined.
Also the suboption 'except a.b.c.d/z' still works on the same line.

So it's now: option forwardfor [except a.b.c.d[/z]] [header XYZ]
diff --git a/doc/configuration.txt b/doc/configuration.txt
index e0e6d7e..943158a 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -1836,13 +1836,15 @@
   See also : "option httpclose"
 
 
-option forwardfor [ except <network> ]
+option forwardfor [ except <network> ] [ header <name> ]
   Enable insertion of the X-Forwarded-For header to requests sent to servers
   May be used in sections :   defaults | frontend | listen | backend
                                  yes   |    yes   |   yes  |   yes
   Arguments :
     <network> is an optional argument used to disable this option for sources
               matching <network>
+    <name>    an optional argument to specify a different "X-Forwarded-For"
+              header name.  
 
   Since HAProxy works in reverse-proxy mode, the servers see its IP address as
   their client address. This is sometimes annoying when the client's IP address
@@ -1851,7 +1853,16 @@
   This header contains a value representing the client's IP address. Since this
   header is always appended at the end of the existing header list, the server
   must be configured to always use the last occurrence of this header only. See
-  the server's manual to find how to enable use of this standard header.
+  the server's manual to find how to enable use of this standard header. Note
+  that only the last occurrence of the header must be used, since it is really
+  possible that the client has already brought one.
+
+  The keyword "header" may be used to supply a different header name to replace 
+  the default "X-Forwarded-For". This can be useful where you might already
+  have a "X-Forwarded-For" header from a different application (eg: stunnel), 
+  and you need preserve it. Also if your backend server doesn't use the 
+  "X-Forwarded-For" header and requires different one (eg: Zeus Web Servers
+  require "X-Cluster-Client-IP").
 
   Sometimes, a same HAProxy instance may be shared between a direct client
   access and a reverse-proxy access (for instance when an SSL reverse-proxy is
@@ -1862,19 +1873,26 @@
   private networks or 127.0.0.1.
 
   This option may be specified either in the frontend or in the backend. If at
-  least one of them uses it, the header will be added.
+  least one of them uses it, the header will be added. Note that the backend's
+  setting of the header subargument takes precedence over the frontend's if
+  both are defined.
 
   It is important to note that as long as HAProxy does not support keep-alive
   connections, only the first request of a connection will receive the header.
   For this reason, it is important to ensure that "option httpclose" is set
   when using this option.
 
-  Example :
+  Examples :
     # Public HTTP address also used by stunnel on the same machine
     frontend www
         mode http
         option forwardfor except 127.0.0.1  # stunnel already adds the header
 
+    # Those servers want the IP Address in X-Client
+    backend www
+        mode http
+        option forwardfor header X-Client
+
   See also : "option httpclose"
 
 
diff --git a/include/common/defaults.h b/include/common/defaults.h
index da9bdd8..05628e1 100644
--- a/include/common/defaults.h
+++ b/include/common/defaults.h
@@ -108,6 +108,9 @@
 #define DEF_CHECK_REQ   "OPTIONS / HTTP/1.0\r\n\r\n"
 #define DEF_SMTP_CHECK_REQ   "HELO localhost\r\n"
 
+// X-Forwarded-For header default
+#define DEF_XFORWARDFOR_HDR	"X-Forwarded-For"
+
 /* Default connections limit.
  *
  * A system limit can be enforced at build time in order to avoid using haproxy
diff --git a/include/types/proxy.h b/include/types/proxy.h
index 415b1a1..03cb5f6 100644
--- a/include/types/proxy.h
+++ b/include/types/proxy.h
@@ -206,6 +206,8 @@
 	unsigned int maxconn;			/* max # of active sessions on the frontend */
 	unsigned int fullconn;			/* #conns on backend above which servers are used at full load */
 	struct in_addr except_net, except_mask; /* don't x-forward-for for this address. FIXME: should support IPv6 */
+	char *fwdfor_hdr_name;			/* header to use - default: "x-forwarded-for" */
+	int fwdfor_hdr_len;			/* length of "x-forwarded-for" header */
 
 	unsigned down_trans;			/* up-down transitions */
 	unsigned down_time;			/* total time the proxy was down */
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 09f63a4..ea73f53 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -1443,25 +1443,49 @@
 			}
 		}
 		else if (!strcmp(args[1], "forwardfor")) {
-			/* insert x-forwarded-for field, but not for the
-			 * IP address listed as an except.
+			int cur_arg;
+
+			/* insert x-forwarded-for field, but not for the IP address listed as an except.
+			 * set default options (ie: bitfield, header name, etc) 
 			 */
-			if (*(args[2])) {
-				if (!strcmp(args[2], "except")) {
-					if (!*args[3] || !str2net(args[3], &curproxy->except_net, &curproxy->except_mask)) {
-						Alert("parsing [%s:%d] : '%s' only supports optional 'except' address[/mask].\n",
-						      file, linenum, args[0]);
+
+			curproxy->options |= PR_O_FWDFOR;
+
+			free(curproxy->fwdfor_hdr_name);
+			curproxy->fwdfor_hdr_name = strdup(DEF_XFORWARDFOR_HDR);
+			curproxy->fwdfor_hdr_len  = strlen(DEF_XFORWARDFOR_HDR);
+
+			/* loop to go through arguments - start at 2, since 0+1 = "option" "forwardfor" */
+			cur_arg = 2;
+			while (*(args[cur_arg])) {
+				if (!strcmp(args[cur_arg], "except")) {
+					/* suboption except - needs additional argument for it */
+					if (!*(args[cur_arg+1]) || !str2net(args[cur_arg+1], &curproxy->except_net, &curproxy->except_mask)) {
+						Alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
+						      file, linenum, args[0], args[1], args[cur_arg]);
 						return -1;
 					}
 					/* flush useless bits */
 					curproxy->except_net.s_addr &= curproxy->except_mask.s_addr;
+					cur_arg += 2;
+				} else if (!strcmp(args[cur_arg], "header")) {
+					/* suboption header - needs additional argument for it */
+					if (*(args[cur_arg+1]) == 0) {
+						Alert("parsing [%s:%d] : '%s %s %s' expects <header_name> as argument.\n",
+						      file, linenum, args[0], args[1], args[cur_arg]);
+						return -1;
+					}
+					free(curproxy->fwdfor_hdr_name);
+					curproxy->fwdfor_hdr_name = strdup(args[cur_arg+1]);
+					curproxy->fwdfor_hdr_len  = strlen(curproxy->fwdfor_hdr_name);
+					cur_arg += 2;
 				} else {
-					Alert("parsing [%s:%d] : '%s' only supports optional 'except' address[/mask].\n",
-					      file, linenum, args[0]);
+					/* unknown suboption - catchall */
+					Alert("parsing [%s:%d] : '%s %s' only supports optional values: 'except' and 'header'.\n",
+					      file, linenum, args[0], args[1]);
 					return -1;
 				}
-			}
-			curproxy->options |= PR_O_FWDFOR;
+			} /* end while loop */
 		}
 		else {
 			Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
diff --git a/src/proto_http.c b/src/proto_http.c
index 5b11cb2..9ab5a80 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -2214,10 +2214,21 @@
 					unsigned char *pn;
 					pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
 
-					len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d",
-						      pn[0], pn[1], pn[2], pn[3]);
+					/* Note: we rely on the backend to get the header name to be used for
+					 * x-forwarded-for, because the header is really meant for the backends.
+					 * However, if the backend did not specify any option, we have to rely
+					 * on the frontend's header name.
+					 */
+					if (t->be->fwdfor_hdr_len) {
+						len = t->be->fwdfor_hdr_len;
+						memcpy(trash, t->be->fwdfor_hdr_name, len);
+					} else {
+						len = t->fe->fwdfor_hdr_len;
+						memcpy(trash, t->fe->fwdfor_hdr_name, len);
+					}
+					len += sprintf(trash + len, ": %d.%d.%d.%d", pn[0], pn[1], pn[2], pn[3]);
 
-					if (unlikely(http_header_add_tail2(req, &txn->req,
+ 					if (unlikely(http_header_add_tail2(req, &txn->req,
 									   &txn->hdr_idx, trash, len)) < 0)
 						goto return_bad_req;
 				}
@@ -2231,7 +2242,21 @@
 				inet_ntop(AF_INET6,
 					  (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
 					  pn, sizeof(pn));
-				len = sprintf(trash, "X-Forwarded-For: %s", pn);
+
+				/* Note: we rely on the backend to get the header name to be used for
+				 * x-forwarded-for, because the header is really meant for the backends.
+				 * However, if the backend did not specify any option, we have to rely
+				 * on the frontend's header name.
+				 */
+				if (t->be->fwdfor_hdr_len) {
+					len = t->be->fwdfor_hdr_len;
+					memcpy(trash, t->be->fwdfor_hdr_name, len);
+				} else {
+					len = t->fe->fwdfor_hdr_len;
+					memcpy(trash, t->fe->fwdfor_hdr_name, len);
+				}
+				len += sprintf(trash + len, ": %s", pn);
+ 
 				if (unlikely(http_header_add_tail2(req, &txn->req,
 								   &txn->hdr_idx, trash, len)) < 0)
 					goto return_bad_req;