123 lines
2.4 KiB
Go
123 lines
2.4 KiB
Go
package parser
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"errors"
|
|
"io"
|
|
"net/netip"
|
|
"strings"
|
|
|
|
"github.com/miekg/dns"
|
|
)
|
|
|
|
var ErrNoParser = errors.New("no suitable parser could be found")
|
|
|
|
type Parser interface {
|
|
CanHandle(line string) bool
|
|
}
|
|
|
|
type DomainsParser interface {
|
|
Parser
|
|
ParseDomains(io.Reader) (domains []string, ignored int, err error)
|
|
}
|
|
|
|
type NetworksParser interface {
|
|
Parser
|
|
ParseNetworks(io.Reader) (prefixes []netip.Prefix, ignored int, err error)
|
|
}
|
|
|
|
var (
|
|
domainsParsers []DomainsParser
|
|
networksParsers []NetworksParser
|
|
)
|
|
|
|
func RegisterDomainsParser(parser DomainsParser) {
|
|
domainsParsers = append(domainsParsers, parser)
|
|
}
|
|
|
|
func RegisterNetworksParser(parser NetworksParser) {
|
|
networksParsers = append(networksParsers, parser)
|
|
}
|
|
|
|
func ParseDomains(r io.Reader) (domains []string, ignored int, err error) {
|
|
var (
|
|
buffer = new(bytes.Buffer)
|
|
scanner = bufio.NewScanner(io.TeeReader(r, buffer))
|
|
line string
|
|
parser DomainsParser
|
|
)
|
|
for scanner.Scan() {
|
|
line = strings.TrimSpace(scanner.Text())
|
|
if isComment(line) {
|
|
continue
|
|
}
|
|
for _, parser = range domainsParsers {
|
|
if parser.CanHandle(line) {
|
|
// log.Printf("using parser %T", parser)
|
|
return parser.ParseDomains(io.MultiReader(buffer, r))
|
|
}
|
|
}
|
|
break
|
|
}
|
|
return nil, 0, ErrNoParser
|
|
}
|
|
|
|
func ParseNetworks(r io.Reader) (prefixes []netip.Prefix, ignored int, err error) {
|
|
var (
|
|
buffer = new(bytes.Buffer)
|
|
scanner = bufio.NewScanner(io.TeeReader(r, buffer))
|
|
line string
|
|
parser NetworksParser
|
|
)
|
|
for scanner.Scan() {
|
|
line = strings.TrimSpace(scanner.Text())
|
|
if isComment(line) {
|
|
continue
|
|
}
|
|
for _, parser = range networksParsers {
|
|
if parser.CanHandle(line) {
|
|
// log.Printf("using parser %T", parser)
|
|
return parser.ParseNetworks(io.MultiReader(buffer, r))
|
|
}
|
|
}
|
|
break
|
|
}
|
|
return nil, 0, ErrNoParser
|
|
}
|
|
|
|
func isComment(line string) bool {
|
|
return line == "" || line[0] == '#' || line[0] == '!'
|
|
}
|
|
|
|
func isDomainName(s string) bool {
|
|
n, ok := dns.IsDomainName(s)
|
|
return n >= 2 && ok
|
|
}
|
|
|
|
func isIP(s string) bool {
|
|
_, err := netip.ParseAddr(s)
|
|
return err == nil
|
|
}
|
|
|
|
func isPrefix(s string) bool {
|
|
_, err := netip.ParsePrefix(s)
|
|
return err == nil
|
|
}
|
|
|
|
func addrToPrefix(addr netip.Addr) netip.Prefix {
|
|
switch {
|
|
case addr.Is4():
|
|
prefix, _ := addr.Prefix(32)
|
|
return prefix
|
|
case addr.Is4In6():
|
|
prefix, _ := addr.Unmap().Prefix(32)
|
|
return prefix
|
|
case addr.Is6():
|
|
prefix, _ := addr.Prefix(128)
|
|
return prefix
|
|
default:
|
|
return netip.Prefix{}
|
|
}
|
|
}
|