From 3dd42bc9fdbec021eea60f893c9d635c174c8ba2 Mon Sep 17 00:00:00 2001 From: "Thibault \"bui\" Koechlin" Date: Fri, 3 Jul 2020 11:40:12 +0200 Subject: [PATCH] add ability to filter 'ban list' output (`--ip` `--range` `--as` `--country` `--reason`) (#115) * add ability to filter 'ban list' output --- cmd/crowdsec-cli/ban.go | 113 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/cmd/crowdsec-cli/ban.go b/cmd/crowdsec-cli/ban.go index 61aba814e..5507c4961 100644 --- a/cmd/crowdsec-cli/ban.go +++ b/cmd/crowdsec-cli/ban.go @@ -22,6 +22,9 @@ var remediationType string var atTime string var all bool +//user supplied filters +var ipFilter, rangeFilter, reasonFilter, countryFilter, asFilter string + func simpleBanToSignal(targetIP string, reason string, expirationStr string, action string, asName string, asNum string, country string, banSource string) (types.SignalOccurence, error) { var signalOcc types.SignalOccurence @@ -84,6 +87,102 @@ func simpleBanToSignal(targetIP string, reason string, expirationStr string, act return signalOcc, nil } +func filterBans(bans []map[string]string) ([]map[string]string, error) { + + var retBans []map[string]string + + for _, ban := range bans { + var banIP net.IP + var banRange *net.IPNet + var keep bool = true + var err error + + if ban["iptext"] != "" { + if strings.Contains(ban["iptext"], "/") { + log.Debugf("%s is a range", ban["iptext"]) + banIP, banRange, err = net.ParseCIDR(ban["iptext"]) + if err != nil { + log.Warningf("failed to parse range '%s' from database : %s", ban["iptext"], err) + } + } else { + log.Debugf("%s is IP", ban["iptext"]) + banIP = net.ParseIP(ban["iptext"]) + } + } + + if ipFilter != "" { + var filterBinIP net.IP = net.ParseIP(ipFilter) + + if banRange != nil { + if banRange.Contains(filterBinIP) { + log.Debugf("[keep] ip filter is set, and range contains ip") + keep = true + } else { + log.Debugf("[discard] ip filter is set, and range doesn't contain ip") + keep = false + } + } else { + if ipFilter == ban["iptext"] { + log.Debugf("[keep] (ip) %s == %s", ipFilter, ban["iptext"]) + keep = true + } else { + log.Debugf("[discard] (ip) %s == %s", ipFilter, ban["iptext"]) + keep = false + } + } + } + if rangeFilter != "" { + _, filterBinRange, err := net.ParseCIDR(rangeFilter) + if err != nil { + return nil, fmt.Errorf("failed to parse range '%s' : %s", rangeFilter, err) + } + if filterBinRange.Contains(banIP) { + log.Debugf("[keep] range filter %s contains %s", rangeFilter, banIP.String()) + keep = true + } else { + log.Debugf("[discard] range filter %s doesn't contain %s", rangeFilter, banIP.String()) + keep = false + } + } + if reasonFilter != "" { + if strings.Contains(ban["reason"], reasonFilter) { + log.Debugf("[keep] reason filter %s matches %s", reasonFilter, ban["reason"]) + keep = true + } else { + log.Debugf("[discard] reason filter %s doesn't match %s", reasonFilter, ban["reason"]) + keep = false + } + } + + if countryFilter != "" { + if ban["cn"] == countryFilter { + log.Debugf("[keep] country filter %s matches %s", countryFilter, ban["cn"]) + keep = true + } else { + log.Debugf("[discard] country filter %s matches %s", countryFilter, ban["cn"]) + keep = false + } + } + + if asFilter != "" { + if strings.Contains(ban["as"], asFilter) { + log.Debugf("[keep] AS filter %s matches %s", asFilter, ban["as"]) + keep = true + } else { + log.Debugf("[discard] AS filter %s doesn't match %s", asFilter, ban["as"]) + keep = false + } + } + + if keep { + retBans = append(retBans, ban) + } else { + log.Debugf("[discard] discard %v", ban) + } + } + return retBans, nil +} + func BanList() error { at := time.Now() if atTime != "" { @@ -96,6 +195,10 @@ func BanList() error { if err != nil { return fmt.Errorf("unable to get records from sqlite : %v", err) } + ret, err = filterBans(ret) + if err != nil { + log.Errorf("Error while filtering : %s", err) + } if config.output == "raw" { fmt.Printf("source,ip,reason,bans,action,country,as,events_count,expiration\n") for _, rm := range ret { @@ -312,6 +415,10 @@ Time can be specified with --at and support a variety of date formats: - 2006-01-02 - 2006-01-02 15:04 `, + Example: `ban list --range 0.0.0.0/0 : will list all + ban list --country CN + ban list --reason crowdsecurity/http-probing + ban list --as OVH`, Args: cobra.ExactArgs(0), Run: func(cmd *cobra.Command, args []string) { if err := BanList(); err != nil { @@ -321,6 +428,12 @@ Time can be specified with --at and support a variety of date formats: } cmdBanList.PersistentFlags().StringVar(&atTime, "at", "", "List bans at given time") cmdBanList.PersistentFlags().BoolVarP(&all, "all", "a", false, "List as well bans received from API") + cmdBanList.PersistentFlags().StringVar(&ipFilter, "ip", "", "List bans for given IP") + cmdBanList.PersistentFlags().StringVar(&rangeFilter, "range", "", "List bans belonging to given range") + cmdBanList.PersistentFlags().StringVar(&reasonFilter, "reason", "", "List bans containing given reason") + cmdBanList.PersistentFlags().StringVar(&countryFilter, "country", "", "List bans belonging to given country code") + cmdBanList.PersistentFlags().StringVar(&asFilter, "as", "", "List bans belonging to given AS name") + cmdBan.AddCommand(cmdBanList) return cmdBan }