123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- package main
- import (
- "errors"
- "io/ioutil"
- "log"
- "net"
- "net/http"
- "os"
- "strings"
- )
- var (
- lists = []string{
- "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts",
- "https://mirror1.malwaredomains.com/files/justdomains",
- "http://sysctl.org/cameleon/hosts",
- "https://zeustracker.abuse.ch/blocklist.php?download=domainblocklist",
- "https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt",
- "https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt",
- "https://hosts-file.net/ad_servers.txt",
- }
- invalid = []string{
- "localhost", "localhost.localdomain", "local", "broadcasthost",
- "ip6-localhost", "ip6-loopback", "ip6-localnet",
- "ip6-mcastprefix", "ip6-allnodes", "ip6-allrouters",
- "ip6-allhosts",
- }
- )
- func main() {
- if len(os.Args) < 2 {
- log.Fatal("Please provide a zone file to write to.")
- }
- zone_file := os.Args[1]
- // Open the zone file, and create it if needed
- f, err := os.OpenFile(zone_file, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
- if err != nil {
- log.Fatal(err)
- }
- defer f.Close()
- // Override the current content
- if err := f.Truncate(0); err != nil {
- log.Fatal(err)
- }
- // Fetch and parse the zone content from lists
- c := make(chan string)
- for _, list := range lists {
- go handle(list, c)
- }
- // Write the zones
- for range lists {
- if _, err = f.WriteString(<-c); err != nil {
- log.Fatal(err)
- }
- }
- }
- func handle(url string, zone chan string) {
- body, err := fetch(url)
- if err != nil {
- return
- }
- zone <- sanitize(body)
- }
- func fetch(url string) (string, error) {
- req, err := http.Get(url)
- if err != nil {
- return "", err
- }
- defer req.Body.Close()
- body, err := ioutil.ReadAll(req.Body)
- if err != nil {
- return "", err
- }
- return string(body), nil
- }
- func sanitize(records string) string {
- var sanitized []string
- for _, line := range strings.Split(records, "\n") {
- ip, domain, err := parse_record(line)
- if err != nil {
- continue
- }
- // Domain is invalid (e.g., "localhost")
- if is_invalid(domain) {
- continue
- }
- // Domain is an IP address
- if net.ParseIP(domain) != nil {
- continue
- }
- // Unify the records
- if ip != "127.0.0.1" {
- ip = "127.0.0.1"
- }
- sanitized = append(sanitized, ip + " " + domain)
- }
- return strings.Join(sanitized, "\n")
- }
- func parse_record(record string) (string, string, error) {
- if len(record) == 0 {
- return "", "", errors.New("Empty line")
- }
- if strings.HasPrefix(record, "#") {
- return "", "", errors.New("Comment")
- }
- words := strings.Fields(record)
- // Domain-only list
- if len(words) == 1 {
- return "", words[0], nil
- }
- return words[0], words[1], nil
- }
- func is_invalid(domain string) bool {
- for _, i := range invalid {
- if domain == i {
- return true
- }
- }
- return false
- }
|