From: Willy Tarreau Date: Thu, 7 Oct 2010 18:06:11 +0000 (+0200) Subject: [MEDIUM] cookie: check for maxidle and maxlife for incoming dated cookies X-Git-Tag: v1.5-dev8~443 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f64d1410fc5391283313b38706a923c9fb0e7d7b;p=thirdparty%2Fhaproxy.git [MEDIUM] cookie: check for maxidle and maxlife for incoming dated cookies If a cookie comes in with a first or last date, and they are configured on the backend, they're checked. If a date is expired or too far in the future, then the cookie is ignored and the specific reason appears in the cookie field of the logs. (cherry picked from commit faa3019107eabe6b3ab76ffec9754f2f31aa24c6) --- diff --git a/include/types/proto_http.h b/include/types/proto_http.h index 05bd5e91c5..2222304c1a 100644 --- a/include/types/proto_http.h +++ b/include/types/proto_http.h @@ -326,6 +326,8 @@ struct http_txn { char *cli_cookie; /* cookie presented by the client, in capture mode */ char *srv_cookie; /* cookie presented by the server, in capture mode */ char *sessid; /* the appsession id, if found in the request or in the response */ + int cookie_first_date; /* if non-zero, first date the expirable cookie was set/seen */ + int cookie_last_date; /* if non-zero, last date the expirable cookie was set/seen */ struct http_auth_data auth; /* HTTP auth data */ }; diff --git a/src/proto_http.c b/src/proto_http.c index 36694db050..d7cea8c0ee 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -5967,12 +5967,55 @@ void manage_client_side_cookies(struct session *t, struct buffer *req) vbar1 = memchr(val_beg, COOKIE_DELIM_DATE, val_end - val_beg); if (vbar1) { /* OK, so left of the bar is the server's cookie and - * right is the last seen date. + * right is the last seen date. It is a base64 encoded + * 30-bit value representing the UNIX date since the + * epoch in 4-second quantities. */ + int val; delim = vbar1++; + if (val_end - vbar1 >= 5) { + val = b64tos30(vbar1); + if (val > 0) + txn->cookie_last_date = val << 2; + } + /* look for a second vertical bar */ + vbar1 = memchr(vbar1, COOKIE_DELIM_DATE, val_end - vbar1); + if (vbar1 && (val_end - vbar1 > 5)) { + val = b64tos30(vbar1 + 1); + if (val > 0) + txn->cookie_first_date = val << 2; + } } } + /* if the cookie has an expiration date and the proxy wants to check + * it, then we do that now. We first check if the cookie is too old, + * then only if it has expired. We detect strict overflow because the + * time resolution here is not great (4 seconds). Cookies with dates + * in the future are ignored if their offset is beyond one day. This + * allows an admin to fix timezone issues without expiring everyone + * and at the same time avoids keeping unwanted side effects for too + * long. + */ + if (txn->cookie_first_date && t->be->cookie_maxlife && + ((signed)(date.tv_sec - txn->cookie_first_date) > t->be->cookie_maxlife || + (signed)(txn->cookie_first_date - date.tv_sec) > 86400)) { + txn->flags &= ~TX_CK_MASK; + txn->flags |= TX_CK_OLD; + delim = val_beg; // let's pretend we have not found the cookie + txn->cookie_first_date = 0; + txn->cookie_last_date = 0; + } + else if (txn->cookie_last_date && t->be->cookie_maxidle && + ((signed)(date.tv_sec - txn->cookie_last_date) > t->be->cookie_maxidle || + (signed)(txn->cookie_last_date - date.tv_sec) > 86400)) { + txn->flags &= ~TX_CK_MASK; + txn->flags |= TX_CK_EXPIRED; + delim = val_beg; // let's pretend we have not found the cookie + txn->cookie_first_date = 0; + txn->cookie_last_date = 0; + } + /* Here, we'll look for the first running server which supports the cookie. * This allows to share a same cookie between several servers, for example * to dedicate backup servers to specific servers only. @@ -6008,7 +6051,7 @@ void manage_client_side_cookies(struct session *t, struct buffer *req) srv = srv->next; } - if (!srv && !(txn->flags & TX_CK_DOWN)) { + if (!srv && !(txn->flags & (TX_CK_DOWN|TX_CK_EXPIRED|TX_CK_OLD))) { /* no server matched this cookie */ txn->flags &= ~TX_CK_MASK; txn->flags |= TX_CK_INVALID; @@ -7037,6 +7080,9 @@ void http_init_txn(struct session *s) txn->flags = 0; txn->status = -1; + txn->cookie_first_date = 0; + txn->cookie_last_date = 0; + txn->req.sol = txn->req.eol = NULL; txn->req.som = txn->req.eoh = 0; /* relative to the buffer */ txn->rsp.sol = txn->rsp.eol = NULL;