[MINOR] acl: add support for matching of RDP cookies

The RDP protocol is quite simple and documented, which permits
an easy detection and extraction of cookies. It can be useful
to match the MSTS cookie which can contain the username specified
by the client.
This commit is contained in:
Emeric Brun 2009-06-30 17:54:00 +02:00 committed by Willy Tarreau
parent 51d5dad90a
commit bede3d0ef4
4 changed files with 132 additions and 1 deletions

View File

@ -4822,7 +4822,7 @@ through TCP request content inspection. Please see the "tcp-request" keyword
for more detailed information on the subject.
req_len <integer>
Returns true when the lenght of the data in the request buffer matches the
Returns true when the length of the data in the request buffer matches the
specified range. It is important to understand that this test does not
return false as long as the buffer is changing. This means that a check with
equality to zero will almost always immediately match at the beginning of the
@ -4837,6 +4837,25 @@ req_proto_http
to direct HTTP traffic to a given port and HTTPS traffic to another one
using TCP request content inspection rules.
req_rdp_cookie <string>
req_rdp_cookie(name) <string>
Returns true when data in the request buffer look like the RDP protocol, and
a cookie is present and equal to <string>. By default, any cookie name is
checked, but a specific cookie name can be specified in parenthesis. The
parser only checks for the first cookie, as illustrated in the RDP protocol
specification. The cookie name is case insensitive. This ACL can be useful
with the "MSTS" cookie, as it can contain the user name of the client
connecting to the server if properly configured on the client. This can be
used to restrict access to certain servers to certain users.
req_rdp_cookie_cnt <integer>
req_rdp_cookie_cnt(name) <integer>
Returns true when the data in the request buffer look like the RDP protocol
and the number of RDP cookies matches the specified range (typically zero or
one). Optionally a specific cookie name can be checked. This is a simple way
of detecting the RDP protocol, as clients generally send the MSTS or MSTSHASH
cookies.
req_ssl_ver <decimal>
Returns true when data in the request buffer look like SSL, with a protocol
version matching the specified range. Both SSLv2 hello messages and SSLv3
@ -5055,6 +5074,7 @@ HTTP_URL_ABS url_reg ^[^/:]*:// match absolute URL with scheme
HTTP_URL_SLASH url_beg / match URL begining with "/"
HTTP_URL_STAR url * match URL equal to "*"
HTTP_CONTENT hdr_val(content-length) gt 0 match an existing content-length
RDP_COOKIE req_rdp_cookie_cnt gt 0 match presence of an RDP cookie
REQ_CONTENT req_len gt 0 match data in the request buffer
WAIT_END wait_end wait for end of content analysis
---------------+-----------------------------+---------------------------------

View File

@ -33,6 +33,8 @@ void tcpv4_add_listener(struct listener *listener);
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 an_bit);
int acl_fetch_rdp_cookie(struct proxy *px, struct session *l4, void *l7, int dir,
struct acl_expr *expr, struct acl_test *test);
#endif /* _PROTO_PROTO_TCP_H */

View File

@ -810,6 +810,7 @@ const struct {
{ .name = "HTTP_URL_SLASH", .expr = {"url_beg","/",""}},
{ .name = "HTTP_URL_STAR", .expr = {"url","*",""}},
{ .name = "HTTP_CONTENT", .expr = {"hdr_val(content-length)","gt","0",""}},
{ .name = "RDP_COOKIE", .expr = {"req_rdp_cookie_cnt","gt","0",""}},
{ .name = "REQ_CONTENT", .expr = {"req_len","gt","0",""}},
{ .name = "WAIT_END", .expr = {"wait_end",""}},
{ .name = NULL, .expr = {""}}

View File

@ -690,6 +690,112 @@ acl_fetch_req_ssl_ver(struct proxy *px, struct session *l4, void *l7, int dir,
return 0;
}
int
acl_fetch_rdp_cookie(struct proxy *px, struct session *l4, void *l7, int dir,
struct acl_expr *expr, struct acl_test *test)
{
int bleft;
const unsigned char *data;
if (!l4 || !l4->req)
return 0;
test->flags = 0;
bleft = l4->req->l;
if (bleft <= 11)
goto too_short;
data = (const unsigned char *)l4->req->w + 11;
bleft -= 11;
if (bleft <= 7)
goto too_short;
if (strncasecmp((const char *)data, "Cookie:", 7) != 0)
goto not_cookie;
data += 7;
bleft -= 7;
while (bleft > 0 && *data == ' ') {
data++;
bleft--;
}
if (expr->arg_len) {
if (bleft <= expr->arg_len)
goto too_short;
if ((data[expr->arg_len] != '=') ||
strncasecmp(expr->arg.str, (const char *)data, expr->arg_len) != 0)
goto not_cookie;
data += expr->arg_len + 1;
bleft -= expr->arg_len + 1;
} else {
while (bleft > 0 && *data != '=') {
if (*data == '\r' || *data == '\n')
goto not_cookie;
data++;
bleft--;
}
if (bleft < 1)
goto too_short;
if (*data != '=')
goto not_cookie;
data++;
bleft--;
}
/* data points to cookie value */
test->ptr = (char *)data;
test->len = 0;
while (bleft > 0 && *data != '\r') {
data++;
bleft--;
}
if (bleft < 2)
goto too_short;
if (data[0] != '\r' || data[1] != '\n')
goto not_cookie;
test->len = (char *)data - test->ptr;
test->flags = ACL_TEST_F_VOLATILE;
return 1;
too_short:
test->flags = ACL_TEST_F_MAY_CHANGE;
not_cookie:
return 0;
}
static int
acl_fetch_rdp_cookie_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
struct acl_expr *expr, struct acl_test *test)
{
int ret;
ret = acl_fetch_rdp_cookie(px, l4, l7, dir, expr, test);
test->ptr = NULL;
test->len = 0;
if (test->flags & ACL_TEST_F_MAY_CHANGE)
return 0;
test->flags = ACL_TEST_F_VOLATILE;
test->i = ret;
return 1;
}
static struct cfg_kw_list cfg_kws = {{ },{
{ CFG_LISTEN, "tcp-request", tcp_parse_tcp_req },
@ -699,6 +805,8 @@ static struct cfg_kw_list cfg_kws = {{ },{
static struct acl_kw_list acl_kws = {{ },{
{ "req_len", acl_parse_int, acl_fetch_req_len, acl_match_int, ACL_USE_L4REQ_VOLATILE },
{ "req_ssl_ver", acl_parse_dotted_ver, acl_fetch_req_ssl_ver, acl_match_int, ACL_USE_L4REQ_VOLATILE },
{ "req_rdp_cookie", acl_parse_str, acl_fetch_rdp_cookie, acl_match_str, ACL_USE_L4REQ_VOLATILE },
{ "req_rdp_cookie_cnt", acl_parse_int, acl_fetch_rdp_cookie_cnt, acl_match_int, ACL_USE_L4REQ_VOLATILE },
{ NULL, NULL, NULL, NULL },
}};