blob: 38f756edcb7883750d6e32599f39884a73265984 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define TABLE_SIZE 2048
#define MAX_KEY_LEN 46
#define STALE_SECONDS 30
struct rl_entry {
char ip[ MAX_KEY_LEN ];
time_t last_request;
int count;
int in_use;
};
struct rl_table {
struct rl_entry entries[ TABLE_SIZE ];
pthread_mutex_t mutex;
};
struct rl_table* global_ratelimit = NULL;
void ratelimit_init() {
if (global_ratelimit != NULL) return;
struct rl_table* table = malloc(sizeof(struct rl_table));
if (!table) {
perror("failed to alloc ratelimit table");
exit(1);
}
memset(table->entries, 0, sizeof(table->entries));
pthread_mutex_init(&table->mutex, NULL);
global_ratelimit = table;
}
static uint32_t hash_ip(const char* ip) {
uint32_t hash = 5381;
while (*ip) hash = (hash << 5) + hash + *ip++;
return hash % TABLE_SIZE;
}
int ratelimit_check(const char* ip) {
ratelimit_init();
pthread_mutex_lock(&global_ratelimit->mutex);
time_t now = time(NULL);
uint32_t index = hash_ip(ip);
uint32_t probes = 0;
while (probes < TABLE_SIZE) {
struct rl_entry* entry = &global_ratelimit->entries[ index ];
if (!entry->in_use) {
strncpy(entry->ip, ip, MAX_KEY_LEN - 1);
entry->ip[ MAX_KEY_LEN - 1 ] = '\0';
entry->last_request = now;
entry->count = 1;
entry->in_use = 1;
pthread_mutex_unlock(&global_ratelimit->mutex);
return 1;
}
if (strcmp(entry->ip, ip) == 0) {
if (now > entry->last_request) {
entry->last_request = now;
entry->count = 1;
} else if (entry->count >= 4) {
pthread_mutex_unlock(&global_ratelimit->mutex);
return 0;
} else {
entry->count++;
}
pthread_mutex_unlock(&global_ratelimit->mutex);
return 1;
}
if (entry->in_use && (now - entry->last_request) > STALE_SECONDS) {
entry->in_use = 0;
entry->count = 0;
entry->last_request = 0;
entry->ip[ 0 ] = '\0';
strncpy(entry->ip, ip, MAX_KEY_LEN - 1);
entry->ip[ MAX_KEY_LEN - 1 ] = '\0';
entry->last_request = now;
entry->count = 1;
entry->in_use = 1;
pthread_mutex_unlock(&global_ratelimit->mutex);
return 1;
}
index = (index + 1) % TABLE_SIZE;
probes++;
}
pthread_mutex_unlock(&global_ratelimit->mutex);
return 0;
}
void ratelimit_free(struct rl_table* table) {
if (table) {
pthread_mutex_destroy(&table->mutex);
free(table);
}
}
|