mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-19 22:28:45 +05:00
Added *apiban filter
This commit is contained in:
committed by
Dan Christian Bogos
parent
8bb549a024
commit
0bc0b58a69
@@ -20,6 +20,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/baningo"
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"github.com/cgrates/ltcache"
|
||||
@@ -73,6 +74,7 @@ var (
|
||||
utils.RateProfilesFilterIndexPrfx: {},
|
||||
utils.RateFilterIndexPrfx: {},
|
||||
utils.FilterIndexPrfx: {},
|
||||
utils.MetaAPIBan: {}, // not realy a prefix as this is not stored in DB
|
||||
}
|
||||
)
|
||||
|
||||
@@ -133,7 +135,8 @@ func (dm *DataManager) CacheDataFromDB(prfx string, ids []string, mustBeCached b
|
||||
if dm.cacheCfg.Partitions[utils.CachePrefixToInstance[prfx]].Limit == 0 {
|
||||
return
|
||||
}
|
||||
if ids == nil {
|
||||
if ids == nil &&
|
||||
prfx != utils.MetaAPIBan { // no need for ids in this case
|
||||
if mustBeCached {
|
||||
ids = Cache.GetItemIDs(utils.CachePrefixToInstance[prfx], utils.EmptyString)
|
||||
} else {
|
||||
@@ -282,6 +285,8 @@ func (dm *DataManager) CacheDataFromDB(prfx string, ids []string, mustBeCached b
|
||||
_, err = dm.GetIndexes(utils.CacheReverseFilterIndexes, dataID[:idx], dataID[idx+1:], false, true)
|
||||
case utils.LoadIDPrefix:
|
||||
_, err = dm.GetItemLoadIDs(utils.EmptyString, true)
|
||||
case utils.MetaAPIBan:
|
||||
_, err = dm.GetAPIBan(utils.EmptyString, config.CgrConfig().APIBanCfg().Keys, false, false, true)
|
||||
}
|
||||
if err != nil {
|
||||
if err != utils.ErrNotFound {
|
||||
@@ -3359,3 +3364,42 @@ func (dm *DataManager) RemoveIndexes(idxItmType, tntCtx, idxKey string) (err err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (dm *DataManager) GetAPIBan(ip string, apiKeys []string, single, cacheRead, cacheWrite bool) (banned bool, err error) {
|
||||
if cacheRead {
|
||||
if x, ok := Cache.Get(utils.MetaAPIBan, ip); ok && x != nil { // Attempt to find in cache first
|
||||
return x.(bool), nil
|
||||
}
|
||||
}
|
||||
if single {
|
||||
if banned, err = baningo.CheckIP(ip, apiKeys...); err != nil {
|
||||
return
|
||||
}
|
||||
if cacheWrite {
|
||||
if err = Cache.Set(utils.MetaAPIBan, ip, banned, nil, true, utils.NonTransactional); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
var bannedIPs []string
|
||||
if bannedIPs, err = baningo.GetBannedIPs(apiKeys...); err != nil {
|
||||
return
|
||||
}
|
||||
for _, bannedIP := range bannedIPs {
|
||||
if bannedIP == ip {
|
||||
banned = true
|
||||
}
|
||||
if cacheWrite {
|
||||
if err = Cache.Set(utils.MetaAPIBan, bannedIP, true, nil, true, utils.NonTransactional); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(ip) != 0 && !banned && cacheWrite {
|
||||
if err = Cache.Set(utils.MetaAPIBan, ip, false, nil, true, utils.NonTransactional); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -223,16 +223,16 @@ var supportedFiltersType utils.StringSet = utils.NewStringSet([]string{
|
||||
utils.MetaTimings, utils.MetaRSR, utils.MetaDestinations,
|
||||
utils.MetaEmpty, utils.MetaExists, utils.MetaLessThan, utils.MetaLessOrEqual,
|
||||
utils.MetaGreaterThan, utils.MetaGreaterOrEqual, utils.MetaEqual,
|
||||
utils.MetaNotEqual, utils.MetaIPNet})
|
||||
utils.MetaNotEqual, utils.MetaIPNet, utils.MetaAPIBan})
|
||||
var needsFieldName utils.StringSet = utils.NewStringSet([]string{
|
||||
utils.MetaString, utils.MetaPrefix, utils.MetaSuffix,
|
||||
utils.MetaTimings, utils.MetaRSR, utils.MetaDestinations, utils.MetaLessThan,
|
||||
utils.MetaEmpty, utils.MetaExists, utils.MetaLessOrEqual, utils.MetaGreaterThan,
|
||||
utils.MetaGreaterOrEqual, utils.MetaEqual, utils.MetaNotEqual, utils.MetaIPNet})
|
||||
utils.MetaGreaterOrEqual, utils.MetaEqual, utils.MetaNotEqual, utils.MetaIPNet, utils.MetaAPIBan})
|
||||
var needsValues utils.StringSet = utils.NewStringSet([]string{utils.MetaString, utils.MetaPrefix,
|
||||
utils.MetaSuffix, utils.MetaTimings, utils.MetaRSR, utils.MetaDestinations,
|
||||
utils.MetaLessThan, utils.MetaLessOrEqual, utils.MetaGreaterThan, utils.MetaGreaterOrEqual,
|
||||
utils.MetaEqual, utils.MetaNotEqual, utils.MetaIPNet})
|
||||
utils.MetaEqual, utils.MetaNotEqual, utils.MetaIPNet, utils.MetaAPIBan})
|
||||
|
||||
// NewFilterRule returns a new filter
|
||||
func NewFilterRule(rfType, fieldName string, vals []string) (*FilterRule, error) {
|
||||
@@ -335,6 +335,8 @@ func (fltr *FilterRule) Pass(dDP utils.DataProvider) (result bool, err error) {
|
||||
result, err = fltr.passEqualTo(dDP)
|
||||
case utils.MetaIPNet, utils.MetaNotIPNet:
|
||||
result, err = fltr.passIPNet(dDP)
|
||||
case utils.MetaAPIBan, utils.MetaNotAPIBan:
|
||||
result, err = fltr.passAPIBan(dDP)
|
||||
default:
|
||||
err = utils.ErrPrefixNotErrNotImplemented(fltr.Type)
|
||||
}
|
||||
@@ -600,6 +602,21 @@ func (fltr *FilterRule) passIPNet(dDP utils.DataProvider) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (fltr *FilterRule) passAPIBan(dDP utils.DataProvider) (bool, error) {
|
||||
strVal, err := fltr.rsrElement.ParseDataProvider(dDP)
|
||||
if err != nil {
|
||||
if err == utils.ErrNotFound {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
if fltr.Values[0] != utils.MetaAll &&
|
||||
fltr.Values[0] != utils.MetaSingle { // force only valid values
|
||||
return false, fmt.Errorf("invalid value for apiban filter: <%s>", fltr.Values[0])
|
||||
}
|
||||
return dm.GetAPIBan(strVal, config.CgrConfig().APIBanCfg().Keys, fltr.Values[0] != utils.MetaAll, true, true)
|
||||
}
|
||||
|
||||
func newDynamicDP(cfg *config.CGRConfig, connMgr *ConnManager,
|
||||
tenant string, initialDP utils.DataProvider) *dynamicDP {
|
||||
return &dynamicDP{
|
||||
|
||||
@@ -15,10 +15,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package engine
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/baningo"
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
@@ -1457,3 +1460,106 @@ func TestFilterPassIPNet(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIBan(t *testing.T) {
|
||||
var counter int
|
||||
testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
responses := map[string]struct {
|
||||
code int
|
||||
body []byte
|
||||
}{
|
||||
"/testKey/check/1.2.3.251": {code: http.StatusOK, body: []byte(`{"ipaddress":["1.2.3.251"], "ID":"987654321"}`)},
|
||||
"/testKey/check/1.2.3.254": {code: http.StatusBadRequest, body: []byte(`{"ipaddress":["not blocked"], "ID":"none"}`)},
|
||||
}
|
||||
if val, has := responses[r.URL.EscapedPath()]; has {
|
||||
w.WriteHeader(val.code)
|
||||
if val.body != nil {
|
||||
w.Write(val.body)
|
||||
}
|
||||
return
|
||||
}
|
||||
counter++
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if counter < 2 {
|
||||
_, _ = w.Write([]byte(`{"ipaddress": ["1.2.3.251", "1.2.3.252"], "ID": "100"}`))
|
||||
} else {
|
||||
_, _ = w.Write([]byte(`{"ID": "none"}`))
|
||||
counter = 0
|
||||
}
|
||||
}))
|
||||
defer testServer.Close()
|
||||
baningo.RootURL = testServer.URL + "/"
|
||||
|
||||
dp := utils.MapStorage{
|
||||
utils.MetaReq: utils.MapStorage{
|
||||
"bannedIP": "1.2.3.251",
|
||||
"bannedIP2": "1.2.3.252",
|
||||
"IP": "1.2.3.253",
|
||||
"IP2": "1.2.3.254",
|
||||
},
|
||||
}
|
||||
cfg, _ := config.NewDefaultCGRConfig()
|
||||
data := NewInternalDB(nil, nil, true)
|
||||
dmFilterPass := NewDataManager(data, config.CgrConfig().CacheCfg(), nil)
|
||||
filterS := FilterS{
|
||||
cfg: cfg,
|
||||
dm: dmFilterPass,
|
||||
}
|
||||
config.CgrConfig().APIBanCfg().Keys = []string{"testKey"}
|
||||
if pass, err := filterS.Pass("cgrates.org", []string{"*apiban:~*req.IP:*all"}, dp); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if pass {
|
||||
t.Error("Expected not to pass")
|
||||
}
|
||||
// from cache
|
||||
if pass, err := filterS.Pass("cgrates.org", []string{"*apiban:~*req.IP:*all"}, dp); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if pass {
|
||||
t.Error("Expected not to pass")
|
||||
}
|
||||
if pass, err := filterS.Pass("cgrates.org", []string{"*apiban:~*req.IP2:*single"}, dp); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if pass {
|
||||
t.Error("Expected not to pass")
|
||||
}
|
||||
Cache.Clear([]string{utils.MetaAPIBan})
|
||||
if pass, err := filterS.Pass("cgrates.org", []string{"*apiban:~*req.bannedIP:*single"}, dp); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !pass {
|
||||
t.Error("Expected to pass")
|
||||
}
|
||||
if pass, err := filterS.Pass("cgrates.org", []string{"*apiban:~*req.bannedIP2:*all"}, dp); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !pass {
|
||||
t.Error("Expected to pass")
|
||||
}
|
||||
|
||||
if pass, err := filterS.Pass("cgrates.org", []string{"*apiban:~*req.notFound:*all"}, dp); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if pass {
|
||||
t.Error("Expected not to pass")
|
||||
}
|
||||
expErr := "invalid value for apiban filter: <*any>"
|
||||
if _, err := filterS.Pass("cgrates.org", []string{"*apiban:~*req.IP:*any"}, dp); err == nil || err.Error() != expErr {
|
||||
t.Errorf("Expected error %s received: %v", expErr, err)
|
||||
}
|
||||
baningo.RootURL = "http://127.0.0.1:80/"
|
||||
|
||||
expErr = `Get "http://127.0.0.1:80/testKey/banned/100": dial tcp 127.0.0.1:80: connect: connection refused`
|
||||
if _, err := filterS.Pass("cgrates.org", []string{"*apiban:~*req.IP:*all"}, dp); err == nil || err.Error() != expErr {
|
||||
t.Errorf("Expected error %s received: %v", expErr, err)
|
||||
}
|
||||
expErr = `Get "http://127.0.0.1:80/testKey/check/1.2.3.253": dial tcp 127.0.0.1:80: connect: connection refused`
|
||||
if _, err := filterS.Pass("cgrates.org", []string{"*apiban:~*req.IP:*single"}, dp); err == nil || err.Error() != expErr {
|
||||
t.Errorf("Expected error %s received: %v", expErr, err)
|
||||
}
|
||||
|
||||
expErr = `invalid converter value in string: <*>, err: unsupported converter definition: <*>`
|
||||
if _, err := filterS.Pass("cgrates.org", []string{"*apiban:~*req.<~*req.IP>{*}:*all"}, dp); err == nil || err.Error() != expErr {
|
||||
t.Errorf("Expected error %s received: %v", expErr, err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user