aboutsummaryrefslogtreecommitdiffstats
path: root/hosts/hosts.go
blob: 320b96fab46ecad38cf686418be6770f6fb04415 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package hosts

import (
	"bufio"
	"fmt"
	"io"
	"net"
	"strings"
)

// LocalNames represent host names that are considered local.
var LocalNames = []string{
	"localhost",
	"localhost.localdomain",
	"local",
	"broadcasthost",
	"ip6-localhost",
	"ip6-loopback",
	"ip6-localnet",
	"ip6-mcastprefix",
	"ip6-allnodes",
	"ip6-allrouters",
	"ip6-allhosts",
	"0.0.0.0",
}

// DefaultParser is the default parser
var DefaultParser = &Parser{IgnoredHosts: LocalNames}

// Parser represents a hosts parser.
type Parser struct {
	IgnoredHosts []string
}

// Hosts represents a hosts file.
type Hosts map[string][]net.IPAddr

// Parse uses DefaultParser to parse hosts from reader r.
func Parse(r io.Reader) (Hosts, error) {
	return DefaultParser.Parse(r)
}

// Get returns the IP addresses of name.
func (h Hosts) Get(name string) ([]net.IPAddr, bool) {
	ipAddrs, ok := h[name]
	return ipAddrs, ok
}

// Del deletes the hosts entry of name.
func (h Hosts) Del(name string) {
	delete(h, name)
}

func (p *Parser) ignore(name string) bool {
	for _, ignored := range p.IgnoredHosts {
		if ignored == name {
			return true
		}
	}
	return false
}

// Parse parses hosts from reader r.
func (p *Parser) Parse(r io.Reader) (Hosts, error) {
	entries := make(map[string][]net.IPAddr)
	scanner := bufio.NewScanner(r)
	n := 0
	for scanner.Scan() {
		n++
		line := scanner.Text()
		fields := strings.Fields(line)
		if len(fields) < 2 {
			continue
		}
		ip := fields[0]
		if strings.HasPrefix(ip, "#") {
			continue
		}
		ipAddr, err := net.ResolveIPAddr("", ip)
		if err != nil {
			return nil, fmt.Errorf("line %d: invalid ip address: %s - %s", n, fields[0], line)
		}
		for _, name := range fields[1:] {
			if strings.HasPrefix(name, "#") {
				break
			}
			if p.ignore(name) {
				continue
			}
			entries[name] = append(entries[name], *ipAddr)
		}
	}
	return entries, nil
}