package parser import ( "bufio" "io" "strings" "github.com/miekg/dns" ) func init() { RegisterDomainsParser(dnsmasqDomainsParser{}) RegisterDomainsParser(mosDNSDomainsParser{}) RegisterDomainsParser(smartDNSDomainsParser{}) RegisterDomainsParser(unboundDomainsParser{}) } type dnsmasqDomainsParser struct{} func (dnsmasqDomainsParser) CanHandle(line string) bool { return strings.HasPrefix(line, "address=/") } func (dnsmasqDomainsParser) ParseDomains(r io.Reader) (domains []string, ignored int, err error) { scanner := bufio.NewScanner(r) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if isComment(line) { continue } switch { case strings.HasPrefix(line, "address=/"): part := strings.FieldsFunc(line, func(r rune) bool { return r == '/' }) if len(part) >= 3 && isDomainName(part[1]) { domains = append(domains, part[1]) continue } } ignored++ } if err = scanner.Err(); err != nil { return } return unique(domains), ignored, nil } type mosDNSDomainsParser struct{} func (mosDNSDomainsParser) CanHandle(line string) bool { if strings.HasPrefix(line, "domain:") { return isDomainName(line[7:]) } return false } func (mosDNSDomainsParser) ParseDomains(r io.Reader) (domains []string, ignored int, err error) { scanner := bufio.NewScanner(r) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if isComment(line) { continue } if strings.HasPrefix(line, "domain:") { domains = append(domains, line[7:]) continue } ignored++ } if err = scanner.Err(); err != nil { return } return unique(domains), ignored, nil } type smartDNSDomainsParser struct{} func (smartDNSDomainsParser) CanHandle(line string) bool { return strings.HasPrefix(line, "address /") } func (smartDNSDomainsParser) ParseDomains(r io.Reader) (domains []string, ignored int, err error) { scanner := bufio.NewScanner(r) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if isComment(line) { continue } if strings.HasPrefix(line, "address /") { if i := strings.IndexByte(line[9:], '/'); i > -1 { domains = append(domains, line[9:i+9]) continue } } ignored++ } if err = scanner.Err(); err != nil { return } return unique(domains), ignored, nil } type unboundDomainsParser struct{} func (unboundDomainsParser) CanHandle(line string) bool { return strings.HasPrefix(line, "local-data:") || strings.HasPrefix(line, "local-zone:") } func (unboundDomainsParser) ParseDomains(r io.Reader) (domains []string, ignored int, err error) { scanner := bufio.NewScanner(r) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if isComment(line) { continue } switch { case strings.HasPrefix(line, "local-data:"): record := strings.Trim(strings.TrimSpace(line[11:]), `"`) if rr, err := dns.NewRR(record); err == nil { switch rr.Header().Rrtype { case dns.TypeA, dns.TypeAAAA, dns.TypeCNAME: domains = append(domains, strings.Trim(rr.Header().Name, `.`)) continue } } case strings.HasPrefix(line, "local-zone:") && strings.HasSuffix(line, " reject"): line = strings.Trim(strings.TrimSpace(line[11:]), `"`) if i := strings.IndexByte(line, '"'); i > -1 { domains = append(domains, line[:i]) continue } } ignored++ } if err = scanner.Err(); err != nil { return } return unique(domains), ignored, nil }