[PATCH] Allow to specify a domain for a cookie

From: Krzysztof Oledzki <ole#ans.pl>
Date: Fri, 23 May 2008 23:59:12 +0200


From 9c1f6f13fd0519cdef68bb5c9bf62a10a178dad6 Mon Sep 17 00:00:00 2001 From: Krzysztof Piotr Oledzki <ole#ans.pl> Date: Fri, 23 May 2008 23:49:32 +0200
Subject: [MINOR] Allow to specify a domain for a cookie

This patch allows to specify a domain used when inserting a cookie providing a session stickiness. Usefull for example with wildcard domains.

The patch adds one new variable to the struct proxy: cookiedomain. When set the domain is appended to a Set-Cookie header.

Domain name is validated using the new invalid_domainchar() function. It is basically invalid_char() limited to [A-Za-z0-9_.-]. Yes, the test is too trivial and does not cover all wrong situations, but the main purpose is to detect most common mistakes, not intentional abuses.

The underscore ("_") character is not RFC-valid but as it is often (mis)used so I decided to allow it.

---
 doc/configuration.txt     |    6 +++++-
 include/common/standard.h |    7 +++++++
 include/types/proxy.h     |    1 +
 src/cfgparse.c            |   27 ++++++++++++++++++++++++++-
 src/proto_http.c          |    3 +++
 src/standard.c            |   21 +++++++++++++++++++++
 6 files changed, 63 insertions(+), 2 deletions(-)

diff --git a/doc/configuration.txt b/doc/configuration.txt
index 399bebb..220990f 100644
--- a/doc/configuration.txt

+++ b/doc/configuration.txt
@@ -1087,7 +1087,7 @@ contimeout <timeout> "timeout server", "contimeout". -cookie <name> [ rewrite|insert|prefix ] [ indirect ] [ nocache ] [ postonly ]
+cookie <name> [ rewrite|insert|prefix ] [ indirect ] [ nocache ] [ postonly ] [domain <domain>]
Enable cookie-based persistence in a backend. May be used in sections : defaults | frontend | listen | backend yes | no | yes | yes @@ -1167,6 +1167,10 @@ cookie <name> [ rewrite|insert|prefix ] [ indirect ] [ nocache ] [ postonly ] persistence cookie in the cache. See also the "insert" and "nocache" options.
+ domain This option allows to specify the domain at which a cookie is
+ inserted. It requires exactly one paramater: a valid domain
+ name.
+
There can be only one persistence cookie per HTTP backend, and it can be declared in a defaults section. The value of the cookie will be the value indicated after the "cookie" keyword in a "server" statement. If no cookie diff --git a/include/common/standard.h b/include/common/standard.h index a120f56..dae7bd5 100644 --- a/include/common/standard.h
+++ b/include/common/standard.h
@@ -136,6 +136,13 @@ extern int ishex(char s); extern const char *invalid_char(const char *name); /*
+ * Checks <domainname> for invalid characters. Valid chars are [A-Za-z0-9_.-].
+ * If an invalid character is found, a pointer to it is returned.
+ * If everything is fine, NULL is returned.
+ */
+extern const char *invalid_domainchar(const char *name);
+
+/*
* converts <str> to a struct sockaddr_un* which is locally allocated. * The format is "/path", where "/path" is a path to a UNIX domain socket. */ diff --git a/include/types/proxy.h b/include/types/proxy.h index fe69b08..81e182d 100644 --- a/include/types/proxy.h
+++ b/include/types/proxy.h
@@ -161,6 +161,7 @@ struct proxy { void (*server_drop_conn)(struct server *);/* to be called when connection is dropped */ } lbprm; /* LB parameters for all algorithms */
+ char *cookiedomain; /* domain used to insert the cookie */
char *cookie_name; /* name of the cookie to look for */ int cookie_len; /* strlen(cookie_name), computed only once */ char *url_param_name; /* name of the URL parameter used for hashing */ diff --git a/src/cfgparse.c b/src/cfgparse.c index 7dbadd1..9ca8ae6 100644 --- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -895,8 +895,33 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv) else if (!strcmp(args[cur_arg], "prefix")) { curproxy->options |= PR_O_COOK_PFX; }
+ else if (!strcmp(args[cur_arg], "domain")) {
+ if (!*args[cur_arg + 1]) {
+ Alert("parsing [%s:%d]: '%s' expects <domain> as argument.\n",
+ file, linenum, args[cur_arg]);
+ return -1;
+ }
+
+ if (*args[cur_arg + 1] != '.' || !strchr(args[cur_arg + 1] + 1, '.')) {
+ /* rfc2109, 4.3.2 Rejecting Cookies */
+ Alert("parsing [%s:%d]: domain '%s' contains no embedded"
+ " dots or does not start with a dot.\n",
+ file, linenum, args[cur_arg + 1]);
+ return -1;
+ }
+
+ err = invalid_domainchar(args[cur_arg + 1]);
+ if (err) {
+ Alert("parsing [%s:%d]: character '%c' is not permitted in domain name '%s'.\n",
+ file, linenum, *err, args[cur_arg + 1]);
+ return -1;
+ }
+
+ curproxy->cookiedomain = strdup(args[cur_arg + 1]);
+ cur_arg++;
+ }
else { - Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
+ Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly', 'domain' options.\n",
file, linenum, args[0]); return -1; } diff --git a/src/proto_http.c b/src/proto_http.c index 2c07030..3caeba1 100644 --- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -3222,6 +3222,9 @@ int process_srv(struct session *t) t->be->cookie_name, t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
+ if (t->be->cookiedomain)
+ len += sprintf(trash+len, "; domain=%s", t->be->cookiedomain);
+
if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx, trash, len)) < 0) goto return_bad_resp; diff --git a/src/standard.c b/src/standard.c index 7f749f9..a855528 100644 --- a/src/standard.c
+++ b/src/standard.c
@@ -141,6 +141,27 @@ const char *invalid_char(const char *name) } /*
+ * Checks <domainname> for invalid characters. Valid chars are [A-Za-z0-9_.-].
+ * If an invalid character is found, a pointer to it is returned.
+ * If everything is fine, NULL is returned.
+ */
+const char *invalid_domainchar(const char *name) {
+
+ if (!*name)
+ return name;
+
+ while (*name) {
+ if (!isalnum((int)*name) && *name != '.' &&
+ *name != '_' && *name != '-')
+ return name;
+
+ name++;
+ }
+
+ return NULL;
+}
+
+/*
* converts <str> to a struct sockaddr_in* which is locally allocated. * The format is "addr:port", where "addr" can be a dotted IPv4 address, * a host name, or empty or "*" to indicate INADDR_ANY. -- 1.5.5.1
Received on 2008/05/23 23:59

This archive was generated by hypermail 2.2.0 : 2008/05/24 00:00 CEST