diff options
Diffstat (limited to '')
| -rw-r--r-- | main.go | 51 |
1 files changed, 44 insertions, 7 deletions
@@ -1,7 +1,21 @@ +// Package main provides a tool to generate Unbound DNS server configuration +// for domain blocking. It fetches domain lists from URLs and converts them +// into Unbound local-zone configuration format. +// +// Usage: +// +// unbound-ads <url-list> <output-file> +// +// The url-list should contain HTTP(S) URLs, one per line, pointing to files +// containing domain lists. Comments (lines starting with #) are ignored. +// The output file will contain Unbound configuration in the format: +// +// local-zone: "domain.com" refuse package main import ( "bufio" + "flag" "fmt" "log/slog" "net/http" @@ -9,19 +23,33 @@ import ( "strings" ) +// Version is set during build using ldflags +var Version = "dev-" + strings.Split(strings.TrimPrefix(`$Format:%H$`, "$Format:"), "-")[0] + +// main processes a list of URLs containing domain lists and generates +// an Unbound DNS server configuration file for domain blocking. func main() { - if len(os.Args) != 3 { - slog.Error("usage: program <url-list> <output-file>") + showVersion := flag.Bool("version", false, "Show version information") + flag.Parse() + + if *showVersion { + fmt.Println("unbound-ads version:", Version) + return + } + + args := flag.Args() + if len(args) != 2 { + slog.Error("usage: unbound-ads <url-list> <output-file>") os.Exit(1) } - urls, err := fetchURLList(os.Args[1]) + urls, err := fetchURLList(args[0]) if err != nil { slog.Error("failed to fetch URL list", "error", err) os.Exit(1) } - f, err := os.Create(os.Args[2]) + f, err := os.Create(args[1]) if err != nil { slog.Error("failed to create output file", "error", err) os.Exit(1) @@ -42,6 +70,9 @@ func main() { slog.Info("completed", "total_domains", len(domains)) } +// fetchURLList retrieves a list of URLs from the specified URL. +// It ignores empty lines and comments (lines starting with #). +// Returns a slice of URLs or an error if the fetch fails. func fetchURLList(url string) ([]string, error) { resp, err := http.Get(url) if err != nil { @@ -61,6 +92,11 @@ func fetchURLList(url string) ([]string, error) { return urls, scanner.Err() } +// fetchDomainsAndWrite retrieves domains from the specified URL and writes them +// to the output in Unbound configuration format. It handles various domain list +// formats including "0.0.0.0 domain.com" and plain domain lists. +// Domains are deduplicated using the seen map. +// Returns an error if fetching or writing fails. func fetchDomainsAndWrite(url string, w *bufio.Writer, seen map[string]struct{}) error { resp, err := http.Get(url) if err != nil { @@ -72,12 +108,13 @@ func fetchDomainsAndWrite(url string, w *bufio.Writer, seen map[string]struct{}) scanner := bufio.NewScanner(resp.Body) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) + // Skip empty lines and comments if line == "" || strings.HasPrefix(line, "#") { continue } + // Handle both "0.0.0.0 domain.com" and plain domain formats var domain string - // Handle "0.0.0.0 domain.com" format if strings.Contains(line, " ") { parts := strings.Fields(line) if len(parts) >= 2 { @@ -87,13 +124,13 @@ func fetchDomainsAndWrite(url string, w *bufio.Writer, seen map[string]struct{}) domain = line } - // Basic domain validation and normalization + // Normalize and validate domain format domain = strings.ToLower(strings.TrimSpace(domain)) if domain == "" || !strings.Contains(domain, ".") || strings.HasPrefix(domain, ".") || strings.HasSuffix(domain, ".") { continue } - // Skip if we've seen this domain before + // Deduplicate domains if _, exists := seen[domain]; exists { continue } |