From ba20dbe831194e80404584a43db9d41bd2cc141d Mon Sep 17 00:00:00 2001 From: gezimbll Date: Wed, 12 Jul 2023 10:25:42 -0400 Subject: [PATCH] Added filter implementation for sentrypeer --- config/apiban.go | 33 +++++++++++++++++++++++++ config/config.go | 21 +++++++++++++++- config/config_defaults.go | 5 +++- config/config_json.go | 15 ++++++++++- config/libconfig_json.go | 5 ++++ engine/filterhelpers.go | 52 +++++++++++++++++++++++++++++++++++++++ engine/filters.go | 16 ++++++++++++ utils/consts.go | 2 ++ 8 files changed, 146 insertions(+), 3 deletions(-) diff --git a/config/apiban.go b/config/apiban.go index 669d0925b..b839a3271 100644 --- a/config/apiban.go +++ b/config/apiban.go @@ -61,3 +61,36 @@ func (ban APIBanCfg) Clone() (cln *APIBanCfg) { } return } + +type SentryPeerCfg struct { + Token string + Addr string +} + +func (sp *SentryPeerCfg) loadFromJSONCfg(jsnCfg *SentryPeerJsonCfg) (err error) { + if jsnCfg == nil { + return + } + if jsnCfg.Addr != nil { + sp.Addr = *jsnCfg.Addr + } + if jsnCfg.Token != nil { + sp.Token = *jsnCfg.Token + } + return +} + +func (sp *SentryPeerCfg) AsMapInterface() map[string]any { + return map[string]any{ + "Addres": sp.Addr, + "Token": sp.Token, + } +} + +func (sp *SentryPeerCfg) Clone() (cln *SentryPeerCfg) { + cln = &SentryPeerCfg{ + Addr: sp.Addr, + Token: sp.Token, + } + return +} diff --git a/config/config.go b/config/config.go index 0c2bd05f7..4f7d1e3cc 100644 --- a/config/config.go +++ b/config/config.go @@ -175,6 +175,7 @@ func newCGRConfig(config []byte) (cfg *CGRConfig, err error) { cfg.sipAgentCfg = new(SIPAgentCfg) cfg.configSCfg = new(ConfigSCfg) cfg.apiBanCfg = new(APIBanCfg) + cfg.sentryPeerCfg = new(SentryPeerCfg) cfg.coreSCfg = new(CoreSCfg) cfg.dfltEvExp = &EventExporterCfg{Opts: &EventExporterOpts{ Els: new(ElsOpts), @@ -325,6 +326,7 @@ type CGRConfig struct { sipAgentCfg *SIPAgentCfg // SIPAgent config configSCfg *ConfigSCfg // ConfigS config apiBanCfg *APIBanCfg // APIBan config + sentryPeerCfg *SentryPeerCfg //SentryPeer config coreSCfg *CoreSCfg // CoreS config cacheDP map[string]utils.MapStorage @@ -398,7 +400,7 @@ func (cfg *CGRConfig) loadFromJSONCfg(jsnCfg *CgrJsonCfg) (err error) { cfg.loadLoaderCgrCfg, cfg.loadMigratorCgrCfg, cfg.loadTLSCgrCfg, cfg.loadAnalyzerCgrCfg, cfg.loadApierCfg, cfg.loadErsCfg, cfg.loadEesCfg, cfg.loadSIPAgentCfg, cfg.loadRegistrarCCfg, - cfg.loadConfigSCfg, cfg.loadAPIBanCgrCfg, cfg.loadCoreSCfg} { + cfg.loadConfigSCfg, cfg.loadAPIBanCgrCfg, cfg.loadSentryPeerCgrCfg, cfg.loadCoreSCfg} { if err = loadFunc(jsnCfg); err != nil { return } @@ -777,6 +779,13 @@ func (cfg *CGRConfig) loadAPIBanCgrCfg(jsnCfg *CgrJsonCfg) (err error) { } return cfg.apiBanCfg.loadFromJSONCfg(jsnAPIBanCfg) } +func (cfg *CGRConfig) loadSentryPeerCgrCfg(jsnCfg *CgrJsonCfg) (err error) { + var jsnSentryPeerCfg *SentryPeerJsonCfg + if jsnSentryPeerCfg, err = jsnCfg.SentryPeerJson(); err != nil { + return + } + return cfg.sentryPeerCfg.loadFromJSONCfg(jsnSentryPeerCfg) +} // loadApierCfg loads the Apier section of the configuration func (cfg *CGRConfig) loadApierCfg(jsnCfg *CgrJsonCfg) (err error) { @@ -1136,6 +1145,11 @@ func (cfg *CGRConfig) APIBanCfg() *APIBanCfg { defer cfg.lks[APIBanCfgJson].Unlock() return cfg.apiBanCfg } +func (cfg *CGRConfig) SentryPeerCfg() *SentryPeerCfg { + cfg.lks[SentryPeerCfgJson].Lock() + defer cfg.lks[SentryPeerCfgJson].Unlock() + return cfg.sentryPeerCfg +} // CoreSCfg reads the CoreS configuration func (cfg *CGRConfig) CoreSCfg() *CoreSCfg { @@ -1254,6 +1268,7 @@ func (cfg *CGRConfig) getLoadFunctions() map[string]func(*CgrJsonCfg) error { TemplatesJson: cfg.loadTemplateSCfg, ConfigSJson: cfg.loadConfigSCfg, APIBanCfgJson: cfg.loadAPIBanCgrCfg, + SentryPeerCfgJson: cfg.loadSentryPeerCgrCfg, CoreSCfgJson: cfg.loadCoreSCfg, } } @@ -1450,6 +1465,7 @@ func (cfg *CGRConfig) reloadSections(sections ...string) { case TemplatesJson: case TlsCfgJson: // nothing to reload case APIBanCfgJson: // nothing to reload + case SentryPeerCfgJson: case CoreSCfgJson: // nothing to reload case HTTP_JSN: cfg.rldChans[HTTP_JSN] <- struct{}{} @@ -1547,6 +1563,7 @@ func (cfg *CGRConfig) AsMapInterface(separator string) (mp map[string]any) { ApierS: cfg.apier.AsMapInterface(), ERsJson: cfg.ersCfg.AsMapInterface(separator), APIBanCfgJson: cfg.apiBanCfg.AsMapInterface(), + SentryPeerCfgJson: cfg.sentryPeerCfg.AsMapInterface(), EEsJson: cfg.eesCfg.AsMapInterface(separator), SIPAgentJson: cfg.sipAgentCfg.AsMapInterface(separator), TemplatesJson: cfg.templates.AsMapInterface(separator), @@ -1704,6 +1721,8 @@ func (cfg *CGRConfig) V1GetConfig(args *SectionWithAPIOpts, reply *map[string]an mp = cfg.ConfigSCfg().AsMapInterface() case APIBanCfgJson: mp = cfg.APIBanCfg().AsMapInterface() + case SentryPeerCfgJson: + mp = cfg.SentryPeerCfg().AsMapInterface() case HttpAgentJson: mp = cfg.HTTPAgentCfg().AsMapInterface(cfg.GeneralCfg().RSRSep) case MAILER_JSN: diff --git a/config/config_defaults.go b/config/config_defaults.go index 917cb4ed5..ea8a2b5cd 100644 --- a/config/config_defaults.go +++ b/config/config_defaults.go @@ -1266,6 +1266,9 @@ const CGRATES_CFG_JSON = ` "enabled": false, "keys": [], }, - +"sentrypeer":{ + "addr":"", + "token":"", +} }` diff --git a/config/config_json.go b/config/config_json.go index 36a7f6774..a0401fed8 100644 --- a/config/config_json.go +++ b/config/config_json.go @@ -64,6 +64,7 @@ const ( TemplatesJson = "templates" ConfigSJson = "configs" APIBanCfgJson = "apiban" + SentryPeerCfgJson = "sentrypeer" CoreSCfgJson = "cores" ) @@ -72,7 +73,7 @@ var ( CACHE_JSN, FilterSjsn, RALS_JSN, CDRS_JSN, ERsJson, SessionSJson, AsteriskAgentJSN, FreeSWITCHAgentJSN, KamailioAgentJSN, DA_JSN, RA_JSN, HttpAgentJson, DNSAgentJson, ATTRIBUTE_JSN, ChargerSCfgJson, RESOURCES_JSON, STATS_JSON, THRESHOLDS_JSON, RouteSJson, LoaderJson, MAILER_JSN, SURETAX_JSON, CgrLoaderCfgJson, CgrMigratorCfgJson, DispatcherSJson, - AnalyzerCfgJson, ApierS, EEsJson, SIPAgentJson, RegistrarCJson, TemplatesJson, ConfigSJson, APIBanCfgJson, CoreSCfgJson} + AnalyzerCfgJson, ApierS, EEsJson, SIPAgentJson, RegistrarCJson, TemplatesJson, ConfigSJson, APIBanCfgJson, SentryPeerCfgJson, CoreSCfgJson} ) // Loads the json config out of io.Reader, eg other sources than file, maybe over http @@ -559,6 +560,18 @@ func (jsnCfg CgrJsonCfg) ApiBanCfgJson() (*APIBanJsonCfg, error) { return cfg, nil } +func (jsnCfg CgrJsonCfg) SentryPeerJson() (*SentryPeerJsonCfg, error) { + rawCfg, hasKey := jsnCfg[SentryPeerCfgJson] + if !hasKey { + return nil, nil + } + cfg := new(SentryPeerJsonCfg) + if err := json.Unmarshal(*rawCfg, cfg); err != nil { + return nil, err + } + return cfg, nil +} + func (jsnCfg CgrJsonCfg) CoreSCfgJson() (*CoreSJsonCfg, error) { rawCfg, hasKey := jsnCfg[CoreSCfgJson] if !hasKey { diff --git a/config/libconfig_json.go b/config/libconfig_json.go index 4a945112f..b83830457 100644 --- a/config/libconfig_json.go +++ b/config/libconfig_json.go @@ -876,6 +876,11 @@ type APIBanJsonCfg struct { Keys *[]string } +type SentryPeerJsonCfg struct { + Token *string + Addr *string +} + type CoreSJsonCfg struct { Caps *int Caps_strategy *string diff --git a/engine/filterhelpers.go b/engine/filterhelpers.go index c6f2037f2..14052ea0a 100644 --- a/engine/filterhelpers.go +++ b/engine/filterhelpers.go @@ -19,6 +19,9 @@ along with this program. If not, see package engine import ( + "fmt" + "net/http" + "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/guardian" "github.com/cgrates/cgrates/utils" @@ -117,3 +120,52 @@ func WeightFromDynamics(dWs []*utils.DynamicWeight, } return 0.0, nil } + +func GetSentryPeer(val, addr, token, path string, cacheRead, cacheWrite bool) (found bool, err error) { + valpath := utils.ConcatenatedKey(path, val) + if cacheRead { + if x, ok := Cache.Get(utils.MetaSentryPeer, valpath); ok && x != nil { // Attempt to find in cache first + return x.(bool), nil + } + } + var req *http.Request + if req, err = http.NewRequest("GET", addr+path+"/"+val, nil); err != nil { + return + } + req.Header = http.Header{ + "Authorization": {fmt.Sprintf("Bearer %s", token)}, + } + var resp *http.Response + resp, err = http.DefaultClient.Do(req) + if err != nil { + return false, err + } + defer resp.Body.Close() + if resp.StatusCode >= 200 && resp.StatusCode < 300 { + if cacheWrite { + if err = Cache.Set(utils.MetaSentryPeer, valpath, true, nil, true, utils.NonTransactional); err != nil { + return false, err + } + } + return true, nil + } else { + switch { + case resp.StatusCode == http.StatusNotFound: + if cacheWrite { + if err = Cache.Set(utils.MetaSentryPeer, valpath, false, nil, true, utils.NonTransactional); err != nil { + return false, err + } + } + return + case resp.StatusCode >= 400 && resp.StatusCode < 500: + err = fmt.Errorf("client error<%s>", resp.Status) + return + case resp.StatusCode >= 500: + err = fmt.Errorf("server error<%s>", resp.Status) + return + default: + err = fmt.Errorf("unexpected status code<%s>", resp.Status) + } + } + return +} diff --git a/engine/filters.go b/engine/filters.go index 9f51f70b7..7a601f318 100644 --- a/engine/filters.go +++ b/engine/filters.go @@ -351,6 +351,8 @@ func (fltr *FilterRule) Pass(dDP utils.DataProvider) (result bool, err error) { result, err = fltr.passIPNet(dDP) case utils.MetaAPIBan, utils.MetaNotAPIBan: result, err = fltr.passAPIBan(dDP) + case utils.MetaSentryPeer, utils.MetaNotSentryPeer: + result, err = fltr.passSentryPeer(dDP) case utils.MetaActivationInterval, utils.MetaNotActivationInterval: result, err = fltr.passActivationInterval(dDP) case utils.MetaRegex, utils.MetaNotRegex: @@ -646,6 +648,20 @@ func (fltr *FilterRule) passAPIBan(dDP utils.DataProvider) (bool, error) { return dm.GetAPIBan(strVal, config.CgrConfig().APIBanCfg().Keys, fltr.Values[0] != utils.MetaAll, true, true) } +func (fltr *FilterRule) passSentryPeer(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] != "phone-numbers" && fltr.Values[0] != "ip-addresses" { + return false, fmt.Errorf("invalid value for sentrypeer filter: <%s>", fltr.Values[0]) + } + return GetSentryPeer(strVal, config.CgrConfig().SentryPeerCfg().Addr, config.CgrConfig().SentryPeerCfg().Token, fltr.Values[0], true, true) +} + func parseTime(rsr *config.RSRParser, dDp utils.DataProvider) (_ time.Time, err error) { var str string if str, err = rsr.ParseDataProvider(dDp); err != nil { diff --git a/utils/consts.go b/utils/consts.go index 60567d88c..5ae02affd 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -1157,6 +1157,7 @@ const ( MetaEqual = "*eq" MetaIPNet = "*ipnet" MetaAPIBan = "*apiban" + MetaSentryPeer = "*sentrypeer" MetaActivationInterval = "*ai" MetaRegex = "*regex" @@ -1173,6 +1174,7 @@ const ( MetaNotEqual = "*noteq" MetaNotIPNet = "*notipnet" MetaNotAPIBan = "*notapiban" + MetaNotSentryPeer = "*notsentrypeer" MetaNotActivationInterval = "*notai" MetaNotRegex = "*notregex"