mirror of https://github.com/ginuerzh/gost
17 changed files with 47 additions and 634 deletions
@ -1,298 +0,0 @@ |
|||||
package gost |
|
||||
|
|
||||
import ( |
|
||||
"bufio" |
|
||||
"bytes" |
|
||||
"fmt" |
|
||||
"io" |
|
||||
"net" |
|
||||
"strconv" |
|
||||
"strings" |
|
||||
"sync" |
|
||||
"time" |
|
||||
|
|
||||
glob "github.com/gobwas/glob" |
|
||||
) |
|
||||
|
|
||||
// Matcher is a generic pattern matcher,
|
|
||||
// it gives the match result of the given pattern for specific v.
|
|
||||
type Matcher interface { |
|
||||
Match(v string) bool |
|
||||
String() string |
|
||||
} |
|
||||
|
|
||||
// NewMatcher creates a Matcher for the given pattern.
|
|
||||
// The acutal Matcher depends on the pattern:
|
|
||||
// IP Matcher if pattern is a valid IP address.
|
|
||||
// CIDR Matcher if pattern is a valid CIDR address.
|
|
||||
// Domain Matcher if both of the above are not.
|
|
||||
func NewMatcher(pattern string) Matcher { |
|
||||
if pattern == "" { |
|
||||
return nil |
|
||||
} |
|
||||
if ip := net.ParseIP(pattern); ip != nil { |
|
||||
return IPMatcher(ip) |
|
||||
} |
|
||||
if _, inet, err := net.ParseCIDR(pattern); err == nil { |
|
||||
return CIDRMatcher(inet) |
|
||||
} |
|
||||
return DomainMatcher(pattern) |
|
||||
} |
|
||||
|
|
||||
type ipMatcher struct { |
|
||||
ip net.IP |
|
||||
} |
|
||||
|
|
||||
// IPMatcher creates a Matcher for a specific IP address.
|
|
||||
func IPMatcher(ip net.IP) Matcher { |
|
||||
return &ipMatcher{ |
|
||||
ip: ip, |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
func (m *ipMatcher) Match(ip string) bool { |
|
||||
if m == nil { |
|
||||
return false |
|
||||
} |
|
||||
return m.ip.Equal(net.ParseIP(ip)) |
|
||||
} |
|
||||
|
|
||||
func (m *ipMatcher) String() string { |
|
||||
return "ip " + m.ip.String() |
|
||||
} |
|
||||
|
|
||||
type cidrMatcher struct { |
|
||||
ipNet *net.IPNet |
|
||||
} |
|
||||
|
|
||||
// CIDRMatcher creates a Matcher for a specific CIDR notation IP address.
|
|
||||
func CIDRMatcher(inet *net.IPNet) Matcher { |
|
||||
return &cidrMatcher{ |
|
||||
ipNet: inet, |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
func (m *cidrMatcher) Match(ip string) bool { |
|
||||
if m == nil || m.ipNet == nil { |
|
||||
return false |
|
||||
} |
|
||||
return m.ipNet.Contains(net.ParseIP(ip)) |
|
||||
} |
|
||||
|
|
||||
func (m *cidrMatcher) String() string { |
|
||||
return "cidr " + m.ipNet.String() |
|
||||
} |
|
||||
|
|
||||
type domainMatcher struct { |
|
||||
pattern string |
|
||||
glob glob.Glob |
|
||||
} |
|
||||
|
|
||||
// DomainMatcher creates a Matcher for a specific domain pattern,
|
|
||||
// the pattern can be a plain domain such as 'example.com',
|
|
||||
// a wildcard such as '*.exmaple.com' or a special wildcard '.example.com'.
|
|
||||
func DomainMatcher(pattern string) Matcher { |
|
||||
p := pattern |
|
||||
if strings.HasPrefix(pattern, ".") { |
|
||||
p = pattern[1:] // trim the prefix '.'
|
|
||||
pattern = "*" + p |
|
||||
} |
|
||||
return &domainMatcher{ |
|
||||
pattern: p, |
|
||||
glob: glob.MustCompile(pattern), |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
func (m *domainMatcher) Match(domain string) bool { |
|
||||
if m == nil || m.glob == nil { |
|
||||
return false |
|
||||
} |
|
||||
|
|
||||
if domain == m.pattern { |
|
||||
return true |
|
||||
} |
|
||||
return m.glob.Match(domain) |
|
||||
} |
|
||||
|
|
||||
func (m *domainMatcher) String() string { |
|
||||
return "domain " + m.pattern |
|
||||
} |
|
||||
|
|
||||
// Bypass is a filter for address (IP or domain).
|
|
||||
// It contains a list of matchers.
|
|
||||
type Bypass struct { |
|
||||
matchers []Matcher |
|
||||
period time.Duration // the period for live reloading
|
|
||||
reversed bool |
|
||||
stopped chan struct{} |
|
||||
mux sync.RWMutex |
|
||||
} |
|
||||
|
|
||||
// NewBypass creates and initializes a new Bypass using matchers as its match rules.
|
|
||||
// The rules will be reversed if the reversed is true.
|
|
||||
func NewBypass(reversed bool, matchers ...Matcher) *Bypass { |
|
||||
return &Bypass{ |
|
||||
matchers: matchers, |
|
||||
reversed: reversed, |
|
||||
stopped: make(chan struct{}), |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// NewBypassPatterns creates and initializes a new Bypass using matcher patterns as its match rules.
|
|
||||
// The rules will be reversed if the reverse is true.
|
|
||||
func NewBypassPatterns(reversed bool, patterns ...string) *Bypass { |
|
||||
var matchers []Matcher |
|
||||
for _, pattern := range patterns { |
|
||||
if m := NewMatcher(pattern); m != nil { |
|
||||
matchers = append(matchers, m) |
|
||||
} |
|
||||
} |
|
||||
bp := NewBypass(reversed) |
|
||||
bp.AddMatchers(matchers...) |
|
||||
return bp |
|
||||
} |
|
||||
|
|
||||
// Contains reports whether the bypass includes addr.
|
|
||||
func (bp *Bypass) Contains(addr string) bool { |
|
||||
if bp == nil || addr == "" { |
|
||||
return false |
|
||||
} |
|
||||
|
|
||||
// try to strip the port
|
|
||||
if host, port, _ := net.SplitHostPort(addr); host != "" && port != "" { |
|
||||
if p, _ := strconv.Atoi(port); p > 0 { // port is valid
|
|
||||
addr = host |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
bp.mux.RLock() |
|
||||
defer bp.mux.RUnlock() |
|
||||
|
|
||||
if len(bp.matchers) == 0 { |
|
||||
return false |
|
||||
} |
|
||||
|
|
||||
var matched bool |
|
||||
for _, matcher := range bp.matchers { |
|
||||
if matcher == nil { |
|
||||
continue |
|
||||
} |
|
||||
if matcher.Match(addr) { |
|
||||
matched = true |
|
||||
break |
|
||||
} |
|
||||
} |
|
||||
return !bp.reversed && matched || |
|
||||
bp.reversed && !matched |
|
||||
} |
|
||||
|
|
||||
// AddMatchers appends matchers to the bypass matcher list.
|
|
||||
func (bp *Bypass) AddMatchers(matchers ...Matcher) { |
|
||||
bp.mux.Lock() |
|
||||
defer bp.mux.Unlock() |
|
||||
|
|
||||
bp.matchers = append(bp.matchers, matchers...) |
|
||||
} |
|
||||
|
|
||||
// Matchers return the bypass matcher list.
|
|
||||
func (bp *Bypass) Matchers() []Matcher { |
|
||||
bp.mux.RLock() |
|
||||
defer bp.mux.RUnlock() |
|
||||
|
|
||||
return bp.matchers |
|
||||
} |
|
||||
|
|
||||
// Reversed reports whether the rules of the bypass are reversed.
|
|
||||
func (bp *Bypass) Reversed() bool { |
|
||||
bp.mux.RLock() |
|
||||
defer bp.mux.RUnlock() |
|
||||
|
|
||||
return bp.reversed |
|
||||
} |
|
||||
|
|
||||
// Reload parses config from r, then live reloads the bypass.
|
|
||||
func (bp *Bypass) Reload(r io.Reader) error { |
|
||||
var matchers []Matcher |
|
||||
var period time.Duration |
|
||||
var reversed bool |
|
||||
|
|
||||
if r == nil || bp.Stopped() { |
|
||||
return nil |
|
||||
} |
|
||||
|
|
||||
scanner := bufio.NewScanner(r) |
|
||||
for scanner.Scan() { |
|
||||
line := scanner.Text() |
|
||||
ss := splitLine(line) |
|
||||
if len(ss) == 0 { |
|
||||
continue |
|
||||
} |
|
||||
switch ss[0] { |
|
||||
case "reload": // reload option
|
|
||||
if len(ss) > 1 { |
|
||||
period, _ = time.ParseDuration(ss[1]) |
|
||||
} |
|
||||
case "reverse": // reverse option
|
|
||||
if len(ss) > 1 { |
|
||||
reversed, _ = strconv.ParseBool(ss[1]) |
|
||||
} |
|
||||
default: |
|
||||
matchers = append(matchers, NewMatcher(ss[0])) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if err := scanner.Err(); err != nil { |
|
||||
return err |
|
||||
} |
|
||||
|
|
||||
bp.mux.Lock() |
|
||||
defer bp.mux.Unlock() |
|
||||
|
|
||||
bp.matchers = matchers |
|
||||
bp.period = period |
|
||||
bp.reversed = reversed |
|
||||
|
|
||||
return nil |
|
||||
} |
|
||||
|
|
||||
// Period returns the reload period.
|
|
||||
func (bp *Bypass) Period() time.Duration { |
|
||||
if bp.Stopped() { |
|
||||
return -1 |
|
||||
} |
|
||||
|
|
||||
bp.mux.RLock() |
|
||||
defer bp.mux.RUnlock() |
|
||||
|
|
||||
return bp.period |
|
||||
} |
|
||||
|
|
||||
// Stop stops reloading.
|
|
||||
func (bp *Bypass) Stop() { |
|
||||
select { |
|
||||
case <-bp.stopped: |
|
||||
default: |
|
||||
close(bp.stopped) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// Stopped checks whether the reloader is stopped.
|
|
||||
func (bp *Bypass) Stopped() bool { |
|
||||
select { |
|
||||
case <-bp.stopped: |
|
||||
return true |
|
||||
default: |
|
||||
return false |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
func (bp *Bypass) String() string { |
|
||||
b := &bytes.Buffer{} |
|
||||
fmt.Fprintf(b, "reversed: %v\n", bp.Reversed()) |
|
||||
fmt.Fprintf(b, "reload: %v\n", bp.Period()) |
|
||||
for _, m := range bp.Matchers() { |
|
||||
b.WriteString(m.String()) |
|
||||
b.WriteByte('\n') |
|
||||
} |
|
||||
return b.String() |
|
||||
} |
|
||||
@ -1,303 +0,0 @@ |
|||||
package gost |
|
||||
|
|
||||
import ( |
|
||||
"bytes" |
|
||||
"fmt" |
|
||||
"io" |
|
||||
"testing" |
|
||||
"time" |
|
||||
) |
|
||||
|
|
||||
var bypassContainTests = []struct { |
|
||||
patterns []string |
|
||||
reversed bool |
|
||||
addr string |
|
||||
bypassed bool |
|
||||
}{ |
|
||||
// empty pattern
|
|
||||
{[]string{""}, false, "", false}, |
|
||||
{[]string{""}, false, "192.168.1.1", false}, |
|
||||
{[]string{""}, true, "", false}, |
|
||||
{[]string{""}, true, "192.168.1.1", false}, |
|
||||
|
|
||||
// IP address
|
|
||||
{[]string{"192.168.1.1"}, false, "192.168.1.1", true}, |
|
||||
{[]string{"192.168.1.1"}, true, "192.168.1.1", false}, |
|
||||
{[]string{"192.168.1.1"}, false, "192.168.1.2", false}, |
|
||||
{[]string{"192.168.1.1"}, true, "192.168.1.2", true}, |
|
||||
{[]string{"0.0.0.0"}, false, "0.0.0.0", true}, |
|
||||
{[]string{"0.0.0.0"}, true, "0.0.0.0", false}, |
|
||||
|
|
||||
// CIDR address
|
|
||||
{[]string{"192.168.1.0/0"}, false, "1.2.3.4", true}, |
|
||||
{[]string{"192.168.1.0/0"}, true, "1.2.3.4", false}, |
|
||||
{[]string{"192.168.1.0/8"}, false, "192.1.0.255", true}, |
|
||||
{[]string{"192.168.1.0/8"}, true, "192.1.0.255", false}, |
|
||||
{[]string{"192.168.1.0/8"}, false, "191.1.0.255", false}, |
|
||||
{[]string{"192.168.1.0/8"}, true, "191.1.0.255", true}, |
|
||||
{[]string{"192.168.1.0/16"}, false, "192.168.0.255", true}, |
|
||||
{[]string{"192.168.1.0/16"}, true, "192.168.0.255", false}, |
|
||||
{[]string{"192.168.1.0/16"}, false, "192.0.1.255", false}, |
|
||||
{[]string{"192.168.1.0/16"}, true, "192.0.0.255", true}, |
|
||||
{[]string{"192.168.1.0/24"}, false, "192.168.1.255", true}, |
|
||||
{[]string{"192.168.1.0/24"}, true, "192.168.1.255", false}, |
|
||||
{[]string{"192.168.1.0/24"}, false, "192.168.0.255", false}, |
|
||||
{[]string{"192.168.1.0/24"}, true, "192.168.0.255", true}, |
|
||||
{[]string{"192.168.1.1/32"}, false, "192.168.1.1", true}, |
|
||||
{[]string{"192.168.1.1/32"}, true, "192.168.1.1", false}, |
|
||||
{[]string{"192.168.1.1/32"}, false, "192.168.1.2", false}, |
|
||||
{[]string{"192.168.1.1/32"}, true, "192.168.1.2", true}, |
|
||||
|
|
||||
// plain domain
|
|
||||
{[]string{"www.example.com"}, false, "www.example.com", true}, |
|
||||
{[]string{"www.example.com"}, true, "www.example.com", false}, |
|
||||
{[]string{"http://www.example.com"}, false, "http://www.example.com", true}, |
|
||||
{[]string{"http://www.example.com"}, true, "http://www.example.com", false}, |
|
||||
{[]string{"http://www.example.com"}, false, "http://example.com", false}, |
|
||||
{[]string{"http://www.example.com"}, true, "http://example.com", true}, |
|
||||
{[]string{"www.example.com"}, false, "example.com", false}, |
|
||||
{[]string{"www.example.com"}, true, "example.com", true}, |
|
||||
|
|
||||
// host:port
|
|
||||
{[]string{"192.168.1.1"}, false, "192.168.1.1:80", true}, |
|
||||
{[]string{"192.168.1.1"}, true, "192.168.1.1:80", false}, |
|
||||
{[]string{"192.168.1.1:80"}, false, "192.168.1.1", false}, |
|
||||
{[]string{"192.168.1.1:80"}, true, "192.168.1.1", true}, |
|
||||
{[]string{"192.168.1.1:80"}, false, "192.168.1.1:80", false}, |
|
||||
{[]string{"192.168.1.1:80"}, true, "192.168.1.1:80", true}, |
|
||||
{[]string{"192.168.1.1:80"}, false, "192.168.1.1:8080", false}, |
|
||||
{[]string{"192.168.1.1:80"}, true, "192.168.1.1:8080", true}, |
|
||||
|
|
||||
{[]string{"example.com"}, false, "example.com:80", true}, |
|
||||
{[]string{"example.com"}, true, "example.com:80", false}, |
|
||||
{[]string{"example.com:80"}, false, "example.com", false}, |
|
||||
{[]string{"example.com:80"}, true, "example.com", true}, |
|
||||
{[]string{"example.com:80"}, false, "example.com:80", false}, |
|
||||
{[]string{"example.com:80"}, true, "example.com:80", true}, |
|
||||
{[]string{"example.com:80"}, false, "example.com:8080", false}, |
|
||||
{[]string{"example.com:80"}, true, "example.com:8080", true}, |
|
||||
|
|
||||
// domain wildcard
|
|
||||
|
|
||||
{[]string{"*"}, false, "", false}, |
|
||||
{[]string{"*"}, false, "192.168.1.1", true}, |
|
||||
{[]string{"*"}, false, "192.168.0.0/16", true}, |
|
||||
{[]string{"*"}, false, "http://example.com", true}, |
|
||||
{[]string{"*"}, false, "example.com:80", true}, |
|
||||
{[]string{"*"}, true, "", false}, |
|
||||
{[]string{"*"}, true, "192.168.1.1", false}, |
|
||||
{[]string{"*"}, true, "192.168.0.0/16", false}, |
|
||||
{[]string{"*"}, true, "http://example.com", false}, |
|
||||
{[]string{"*"}, true, "example.com:80", false}, |
|
||||
|
|
||||
// sub-domain
|
|
||||
{[]string{"*.example.com"}, false, "example.com", false}, |
|
||||
{[]string{"*.example.com"}, false, "http://example.com", false}, |
|
||||
{[]string{"*.example.com"}, false, "www.example.com", true}, |
|
||||
{[]string{"*.example.com"}, false, "http://www.example.com", true}, |
|
||||
{[]string{"*.example.com"}, false, "abc.def.example.com", true}, |
|
||||
|
|
||||
{[]string{"*.*.example.com"}, false, "example.com", false}, |
|
||||
{[]string{"*.*.example.com"}, false, "www.example.com", false}, |
|
||||
{[]string{"*.*.example.com"}, false, "abc.def.example.com", true}, |
|
||||
{[]string{"*.*.example.com"}, false, "abc.def.ghi.example.com", true}, |
|
||||
|
|
||||
{[]string{"**.example.com"}, false, "example.com", false}, |
|
||||
{[]string{"**.example.com"}, false, "www.example.com", true}, |
|
||||
{[]string{"**.example.com"}, false, "abc.def.ghi.example.com", true}, |
|
||||
|
|
||||
// prefix wildcard
|
|
||||
{[]string{"*example.com"}, false, "example.com", true}, |
|
||||
{[]string{"*example.com"}, false, "www.example.com", true}, |
|
||||
{[]string{"*example.com"}, false, "abc.defexample.com", true}, |
|
||||
{[]string{"*example.com"}, false, "abc.def-example.com", true}, |
|
||||
{[]string{"*example.com"}, false, "abc.def.example.com", true}, |
|
||||
{[]string{"*example.com"}, false, "http://www.example.com", true}, |
|
||||
{[]string{"*example.com"}, false, "e-xample.com", false}, |
|
||||
|
|
||||
{[]string{"http://*.example.com"}, false, "example.com", false}, |
|
||||
{[]string{"http://*.example.com"}, false, "http://example.com", false}, |
|
||||
{[]string{"http://*.example.com"}, false, "http://www.example.com", true}, |
|
||||
{[]string{"http://*.example.com"}, false, "https://www.example.com", false}, |
|
||||
{[]string{"http://*.example.com"}, false, "http://abc.def.example.com", true}, |
|
||||
|
|
||||
{[]string{"www.*.com"}, false, "www.example.com", true}, |
|
||||
{[]string{"www.*.com"}, false, "www.abc.def.com", true}, |
|
||||
|
|
||||
{[]string{"www.*.*.com"}, false, "www.example.com", false}, |
|
||||
{[]string{"www.*.*.com"}, false, "www.abc.def.com", true}, |
|
||||
{[]string{"www.*.*.com"}, false, "www.abc.def.ghi.com", true}, |
|
||||
|
|
||||
{[]string{"www.*example*.com"}, false, "www.example.com", true}, |
|
||||
{[]string{"www.*example*.com"}, false, "www.abc.example.def.com", true}, |
|
||||
{[]string{"www.*example*.com"}, false, "www.e-xample.com", false}, |
|
||||
|
|
||||
{[]string{"www.example.*"}, false, "www.example.com", true}, |
|
||||
{[]string{"www.example.*"}, false, "www.example.io", true}, |
|
||||
{[]string{"www.example.*"}, false, "www.example.com.cn", true}, |
|
||||
|
|
||||
{[]string{".example.com"}, false, "www.example.com", true}, |
|
||||
{[]string{".example.com"}, false, "example.com", true}, |
|
||||
{[]string{".example.com"}, false, "www.example.com.cn", false}, |
|
||||
|
|
||||
{[]string{"example.com*"}, false, "example.com", true}, |
|
||||
{[]string{"example.com:*"}, false, "example.com", false}, |
|
||||
{[]string{"example.com:*"}, false, "example.com:80", false}, |
|
||||
{[]string{"example.com:*"}, false, "example.com:8080", false}, |
|
||||
{[]string{"example.com:*"}, false, "example.com:http", true}, |
|
||||
{[]string{"example.com:*"}, false, "http://example.com:80", false}, |
|
||||
|
|
||||
{[]string{"*example.com*"}, false, "example.com:80", true}, |
|
||||
{[]string{"*example.com:*"}, false, "example.com:80", false}, |
|
||||
|
|
||||
{[]string{".example.com:*"}, false, "www.example.com", false}, |
|
||||
{[]string{".example.com:*"}, false, "http://www.example.com", false}, |
|
||||
{[]string{".example.com:*"}, false, "example.com:80", false}, |
|
||||
{[]string{".example.com:*"}, false, "www.example.com:8080", false}, |
|
||||
{[]string{".example.com:*"}, false, "http://www.example.com:80", true}, |
|
||||
} |
|
||||
|
|
||||
func TestBypassContains(t *testing.T) { |
|
||||
for i, tc := range bypassContainTests { |
|
||||
tc := tc |
|
||||
t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) { |
|
||||
bp := NewBypassPatterns(tc.reversed, tc.patterns...) |
|
||||
if bp.Contains(tc.addr) != tc.bypassed { |
|
||||
t.Errorf("#%d test failed: %v, %s", i, tc.patterns, tc.addr) |
|
||||
} |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
var bypassReloadTests = []struct { |
|
||||
r io.Reader |
|
||||
|
|
||||
reversed bool |
|
||||
period time.Duration |
|
||||
|
|
||||
addr string |
|
||||
bypassed bool |
|
||||
stopped bool |
|
||||
}{ |
|
||||
{ |
|
||||
r: nil, |
|
||||
reversed: false, |
|
||||
period: 0, |
|
||||
addr: "192.168.1.1", |
|
||||
bypassed: false, |
|
||||
stopped: false, |
|
||||
}, |
|
||||
{ |
|
||||
r: bytes.NewBufferString(""), |
|
||||
reversed: false, |
|
||||
period: 0, |
|
||||
addr: "192.168.1.1", |
|
||||
bypassed: false, |
|
||||
stopped: false, |
|
||||
}, |
|
||||
{ |
|
||||
r: bytes.NewBufferString("reverse true\nreload 10s"), |
|
||||
reversed: true, |
|
||||
period: 10 * time.Second, |
|
||||
addr: "192.168.1.1", |
|
||||
bypassed: false, |
|
||||
stopped: false, |
|
||||
}, |
|
||||
{ |
|
||||
r: bytes.NewBufferString("reverse false\nreload 10s\n192.168.1.1"), |
|
||||
reversed: false, |
|
||||
period: 10 * time.Second, |
|
||||
addr: "192.168.1.1", |
|
||||
bypassed: true, |
|
||||
stopped: false, |
|
||||
}, |
|
||||
{ |
|
||||
r: bytes.NewBufferString("#reverse true\n#reload 10s\n192.168.0.0/16"), |
|
||||
reversed: false, |
|
||||
period: 0, |
|
||||
addr: "192.168.10.2", |
|
||||
bypassed: true, |
|
||||
stopped: true, |
|
||||
}, |
|
||||
{ |
|
||||
r: bytes.NewBufferString("#reverse true\n#reload 10s\n192.168.1.0/24 #comment"), |
|
||||
reversed: false, |
|
||||
period: 0, |
|
||||
addr: "192.168.10.2", |
|
||||
bypassed: false, |
|
||||
stopped: true, |
|
||||
}, |
|
||||
{ |
|
||||
r: bytes.NewBufferString("reverse false\nreload 10s\n192.168.1.1\n#example.com"), |
|
||||
reversed: false, |
|
||||
period: 10 * time.Second, |
|
||||
addr: "example.com", |
|
||||
bypassed: false, |
|
||||
stopped: false, |
|
||||
}, |
|
||||
{ |
|
||||
r: bytes.NewBufferString("#reverse true\n#reload 10s\n192.168.1.1\n#example.com"), |
|
||||
reversed: false, |
|
||||
period: 0, |
|
||||
addr: "192.168.1.1", |
|
||||
bypassed: true, |
|
||||
stopped: true, |
|
||||
}, |
|
||||
{ |
|
||||
r: bytes.NewBufferString("#reverse true\n#reload 10s\nexample.com #comment"), |
|
||||
reversed: false, |
|
||||
period: 0, |
|
||||
addr: "example.com", |
|
||||
bypassed: true, |
|
||||
stopped: true, |
|
||||
}, |
|
||||
{ |
|
||||
r: bytes.NewBufferString("#reverse true\n#reload 10s\n.example.com"), |
|
||||
reversed: false, |
|
||||
period: 0, |
|
||||
addr: "example.com", |
|
||||
bypassed: true, |
|
||||
stopped: true, |
|
||||
}, |
|
||||
{ |
|
||||
r: bytes.NewBufferString("#reverse true\n#reload 10s\n*.example.com"), |
|
||||
reversed: false, |
|
||||
period: 0, |
|
||||
addr: "example.com", |
|
||||
bypassed: false, |
|
||||
stopped: true, |
|
||||
}, |
|
||||
} |
|
||||
|
|
||||
func TestByapssReload(t *testing.T) { |
|
||||
for i, tc := range bypassReloadTests { |
|
||||
bp := NewBypass(false) |
|
||||
if err := bp.Reload(tc.r); err != nil { |
|
||||
t.Error(err) |
|
||||
} |
|
||||
t.Log(bp.String()) |
|
||||
|
|
||||
if bp.Reversed() != tc.reversed { |
|
||||
t.Errorf("#%d test failed: reversed value should be %v, got %v", |
|
||||
i, tc.reversed, bp.reversed) |
|
||||
} |
|
||||
if bp.Period() != tc.period { |
|
||||
t.Errorf("#%d test failed: period value should be %v, got %v", |
|
||||
i, tc.period, bp.Period()) |
|
||||
} |
|
||||
if bp.Contains(tc.addr) != tc.bypassed { |
|
||||
t.Errorf("#%d test failed: %v, %s", i, bp.reversed, tc.addr) |
|
||||
} |
|
||||
if tc.stopped { |
|
||||
bp.Stop() |
|
||||
if bp.Period() >= 0 { |
|
||||
t.Errorf("period of the stopped reloader should be minus value") |
|
||||
} |
|
||||
bp.Stop() |
|
||||
} |
|
||||
if bp.Stopped() != tc.stopped { |
|
||||
t.Errorf("#%d test failed: stopped value should be %v, got %v", |
|
||||
i, tc.stopped, bp.Stopped()) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,5 @@ |
|||||
|
reload 3s |
||||
|
|
||||
|
reverse true |
||||
|
|
||||
|
.baidu.com |
||||
Loading…
Reference in new issue