From: Krzysztof Piotr Oledzki Date: Fri, 23 May 2008 21:49:32 +0000 (+0200) Subject: [MINOR] Allow to specify a domain for a cookie X-Git-Tag: v1.3.16-rc1~271 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=efe3b6f524c5cc6328233941ca44247993342d71;p=thirdparty%2Fhaproxy.git [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. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index 399bebb6d5..220990fee7 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -1087,7 +1087,7 @@ contimeout "timeout server", "contimeout". -cookie [ rewrite|insert|prefix ] [ indirect ] [ nocache ] [ postonly ] +cookie [ rewrite|insert|prefix ] [ indirect ] [ nocache ] [ postonly ] [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 [ 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 a120f56bd4..dae7bd54f7 100644 --- a/include/common/standard.h +++ b/include/common/standard.h @@ -135,6 +135,13 @@ extern int ishex(char s); */ extern const char *invalid_char(const char *name); +/* + * Checks 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 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 fe69b08967..81e182dd0b 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 7dbadd1e7e..9ca8ae64f4 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 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 2c07030639..3caeba1cff 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 7f749f9575..a85552866c 100644 --- a/src/standard.c +++ b/src/standard.c @@ -140,6 +140,27 @@ const char *invalid_char(const char *name) return NULL; } +/* + * Checks 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 to a struct sockaddr_in* which is locally allocated. * The format is "addr:port", where "addr" can be a dotted IPv4 address,