mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2025-05-08 08:43:01 +03:00
Pull request: 2826 auth block
Merge in DNS/adguard-home from 2826-auth-block to master Updates #2826. Squashed commit of the following: commit ae87360379270012869ad2bc4e528e07eb9af91e Author: Eugene Burkov <e.burkov@adguard.com> Date: Tue Apr 27 15:35:49 2021 +0300 home: fix mistake commit dfa2ab05e9a8e70ac1bec36c4eb8ef3b02283b92 Author: Eugene Burkov <e.burkov@adguard.com> Date: Tue Apr 27 15:31:53 2021 +0300 home: imp code commit ff4220d3c3d92ae604e92a0c5c274d9527350d99 Author: Eugene Burkov <e.burkov@adguard.com> Date: Tue Apr 27 15:14:20 2021 +0300 home: imp authratelimiter commit c73a407d8652d64957e35046dbae7168aa45202f Author: Eugene Burkov <e.burkov@adguard.com> Date: Tue Apr 27 14:20:17 2021 +0300 home: fix authratelimiter commit 724db4380928b055f9995006cf421cbe9c5363e7 Author: Eugene Burkov <e.burkov@adguard.com> Date: Fri Apr 23 12:15:48 2021 +0300 home: introduce auth blocker
This commit is contained in:
parent
3f1b71fdf3
commit
f603c21b55
9 changed files with 415 additions and 22 deletions
internal/home
109
internal/home/authratelimiter.go
Normal file
109
internal/home/authratelimiter.go
Normal file
|
@ -0,0 +1,109 @@
|
|||
package home
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// failedAuthTTL is the period of time for which the failed attempt will stay in
|
||||
// cache.
|
||||
const failedAuthTTL = 1 * time.Minute
|
||||
|
||||
// failedAuth is an entry of authRateLimiter's cache.
|
||||
type failedAuth struct {
|
||||
until time.Time
|
||||
num uint
|
||||
}
|
||||
|
||||
// authRateLimiter used to cache failed authentication attempts.
|
||||
type authRateLimiter struct {
|
||||
failedAuths map[string]failedAuth
|
||||
// failedAuthsLock protects failedAuths.
|
||||
failedAuthsLock sync.Mutex
|
||||
blockDur time.Duration
|
||||
maxAttempts uint
|
||||
}
|
||||
|
||||
// newAuthRateLimiter returns properly initialized *authRateLimiter.
|
||||
func newAuthRateLimiter(blockDur time.Duration, maxAttempts uint) (ab *authRateLimiter) {
|
||||
return &authRateLimiter{
|
||||
failedAuths: make(map[string]failedAuth),
|
||||
blockDur: blockDur,
|
||||
maxAttempts: maxAttempts,
|
||||
}
|
||||
}
|
||||
|
||||
// cleanupLocked checks each blocked users removing ones with expired TTL. For
|
||||
// internal use only.
|
||||
func (ab *authRateLimiter) cleanupLocked(now time.Time) {
|
||||
for k, v := range ab.failedAuths {
|
||||
if now.After(v.until) {
|
||||
delete(ab.failedAuths, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checkLocked checks the attempter for it's state. For internal use only.
|
||||
func (ab *authRateLimiter) checkLocked(usrID string, now time.Time) (left time.Duration) {
|
||||
a, ok := ab.failedAuths[usrID]
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
if a.num < ab.maxAttempts {
|
||||
return 0
|
||||
}
|
||||
|
||||
return a.until.Sub(now)
|
||||
}
|
||||
|
||||
// check returns the time left until unblocking. The nonpositive result should
|
||||
// be interpreted as not blocked attempter.
|
||||
func (ab *authRateLimiter) check(usrID string) (left time.Duration) {
|
||||
now := time.Now()
|
||||
|
||||
ab.failedAuthsLock.Lock()
|
||||
defer ab.failedAuthsLock.Unlock()
|
||||
|
||||
ab.cleanupLocked(now)
|
||||
return ab.checkLocked(usrID, now)
|
||||
}
|
||||
|
||||
// incLocked increments the number of unsuccessful attempts for attempter with
|
||||
// ip and updates it's blocking moment if needed. For internal use only.
|
||||
func (ab *authRateLimiter) incLocked(usrID string, now time.Time) {
|
||||
var until time.Time = now.Add(failedAuthTTL)
|
||||
var attNum uint = 1
|
||||
|
||||
a, ok := ab.failedAuths[usrID]
|
||||
if ok {
|
||||
until = a.until
|
||||
attNum = a.num + 1
|
||||
}
|
||||
if attNum >= ab.maxAttempts {
|
||||
until = now.Add(ab.blockDur)
|
||||
}
|
||||
|
||||
ab.failedAuths[usrID] = failedAuth{
|
||||
num: attNum,
|
||||
until: until,
|
||||
}
|
||||
}
|
||||
|
||||
// inc updates the failed attempt in cache.
|
||||
func (ab *authRateLimiter) inc(usrID string) {
|
||||
now := time.Now()
|
||||
|
||||
ab.failedAuthsLock.Lock()
|
||||
defer ab.failedAuthsLock.Unlock()
|
||||
|
||||
ab.incLocked(usrID, now)
|
||||
}
|
||||
|
||||
// remove stops any tracking and any blocking of the user.
|
||||
func (ab *authRateLimiter) remove(usrID string) {
|
||||
ab.failedAuthsLock.Lock()
|
||||
defer ab.failedAuthsLock.Unlock()
|
||||
|
||||
delete(ab.failedAuths, usrID)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue