[MEDIUM] add support for RDP cookie persistence
The new statement "persist rdp-cookie" enables RDP cookie
persistence. The RDP cookie is then extracted from the RDP
protocol, and compared against available servers. If a server
matches the RDP cookie, then it gets the connection.
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 93fc126..ff32726 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -446,6 +446,74 @@
return 1;
}
+/* Apply RDP cookie persistence to the current session. For this, the function
+ * tries to extract an RDP cookie from the request buffer, and look for the
+ * matching server in the list. If the server is found, it is assigned to the
+ * session. This always returns 1, and the analyser removes itself from the
+ * list. Nothing is performed if a server was already assigned.
+ */
+int tcp_persist_rdp_cookie(struct session *s, struct buffer *req, int an_bit)
+{
+ struct proxy *px = s->be;
+ int ret;
+ struct acl_expr expr;
+ struct acl_test test;
+ struct server *srv = px->srv;
+ struct sockaddr_in addr;
+ char *p;
+
+ 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);
+
+ if (s->flags & SN_ASSIGNED)
+ goto no_cookie;
+
+ memset(&expr, 0, sizeof(expr));
+ memset(&test, 0, sizeof(test));
+
+ expr.arg.str = s->be->rdp_cookie_name;
+ expr.arg_len = s->be->rdp_cookie_len;
+
+ ret = acl_fetch_rdp_cookie(px, s, NULL, ACL_DIR_REQ, &expr, &test);
+ if (ret == 0 || (test.flags & ACL_TEST_F_MAY_CHANGE) || test.len == 0)
+ goto no_cookie;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+
+ /* Considering an rdp cookie detected using acl, test.ptr ended with <cr><lf> and should return */
+ addr.sin_addr.s_addr = strtoul(test.ptr, &p, 10);
+ if (*p != '.')
+ goto no_cookie;
+ p++;
+ addr.sin_port = (unsigned short)strtoul(p, &p, 10);
+ if (*p != '.')
+ goto no_cookie;
+
+ while (srv) {
+ if (memcmp(&addr, &(srv->addr), sizeof(addr)) == 0) {
+ if ((srv->state & SRV_RUNNING) || (px->options & PR_O_PERSIST)) {
+ /* we found the server and it is usable */
+ s->flags |= SN_DIRECT | SN_ASSIGNED;
+ s->srv = srv;
+ break;
+ }
+ }
+ srv = srv->next;
+ }
+
+no_cookie:
+ req->analysers &= ~an_bit;
+ req->analyse_exp = TICK_ETERNITY;
+ return 1;
+}
+
/* This function should be called to parse a line starting with the "tcp-request"
* keyword.