145 lines
3.2 KiB
Go
145 lines
3.2 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"os"
|
||
|
"strings"
|
||
|
"unicode"
|
||
|
)
|
||
|
|
||
|
// Basic application info.
|
||
|
const (
|
||
|
appName = "dnsbl-scanner"
|
||
|
appDescription = "Scans DNSBL formatted files for IP ranges."
|
||
|
appVersion = "0.1"
|
||
|
)
|
||
|
|
||
|
// Structure for the App.
|
||
|
type App struct {
|
||
|
flags *Flags
|
||
|
config *Config
|
||
|
}
|
||
|
|
||
|
var app *App
|
||
|
|
||
|
// Main program function.
|
||
|
func main() {
|
||
|
// Parse flags and config.
|
||
|
app = new(App)
|
||
|
app.ParseFlags()
|
||
|
app.ReadConfig()
|
||
|
|
||
|
// Confirm blocklist files are provided.
|
||
|
if len(app.config.DNSBLFiles) == 0 {
|
||
|
log.Fatalln("no DNSBL files to scan, please provide in either a config file or via flags.")
|
||
|
}
|
||
|
// Confirm IP addresses to check are provided.
|
||
|
if len(app.config.IPAddresses) == 0 {
|
||
|
log.Fatalln("no IP addresses to search, please provide in either a config file or via flags.")
|
||
|
}
|
||
|
|
||
|
// Parse provided IP addresses into networks.
|
||
|
var networks []*IPAddr
|
||
|
for _, ipAddr := range app.config.IPAddresses {
|
||
|
ip, err := ParseIPAddr(ipAddr)
|
||
|
if err != nil {
|
||
|
log.Fatal("Unable to parse provided IP address:", ipAddr)
|
||
|
}
|
||
|
networks = append(networks, ip)
|
||
|
}
|
||
|
|
||
|
// Print CSV header.
|
||
|
fmt.Println("IP Address,Network,DNSBL File")
|
||
|
|
||
|
// Read each DNS blocklist file, parse and check networks.
|
||
|
for _, dnsblFile := range app.config.DNSBLFiles {
|
||
|
// Open file, continue to next file if failure opening.
|
||
|
file, err := os.Open(dnsblFile)
|
||
|
if err != nil {
|
||
|
log.Println("Unable to open file:", dnsblFile, err)
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
// Networks to exclude.
|
||
|
var excluded []*IPAddr
|
||
|
|
||
|
// Scan each line of the file and check if IP is in networks.
|
||
|
scanner := bufio.NewScanner(file)
|
||
|
for scanner.Scan() {
|
||
|
line := scanner.Text()
|
||
|
|
||
|
// Remove comments.
|
||
|
commentI := strings.Index(line, "#")
|
||
|
if commentI != -1 {
|
||
|
line = line[:commentI]
|
||
|
}
|
||
|
|
||
|
// Trim whitespace.
|
||
|
line = strings.TrimSpace(line)
|
||
|
|
||
|
// Ignore variables.
|
||
|
if strings.HasPrefix(line, "$") {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
// Ignore descriptions.
|
||
|
if strings.HasPrefix(line, ":") {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
// Ignore empty lines.
|
||
|
if line == "" {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
// Only need first field.
|
||
|
spaceI := strings.IndexFunc(line, unicode.IsSpace)
|
||
|
if spaceI != -1 {
|
||
|
line = line[:spaceI]
|
||
|
}
|
||
|
|
||
|
// If excluded, add to exclude list.
|
||
|
if strings.HasPrefix(line, "!") {
|
||
|
// Remove exclamation mark.
|
||
|
line = line[1:]
|
||
|
|
||
|
// Parse IP, failures should move to next line.
|
||
|
ipAddr, err := ParseIPAddr(line)
|
||
|
if err != nil {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
// Add to excluded list and move to next line.
|
||
|
excluded = append(excluded, ipAddr)
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
// This should be an IP address that is block listed.
|
||
|
// Parse the IP address, and move to next line on parse failures.
|
||
|
ipAddr, err := ParseIPAddr(line)
|
||
|
if err != nil {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
// If excluded, move to next line.
|
||
|
for _, exclude := range excluded {
|
||
|
if exclude.Contains(ipAddr) {
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Check networks to see if IP block list is intercepted.
|
||
|
for _, network := range networks {
|
||
|
if network.Intercepts(ipAddr) {
|
||
|
// If intercepts, print IP address, network, and block list file name in CSV format.
|
||
|
fmt.Printf("%s,%s,%s\n", ipAddr, network, dnsblFile)
|
||
|
// We can move on to next line now.
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|