diff -Nur haproxy-1.3.17/include/proto/proto_tcp.h haproxy-1.3.17-tcp-inject/include/proto/proto_tcp.h
--- haproxy-1.3.17/include/proto/proto_tcp.h 2009-03-29 15:26:57.000000000 +0200
+++ haproxy-1.3.17-tcp-inject/include/proto/proto_tcp.h 2009-04-17 02:37:44.000000000 +0200
@@ -33,6 +33,7 @@
void tcpv6_add_listener(struct listener *listener);
int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen);
int tcp_inspect_request(struct session *s, struct buffer *req);
+int tcp_inject_request(struct session *s, struct buffer *req);
#endif /* _PROTO_PROTO_TCP_H */
diff -Nur haproxy-1.3.17/include/types/buffers.h haproxy-1.3.17-tcp-inject/include/types/buffers.h
--- haproxy-1.3.17/include/types/buffers.h 2009-03-29 15:26:57.000000000 +0200
+++ haproxy-1.3.17-tcp-inject/include/types/buffers.h 2009-04-17 02:37:44.000000000 +0200
@@ -111,6 +111,7 @@
#define AN_REQ_HTTP_TARPIT 0x00000008 /* wait for end of HTTP tarpit */
#define AN_RTR_HTTP_HDR 0x00000010 /* inspect HTTP response headers */
#define AN_REQ_UNIX_STATS 0x00000020 /* process unix stats socket request */
+#define AN_REQ_INJECT 0x00000040 /* inject header lines into tcp session */
/* describes a chunk of string */
struct chunk {
diff -Nur haproxy-1.3.17/src/cfgparse.c haproxy-1.3.17-tcp-inject/src/cfgparse.c
--- haproxy-1.3.17/src/cfgparse.c 2009-03-29 15:26:57.000000000 +0200
+++ haproxy-1.3.17-tcp-inject/src/cfgparse.c 2009-04-17 04:12:18.000000000 +0200
@@ -1604,6 +1604,78 @@
}
}
}
+ else if (!strcmp(args[1], "inject")) {
+ int cur_arg;
+
+ /* inject x-forwarded-for field at the beginning of tcp session. */
+ 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);
+
+ /* next argument must be "req" or "rep" */
+ if (!strcmp(args[2], "req")) {
+ curproxy->listen->analysers |= AN_REQ_INJECT;
+ } else if (!strcmp(args[2], "rsp")) {
+// TODO: implement it
+ Alert("parsing [%s:%d] : '%s %s %s' not yet implemented.\n",
+ file, linenum, args[0], args[1], args[2]);
+ return -1;
+ } else {
+ Alert("parsing [%s:%d] : '%s %s' expects 'req' or 'rsp' as argument.\n",
+ file, linenum, args[0], args[1]);
+ return -1;
+ }
+
+ /* next argument is the inject order. */
+// TODO: implement it atol(args[3]);
+
+ /* check what data should be injected. */
+ if (!strcmp(args[4], "forwardfor")) {
+
+ /* loop to go through arguments - start at 2, since 0+1 = "option" "inject" */
+ cur_arg = 5;
+ 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 %s %s %s' expects
[/mask] as argument.\n",
+ file, linenum, args[0], args[1], args[2], args[3], args[4], 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 %s %s %s' expects as argument.\n",
+ file, linenum, args[0], args[1], args[2], args[3], args[4], 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 {
+ /* 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;
+ }
+ } /* end while loop */
+ } else if (!strcmp(args[4], "data")) {
+// TODO: implement it
+ Alert("parsing [%s:%d] : '%s %s %s %s %s' not yet implemented.\n",
+ file, linenum, args[0], args[1], args[2], args[3], args[4]);
+ return -1;
+ } else {
+ Alert("parsing [%s:%d] : '%s %s %s %s' expects 'forwardfor' or 'data' as argument.\n",
+ file, linenum, args[0], args[1], args[2], args[3]);
+ return -1;
+ }
+ }
else if (!strcmp(args[1], "forwardfor")) {
int cur_arg;
diff -Nur haproxy-1.3.17/src/proto_tcp.c haproxy-1.3.17-tcp-inject/src/proto_tcp.c
--- haproxy-1.3.17/src/proto_tcp.c 2009-03-29 15:26:57.000000000 +0200
+++ haproxy-1.3.17-tcp-inject/src/proto_tcp.c 2009-04-17 02:37:44.000000000 +0200
@@ -40,6 +40,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -428,6 +429,136 @@
return 1;
}
+/* Add some data in the current server TCP session. This makes a backend
+ * behind us able to parse them and make decisions based on it.
+ */
+int tcp_inject_request(struct session *s, struct buffer *req)
+{
+
+ /* position of buffer. */
+ int buf_pos = 0;
+
+ DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
+ now_ms, __FUNCTION__,
+ s,
+ req,
+ req->rex, req->wex,
+ req->flags,
+ req->l,
+ req->analysers);
+
+ /* FIXME: I have no real idea how the timeouts are handled here,
+ * so is it required to add some handler here?
+ */
+
+ /* 1: add X-Forward-For if either the frontend or the backend asks for it. (IPv4) */
+ if (((s->fe->options | s->be->options) & PR_O_FWDFOR) != 0 && s->cli_addr.ss_family == AF_INET) {
+
+ /* add an X-Forward-For header unless the source ip is in the 'except' network range. */
+ if (((s->fe->except_mask.s_addr == 0) || (((struct sockaddr_in *)&s->cli_addr)->sin_addr.s_addr & s->fe->except_mask.s_addr) != s->fe->except_net.s_addr) &&
+ ((s->be->except_mask.s_addr == 0) || (((struct sockaddr_in *)&s->cli_addr)->sin_addr.s_addr & s->be->except_mask.s_addr) != s->be->except_net.s_addr)) {
+
+ /* variables to build the header entry. */
+ int len;
+ unsigned char *pn;
+ pn = (unsigned char *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr;
+
+ /* Note: we rely on the backend to get the header name to be used for
+ * X-Forward-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 (s->be->fwdfor_hdr_len) {
+ len = s->be->fwdfor_hdr_len;
+ memcpy(trash, s->be->fwdfor_hdr_name, len);
+ } else {
+ len = s->fe->fwdfor_hdr_len;
+ memcpy(trash, s->fe->fwdfor_hdr_name, len);
+ }
+
+ /* fetch length of complete header. */
+ len += sprintf(trash + len, ": %d.%d.%d.%d", pn[0], pn[1], pn[2], pn[3]);
+
+ /* copy the header into connection. */
+ if ((buf_pos = buffer_insert_line2(req, req->data, trash, len)) < 0) {
+
+ /* marks the buffer as "shutdown" ASAP in both directions. */
+ buffer_abort(req);
+ buffer_abort(s->rep);
+ req->analysers = 0;
+ s->fe->failed_req++;
+
+ if ((s->flags & SN_ERR_MASK) == 0) {
+ s->flags |= SN_ERR_PRXCOND;
+ }
+
+ if ((s->flags & SN_FINST_MASK) == 0) {
+ s->flags |= SN_FINST_R;
+ }
+
+ /* error occured. */
+ return 0;
+ }
+ }
+ }
+
+ /* IPv6. */
+ else if (((s->fe->options | s->be->options) & PR_O_FWDFOR) != 0 && s->cli_addr.ss_family == AF_INET6) {
+
+ /* FIXME: for the sake of completeness, we should also support
+ * 'except' here, although it is mostly useless in this case.
+ */
+
+ /* variables to build the header entry. */
+ int len;
+ char pn[INET6_ADDRSTRLEN];
+ inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr, pn, sizeof(pn));
+
+ /* Note: we rely on the backend to get the header name to be used for
+ * X-Forward-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 (s->be->fwdfor_hdr_len) {
+ len = s->be->fwdfor_hdr_len;
+ memcpy(trash, s->be->fwdfor_hdr_name, len);
+ } else {
+ len = s->fe->fwdfor_hdr_len;
+ memcpy(trash, s->fe->fwdfor_hdr_name, len);
+ }
+
+ /* fetch length of complete header. */
+ len += sprintf(trash + len, ": %s", pn);
+
+ /* copy the header into connection. */
+ if ((buf_pos = buffer_insert_line2(req, req->data, trash, len)) < 0) {
+
+ /* marks the buffer as "shutdown" ASAP in both directions. */
+ buffer_abort(req);
+ buffer_abort(s->rep);
+ req->analysers = 0;
+ s->fe->failed_req++;
+
+ if ((s->flags & SN_ERR_MASK) == 0) {
+ s->flags |= SN_ERR_PRXCOND;
+ }
+
+ if ((s->flags & SN_FINST_MASK) == 0) {
+ s->flags |= SN_FINST_R;
+ }
+
+ /* error occured. */
+ return 0;
+ }
+ }
+
+ /* if we get there, it means we have no rule which matches, or
+ * we have an explicit accept, so we apply the default accept.
+ */
+ req->analysers &= ~AN_REQ_INJECT;
+ req->analyse_exp = TICK_ETERNITY;
+ return 1;
+}
/* This function should be called to parse a line starting with the "tcp-request"
* keyword.
diff -Nur haproxy-1.3.17/src/session.c haproxy-1.3.17-tcp-inject/src/session.c
--- haproxy-1.3.17/src/session.c 2009-03-29 15:26:57.000000000 +0200
+++ haproxy-1.3.17-tcp-inject/src/session.c 2009-04-17 02:37:44.000000000 +0200
@@ -755,8 +755,12 @@
if (!http_process_request_body(s, s->req))
break;
+ if (s->req->analysers & AN_REQ_INJECT)
+ if (!tcp_inject_request(s, s->req))
+ break;
+
/* Just make sure that nobody set a wrong flag causing an endless loop */
- s->req->analysers &= AN_REQ_INSPECT | AN_REQ_HTTP_HDR | AN_REQ_HTTP_TARPIT | AN_REQ_HTTP_BODY;
+ s->req->analysers &= AN_REQ_INSPECT | AN_REQ_HTTP_HDR | AN_REQ_HTTP_TARPIT | AN_REQ_HTTP_BODY | AN_REQ_INJECT;
/* we don't want to loop anyway */
break;