4
4
#include "protocols/redis/decoding-maps.h"
5
5
#include "protocols/helpers/pktbuf.h"
6
6
7
- #define BLK_SIZE (16)
8
- PKTBUF_READ_INTO_BUFFER (redis_bulk , MAX_KEY_LEN , BLK_SIZE )
7
+ PKTBUF_READ_INTO_BUFFER (redis_bulk , MAX_KEY_LEN , READ_KEY_CHUNK_SIZE )
9
8
10
9
// Read a CRLF terminator from the packet buffer. The terminator is expected to be in the format: \r\n.
11
10
// The function returns true if the terminator was successfully read, or false if the terminator could not be read.
@@ -49,6 +48,8 @@ static __always_inline u32 read_array_message_param_count(pktbuf_t pkt) {
49
48
return param_count - '0' ;
50
49
}
51
50
51
+ // Extracts and returns the length of a Redis key from a RESP bulk string.
52
+ // Validates the format and returns 0 if invalid or exceeds maximum length.
52
53
static __always_inline u16 get_key_len (pktbuf_t pkt ) {
53
54
u32 current_offset = pktbuf_data_offset (pkt );
54
55
const u32 data_end = pktbuf_data_end (pkt );
@@ -63,8 +64,8 @@ static __always_inline u16 get_key_len(pktbuf_t pkt) {
63
64
}
64
65
current_offset ++ ;
65
66
66
- // Read key length (up to 3 digits)
67
- char key_size_bytes [3 ] = {};
67
+ // Read key length (up to MAX_DIGITS_KEY_LEN_PREFIX digits)
68
+ char key_size_bytes [MAX_DIGITS_KEY_LEN_PREFIX ] = {};
68
69
if (current_offset + sizeof (key_size_bytes ) > data_end ) {
69
70
return 0 ;
70
71
}
@@ -75,8 +76,8 @@ static __always_inline u16 get_key_len(pktbuf_t pkt) {
75
76
u16 key_size = 0 ;
76
77
u32 digits_read = 0 ;
77
78
// The key length is a decimal number, so we need to convert it from ASCII to an integer.
78
- #pragma unroll (3 )
79
- for (int i = 0 ; i < 3 ; i ++ ) {
79
+ #pragma unroll (MAX_DIGITS_KEY_LEN_PREFIX )
80
+ for (int i = 0 ; i < MAX_DIGITS_KEY_LEN_PREFIX ; i ++ ) {
80
81
if (key_size_bytes [i ] == RESP_TERMINATOR_1 ) {
81
82
break ;
82
83
}
@@ -95,13 +96,15 @@ static __always_inline u16 get_key_len(pktbuf_t pkt) {
95
96
return 0 ;
96
97
}
97
98
98
- if (key_size <= 0 || key_size > 999 ) {
99
+ if (key_size <= 0 || key_size > MAX_READABLE_KEY_LEN ) {
99
100
return 0 ;
100
101
}
101
102
102
103
return key_size ;
103
104
}
104
105
106
+ // Reads a Redis key name into the provided buffer with length validation.
107
+ // Sets truncated flag if key was too long for buffer, and out_key_len as the key size after clamping.
105
108
static __always_inline bool read_key_name (pktbuf_t pkt , char * buf , u8 buf_len , u16 * out_key_len , bool * truncated ) {
106
109
const u32 key_size = * out_key_len > MAX_KEY_LEN - 1 ? MAX_KEY_LEN - 1 : * out_key_len ;
107
110
const u32 final_key_size = key_size > buf_len ? buf_len : key_size ;
@@ -124,15 +127,16 @@ static __always_inline bool read_key_name(pktbuf_t pkt, char *buf, u8 buf_len, u
124
127
return true;
125
128
}
126
129
127
- // Process a Redis request from the packet buffer. The function reads the request from the packet buffer,
128
- // and returns the method (GET or SET) and the key(up to MAX_KEY_LEN bytes).
130
+
131
+ // Processes incoming Redis requests (GET or SET commands).
132
+ // Extracts command type and key (up to MAX_KEY_LEN bytes), stores transaction info in redis_in_flight map.
129
133
static __always_inline void process_redis_request (pktbuf_t pkt , conn_tuple_t * conn_tuple ) {
130
134
u32 param_count = read_array_message_param_count (pkt );
131
135
if (param_count == 0 ) {
132
136
return ;
133
137
}
134
138
// GET message has 2 parameters, SET message has 3-5 parameters. Anything else is irrelevant for us.
135
- if (param_count < 2 || param_count > 5 ) {
139
+ if (param_count < MIN_PARAM_COUNT || param_count > MAX_PARAM_COUNT ) {
136
140
return ;
137
141
}
138
142
@@ -174,10 +178,12 @@ static __always_inline void process_redis_request(pktbuf_t pkt, conn_tuple_t *co
174
178
return ;
175
179
}
176
180
177
- bpf_map_update_elem ( & redis_in_flight , conn_tuple , & transaction , BPF_ANY );
181
+ bpf_map_update_with_telemetry ( redis_in_flight , conn_tuple , & transaction , BPF_ANY );
178
182
}
179
183
180
- // Handles a TCP termination event by deleting the connection tuple from the in-flight map.
184
+
185
+ // Handles TCP connection termination by cleaning up in-flight transactions.
186
+ // Removes entries from redis_in_flight map for both directions.
181
187
static void __always_inline redis_tcp_termination (conn_tuple_t * tup ) {
182
188
bpf_map_delete_elem (& redis_in_flight , tup );
183
189
flip_tuple (tup );
@@ -198,6 +204,8 @@ static __always_inline void redis_batch_enqueue_wrapper(conn_tuple_t *tuple, red
198
204
redis_batch_enqueue (event );
199
205
}
200
206
207
+ // Processes Redis response messages and validates their format.
208
+ // Handles error responses and command-specific response types.
201
209
static void __always_inline process_redis_response (pktbuf_t pkt , conn_tuple_t * tup , redis_transaction_t * transaction ) {
202
210
char first_byte ;
203
211
if (pktbuf_load_bytes_from_current_offset (pkt , & first_byte , sizeof (first_byte )) < 0 ) {
@@ -207,16 +215,12 @@ static void __always_inline process_redis_response(pktbuf_t pkt, conn_tuple_t *t
207
215
transaction -> is_error = true;
208
216
goto enqueue ;
209
217
}
210
- if (transaction -> command == REDIS_GET ) {
211
- if (first_byte != RESP_BULK_PREFIX ) {
212
- goto cleanup ;
213
- }
218
+ if (transaction -> command == REDIS_GET && first_byte == RESP_BULK_PREFIX ) {
214
219
goto enqueue ;
215
- } else {
216
- if (first_byte != RESP_SIMPLE_STRING_PREFIX ) {
217
- goto cleanup ;
218
- }
220
+ } else if (transaction -> command == REDIS_SET && first_byte == RESP_SIMPLE_STRING_PREFIX ){
219
221
goto enqueue ;
222
+ } else {
223
+ goto cleanup ;
220
224
}
221
225
222
226
enqueue :
@@ -226,6 +230,8 @@ static void __always_inline process_redis_response(pktbuf_t pkt, conn_tuple_t *t
226
230
bpf_map_delete_elem (& redis_in_flight , tup );
227
231
}
228
232
233
+ // Main socket processing function for Redis traffic.
234
+ // Handles both requests and responses based on connection state.
229
235
SEC ("socket/redis_process" )
230
236
int socket__redis_process (struct __sk_buff * skb ) {
231
237
skb_info_t skb_info = {};
@@ -251,6 +257,8 @@ int socket__redis_process(struct __sk_buff *skb) {
251
257
return 0 ;
252
258
}
253
259
260
+ // Processes Redis messages over TLS connections.
261
+ // Similar to socket__redis_process but handles TLS-encrypted traffic.
254
262
SEC ("uprobe/redis_tls_process" )
255
263
int uprobe__redis_tls_process (struct pt_regs * ctx ) {
256
264
const __u32 zero = 0 ;
@@ -262,6 +270,7 @@ int uprobe__redis_tls_process(struct pt_regs *ctx) {
262
270
263
271
// Copying the tuple to the stack to handle verifier issues on kernel 4.14.
264
272
conn_tuple_t tup = args -> tup ;
273
+ normalize_tuple (& tup );
265
274
266
275
pktbuf_t pkt = pktbuf_from_tls (ctx , args );
267
276
redis_transaction_t * transaction = bpf_map_lookup_elem (& redis_in_flight , & tup );
@@ -273,6 +282,8 @@ int uprobe__redis_tls_process(struct pt_regs *ctx) {
273
282
return 0 ;
274
283
}
275
284
285
+ // Handles termination of TLS Redis connections.
286
+ // Cleans up connection state for TLS connections.
276
287
SEC ("uprobe/redis_tls_termination" )
277
288
int uprobe__redis_tls_termination (struct pt_regs * ctx ) {
278
289
const __u32 zero = 0 ;
@@ -284,6 +295,7 @@ int uprobe__redis_tls_termination(struct pt_regs *ctx) {
284
295
285
296
// Copying the tuple to the stack to handle verifier issues on kernel 4.14.
286
297
conn_tuple_t tup = args -> tup ;
298
+ normalize_tuple (& tup );
287
299
redis_tcp_termination (& tup );
288
300
289
301
return 0 ;
0 commit comments