-
Notifications
You must be signed in to change notification settings - Fork 18
/
host_rule.go
119 lines (99 loc) · 2.6 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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package rules
import (
"net"
"strings"
"github.com/AdguardTeam/urlfilter/filterutil"
)
// 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
}
// Split string by whitespace (' ' or '\t') and return the first element
func splitNextByWhitespace(ps *string) string {
s := *ps
i := 0
// trim space
for ; i < len(s); i++ {
if !(s[i] == ' ' || s[i] == '\t') {
break
}
}
begin := i
// find space or tab
for ; i < len(s); i++ {
if s[i] == ' ' || s[i] == '\t' {
break
}
}
r := s[begin:i]
// trim space
for ; i < len(s); i++ {
if !(s[i] == ' ' || s[i] == '\t') {
break
}
}
*ps = s[i:]
return r
}
// 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]
}
first := splitNextByWhitespace(&ruleText)
if len(ruleText) == 0 {
if !filterutil.IsDomainName(first) {
return nil, &RuleSyntaxError{msg: "invalid syntax", ruleText: ruleText}
}
h.Hostnames = append(h.Hostnames, first)
h.IP = net.IPv4(0, 0, 0, 0)
} else {
h.IP = net.ParseIP(first)
if h.IP == nil {
return nil, &RuleSyntaxError{msg: "cannot parse IP", ruleText: ruleText}
}
for len(ruleText) != 0 {
host := splitNextByWhitespace(&ruleText)
h.Hostnames = append(h.Hostnames, host)
}
}
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
}