1
1
package antiDdos
2
2
3
3
import (
4
+ "net"
4
5
"net/http"
5
- "strings"
6
6
"sync"
7
7
"time"
8
8
9
9
"golang.org/x/time/rate"
10
10
)
11
11
12
- // r - time.second
13
- // b - request/per time
14
-
12
+ // IPRateLimiter представляет собой ограничитель скорости по IP-адресу.
15
13
type IPRateLimiter struct {
16
- ips map [string ]* rate.Limiter
17
- mu * sync.RWMutex
18
- r rate.Limit
19
- b int
14
+ ips map [string ]* rate.Limiter // Карта IP-адресов и соответствующих ограничителей скорости
15
+ mu * sync.RWMutex // Мьютекс для безопасного доступа к картам IP-адресов
16
+ r rate.Limit // Предел скорости
17
+ b int // Максимальное количество запросов, разрешенных в интервал времени
20
18
}
21
19
20
+ // NewIPRateLimiter создает новый экземпляр IPRateLimiter с заданным интервалом времени и максимальным количеством запросов.
22
21
func NewIPRateLimiter (t time.Duration , b int ) * IPRateLimiter {
23
22
i := & IPRateLimiter {
24
23
ips : make (map [string ]* rate.Limiter ),
@@ -30,6 +29,7 @@ func NewIPRateLimiter(t time.Duration, b int) *IPRateLimiter {
30
29
return i
31
30
}
32
31
32
+ // AddIP добавляет IP-адрес в карту IP-адресов и создает для него новый ограничитель скорости.
33
33
func (i * IPRateLimiter ) AddIP (ip string ) * rate.Limiter {
34
34
i .mu .Lock ()
35
35
defer i .mu .Unlock ()
@@ -41,24 +41,35 @@ func (i *IPRateLimiter) AddIP(ip string) *rate.Limiter {
41
41
return limiter
42
42
}
43
43
44
+ // GetLimiter возвращает ограничитель скорости для заданного IP-адреса.
45
+ // Если ограничитель для данного IP-адреса уже существует, он возвращается.
46
+ // В противном случае создается новый ограничитель и добавляется в карту IP-адресов.
44
47
func (i * IPRateLimiter ) GetLimiter (ip string ) * rate.Limiter {
45
48
i .mu .Lock ()
49
+ defer i .mu .Unlock ()
50
+
46
51
limiter , exists := i .ips [ip ]
47
52
48
53
if ! exists {
49
- i .mu .Unlock ()
50
- return i .AddIP (ip )
54
+ limiter = i .AddIP (ip )
51
55
}
52
56
53
- i .mu .Unlock ()
54
-
55
57
return limiter
56
58
}
57
59
58
-
59
- func (i * IPRateLimiter ) LimitMiddleware (next http.Handler ) http.Handler {
60
+ // LimitMiddleware является промежуточным обработчиком HTTP и ограничивает скорость запросов для каждого IP-адреса.
61
+ // Если количество запросов превышает максимальное количество разрешенных запросов в заданный интервал времени,
62
+ // возвращается ошибка "Too Many Requests" (код 429).
63
+ func (i * IPRateLimiter ) LimitMiddleware (next http.Handler ) http.Handler {
60
64
return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
61
- limiter := i .GetLimiter (getIPFromRemoteAddr (r .RemoteAddr ))
65
+ ip := getClientIP (r )
66
+
67
+ if ip == "" {
68
+ http .Error (w , http .StatusText (http .StatusBadRequest ), http .StatusBadRequest )
69
+ return
70
+ }
71
+
72
+ limiter := i .GetLimiter (ip )
62
73
63
74
if ! limiter .Allow () {
64
75
http .Error (w , http .StatusText (http .StatusTooManyRequests ), http .StatusTooManyRequests )
@@ -69,8 +80,14 @@ func (i *IPRateLimiter) LimitMiddleware(next http.Handler) http.Handler {
69
80
})
70
81
}
71
82
72
- func getIPFromRemoteAddr (remoteAddr string ) (ip string ) {
73
- trim := strings .Split (remoteAddr , ":" )
74
- ip = trim [0 ]
75
- return
76
- }
83
+ // getClientIP возвращает IP-адрес клиента из заголовка X-Forwarded-For
84
+ // Если заголовок отсутствует, то IP-адрес извлекается из RemoteAddr.
85
+ func getClientIP (r * http.Request ) string {
86
+ ip := r .Header .Get ("X-Forwarded-For" )
87
+
88
+ if ip == "" {
89
+ ip , _ , _ = net .SplitHostPort (r .RemoteAddr )
90
+ }
91
+
92
+ return ip
93
+ }
0 commit comments