add redis ttl

This commit is contained in:
Max Lerebourg
2022-10-24 21:38:56 +02:00
parent ffcf4356fc
commit 0a186cf9a9
3 changed files with 47 additions and 48 deletions
@@ -59,7 +59,7 @@ services:
- "traefik.http.middlewares.crowdsec2.plugin.bouncer.enabled=true" - "traefik.http.middlewares.crowdsec2.plugin.bouncer.enabled=true"
# crowdseclapikey must be uniq to the middleware attached to the service # crowdseclapikey must be uniq to the middleware attached to the service
- "traefik.http.middlewares.crowdsec2.plugin.bouncer.crowdseclapikey=44c36dac5c4140af9f06f397508e82c7" - "traefik.http.middlewares.crowdsec2.plugin.bouncer.crowdseclapikey=44c36dac5c4140af9f06f397508e82c7"
- "traefik.http.middlewares.crowdsec2.plugin.bouncer.rediscacheenabled=false" - "traefik.http.middlewares.crowdsec2.plugin.bouncer.rediscacheenabled=true"
crowdsec: crowdsec:
+13 -16
View File
@@ -20,7 +20,6 @@ var redis simpleredis.SimpleRedis
var redisEnabled = false var redisEnabled = false
func getDecisionLocalCache(clientIP string) (bool, error) { func getDecisionLocalCache(clientIP string) (bool, error) {
banned, isCached := cache.Get(clientIP) banned, isCached := cache.Get(clientIP)
bannedString, isValid := banned.(string) bannedString, isValid := banned.(string)
@@ -30,29 +29,28 @@ func getDecisionLocalCache(clientIP string) (bool, error) {
return false, fmt.Errorf("no cache data") return false, fmt.Errorf("no cache data")
} }
func SetDecisionLocalCache(clientIP string, value string, duration int64) { func setDecisionLocalCache(clientIP string, value string, duration int64) {
cache.Set(clientIP, value, duration) cache.Set(clientIP, value, duration)
} }
func DeleteDecisionLocalCache(clientIP string) { func deleteDecisionLocalCache(clientIP string) {
cache.Del(clientIP) cache.Del(clientIP)
} }
func getDecisionRedisCache(clientIP string) (bool, error) { func getDecisionRedisCache(clientIP string) (bool, error) {
banned, err := redis.Do("GET", clientIP, nil) banned, err := redis.Get(clientIP)
bannedString := string(banned) bannedString := string(banned)
logger.Info(fmt.Sprintf("%v banned", bannedString))
if err == nil && len(bannedString) > 0 { if err == nil && len(bannedString) > 0 {
return bannedString == cacheBannedValue, nil return bannedString == cacheBannedValue, nil
} }
return false, fmt.Errorf("no cache data") return false, fmt.Errorf("no cache data")
} }
func SetDecisionRedisCache(clientIP string, value string, duration int64) { func setDecisionRedisCache(clientIP string, value string, duration int64) {
redis.Do("SET", clientIP, []byte(value)) redis.Set(clientIP, []byte(value), duration)
} }
func DeleteDecisionRedisCache(clientIP string) { func deleteDecisionRedisCache(clientIP string) {
// err := rdb.Del(ctx, clientIP).Err() // err := rdb.Del(ctx, clientIP).Err()
// if err != nil { // if err != nil {
// logger.Info("Error, could not delete in redis cache IP") // logger.Info("Error, could not delete in redis cache IP")
@@ -60,16 +58,15 @@ func DeleteDecisionRedisCache(clientIP string) {
// errors are not handled // errors are not handled
} }
func DeleteDecision(clientIP string) { func DeleteDecision(clientIP string) {
if redisEnabled { if redisEnabled {
DeleteDecisionRedisCache(clientIP) deleteDecisionRedisCache(clientIP)
} else { } else {
DeleteDecisionLocalCache(clientIP) deleteDecisionLocalCache(clientIP)
} }
} }
// Get Decision check in the cache if the IP has the banned / not banned value.
// GetDecision check in the cache if the IP has the banned / not banned value.
// Otherwise return with an error to add the IP in cache if we are on. // Otherwise return with an error to add the IP in cache if we are on.
func GetDecision(clientIP string) (bool, error) { func GetDecision(clientIP string) (bool, error) {
if redisEnabled { if redisEnabled {
@@ -88,14 +85,14 @@ func SetDecision(clientIP string, isBanned bool, duration int64) {
value = cacheNoBannedValue value = cacheNoBannedValue
} }
if redisEnabled { if redisEnabled {
SetDecisionRedisCache(clientIP, value, duration) setDecisionRedisCache(clientIP, value, duration)
} else { } else {
SetDecisionLocalCache(clientIP, value, duration) setDecisionLocalCache(clientIP, value, duration)
} }
} }
func InitRedisClient(host string, password string) { func InitRedisClient(host string, password string) {
logger.Debug("connect to redis")
redisEnabled = true redisEnabled = true
redis.Init(host) redis.Init(host)
logger.Debug("connect to redis")
} }
+32 -30
View File
@@ -2,22 +2,20 @@ package simpleredis
import ( import (
"fmt" "fmt"
"log"
"net" "net"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/tehnerd/goUtils/netutils" "github.com/tehnerd/goUtils/netutils"
logger "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/pkg/logger"
) )
type RedisCmd struct { type RedisCmd struct {
Command string Command string
Name string Name string
Data []byte Data []byte
Error error Duration int64
Error error
} }
type SimpleRedis struct { type SimpleRedis struct {
@@ -27,26 +25,17 @@ type SimpleRedis struct {
redisCmd RedisCmd redisCmd RedisCmd
} }
func GenRedisArray(params ...[]byte) []byte { func genRedisArray(params ...[]byte) []byte {
CRLF := "\r\n"
MSG := "" MSG := ""
for cntr := 0; cntr < len(params); cntr++ { for cntr := 0; cntr < len(params); cntr++ {
MSG = strings.Join([]string{MSG, string(params[cntr])}, " ") MSG = strings.Join([]string{MSG, string(params[cntr])}, " ")
} }
MSG = strings.Trim(MSG, " ") MSG = strings.Trim(MSG, " ")
MSG = strings.Join([]string{MSG, CRLF}, "") MSG = strings.Join([]string{MSG, "\r\n"}, "")
return []byte(MSG) return []byte(MSG)
} }
func RedisSet(name string, data []byte) []byte { func parseResponse(response []byte, dataBuf []byte, Len *int) ([]byte, []byte, error) {
return GenRedisArray([]byte("SET"), []byte(name), data)
}
func RedisGet(name string) []byte {
return GenRedisArray([]byte("GET"), []byte(name))
}
func ParseRedisResponse(response []byte, dataBuf []byte, Len *int) ([]byte, []byte, error) {
dataBuf = append(dataBuf, response...) dataBuf = append(dataBuf, response...)
lenCRLF := 2 lenCRLF := 2
if *Len != 0 { if *Len != 0 {
@@ -116,7 +105,7 @@ func ParseRedisResponse(response []byte, dataBuf []byte, Len *int) ([]byte, []by
return nil, dataBuf, nil return nil, dataBuf, nil
} }
func RedisContext(hostnamePort string, redisCmdWrite, redisCmdRead chan RedisCmd) { func initContext(hostnamePort string, redisCmdWrite, redisCmdRead chan RedisCmd) {
tcpRemoteAddress, err := net.ResolveTCPAddr("tcp", hostnamePort) tcpRemoteAddress, err := net.ResolveTCPAddr("tcp", hostnamePort)
if err != nil { if err != nil {
panic("cant resolve remote redis address") panic("cant resolve remote redis address")
@@ -131,23 +120,23 @@ func RedisContext(hostnamePort string, redisCmdWrite, redisCmdRead chan RedisCmd
<-readChan <-readChan
dataBuf := make([]byte, 0) dataBuf := make([]byte, 0)
dataLen := 0 dataLen := 0
for true { for {
select { select {
case cmd := <-redisCmdWrite: case cmd := <-redisCmdWrite:
switch cmd.Command { switch cmd.Command {
case "SET": case "SET":
data := RedisSet(cmd.Name, cmd.Data) data := genRedisArray([]byte("SET"), []byte(cmd.Name), cmd.Data, []byte("EX"), []byte(fmt.Sprintf("%v", cmd.Duration)))
writeChan <- data writeChan <- data
case "GET": case "GET":
data := RedisGet(cmd.Name) data := genRedisArray([]byte("GET"), []byte(cmd.Name))
writeChan <- data writeChan <- data
} }
case response := <-readChan: case response := <-readChan:
data, dataBuf, err := ParseRedisResponse(response, dataBuf, &dataLen) data, dataBuf, err := parseResponse(response, dataBuf, &dataLen)
if dataLen != 0 { if dataLen != 0 {
for data == nil { for data == nil {
response = <-readChan response = <-readChan
data, dataBuf, err = ParseRedisResponse(response, dataBuf, &dataLen) data, dataBuf, err = parseResponse(response, dataBuf, &dataLen)
} }
} }
if err != nil { if err != nil {
@@ -182,17 +171,30 @@ func (sr *SimpleRedis) Init(redisHost string) {
sr.redisHost = redisHost sr.redisHost = redisHost
sr.redisChanWrite = make(chan RedisCmd) sr.redisChanWrite = make(chan RedisCmd)
sr.redisChanRead = make(chan RedisCmd) sr.redisChanRead = make(chan RedisCmd)
go RedisContext(sr.redisHost, sr.redisChanWrite, sr.redisChanRead) go initContext(sr.redisHost, sr.redisChanWrite, sr.redisChanRead)
} }
func (sr *SimpleRedis) Do(cmd, name string, data []byte) ([]byte, error) { func (sr *SimpleRedis) Get(name string) ([]byte, error) {
sr.redisCmd.Command = cmd sr.redisCmd.Command = "GET"
sr.redisCmd.Name = name sr.redisCmd.Name = name
sr.redisCmd.Data = data sr.redisCmd.Data = nil
sr.redisChanWrite <- sr.redisCmd sr.redisChanWrite <- sr.redisCmd
resp := <- sr.redisChanRead resp := <-sr.redisChanRead
if resp.Error != nil { if resp.Error != nil {
return nil, resp.Error return nil, resp.Error
} }
return resp.Data, nil return resp.Data, nil
} }
func (sr *SimpleRedis) Set(name string, data []byte, duration int64) error {
sr.redisCmd.Command = "SET"
sr.redisCmd.Name = name
sr.redisCmd.Data = data
sr.redisCmd.Duration = duration
sr.redisChanWrite <- sr.redisCmd
resp := <-sr.redisChanRead
if resp.Error != nil {
return resp.Error
}
return nil
}