main.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. package main
  2. import (
  3. "errors"
  4. "fmt"
  5. "io/ioutil"
  6. "net"
  7. "net/http"
  8. "strings"
  9. )
  10. var (
  11. lists = []string{
  12. "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts",
  13. "https://mirror1.malwaredomains.com/files/justdomains",
  14. "http://sysctl.org/cameleon/hosts",
  15. "https://zeustracker.abuse.ch/blocklist.php?download=domainblocklist",
  16. "https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt",
  17. "https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt",
  18. "https://hosts-file.net/ad_servers.txt",
  19. }
  20. invalid = []string{
  21. "localhost", "localhost.localdomain", "local", "broadcasthost",
  22. "ip6-localhost", "ip6-loopback", "ip6-localnet",
  23. "ip6-mcastprefix", "ip6-allnodes", "ip6-allrouters",
  24. "ip6-allhosts",
  25. }
  26. zone_file = "blacklist.txt"
  27. )
  28. func main() {
  29. fmt.Print(generateList())
  30. }
  31. func generateList() (string, error) {
  32. c := make(chan string)
  33. for _, list := range lists {
  34. go handle(list, c)
  35. }
  36. var zones []string
  37. for range lists {
  38. zones = append(zones, <-c)
  39. }
  40. return strings.Join(zones, "\n"), nil
  41. }
  42. func handle(url string, zone chan string) {
  43. body, err := fetch(url)
  44. if err != nil {
  45. return
  46. }
  47. zone <- sanitize(body)
  48. }
  49. func fetch(url string) (string, error) {
  50. req, err := http.Get(url)
  51. if err != nil {
  52. return "", err
  53. }
  54. defer req.Body.Close()
  55. body, err := ioutil.ReadAll(req.Body)
  56. if err != nil {
  57. return "", err
  58. }
  59. return string(body), nil
  60. }
  61. func sanitize(records string) string {
  62. var sanitized []string
  63. for _, line := range strings.Split(records, "\n") {
  64. ip, domain, err := parse_record(line)
  65. if err != nil {
  66. continue
  67. }
  68. // Domain is invalid (e.g., "localhost")
  69. if is_invalid(domain) {
  70. continue
  71. }
  72. // Domain is an IP address
  73. if net.ParseIP(domain) != nil {
  74. continue
  75. }
  76. // Unify the records
  77. if ip != "127.0.0.1" {
  78. ip = "127.0.0.1"
  79. }
  80. sanitized = append(sanitized, ip + " " + domain)
  81. }
  82. return strings.Join(sanitized, "\n")
  83. }
  84. func parse_record(record string) (string, string, error) {
  85. if len(record) == 0 {
  86. return "", "", errors.New("Empty line")
  87. }
  88. if strings.HasPrefix(record, "#") {
  89. return "", "", errors.New("Comment")
  90. }
  91. words := strings.Fields(record)
  92. // Domain-only list
  93. if len(words) == 1 {
  94. return "", words[0], nil
  95. }
  96. return words[0], words[1], nil
  97. }
  98. func is_invalid(domain string) bool {
  99. for _, i := range invalid {
  100. if domain == i {
  101. return true
  102. }
  103. }
  104. return false
  105. }