32
32
#include "lib/str.h"
33
33
#include "lib/common.h"
34
34
35
+ /* Length of comparison of clients entry by User-Agent. */
36
+ #define UA_CMP_LEN 256
37
+
35
38
static struct {
36
39
unsigned int db_size ;
37
40
const char * db_path ;
@@ -49,17 +52,23 @@ static struct {
49
52
* @users - reference counter.
50
53
* Expiration state will begind, when the counter reaches
51
54
* zero;
55
+ * @user_agent_len - Length of @user_agent
56
+ * @user_agent - UA_CMP_LEN first characters of User-Agent
52
57
*/
53
58
typedef struct {
54
59
TfwClient cli ;
55
60
TfwAddr xff_addr ;
56
61
time_t expires ;
57
62
spinlock_t lock ;
58
63
atomic_t users ;
64
+ unsigned long user_agent_len ;
65
+ char user_agent [UA_CMP_LEN ];
59
66
} TfwClientEntry ;
60
67
61
68
static TDB * client_db ;
62
69
70
+ unsigned long tfw_hash_str_len (const TfwStr * str , unsigned long str_len );
71
+
63
72
/**
64
73
* Called when a client socket is closed.
65
74
*/
@@ -93,6 +102,7 @@ tfw_client_put(TfwClient *cli)
93
102
typedef struct {
94
103
TfwAddr addr ;
95
104
TfwAddr xff_addr ;
105
+ TfwStr user_agent ;
96
106
} TfwClientEqCtx ;
97
107
98
108
static struct in6_addr any_addr = IN6ADDR_ANY_INIT ;
@@ -118,6 +128,12 @@ tfw_client_addr_eq(TdbRec *rec, void (*init)(void *), void *data)
118
128
return false;
119
129
}
120
130
131
+ if (!tfw_str_eq_cstr (& ctx -> user_agent , ent -> user_agent ,
132
+ ent -> user_agent_len , 0 ))
133
+ {
134
+ return false;
135
+ }
136
+
121
137
spin_lock (& ent -> lock );
122
138
123
139
if (curr_time > ent -> expires ) {
@@ -159,23 +175,26 @@ tfw_client_ent_init(TdbRec *rec, void (*init)(void *), void *data)
159
175
160
176
tfw_peer_init ((TfwPeer * )cli , & ctx -> addr );
161
177
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 ));
162
181
163
182
TFW_DBG ("new client: cli=%p\n" , cli );
164
183
TFW_DBG_ADDR ("client address" , & cli -> addr , TFW_NO_PORT );
165
184
TFW_DBG2 ("client %p, users=%d\n" , cli , 1 );
166
185
}
167
186
168
187
/**
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.
172
190
*
173
191
* The returned TfwClient reference must be released via tfw_client_put()
174
192
* when the @sk is closed.
175
193
* TODO #515 employ eviction strategy for the table.
176
194
*/
177
195
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 * ))
179
198
{
180
199
TfwClientEntry * ent ;
181
200
TfwClient * cli ;
@@ -198,6 +217,13 @@ tfw_client_obtain(TfwAddr addr, TfwAddr *xff_addr, void (*init)(void *))
198
217
ctx .xff_addr .sin6_addr = any_addr ;
199
218
}
200
219
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
+
201
227
len = sizeof (TfwClientEntry );
202
228
rec = tdb_rec_get_alloc (client_db , key , & len , & tfw_client_addr_eq ,
203
229
& tfw_client_ent_init , init , & ctx , & is_new );
0 commit comments