Skip to content

Commit 2044c9d

Browse files
committed
use user-agent for searching a client
1 parent 460957d commit 2044c9d

File tree

5 files changed

+39
-9
lines changed

5 files changed

+39
-9
lines changed

tempesta_fw/client.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
#include "lib/str.h"
3333
#include "lib/common.h"
3434

35+
/* Length of comparison of clients entry by User-Agent. */
36+
#define UA_CMP_LEN 256
37+
3538
static struct {
3639
unsigned int db_size;
3740
const char *db_path;
@@ -49,17 +52,23 @@ static struct {
4952
* @users - reference counter.
5053
* Expiration state will begind, when the counter reaches
5154
* zero;
55+
* @user_agent_len - Length of @user_agent
56+
* @user_agent - UA_CMP_LEN first characters of User-Agent
5257
*/
5358
typedef struct {
5459
TfwClient cli;
5560
TfwAddr xff_addr;
5661
time_t expires;
5762
spinlock_t lock;
5863
atomic_t users;
64+
unsigned long user_agent_len;
65+
char user_agent[UA_CMP_LEN];
5966
} TfwClientEntry;
6067

6168
static TDB *client_db;
6269

70+
unsigned long tfw_hash_str_len(const TfwStr *str, unsigned long str_len);
71+
6372
/**
6473
* Called when a client socket is closed.
6574
*/
@@ -93,6 +102,7 @@ tfw_client_put(TfwClient *cli)
93102
typedef struct {
94103
TfwAddr addr;
95104
TfwAddr xff_addr;
105+
TfwStr user_agent;
96106
} TfwClientEqCtx;
97107

98108
static struct in6_addr any_addr = IN6ADDR_ANY_INIT;
@@ -118,6 +128,12 @@ tfw_client_addr_eq(TdbRec *rec, void (*init)(void *), void *data)
118128
return false;
119129
}
120130

131+
if (!tfw_str_eq_cstr(&ctx->user_agent, ent->user_agent,
132+
ent->user_agent_len, 0))
133+
{
134+
return false;
135+
}
136+
121137
spin_lock(&ent->lock);
122138

123139
if (curr_time > ent->expires) {
@@ -159,23 +175,26 @@ tfw_client_ent_init(TdbRec *rec, void (*init)(void *), void *data)
159175

160176
tfw_peer_init((TfwPeer *)cli, &ctx->addr);
161177
ent->xff_addr = ctx->xff_addr;
178+
tfw_str_to_cstr(&ctx->user_agent, ent->user_agent,
179+
sizeof(ent->user_agent));
180+
ent->user_agent_len = min(ctx->user_agent.len, sizeof(ent->user_agent));
162181

163182
TFW_DBG("new client: cli=%p\n", cli);
164183
TFW_DBG_ADDR("client address", &cli->addr, TFW_NO_PORT);
165184
TFW_DBG2("client %p, users=%d\n", cli, 1);
166185
}
167186

168187
/**
169-
* Find a client corresponding to @addr and @xff_addr (e.g. from X-Forwarded-For).
170-
* More advanced identification is possible based on User-Agent,
171-
* Cookie and other HTTP headers.
188+
* Find a client corresponding to @addr, @xff_addr (e.g. from X-Forwarded-For)
189+
* and @user_agent.
172190
*
173191
* The returned TfwClient reference must be released via tfw_client_put()
174192
* when the @sk is closed.
175193
* TODO #515 employ eviction strategy for the table.
176194
*/
177195
TfwClient *
178-
tfw_client_obtain(TfwAddr addr, TfwAddr *xff_addr, void (*init)(void *))
196+
tfw_client_obtain(TfwAddr addr, TfwAddr *xff_addr, TfwStr *user_agent,
197+
void (*init)(void *))
179198
{
180199
TfwClientEntry *ent;
181200
TfwClient *cli;
@@ -198,6 +217,13 @@ tfw_client_obtain(TfwAddr addr, TfwAddr *xff_addr, void (*init)(void *))
198217
ctx.xff_addr.sin6_addr = any_addr;
199218
}
200219

220+
if (user_agent) {
221+
key ^= tfw_hash_str_len(user_agent, UA_CMP_LEN);
222+
ctx.user_agent = *user_agent;
223+
} else {
224+
TFW_STR_INIT(&ctx.user_agent);
225+
}
226+
201227
len = sizeof(TfwClientEntry);
202228
rec = tdb_rec_get_alloc(client_db, key, &len, &tfw_client_addr_eq,
203229
&tfw_client_ent_init, init, &ctx, &is_new);

tempesta_fw/client.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ typedef struct {
3737
} TfwClient;
3838

3939
TfwClient *tfw_client_obtain(TfwAddr addr, TfwAddr *cli_addr,
40-
void (*init)(void *));
40+
TfwStr *user_agent, void (*init)(void *));
4141
void tfw_client_put(TfwClient *cli);
4242
int tfw_client_for_each(int (*fn)(void *));
4343
void tfw_client_set_expires_time(unsigned int expires_time);

tempesta_fw/http.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3011,7 +3011,7 @@ tfw_http_get_ip_from_xff(TfwHttpReq *req)
30113011
static int
30123012
tfw_http_req_client_link(TfwConn *conn, TfwHttpReq *req)
30133013
{
3014-
TfwStr s_ip;
3014+
TfwStr s_ip, s_user_agent, *ua;
30153015
TfwAddr addr;
30163016
TfwClient *cli, *conn_cli;
30173017

@@ -3021,7 +3021,11 @@ tfw_http_req_client_link(TfwConn *conn, TfwHttpReq *req)
30213021
return TFW_BLOCK;
30223022

30233023
conn_cli = (TfwClient *)conn->peer;
3024-
cli = tfw_client_obtain(conn_cli->addr, &addr, NULL);
3024+
ua = &req->h_tbl->tbl[TFW_HTTP_HDR_USER_AGENT];
3025+
tfw_http_msg_clnthdr_val(ua, TFW_HTTP_HDR_USER_AGENT,
3026+
&s_user_agent);
3027+
cli = tfw_client_obtain(conn_cli->addr, &addr, &s_user_agent,
3028+
NULL);
30253029
if (cli) {
30263030
if (cli != conn_cli)
30273031
req->peer = cli;

tempesta_fw/http_limits.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ frang_conn_new(struct sock *sk)
339339
TfwAddr addr;
340340

341341
ss_getpeername(sk, &addr);
342-
cli = tfw_client_obtain(addr, NULL, __frang_init_acc);
342+
cli = tfw_client_obtain(addr, NULL, NULL, __frang_init_acc);
343343
if (unlikely(!cli)) {
344344
TFW_ERR("can't obtain a client for frang accounting\n");
345345
return TFW_BLOCK;

tempesta_fw/sock_clnt.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ tfw_sock_clnt_new(struct sock *sk)
160160
tfw_connection_unlink_from_sk(sk);
161161

162162
ss_getpeername(sk, &addr);
163-
cli = tfw_client_obtain(addr, NULL, NULL);
163+
cli = tfw_client_obtain(addr, NULL, NULL, NULL);
164164
if (!cli) {
165165
TFW_ERR("can't obtain a client for the new socket\n");
166166
return -ENOENT;

0 commit comments

Comments
 (0)