From 0bc0b58a69b93e728ca41e97619647ea3bd5cfe6 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 25 Sep 2020 15:06:11 +0300 Subject: [PATCH] Added *apiban filter --- config/config_defaults.go | 1 + config/config_json_test.go | 3 + config/config_test.go | 134 +++++++++++++++++++------------------ engine/datamanager.go | 46 ++++++++++++- engine/filters.go | 23 ++++++- engine/filters_test.go | 106 +++++++++++++++++++++++++++++ go.mod | 1 + go.sum | 4 ++ packages/debian/changelog | 1 + utils/consts.go | 6 +- 10 files changed, 254 insertions(+), 71 deletions(-) diff --git a/config/config_defaults.go b/config/config_defaults.go index 4d543523f..9f2d3157f 100755 --- a/config/config_defaults.go +++ b/config/config_defaults.go @@ -243,6 +243,7 @@ const CGRATES_CFG_JSON = ` "*rpc_connections": {"limit": -1, "ttl": "", "static_ttl": false, "replicate": false}, // RPC connections caching "*uch": {"limit": -1, "ttl": "3h", "static_ttl": false, "replicate": false}, // User cache "*stir": {"limit": -1, "ttl": "3h", "static_ttl": false, "replicate": false}, // stirShaken cache keys + "*apiban":{"limit": -1, "ttl": "2m", "static_ttl": false, "replicate": false}, // only for *internal database "*versions": {"limit": -1, "ttl": "", "static_ttl": false, "replicate": false}, // for version storing diff --git a/config/config_json_test.go b/config/config_json_test.go index 858cce495..41c022c39 100755 --- a/config/config_json_test.go +++ b/config/config_json_test.go @@ -290,6 +290,9 @@ func TestCacheJsonCfg(t *testing.T) { utils.CacheTBLTPRateProfiles: {Limit: utils.IntPointer(-1), Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)}, + utils.MetaAPIBan: {Limit: utils.IntPointer(-1), + Ttl: utils.StringPointer("2m"), Static_ttl: utils.BoolPointer(false), + Replicate: utils.BoolPointer(false)}, }, Replication_conns: &[]string{}, } diff --git a/config/config_test.go b/config/config_test.go index 693e9d55d..03b47aa86 100755 --- a/config/config_test.go +++ b/config/config_test.go @@ -502,79 +502,79 @@ func TestCgrCfgJSONDefaultsCacheCFG(t *testing.T) { eCacheCfg := &CacheCfg{ Partitions: map[string]*CacheParamCfg{ utils.CacheDestinations: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheReverseDestinations: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheRatingPlans: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheRatingProfiles: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheActions: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheActionPlans: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheAccountActionPlans: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheActionTriggers: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheSharedGroups: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheTimings: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheResourceProfiles: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheResources: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheEventResources: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false}, + TTL: 0, StaticTTL: false}, utils.CacheStatQueueProfiles: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheStatQueues: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheThresholdProfiles: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheThresholds: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheFilters: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheRouteProfiles: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheAttributeProfiles: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheChargerProfiles: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheDispatcherProfiles: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheRateProfiles: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheDispatcherHosts: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheResourceFilterIndexes: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheStatFilterIndexes: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheThresholdFilterIndexes: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheRouteFilterIndexes: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheAttributeFilterIndexes: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheChargerFilterIndexes: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheDispatcherFilterIndexes: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheRateProfilesFilterIndexes: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheRateFilterIndexes: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheReverseFilterIndexes: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheDispatcherRoutes: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheDispatcherLoads: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheDispatchers: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheDiameterMessages: {Limit: -1, TTL: time.Duration(3 * time.Hour), StaticTTL: false}, utils.CacheRPCResponses: {Limit: 0, @@ -586,64 +586,66 @@ func TestCgrCfgJSONDefaultsCacheCFG(t *testing.T) { utils.CacheCDRIDs: {Limit: -1, TTL: time.Duration(10 * time.Minute), StaticTTL: false}, utils.CacheLoadIDs: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheRPCConnections: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false}, + TTL: 0, StaticTTL: false}, utils.CacheUCH: {Limit: -1, TTL: time.Duration(3 * time.Hour), StaticTTL: false}, utils.CacheSTIR: {Limit: -1, TTL: time.Duration(3 * time.Hour), StaticTTL: false}, utils.CacheVersions: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheAccounts: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheTBLTPTimings: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheTBLTPDestinations: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheTBLTPRates: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheTBLTPDestinationRates: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheTBLTPRatingPlans: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheTBLTPRatingProfiles: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheTBLTPSharedGroups: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheTBLTPActions: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheTBLTPActionPlans: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheTBLTPActionTriggers: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheTBLTPAccountActions: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheTBLTPResources: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheTBLTPStats: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheTBLTPThresholds: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheTBLTPFilters: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheSessionCostsTBL: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheCDRsTBL: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheTBLTPRoutes: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheTBLTPAttributes: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheTBLTPChargers: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheTBLTPDispatchers: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheTBLTPDispatcherHosts: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, utils.CacheTBLTPRateProfiles: {Limit: -1, - TTL: time.Duration(0), StaticTTL: false, Precache: false}, + TTL: 0, StaticTTL: false, Precache: false}, + utils.MetaAPIBan: {Limit: -1, + TTL: 2 * time.Minute, StaticTTL: false, Precache: false}, }, ReplicationConns: []string{}, } @@ -1902,7 +1904,7 @@ func TestCgrCdfEventReader(t *testing.T) { Type: utils.META_NONE, FieldSep: ",", HeaderDefineChar: ":", - RunDelay: time.Duration(0), + RunDelay: 0, ConcurrentReqs: 1024, SourcePath: "/var/spool/cgrates/ers/in", ProcessedPath: "/var/spool/cgrates/ers/out", @@ -2198,7 +2200,7 @@ func TestCgrCfgEventReaderDefault(t *testing.T) { Type: utils.META_NONE, FieldSep: ",", HeaderDefineChar: ":", - RunDelay: time.Duration(0), + RunDelay: 0, ConcurrentReqs: 1024, SourcePath: "/var/spool/cgrates/ers/in", ProcessedPath: "/var/spool/cgrates/ers/out", diff --git a/engine/datamanager.go b/engine/datamanager.go index 2f9b5bc02..46de405b5 100644 --- a/engine/datamanager.go +++ b/engine/datamanager.go @@ -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 +} diff --git a/engine/filters.go b/engine/filters.go index 31aed967f..df99eb2cf 100644 --- a/engine/filters.go +++ b/engine/filters.go @@ -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{ diff --git a/engine/filters_test.go b/engine/filters_test.go index 812480327..a51ce0ed6 100644 --- a/engine/filters_test.go +++ b/engine/filters_test.go @@ -15,10 +15,13 @@ along with this program. If not, see 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) + } +} diff --git a/go.mod b/go.mod index 383383f72..eecf21ae7 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( github.com/cenkalti/hub v1.0.1 // indirect github.com/cenkalti/rpc2 v0.0.0-20200203073230-5ce2854ce0fd github.com/cgrates/aringo v0.0.0-20191121125609-d85002bd1667 + github.com/cgrates/baningo v0.0.0-20200925111414-e65b237006c9 github.com/cgrates/cron v0.0.0-20200906113840-dd008627fdca github.com/cgrates/fsock v0.0.0-20191107070144-e7a331109df7 github.com/cgrates/kamevapi v0.0.0-20191001125829-7dbc3ad58817 diff --git a/go.sum b/go.sum index 53cc3231b..2a072a4ed 100644 --- a/go.sum +++ b/go.sum @@ -64,6 +64,10 @@ github.com/cenkalti/rpc2 v0.0.0-20200203073230-5ce2854ce0fd/go.mod h1:v2npkhrXyk github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cgrates/aringo v0.0.0-20191121125609-d85002bd1667 h1:eNku7bwLtSTpn6FQUUTnqohuGWC8jij1KNqDZ2QkGRE= github.com/cgrates/aringo v0.0.0-20191121125609-d85002bd1667/go.mod h1:l0xi5JUVqxL4P7RZ9YitbSCiOtjMY2j7JBOCJIysRWk= +github.com/cgrates/baningo v0.0.0-20200925101338-ccea0136bbb1 h1:MM3w9bIb8DpJ+px6BQ0CkEmn0CLneAS4VHmmdZnje14= +github.com/cgrates/baningo v0.0.0-20200925101338-ccea0136bbb1/go.mod h1:3SwVROaS1Iml5lqEhj0gRhDRtmbBgypZpKcEkVTSleU= +github.com/cgrates/baningo v0.0.0-20200925111414-e65b237006c9 h1:WwluddhgQoHkB72AzbC781qtB2xJLt+B9Rc2+NYy0Ts= +github.com/cgrates/baningo v0.0.0-20200925111414-e65b237006c9/go.mod h1:3SwVROaS1Iml5lqEhj0gRhDRtmbBgypZpKcEkVTSleU= github.com/cgrates/cron v0.0.0-20200906113840-dd008627fdca h1:neuTTEjWsM+WXRyJ+MF1OzsNc+e7DGjrNZKIEIr8x4A= github.com/cgrates/cron v0.0.0-20200906113840-dd008627fdca/go.mod h1:I9cUDn/uzkakr0hmYTjXkQqf6wagg44L2p01gSYRRz0= github.com/cgrates/fsock v0.0.0-20191107070144-e7a331109df7 h1:dxtBWRAr62vRRKkExmJZ0u1EbCw/y0vOkSfdFND5qXw= diff --git a/packages/debian/changelog b/packages/debian/changelog index ff23e4f8e..cf8b85cf2 100644 --- a/packages/debian/changelog +++ b/packages/debian/changelog @@ -102,6 +102,7 @@ cgrates (0.11.0~dev) UNRELEASED; urgency=medium * [ActionS] Replaced the poster action with *export that will send the event to EEs * [AgentS] DiameterAgent return NOT_FOUND instead of "filter not passing" error and let other subsystem to handle this (e.g. FilterS) * [StatS] Change format of metricID when specifying fields ( e.g. *sum#~*req.FieldName ) + * [FilterS] Added *apiban filter -- DanB Wed, 19 Feb 2020 13:25:52 +0200 diff --git a/utils/consts.go b/utils/consts.go index 65385227c..8c71a2979 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -53,7 +53,7 @@ var ( CacheDispatcherRoutes, CacheDispatcherLoads, CacheDiameterMessages, CacheRPCResponses, CacheClosedSessions, CacheCDRIDs, CacheLoadIDs, CacheRPCConnections, CacheRatingProfilesTmp, CacheUCH, CacheSTIR, CacheEventCharges, CacheRateProfiles, CacheRateProfilesFilterIndexes, - CacheRateFilterIndexes, CacheReverseFilterIndexes, + CacheRateFilterIndexes, CacheReverseFilterIndexes, MetaAPIBan, // only internalDB CacheVersions, CacheAccounts, CacheTBLTPTimings, CacheTBLTPDestinations, CacheTBLTPRates, CacheTBLTPDestinationRates, @@ -98,6 +98,7 @@ var ( CacheAccounts: ACCOUNT_PREFIX, CacheRateFilterIndexes: RateFilterIndexPrfx, CacheReverseFilterIndexes: FilterIndexPrfx, + MetaAPIBan: MetaAPIBan, // special case as it is not in a DB } CachePrefixToInstance map[string]string // will be built on init CacheIndexesToPrefix = map[string]string{ // used by match index to get all the ids when index selects is disabled and for compute indexes @@ -261,6 +262,7 @@ const ( ROUNDING_DOWN = "*down" ANY = "*any" MetaAll = "*all" + MetaSingle = "*single" ZERO = "*zero" ASAP = "*asap" COMMENT_CHAR = '#' @@ -1085,6 +1087,7 @@ const ( MetaResources = "*resources" MetaEqual = "*eq" MetaIPNet = "*ipnet" + MetaAPIBan = "*apiban" MetaNotString = "*notstring" MetaNotPrefix = "*notprefix" @@ -1098,6 +1101,7 @@ const ( MetaNotResources = "*notresources" MetaNotEqual = "*noteq" MetaNotIPNet = "*notipnet" + MetaNotAPIBan = "*notapiban" MetaEC = "*ec" )