-
Notifications
You must be signed in to change notification settings - Fork 21
/
host_rule.go
101 lines (85 loc) · 2.37 KB
/
host_rule.go
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
95
96
97
98
99
100
101
package rules
import (
"net"
"strings"
"github.com/asaskevich/govalidator"
)
// HostRule is a structure for simple host-level rules (i.e. /etc/hosts syntax).
// http://man7.org/linux/man-pages/man5/hosts.5.html
// It also supports "just domain" syntax. In this case, the IP will be set to 0.0.0.0.
type HostRule struct {
RuleText string // RuleText is the original rule text
FilterListID int // Filter list identifier
Hostnames []string // Hostnames is the list of hostnames that is configured
IP net.IP // ip address
}
// NewHostRule parses the rule and creates a new HostRule instance
// The format is:
// IP_address canonical_hostname [aliases...]
func NewHostRule(ruleText string, filterListID int) (*HostRule, error) {
h := HostRule{
RuleText: ruleText,
FilterListID: filterListID,
}
// Strip comment
commentIndex := strings.IndexByte(ruleText, '#')
if commentIndex > 0 {
ruleText = ruleText[0 : commentIndex-1]
}
parts := strings.Fields(strings.TrimSpace(ruleText))
var ip net.IP
var hostnames []string
if len(parts) >= 2 {
for i, part := range parts {
if i == 0 {
ip = net.ParseIP(parts[0])
if ip == nil {
return nil, &RuleSyntaxError{msg: "cannot parse IP", ruleText: ruleText}
}
} else {
hostnames = append(hostnames, part)
}
}
} else if len(parts) == 1 &&
isDomainName(parts[0]) {
hostnames = append(hostnames, parts[0])
ip = net.IPv4(0, 0, 0, 0)
} else {
return nil, &RuleSyntaxError{msg: "invalid syntax", ruleText: ruleText}
}
h.Hostnames = hostnames
h.IP = ip
return &h, nil
}
// Text returns the original rule text
// Implements the `Rule` interface
func (f *HostRule) Text() string {
return f.RuleText
}
// GetFilterListID returns ID of the filter list this rule belongs to
func (f *HostRule) GetFilterListID() int {
return f.FilterListID
}
// String returns original rule text
func (f *HostRule) String() string {
return f.RuleText
}
// Match checks if this filtering rule matches the specified hostname
func (f *HostRule) Match(hostname string) bool {
if len(f.Hostnames) == 1 && hostname == f.Hostnames[0] {
return true
}
for _, h := range f.Hostnames {
if h == hostname {
return true
}
}
return false
}
func isDomainName(line string) bool {
if strings.IndexByte(line, '.') == -1 ||
line[len(line)-1] == '.' {
return false
}
return govalidator.IsDNSName(line)
}