-
Notifications
You must be signed in to change notification settings - Fork 18
/
host.go
128 lines (103 loc) · 2.67 KB
/
host.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
120
121
122
123
124
125
126
127
128
package rules
import (
"net/netip"
"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 {
// IP is the address of the rule.
IP netip.Addr
// RuleText is the original text of the rule.
RuleText string
// Hostnames is the slice of hostnames associated with IP.
Hostnames []string
// FilterListID is the identifier of the filter, containing the rule.
FilterListID int
}
// 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) (h *HostRule, err 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 = netip.IPv4Unspecified()
} else {
h.IP, err = netip.ParseAddr(first)
if err != nil {
return nil, &RuleSyntaxError{msg: err.Error(), 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
}