├── .gitignore ├── internal ├── utils │ ├── exists.go │ └── utils.go ├── version │ ├── version_test.go │ └── version.go └── check │ └── check.go ├── cmd └── blacklist-checker │ ├── cmd │ ├── version.go │ ├── list.go │ ├── root.go │ ├── check.go │ ├── ip.go │ └── cidr.go │ └── main.go ├── version.go ├── go.mod ├── LICENSE ├── .goreleaser.yml ├── blacklists.go ├── README.md └── go.sum /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | vendor/ 3 | bin/ 4 | .idea/ 5 | dist/ 6 | .envrc 7 | -------------------------------------------------------------------------------- /internal/utils/exists.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "errors" 5 | "os" 6 | ) 7 | 8 | func FileExists(name string) (bool, error) { 9 | _, err := os.Stat(name) 10 | if err == nil { 11 | return true, nil 12 | } 13 | if errors.Is(err, os.ErrNotExist) { 14 | return false, nil 15 | } 16 | return false, err 17 | } 18 | -------------------------------------------------------------------------------- /internal/version/version_test.go: -------------------------------------------------------------------------------- 1 | package version_test 2 | 3 | import ( 4 | "bufio" 5 | "github.com/ilijamt/blacklist_checker/internal/version" 6 | "github.com/stretchr/testify/assert" 7 | "io/ioutil" 8 | "testing" 9 | ) 10 | 11 | func TestPrintVersion(t *testing.T) { 12 | wr := bufio.NewWriter(ioutil.Discard) 13 | version.PrintVersion(wr) 14 | assert.Equal(t, 71, wr.Buffered()) 15 | assert.NoError(t, wr.Flush()) 16 | } 17 | -------------------------------------------------------------------------------- /cmd/blacklist-checker/cmd/version.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "github.com/ilijamt/blacklist_checker/internal/version" 5 | "github.com/spf13/cobra" 6 | ) 7 | 8 | var versionCmd = &cobra.Command{ 9 | Use: "version", 10 | Short: "Shows the version of the application", 11 | Long: `Shows the version of the application`, 12 | Run: func(cmd *cobra.Command, args []string) { 13 | version.PrintVersion(cmd.OutOrStdout()) 14 | }, 15 | } 16 | 17 | func init() { 18 | rootCmd.AddCommand(versionCmd) 19 | } 20 | -------------------------------------------------------------------------------- /cmd/blacklist-checker/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/ilijamt/blacklist_checker/cmd/blacklist-checker/cmd" 5 | "github.com/rs/zerolog" 6 | "github.com/rs/zerolog/log" 7 | "os" 8 | ) 9 | 10 | func main() { 11 | zerolog.SetGlobalLevel(zerolog.InfoLevel) 12 | zerolog.TimeFieldFormat = zerolog.TimeFormatUnix 13 | log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) 14 | 15 | var err error 16 | if err = cmd.Execute(); err != nil { 17 | log.Fatal().Err(err).Send() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /version.go: -------------------------------------------------------------------------------- 1 | package blacklist_checker 2 | 3 | var ( 4 | // Name is the application name 5 | Name string = "blacklist-checker" 6 | 7 | // Description is the applications description 8 | Description string = "Fast blacklist checker application" 9 | 10 | // Author information 11 | Author = "Ilija Matoski " 12 | 13 | // BuildVersion is the version of the build 14 | BuildVersion string 15 | 16 | // BuildHash is the hash of the version 17 | BuildHash string 18 | 19 | // BuildDate is the time of when the application was built 20 | BuildDate string 21 | ) 22 | -------------------------------------------------------------------------------- /internal/version/version.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | import ( 4 | "fmt" 5 | "github.com/ilijamt/blacklist_checker" 6 | "io" 7 | "runtime" 8 | ) 9 | 10 | // PrintVersion prints the version details to a specified writer 11 | func PrintVersion(w io.Writer) { 12 | _, _ = fmt.Fprintf(w, "Version: %s\n", blacklist_checker.BuildVersion) 13 | _, _ = fmt.Fprintf(w, "Git Commit Hash: %s\n", blacklist_checker.BuildHash) 14 | _, _ = fmt.Fprintf(w, "Build Date: %s\n", blacklist_checker.BuildDate) 15 | _, _ = fmt.Fprintf(w, "OS: %s\n", runtime.GOOS) 16 | _, _ = fmt.Fprintf(w, "Architecture: %s\n", runtime.GOARCH) 17 | } 18 | -------------------------------------------------------------------------------- /cmd/blacklist-checker/cmd/list.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "github.com/ilijamt/blacklist_checker" 6 | "github.com/spf13/cobra" 7 | ) 8 | 9 | var listCmd = &cobra.Command{ 10 | Use: "list", 11 | Short: "List available blacklists.", 12 | PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) { 13 | if err = dsnblFileExists(); err != nil { 14 | return err 15 | } 16 | return nil 17 | }, 18 | RunE: func(cmd *cobra.Command, args []string) error { 19 | hosts, err := blacklist_checker.GetDNSBLs(conf.dnsbl) 20 | if err != nil { 21 | return err 22 | } 23 | for _, host := range hosts { 24 | _, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s\n", host) 25 | } 26 | return err 27 | }, 28 | } 29 | 30 | func init() { 31 | rootCmd.AddCommand(listCmd) 32 | } 33 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/ilijamt/blacklist_checker 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/ilijamt/netprivate v0.1.0 7 | github.com/miekg/dns v1.1.49 8 | github.com/rs/zerolog v1.26.1 9 | github.com/spf13/cobra v1.4.0 10 | github.com/stretchr/testify v1.7.1 11 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c 12 | ) 13 | 14 | require ( 15 | github.com/davecgh/go-spew v1.1.0 // indirect 16 | github.com/inconshreveable/mousetrap v1.0.0 // indirect 17 | github.com/pmezard/go-difflib v1.0.0 // indirect 18 | github.com/spf13/pflag v1.0.5 // indirect 19 | golang.org/x/mod v0.4.2 // indirect 20 | golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d // indirect 21 | golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e // indirect 22 | golang.org/x/tools v0.1.7 // indirect 23 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 24 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect 25 | ) 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Ilija Matoski 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /internal/check/check.go: -------------------------------------------------------------------------------- 1 | package check 2 | 3 | import ( 4 | "fmt" 5 | "github.com/miekg/dns" 6 | "golang.org/x/sync/semaphore" 7 | "net" 8 | ) 9 | 10 | type Item struct { 11 | IP net.IP 12 | Blacklist string 13 | Host string 14 | } 15 | 16 | func Check(sem *semaphore.Weighted, item Item, nameserver string) (blacklisted bool, responses []string, err error) { 17 | defer sem.Release(1) 18 | 19 | client := new(dns.Client) 20 | isIPv6 := item.IP.To4() == nil 21 | 22 | var t = dns.TypeA 23 | m := new(dns.Msg) 24 | if isIPv6 { 25 | t = dns.TypeAAAA 26 | } 27 | m.SetQuestion(item.Blacklist, t) 28 | m.RecursionDesired = true 29 | 30 | var r *dns.Msg 31 | r, _, err = client.Exchange(m, nameserver) 32 | if err != nil { 33 | return blacklisted, responses, err 34 | } 35 | 36 | if r.Rcode != dns.RcodeSuccess { 37 | err = fmt.Errorf("received %v but expected %v (RcodeSuccess) for %s", r.Rcode, dns.RcodeSuccess, item.Blacklist) 38 | return blacklisted, responses, err 39 | } 40 | 41 | if len(r.Answer) > 0 { 42 | blacklisted = true 43 | } 44 | 45 | for _, a := range r.Answer { 46 | switch a.(type) { 47 | case *dns.A: 48 | responses = append(responses, a.(*dns.A).A.String()) 49 | case *dns.AAAA: 50 | responses = append(responses, a.(*dns.AAAA).AAAA.String()) 51 | } 52 | } 53 | 54 | return blacklisted, responses, err 55 | 56 | } 57 | -------------------------------------------------------------------------------- /cmd/blacklist-checker/cmd/root.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "github.com/ilijamt/blacklist_checker" 6 | "github.com/ilijamt/blacklist_checker/internal/utils" 7 | "github.com/spf13/cobra" 8 | "math/rand" 9 | "time" 10 | ) 11 | 12 | func dsnblFileExists() error { 13 | if conf.dnsbl != "" { 14 | exists, err := utils.FileExists(conf.dnsbl) 15 | if err != nil { 16 | return err 17 | } 18 | if !exists { 19 | return fmt.Errorf("file %s does not exist", conf.dnsbl) 20 | } 21 | } 22 | return nil 23 | } 24 | 25 | var rootCmd = &cobra.Command{ 26 | Use: blacklist_checker.Name, 27 | Short: "Check if your IP or CIDR is blacklisted or not.", 28 | Long: `A simple tool that helps you check if your IP or CIDR is blacklisted or not.`, 29 | } 30 | 31 | func init() { 32 | rootCmd.PersistentFlags().StringVar(&conf.dnsbl, "dsnbl", "", "DNSBL file to use, if empty it uses the internal list, should be a list of DNSBL to use, each one on a new line") 33 | 34 | } 35 | 36 | type config struct { 37 | nameservers []string 38 | concurrency int 39 | dnsbl string 40 | } 41 | 42 | func (c config) Nameserver() string { 43 | if len(c.nameservers) > 1 { 44 | rand.Seed(time.Now().Unix()) 45 | return c.nameservers[rand.Intn(len(c.nameservers))] 46 | } 47 | return c.nameservers[0] 48 | } 49 | 50 | var conf config 51 | 52 | func Execute() error { 53 | return rootCmd.Execute() 54 | } 55 | -------------------------------------------------------------------------------- /cmd/blacklist-checker/cmd/check.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "github.com/ilijamt/blacklist_checker/internal/check" 5 | "github.com/rs/zerolog/log" 6 | "github.com/spf13/cobra" 7 | "golang.org/x/sync/semaphore" 8 | "net/netip" 9 | ) 10 | 11 | var checkCmd = &cobra.Command{ 12 | Use: "check", 13 | Short: "Check available blacklists.", 14 | PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) { 15 | if err = dsnblFileExists(); err != nil { 16 | return err 17 | } 18 | for _, n := range conf.nameservers { 19 | _, err = netip.ParseAddrPort(n) 20 | if err != nil { 21 | return err 22 | } 23 | } 24 | return nil 25 | }, 26 | } 27 | 28 | func init() { 29 | checkCmd.PersistentFlags().StringSliceVar(&conf.nameservers, "nameservers", []string{"1.1.1.1:53"}, "Nameservers to use, a random one is used for each request") 30 | checkCmd.PersistentFlags().IntVarP(&conf.concurrency, "concurrency", "n", 25, "How many requests to process at once") 31 | rootCmd.AddCommand(checkCmd) 32 | } 33 | 34 | func processIpCheck(sem *semaphore.Weighted, item check.Item) (blacklisted bool, err error) { 35 | var responses []string 36 | blacklisted, responses, err = check.Check( 37 | sem, 38 | item, 39 | conf.Nameserver(), 40 | ) 41 | if blacklisted { 42 | log.Warn().Str("dnsbl", item.Host).Bool("blacklisted", blacklisted).Strs("responses", responses).IPAddr("ip", item.IP).Send() 43 | } else { 44 | log.Trace().Str("dnsbl", item.Host).Bool("blacklisted", blacklisted).Strs("responses", responses).IPAddr("ip", item.IP).Send() 45 | } 46 | return blacklisted, err 47 | } 48 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | project_name: "blacklist-checker" 2 | 3 | before: 4 | hooks: 5 | - go mod tidy 6 | - go generate ./... 7 | - go mod download 8 | 9 | builds: 10 | - env: 11 | - CGO_ENABLED=0 12 | id: "blacklist-checker" 13 | main: ./cmd/blacklist-checker/main.go 14 | ldflags: 15 | - "-extldflags '-static'" 16 | - "-X 'github.com/ilijamt/blacklist_checker.BuildVersion={{ .Version }}'" 17 | - "-X 'github.com/ilijamt/blacklist_checker.BuildHash={{ .FullCommit }}'" 18 | - "-X 'github.com/ilijamt/blacklist_checker.BuildDate={{ .Date }}'" 19 | goarch: 20 | - 386 21 | - amd64 22 | - arm 23 | - arm64 24 | goos: 25 | - linux 26 | - darwin 27 | - windows 28 | 29 | checksum: 30 | name_template: '{{ .ProjectName }}_checksums.txt' 31 | changelog: 32 | sort: asc 33 | filters: 34 | exclude: 35 | - '^docs:' 36 | - '^test:' 37 | - Merge pull request 38 | - Merge branch 39 | 40 | archives: 41 | - name_template: '{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}' 42 | replacements: 43 | 386: i386 44 | amd64: x86_64 45 | format_overrides: 46 | - goos: windows 47 | format: zip 48 | 49 | release: 50 | github: 51 | owner: ilijamt 52 | name: blacklist-checker 53 | 54 | brews: 55 | - tap: 56 | owner: ilijamt 57 | name: homebrew-tap 58 | folder: Formula 59 | homepage: https://github.com/ilijamt/blacklist-checker 60 | description: A simple tool that helps you check if your IP or CIDR is blacklisted or not. 61 | test: | 62 | system "#{bin}/blacklist-checker version" -------------------------------------------------------------------------------- /internal/utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "net" 5 | "strings" 6 | ) 7 | 8 | func inc(ip net.IP) { 9 | for j := len(ip) - 1; j >= 0; j-- { 10 | ip[j]++ 11 | if ip[j] > 0 { 12 | break 13 | } 14 | } 15 | } 16 | 17 | func dupIP(ip net.IP) net.IP { 18 | dup := make(net.IP, len(ip)) 19 | copy(dup, ip) 20 | return dup 21 | } 22 | 23 | func Hosts(cidr string) (ips []net.IP, err error) { 24 | ip, ipnet, err := net.ParseCIDR(cidr) 25 | if err == nil { 26 | for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); inc(ip) { 27 | ips = append(ips, dupIP(ip)) 28 | } 29 | } 30 | return 31 | } 32 | 33 | func ReverseIP(IP string) string { 34 | var StringSplitIP []string 35 | 36 | if net.ParseIP(IP).To4() != nil { // Check for an IPv4 address 37 | StringSplitIP = strings.Split(IP, ".") // Split into 4 groups 38 | for x, y := 0, len(StringSplitIP)-1; x < y; x, y = x+1, y-1 { 39 | StringSplitIP[x], StringSplitIP[y] = StringSplitIP[y], StringSplitIP[x] // Reverse the groups 40 | } 41 | } else { 42 | StringSplitIP = strings.Split(IP, ":") // Split into however many groups 43 | 44 | /* Due to IPv6 lookups being different than IPv4 we have an extra check here 45 | We have to expand the :: and do 0-padding if there are less than 4 digits */ 46 | for key := range StringSplitIP { 47 | if len(StringSplitIP[key]) == 0 { // Found the :: 48 | StringSplitIP[key] = strings.Repeat("0000", 8-strings.Count(IP, ":")) 49 | } else if len(StringSplitIP[key]) < 4 { // 0-padding needed 50 | StringSplitIP[key] = strings.Repeat("0", 4-len(StringSplitIP[key])) + StringSplitIP[key] 51 | } 52 | } 53 | 54 | // We have to join what we have and split it again to get all the letters split individually 55 | StringSplitIP = strings.Split(strings.Join(StringSplitIP, ""), "") 56 | 57 | for x, y := 0, len(StringSplitIP)-1; x < y; x, y = x+1, y-1 { 58 | StringSplitIP[x], StringSplitIP[y] = StringSplitIP[y], StringSplitIP[x] 59 | } 60 | } 61 | 62 | return strings.Join(StringSplitIP, ".") // Return the IP. 63 | } 64 | -------------------------------------------------------------------------------- /blacklists.go: -------------------------------------------------------------------------------- 1 | package blacklist_checker 2 | 3 | import ( 4 | "github.com/ilijamt/blacklist_checker/internal/utils" 5 | "io/ioutil" 6 | "strings" 7 | ) 8 | 9 | var dnsbls = []string{ 10 | "access.redhawk.org", 11 | "b.barracudacentral.org", 12 | "bl.spamcop.net", 13 | "blackholes.mail-abuse.org", 14 | "bogons.cymru.com", 15 | "cbl.abuseat.org", 16 | "cbl.anti-spam.org.cn", 17 | "cdl.anti-spam.org.cn", 18 | "combined.njabl.org", 19 | "csi.cloudmark.com", 20 | "db.wpbl.info", 21 | "dnsbl.dronebl.org", 22 | "dnsbl.inps.de", 23 | "dnsbl.njabl.org", 24 | "dnsbl.sorbs.net", 25 | "drone.abuse.ch", 26 | "dsn.rfc-ignorant.org", 27 | "dul.dnsbl.sorbs.net", 28 | "dyna.spamrats.com", 29 | "http.dnsbl.sorbs.net", 30 | "httpbl.abuse.ch", 31 | "ips.backscatterer.org", 32 | "ix.dnsbl.manitu.net", 33 | "korea.services.net", 34 | "misc.dnsbl.sorbs.net", 35 | "multi.surbl.org", 36 | "netblock.pedantic.org", 37 | "noptr.spamrats.com", 38 | "opm.tornevall.org", 39 | "pbl.spamhaus.org", 40 | "psbl.surriel.com", 41 | "query.senderbase.org", 42 | "rbl-plus.mail-abuse.org", 43 | "rbl.efnetrbl.org", 44 | "rbl.interserver.net", 45 | "rbl.spamlab.com", 46 | "rbl.suresupport.com", 47 | "relays.mail-abuse.org", 48 | "sbl.spamhaus.org", 49 | "short.rbl.jp", 50 | "smtp.dnsbl.sorbs.net", 51 | "socks.dnsbl.sorbs.net", 52 | "spam.dnsbl.sorbs.net", 53 | "spam.spamrats.com", 54 | "spamguard.leadmon.net", 55 | "spamrbl.imp.ch", 56 | "tor.dan.me.uk", 57 | "ubl.unsubscore.com", 58 | "virbl.bit.nl", 59 | "virus.rbl.jp", 60 | "web.dnsbl.sorbs.net", 61 | "wormrbl.imp.ch", 62 | "xbl.abuseat.org", 63 | "xbl.spamhaus.org", 64 | "zen.spamhaus.org", 65 | "zombie.dnsbl.sorbs.net", 66 | } 67 | 68 | func GetDNSBLs(file string) ([]string, error) { 69 | var exists, _ = utils.FileExists(file) 70 | if !exists { 71 | return dnsbls, nil 72 | } 73 | 74 | fileBytes, err := ioutil.ReadFile(file) 75 | if err != nil { 76 | return []string{}, err 77 | } 78 | 79 | var vals []string 80 | for _, s := range strings.Split(string(fileBytes), "\n") { 81 | vals = append(vals, strings.TrimSpace(s)) 82 | } 83 | 84 | return vals, nil 85 | } 86 | -------------------------------------------------------------------------------- /cmd/blacklist-checker/cmd/ip.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/ilijamt/blacklist_checker" 7 | "github.com/ilijamt/blacklist_checker/internal/check" 8 | "github.com/ilijamt/blacklist_checker/internal/utils" 9 | "github.com/ilijamt/netprivate" 10 | "github.com/rs/zerolog/log" 11 | "github.com/spf13/cobra" 12 | "golang.org/x/sync/semaphore" 13 | "net" 14 | "sync/atomic" 15 | ) 16 | 17 | var ipCmd = &cobra.Command{ 18 | Use: "ip ", 19 | Args: cobra.ExactArgs(1), 20 | Short: "Check IP against available blacklists.", 21 | PreRunE: func(cmd *cobra.Command, args []string) error { 22 | ip := net.ParseIP(args[0]) 23 | if ip == nil { 24 | return fmt.Errorf("invalid IP address: %s", args[0]) 25 | } 26 | 27 | if netprivate.Is(ip) { 28 | return fmt.Errorf("ip: %s is in the private range", ip) 29 | } 30 | 31 | return nil 32 | }, 33 | RunE: func(cmd *cobra.Command, args []string) (err error) { 34 | var sem = semaphore.NewWeighted(int64(conf.concurrency)) 35 | ip := net.ParseIP(args[0]) 36 | 37 | var items []check.Item 38 | var hosts []string 39 | hosts, err = blacklist_checker.GetDNSBLs(conf.dnsbl) 40 | for _, host := range hosts { 41 | items = append(items, check.Item{ 42 | IP: ip, 43 | Blacklist: fmt.Sprintf("%s.%s.", utils.ReverseIP(ip.String()), host), 44 | Host: host, 45 | }) 46 | } 47 | 48 | var blacklisted uint64 49 | 50 | log.Info().Int("queries", len(items)).Int("dsnbl", len(hosts)).Msg("processing") 51 | 52 | for _, i := range items { 53 | if err = sem.Acquire(context.Background(), 1); err != nil { 54 | return err 55 | } 56 | go func(item check.Item) { 57 | if b, _ := processIpCheck(sem, item); b { 58 | atomic.AddUint64(&blacklisted, 1) 59 | } 60 | }(i) 61 | } 62 | 63 | if err = sem.Acquire(context.Background(), int64(conf.concurrency)); err != nil { 64 | return err 65 | } 66 | 67 | log.Info().Uint64("blacklisted", blacklisted).Int("queries", len(items)).Msg("Finished") 68 | return err 69 | }, 70 | } 71 | 72 | func init() { 73 | checkCmd.AddCommand(ipCmd) 74 | } 75 | -------------------------------------------------------------------------------- /cmd/blacklist-checker/cmd/cidr.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/ilijamt/blacklist_checker" 7 | "github.com/ilijamt/blacklist_checker/internal/check" 8 | "github.com/ilijamt/blacklist_checker/internal/utils" 9 | "github.com/ilijamt/netprivate" 10 | "github.com/rs/zerolog/log" 11 | "github.com/spf13/cobra" 12 | "golang.org/x/sync/semaphore" 13 | "net" 14 | "sync/atomic" 15 | ) 16 | 17 | var cidrCmd = &cobra.Command{ 18 | Use: "cidr ", 19 | Args: cobra.ExactArgs(1), 20 | Short: "Check CIDR against available blacklists.", 21 | PreRunE: func(cmd *cobra.Command, args []string) error { 22 | i, _, err := net.ParseCIDR(args[0]) 23 | if err != nil { 24 | return err 25 | } 26 | 27 | if netprivate.Is(i) { 28 | return fmt.Errorf("ip: %s is in the private range", i) 29 | } 30 | 31 | return nil 32 | }, 33 | RunE: func(cmd *cobra.Command, args []string) (err error) { 34 | var sem = semaphore.NewWeighted(int64(conf.concurrency)) 35 | 36 | var ips []net.IP 37 | var hosts []string 38 | var items []check.Item 39 | 40 | ips, err = utils.Hosts(args[0]) 41 | if err != nil { 42 | return err 43 | } 44 | 45 | hosts, err = blacklist_checker.GetDNSBLs(conf.dnsbl) 46 | for _, host := range hosts { 47 | for _, ip := range ips { 48 | items = append(items, check.Item{ 49 | IP: ip, 50 | Blacklist: fmt.Sprintf("%s.%s.", utils.ReverseIP(ip.String()), host), 51 | Host: host, 52 | }) 53 | } 54 | } 55 | 56 | log.Info().Int("queries", len(items)).Int("dsnbl", len(hosts)).Msg("processing") 57 | var blacklisted uint64 58 | 59 | for _, i := range items { 60 | if err = sem.Acquire(context.Background(), 1); err != nil { 61 | return err 62 | } 63 | go func(item check.Item) { 64 | if b, _ := processIpCheck(sem, item); b { 65 | atomic.AddUint64(&blacklisted, 1) 66 | } 67 | }(i) 68 | } 69 | 70 | if err = sem.Acquire(context.Background(), int64(conf.concurrency)); err != nil { 71 | return err 72 | } 73 | 74 | log.Info().Uint64("blacklisted", blacklisted).Int("queries", len(items)).Msg("Finished") 75 | return err 76 | }, 77 | } 78 | 79 | func init() { 80 | checkCmd.AddCommand(cidrCmd) 81 | } 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Blacklist Checker 2 | ================ 3 | 4 | Check if your IP or CIDR is blacklisted or not. 5 | 6 | There are probably faster ways to do this so if anyone want's to cleanup or send a PR feel free to do so 7 | 8 | ## Installation 9 | 10 | ## Getting Started with Blacklist Checker 11 | 12 | ### Requirements 13 | 14 | * [Golang](https://golang.org/dl/) >= 1.8 15 | 16 | ## Install 17 | 18 | ### Pre-compiled binary 19 | 20 | #### manually 21 | 22 | Download the pre-compiled binaries from the [releases](https://github.com/ilijamt/blacklist-checker/releases) page. 23 | 24 | #### homebrew 25 | 26 | ```bash 27 | brew tap ilijamt/tap 28 | brew install blacklist-checker 29 | ``` 30 | 31 | ### Help 32 | ```bash 33 | $ blacklist-checker 34 | A simple tool that helps you check if your IP or CIDR is blacklisted or not. 35 | 36 | Usage: 37 | blacklist-checker [command] 38 | 39 | Available Commands: 40 | check Check available blacklists. 41 | completion Generate the autocompletion script for the specified shell 42 | help Help about any command 43 | list List available blacklists. 44 | version Shows the version of the application 45 | 46 | Flags: 47 | --dsnbl string DNSBL file to use, if empty it uses the internal list, should be a list of DNSBL to use, each one on a new line 48 | -h, --help help for blacklist-checker 49 | 50 | Use "blacklist-checker [command] --help" for more information about a command. /0.1s 51 | ``` 52 | 53 | #### IP 54 | 55 | ```bash 56 | $ blacklist-checker check ip 46.217.104.208 57 | 12:51AM INF processing dsnbl=56 queries=56 58 | 12:51AM WRN blacklisted=true dnsbl=b.barracudacentral.org ip=46.217.104.208 responses=["127.0.0.2"] 59 | 12:51AM WRN blacklisted=true dnsbl=pbl.spamhaus.org ip=46.217.104.208 responses=["127.0.0.11"] 60 | 12:51AM WRN blacklisted=true dnsbl=zen.spamhaus.org ip=46.217.104.208 responses=["127.0.0.11"] 61 | 12:51AM INF Finished blacklisted=3 queries=56 /2.6s 62 | ``` 63 | 64 | #### CIDR 65 | ```bash 66 | $ blacklist-checker check cidr 46.217.104.208/28 67 | 12:51AM INF processing dsnbl=56 queries=896 68 | 12:51AM WRN blacklisted=true dnsbl=b.barracudacentral.org ip=46.217.104.215 responses=["127.0.0.2"] 69 | 12:51AM WRN blacklisted=true dnsbl=b.barracudacentral.org ip=46.217.104.218 responses=["127.0.0.2"] 70 | ... 71 | 12:51AM WRN blacklisted=true dnsbl=b.barracudacentral.org ip=46.217.104.223 responses=["127.0.0.2"] 72 | 12:51AM WRN blacklisted=true dnsbl=pbl.spamhaus.org ip=46.217.104.208 responses=["127.0.0.11"] 73 | 12:51AM WRN blacklisted=true dnsbl=pbl.spamhaus.org ip=46.217.104.209 responses=["127.0.0.11"] 74 | ... 75 | 12:51AM WRN blacklisted=true dnsbl=spam.dnsbl.sorbs.net ip=46.217.104.209 responses=["127.0.0.6"] 76 | 12:51AM WRN blacklisted=true dnsbl=spam.dnsbl.sorbs.net ip=46.217.104.221 responses=["127.0.0.6"] 77 | 12:51AM WRN blacklisted=true dnsbl=spam.dnsbl.sorbs.net ip=46.217.104.222 responses=["127.0.0.6"] 78 | ... 79 | 12:52AM WRN blacklisted=true dnsbl=zen.spamhaus.org ip=46.217.104.222 responses=["127.0.0.11"] 80 | 12:52AM WRN blacklisted=true dnsbl=zen.spamhaus.org ip=46.217.104.218 responses=["127.0.0.11"] 81 | 12:52AM INF Finished blacklisted=51 queries=896 /17.8s 82 | ``` 83 | 84 | #### Blacklist file format 85 | If you want to create your on black list file you want to use, you can use the format bellow, and specify it with the `--dsnbl` flag 86 | 87 | ```shell 88 | $ cat my-dnsbl-list 89 | b.barracudacentral.org 90 | sbl.spamhaus.org 91 | ``` 92 | 93 | #### Blacklists 94 | 95 | Currently there are 56 blacklists in [blacklists.go](blacklists.go) 96 | 97 | ```bash 98 | $ blacklist-checker list 99 | access.redhawk.org 100 | b.barracudacentral.org 101 | bl.spamcop.net 102 | blackholes.mail-abuse.org 103 | bogons.cymru.com 104 | cbl.abuseat.org 105 | cbl.anti-spam.org.cn 106 | cdl.anti-spam.org.cn 107 | combined.njabl.org 108 | csi.cloudmark.com 109 | db.wpbl.info 110 | dnsbl.dronebl.org 111 | dnsbl.inps.de 112 | dnsbl.njabl.org 113 | dnsbl.sorbs.net 114 | drone.abuse.ch 115 | dsn.rfc-ignorant.org 116 | dul.dnsbl.sorbs.net 117 | dyna.spamrats.com 118 | http.dnsbl.sorbs.net 119 | httpbl.abuse.ch 120 | ips.backscatterer.org 121 | ix.dnsbl.manitu.net 122 | korea.services.net 123 | misc.dnsbl.sorbs.net 124 | multi.surbl.org 125 | netblock.pedantic.org 126 | noptr.spamrats.com 127 | opm.tornevall.org 128 | pbl.spamhaus.org 129 | psbl.surriel.com 130 | query.senderbase.org 131 | rbl-plus.mail-abuse.org 132 | rbl.efnetrbl.org 133 | rbl.interserver.net 134 | rbl.spamlab.com 135 | rbl.suresupport.com 136 | relays.mail-abuse.org 137 | sbl.spamhaus.org 138 | short.rbl.jp 139 | smtp.dnsbl.sorbs.net 140 | socks.dnsbl.sorbs.net 141 | spam.dnsbl.sorbs.net 142 | spam.spamrats.com 143 | spamguard.leadmon.net 144 | spamrbl.imp.ch 145 | tor.dan.me.uk 146 | ubl.unsubscore.com 147 | virbl.bit.nl 148 | virus.rbl.jp 149 | web.dnsbl.sorbs.net 150 | wormrbl.imp.ch 151 | xbl.abuseat.org 152 | xbl.spamhaus.org 153 | zen.spamhaus.org 154 | zombie.dnsbl.sorbs.net /0.1s 155 | ``` 156 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 2 | github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 3 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 4 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 6 | github.com/ilijamt/netprivate v0.1.0 h1:fHVRlGTjoHjXxR89To4QDu/igguLkPfCrYaKCXEVqDY= 7 | github.com/ilijamt/netprivate v0.1.0/go.mod h1:obKz9HQ69QXa1rOoqBLWhcsM6kqZOw3YFQhqJrwlHF8= 8 | github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= 9 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 10 | github.com/miekg/dns v1.1.49 h1:qe0mQU3Z/XpFeE+AEBo2rqaS1IPBJ3anmqZ4XiZJVG8= 11 | github.com/miekg/dns v1.1.49/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= 12 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 13 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 14 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 15 | github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= 16 | github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc= 17 | github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc= 18 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 19 | github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= 20 | github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= 21 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 22 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 23 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 24 | github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= 25 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 26 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 27 | github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 28 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 29 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 30 | golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= 31 | golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= 32 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 33 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 34 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 35 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 36 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 37 | golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 38 | golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= 39 | golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 40 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 41 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= 42 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 43 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 44 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 45 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 46 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 47 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 48 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 49 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 50 | golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= 51 | golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 52 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 53 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 54 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 55 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 56 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 57 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 58 | golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 59 | golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= 60 | golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= 61 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 62 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 63 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 64 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 65 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 66 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 67 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 68 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 69 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 70 | --------------------------------------------------------------------------------