move bypass to github.com/go-gost/bypass
This commit is contained in:
parent
de4a896004
commit
4ac048a8a2
298
bypass.go
298
bypass.go
@ -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()
|
||||
}
|
303
bypass_test.go
303
bypass_test.go
@ -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())
|
||||
}
|
||||
}
|
||||
}
|
2
chain.go
2
chain.go
@ -302,7 +302,7 @@ func (c *Chain) selectRouteFor(addr string) (route *Chain, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
if node.Bypass.Contains(addr) {
|
||||
if node.Bypasser.Bypass(addr) {
|
||||
break
|
||||
}
|
||||
|
||||
|
5
cmd/gost/bypass.txt
Normal file
5
cmd/gost/bypass.txt
Normal file
@ -0,0 +1,5 @@
|
||||
reload 3s
|
||||
|
||||
reverse true
|
||||
|
||||
.baidu.com
|
@ -13,6 +13,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/ginuerzh/gost"
|
||||
"github.com/go-gost/bypass"
|
||||
"github.com/go-gost/reload"
|
||||
)
|
||||
|
||||
@ -175,11 +176,11 @@ func parseIP(s string, port string) (ips []string) {
|
||||
return
|
||||
}
|
||||
|
||||
func parseBypass(s string) *gost.Bypass {
|
||||
func parseBypasser(s string) bypass.Bypasser {
|
||||
if s == "" {
|
||||
return nil
|
||||
}
|
||||
var matchers []gost.Matcher
|
||||
var matchers []bypass.Matcher
|
||||
var reversed bool
|
||||
if strings.HasPrefix(s, "~") {
|
||||
reversed = true
|
||||
@ -193,15 +194,17 @@ func parseBypass(s string) *gost.Bypass {
|
||||
if s == "" {
|
||||
continue
|
||||
}
|
||||
matchers = append(matchers, gost.NewMatcher(s))
|
||||
matchers = append(matchers, bypass.NewMatcher(s))
|
||||
}
|
||||
return gost.NewBypass(reversed, matchers...)
|
||||
return bypass.NewBypasser(reversed, matchers...)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
bp := gost.NewBypass(reversed)
|
||||
bp.Reload(f)
|
||||
go reload.PeriodReload(bp, s)
|
||||
bp := bypass.NewBypasser(reversed)
|
||||
if reloader, ok := bp.(reload.Reloader); ok {
|
||||
reloader.Reload(f)
|
||||
go reload.PeriodReload(reloader, s)
|
||||
}
|
||||
|
||||
return bp
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ginuerzh/gost"
|
||||
"github.com/go-gost/reload"
|
||||
)
|
||||
|
||||
type peerConfig struct {
|
||||
@ -74,8 +75,8 @@ func (cfg *peerConfig) Reload(r io.Reader) error {
|
||||
|
||||
nodes := group.SetNodes(gNodes...)
|
||||
for _, node := range nodes[len(cfg.baseNodes):] {
|
||||
if node.Bypass != nil {
|
||||
node.Bypass.Stop() // clear the old nodes
|
||||
if s, ok := node.Bypasser.(reload.Stoppable); ok {
|
||||
s.Stop() // clear the old nodes
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -275,7 +275,7 @@ func parseChainNode(ns string) (nodes []gost.Node, err error) {
|
||||
Transporter: tr,
|
||||
}
|
||||
|
||||
node.Bypass = parseBypass(node.Get("bypass"))
|
||||
node.Bypasser = parseBypasser(node.Get("bypass"))
|
||||
|
||||
ips := parseIP(node.Get("ip"), sport)
|
||||
for _, ip := range ips {
|
||||
@ -581,7 +581,7 @@ func (r *route) GenRouters() ([]router, error) {
|
||||
}
|
||||
}
|
||||
|
||||
node.Bypass = parseBypass(node.Get("bypass"))
|
||||
node.Bypasser = parseBypasser(node.Get("bypass"))
|
||||
hosts := parseHosts(node.Get("hosts"))
|
||||
ips := parseIP(node.Get("ip"), "")
|
||||
|
||||
@ -607,7 +607,7 @@ func (r *route) GenRouters() ([]router, error) {
|
||||
gost.StrategyHandlerOption(gost.NewStrategy(node.Get("strategy"))),
|
||||
gost.MaxFailsHandlerOption(node.GetInt("max_fails")),
|
||||
gost.FailTimeoutHandlerOption(node.GetDuration("fail_timeout")),
|
||||
gost.BypassHandlerOption(node.Bypass),
|
||||
gost.BypasserHandlerOption(node.Bypasser),
|
||||
gost.ResolverHandlerOption(resolver),
|
||||
gost.HostsHandlerOption(hosts),
|
||||
gost.RetryHandlerOption(node.GetInt("retry")), // override the global retry option.
|
||||
|
2
go.mod
2
go.mod
@ -16,10 +16,10 @@ require (
|
||||
github.com/ginuerzh/gosocks5 v0.2.0
|
||||
github.com/ginuerzh/tls-dissector v0.0.2-0.20200224064855-24ab2b3a3796
|
||||
github.com/go-gost/bpool v1.0.0
|
||||
github.com/go-gost/bypass v1.0.0
|
||||
github.com/go-gost/log v1.0.0
|
||||
github.com/go-gost/relay v0.1.0
|
||||
github.com/go-gost/reload v1.0.0
|
||||
github.com/gobwas/glob v0.2.3
|
||||
github.com/golang/mock v1.2.0 // indirect
|
||||
github.com/google/gopacket v1.1.17 // indirect
|
||||
github.com/gorilla/websocket v1.4.0 // indirect
|
||||
|
2
go.sum
2
go.sum
@ -31,6 +31,8 @@ github.com/ginuerzh/tls-dissector v0.0.2-0.20200224064855-24ab2b3a3796 h1:VPXbYR
|
||||
github.com/ginuerzh/tls-dissector v0.0.2-0.20200224064855-24ab2b3a3796/go.mod h1:YyzP8PQrGwDH/XsfHJXwqdHLwWvBYxu77YVKm0+68f0=
|
||||
github.com/go-gost/bpool v1.0.0 h1:Og+6SH6SooHqf8CIwuxcPRHq8k0Si4YEfO2mBEi3/Uk=
|
||||
github.com/go-gost/bpool v1.0.0/go.mod h1:y/Pywm22A4OrJqNF/mL4nW7yb9fCdhlO8cxjyparkFI=
|
||||
github.com/go-gost/bypass v1.0.0 h1:ZhLzA3WY9JDxmpyuGwVUH0ubaFOmWWzNpejzwExvhMA=
|
||||
github.com/go-gost/bypass v1.0.0/go.mod h1:r2MYlxn1/fs24NFs+h/m9HiZKfckBrTnONXklxRUwcE=
|
||||
github.com/go-gost/log v1.0.0 h1:maSjjMvQqLSQYb0Ta5nJTdlRI+aiLMt6WIBYVxajJgs=
|
||||
github.com/go-gost/log v1.0.0/go.mod h1:FCOaaJQ7moHTlLxYk7dsFewlS68U9A1GG3OR+yXkF6s=
|
||||
github.com/go-gost/relay v0.1.0 h1:UOf2YwAzzaUjY5mdpMuLfSw0vz62iIFYk7oJQkuhlGw=
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/ginuerzh/gosocks4"
|
||||
"github.com/ginuerzh/gosocks5"
|
||||
"github.com/go-gost/bypass"
|
||||
"github.com/go-gost/log"
|
||||
)
|
||||
|
||||
@ -30,7 +31,7 @@ type HandlerOptions struct {
|
||||
Strategy Strategy
|
||||
MaxFails int
|
||||
FailTimeout time.Duration
|
||||
Bypass *Bypass
|
||||
Bypasser bypass.Bypasser
|
||||
Retries int
|
||||
Timeout time.Duration
|
||||
Resolver Resolver
|
||||
@ -107,9 +108,9 @@ func BlacklistHandlerOption(blacklist *Permissions) HandlerOption {
|
||||
}
|
||||
|
||||
// BypassHandlerOption sets the bypass option of HandlerOptions.
|
||||
func BypassHandlerOption(bypass *Bypass) HandlerOption {
|
||||
func BypasserHandlerOption(bypasser bypass.Bypasser) HandlerOption {
|
||||
return func(opts *HandlerOptions) {
|
||||
opts.Bypass = bypass
|
||||
opts.Bypasser = bypasser
|
||||
}
|
||||
}
|
||||
|
||||
|
2
http.go
2
http.go
@ -189,7 +189,7 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if h.options.Bypass.Contains(host) {
|
||||
if h.options.Bypasser.Bypass(host) {
|
||||
resp.StatusCode = http.StatusForbidden
|
||||
|
||||
log.Logf("[http] %s - %s bypass %s",
|
||||
|
2
http2.go
2
http2.go
@ -374,7 +374,7 @@ func (h *http2Handler) roundTrip(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if h.options.Bypass.Contains(host) {
|
||||
if h.options.Bypasser.Bypass(host) {
|
||||
log.Logf("[http2] %s - %s bypass %s",
|
||||
r.RemoteAddr, laddr, host)
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
|
4
node.go
4
node.go
@ -8,6 +8,8 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/go-gost/bypass"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -31,7 +33,7 @@ type Node struct {
|
||||
ConnectOptions []ConnectOption
|
||||
Client *Client
|
||||
marker *failMarker
|
||||
Bypass *Bypass
|
||||
Bypasser bypass.Bypasser
|
||||
}
|
||||
|
||||
// ParseNode parses the node info.
|
||||
|
2
sni.go
2
sni.go
@ -113,7 +113,7 @@ func (h *sniHandler) Handle(conn net.Conn) {
|
||||
conn.RemoteAddr(), conn.LocalAddr(), host)
|
||||
return
|
||||
}
|
||||
if h.options.Bypass.Contains(host) {
|
||||
if h.options.Bypasser.Bypass(host) {
|
||||
log.Log("[sni] %s - %s bypass %s",
|
||||
conn.RemoteAddr(), conn.LocalAddr(), host)
|
||||
return
|
||||
|
16
socks.go
16
socks.go
@ -900,7 +900,7 @@ func (h *socks5Handler) handleConnect(conn net.Conn, req *gosocks5.Request) {
|
||||
}
|
||||
return
|
||||
}
|
||||
if h.options.Bypass.Contains(host) {
|
||||
if h.options.Bypasser.Bypass(host) {
|
||||
log.Logf("[socks5] %s - %s : Bypass %s",
|
||||
conn.RemoteAddr(), conn.LocalAddr(), host)
|
||||
rep := gosocks5.NewReply(gosocks5.NotAllowed, nil)
|
||||
@ -1261,7 +1261,7 @@ func (h *socks5Handler) transportUDP(relay, peer net.PacketConn) (err error) {
|
||||
if err != nil {
|
||||
continue // drop silently
|
||||
}
|
||||
if h.options.Bypass.Contains(raddr.String()) {
|
||||
if h.options.Bypasser.Bypass(raddr.String()) {
|
||||
log.Log("[socks5-udp] [bypass] write to", raddr)
|
||||
continue // bypass
|
||||
}
|
||||
@ -1288,7 +1288,7 @@ func (h *socks5Handler) transportUDP(relay, peer net.PacketConn) (err error) {
|
||||
if clientAddr == nil {
|
||||
continue
|
||||
}
|
||||
if h.options.Bypass.Contains(raddr.String()) {
|
||||
if h.options.Bypasser.Bypass(raddr.String()) {
|
||||
log.Log("[socks5-udp] [bypass] read from", raddr)
|
||||
continue // bypass
|
||||
}
|
||||
@ -1341,7 +1341,7 @@ func (h *socks5Handler) tunnelClientUDP(uc *net.UDPConn, cc net.Conn) (err error
|
||||
clientAddr = addr
|
||||
}
|
||||
raddr := dgram.Header.Addr.String()
|
||||
if h.options.Bypass.Contains(raddr) {
|
||||
if h.options.Bypasser.Bypass(raddr) {
|
||||
log.Log("[udp-tun] [bypass] write to", raddr)
|
||||
continue // bypass
|
||||
}
|
||||
@ -1370,7 +1370,7 @@ func (h *socks5Handler) tunnelClientUDP(uc *net.UDPConn, cc net.Conn) (err error
|
||||
continue
|
||||
}
|
||||
raddr := dgram.Header.Addr.String()
|
||||
if h.options.Bypass.Contains(raddr) {
|
||||
if h.options.Bypasser.Bypass(raddr) {
|
||||
log.Log("[udp-tun] [bypass] read from", raddr)
|
||||
continue // bypass
|
||||
}
|
||||
@ -1469,7 +1469,7 @@ func (h *socks5Handler) tunnelServerUDP(cc net.Conn, pc net.PacketConn) (err err
|
||||
errc <- err
|
||||
return
|
||||
}
|
||||
if h.options.Bypass.Contains(addr.String()) {
|
||||
if h.options.Bypasser.Bypass(addr.String()) {
|
||||
log.Log("[socks5] udp-tun bypass read from", addr)
|
||||
continue // bypass
|
||||
}
|
||||
@ -1502,7 +1502,7 @@ func (h *socks5Handler) tunnelServerUDP(cc net.Conn, pc net.PacketConn) (err err
|
||||
if err != nil {
|
||||
continue // drop silently
|
||||
}
|
||||
if h.options.Bypass.Contains(addr.String()) {
|
||||
if h.options.Bypasser.Bypass(addr.String()) {
|
||||
log.Log("[socks5] udp-tun bypass write to", addr)
|
||||
continue // bypass
|
||||
}
|
||||
@ -1715,7 +1715,7 @@ func (h *socks4Handler) handleConnect(conn net.Conn, req *gosocks4.Request) {
|
||||
}
|
||||
return
|
||||
}
|
||||
if h.options.Bypass.Contains(addr) {
|
||||
if h.options.Bypasser.Bypass(addr) {
|
||||
log.Log("[socks4] %s - %s : Bypass %s",
|
||||
conn.RemoteAddr(), conn.LocalAddr(), addr)
|
||||
rep := gosocks4.NewReply(gosocks4.Rejected, nil)
|
||||
|
6
ss.go
6
ss.go
@ -149,7 +149,7 @@ func (h *shadowHandler) Handle(conn net.Conn) {
|
||||
return
|
||||
}
|
||||
|
||||
if h.options.Bypass.Contains(host) {
|
||||
if h.options.Bypasser.Bypass(host) {
|
||||
log.Logf("[ss] %s - %s : Bypass %s",
|
||||
conn.RemoteAddr(), conn.LocalAddr(), host)
|
||||
return
|
||||
@ -435,7 +435,7 @@ func (h *shadowUDPHandler) transportUDP(conn net.Conn, cc net.PacketConn) error
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if h.options.Bypass.Contains(addr.String()) {
|
||||
if h.options.Bypasser.Bypass(addr.String()) {
|
||||
log.Log("[ssu] bypass", addr)
|
||||
return // bypass
|
||||
}
|
||||
@ -463,7 +463,7 @@ func (h *shadowUDPHandler) transportUDP(conn net.Conn, cc net.PacketConn) error
|
||||
if Debug {
|
||||
log.Logf("[ssu] %s <<< %s length: %d", conn.RemoteAddr(), addr, n)
|
||||
}
|
||||
if h.options.Bypass.Contains(addr.String()) {
|
||||
if h.options.Bypasser.Bypass(addr.String()) {
|
||||
log.Log("[ssu] bypass", addr)
|
||||
return // bypass
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user