move bypass to github.com/go-gost/bypass

This commit is contained in:
ginuerzh 2020-03-26 09:16:45 +08:00
parent de4a896004
commit 4ac048a8a2
17 changed files with 47 additions and 634 deletions

298
bypass.go
View File

@ -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()
}

View File

@ -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())
}
}
}

View File

@ -302,7 +302,7 @@ func (c *Chain) selectRouteFor(addr string) (route *Chain, err error) {
return return
} }
if node.Bypass.Contains(addr) { if node.Bypasser.Bypass(addr) {
break break
} }

5
cmd/gost/bypass.txt Normal file
View File

@ -0,0 +1,5 @@
reload 3s
reverse true
.baidu.com

View File

@ -13,6 +13,7 @@ import (
"strings" "strings"
"github.com/ginuerzh/gost" "github.com/ginuerzh/gost"
"github.com/go-gost/bypass"
"github.com/go-gost/reload" "github.com/go-gost/reload"
) )
@ -175,11 +176,11 @@ func parseIP(s string, port string) (ips []string) {
return return
} }
func parseBypass(s string) *gost.Bypass { func parseBypasser(s string) bypass.Bypasser {
if s == "" { if s == "" {
return nil return nil
} }
var matchers []gost.Matcher var matchers []bypass.Matcher
var reversed bool var reversed bool
if strings.HasPrefix(s, "~") { if strings.HasPrefix(s, "~") {
reversed = true reversed = true
@ -193,15 +194,17 @@ func parseBypass(s string) *gost.Bypass {
if s == "" { if s == "" {
continue 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() defer f.Close()
bp := gost.NewBypass(reversed) bp := bypass.NewBypasser(reversed)
bp.Reload(f) if reloader, ok := bp.(reload.Reloader); ok {
go reload.PeriodReload(bp, s) reloader.Reload(f)
go reload.PeriodReload(reloader, s)
}
return bp return bp
} }

View File

@ -11,6 +11,7 @@ import (
"time" "time"
"github.com/ginuerzh/gost" "github.com/ginuerzh/gost"
"github.com/go-gost/reload"
) )
type peerConfig struct { type peerConfig struct {
@ -74,8 +75,8 @@ func (cfg *peerConfig) Reload(r io.Reader) error {
nodes := group.SetNodes(gNodes...) nodes := group.SetNodes(gNodes...)
for _, node := range nodes[len(cfg.baseNodes):] { for _, node := range nodes[len(cfg.baseNodes):] {
if node.Bypass != nil { if s, ok := node.Bypasser.(reload.Stoppable); ok {
node.Bypass.Stop() // clear the old nodes s.Stop() // clear the old nodes
} }
} }

View File

@ -275,7 +275,7 @@ func parseChainNode(ns string) (nodes []gost.Node, err error) {
Transporter: tr, Transporter: tr,
} }
node.Bypass = parseBypass(node.Get("bypass")) node.Bypasser = parseBypasser(node.Get("bypass"))
ips := parseIP(node.Get("ip"), sport) ips := parseIP(node.Get("ip"), sport)
for _, ip := range ips { 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")) hosts := parseHosts(node.Get("hosts"))
ips := parseIP(node.Get("ip"), "") ips := parseIP(node.Get("ip"), "")
@ -607,7 +607,7 @@ func (r *route) GenRouters() ([]router, error) {
gost.StrategyHandlerOption(gost.NewStrategy(node.Get("strategy"))), gost.StrategyHandlerOption(gost.NewStrategy(node.Get("strategy"))),
gost.MaxFailsHandlerOption(node.GetInt("max_fails")), gost.MaxFailsHandlerOption(node.GetInt("max_fails")),
gost.FailTimeoutHandlerOption(node.GetDuration("fail_timeout")), gost.FailTimeoutHandlerOption(node.GetDuration("fail_timeout")),
gost.BypassHandlerOption(node.Bypass), gost.BypasserHandlerOption(node.Bypasser),
gost.ResolverHandlerOption(resolver), gost.ResolverHandlerOption(resolver),
gost.HostsHandlerOption(hosts), gost.HostsHandlerOption(hosts),
gost.RetryHandlerOption(node.GetInt("retry")), // override the global retry option. gost.RetryHandlerOption(node.GetInt("retry")), // override the global retry option.

2
go.mod
View File

@ -16,10 +16,10 @@ require (
github.com/ginuerzh/gosocks5 v0.2.0 github.com/ginuerzh/gosocks5 v0.2.0
github.com/ginuerzh/tls-dissector v0.0.2-0.20200224064855-24ab2b3a3796 github.com/ginuerzh/tls-dissector v0.0.2-0.20200224064855-24ab2b3a3796
github.com/go-gost/bpool v1.0.0 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/log v1.0.0
github.com/go-gost/relay v0.1.0 github.com/go-gost/relay v0.1.0
github.com/go-gost/reload v1.0.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/golang/mock v1.2.0 // indirect
github.com/google/gopacket v1.1.17 // indirect github.com/google/gopacket v1.1.17 // indirect
github.com/gorilla/websocket v1.4.0 // indirect github.com/gorilla/websocket v1.4.0 // indirect

2
go.sum
View File

@ -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/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 h1:Og+6SH6SooHqf8CIwuxcPRHq8k0Si4YEfO2mBEi3/Uk=
github.com/go-gost/bpool v1.0.0/go.mod h1:y/Pywm22A4OrJqNF/mL4nW7yb9fCdhlO8cxjyparkFI= 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 h1:maSjjMvQqLSQYb0Ta5nJTdlRI+aiLMt6WIBYVxajJgs=
github.com/go-gost/log v1.0.0/go.mod h1:FCOaaJQ7moHTlLxYk7dsFewlS68U9A1GG3OR+yXkF6s= github.com/go-gost/log v1.0.0/go.mod h1:FCOaaJQ7moHTlLxYk7dsFewlS68U9A1GG3OR+yXkF6s=
github.com/go-gost/relay v0.1.0 h1:UOf2YwAzzaUjY5mdpMuLfSw0vz62iIFYk7oJQkuhlGw= github.com/go-gost/relay v0.1.0 h1:UOf2YwAzzaUjY5mdpMuLfSw0vz62iIFYk7oJQkuhlGw=

View File

@ -9,6 +9,7 @@ import (
"github.com/ginuerzh/gosocks4" "github.com/ginuerzh/gosocks4"
"github.com/ginuerzh/gosocks5" "github.com/ginuerzh/gosocks5"
"github.com/go-gost/bypass"
"github.com/go-gost/log" "github.com/go-gost/log"
) )
@ -30,7 +31,7 @@ type HandlerOptions struct {
Strategy Strategy Strategy Strategy
MaxFails int MaxFails int
FailTimeout time.Duration FailTimeout time.Duration
Bypass *Bypass Bypasser bypass.Bypasser
Retries int Retries int
Timeout time.Duration Timeout time.Duration
Resolver Resolver Resolver Resolver
@ -107,9 +108,9 @@ func BlacklistHandlerOption(blacklist *Permissions) HandlerOption {
} }
// BypassHandlerOption sets the bypass option of HandlerOptions. // BypassHandlerOption sets the bypass option of HandlerOptions.
func BypassHandlerOption(bypass *Bypass) HandlerOption { func BypasserHandlerOption(bypasser bypass.Bypasser) HandlerOption {
return func(opts *HandlerOptions) { return func(opts *HandlerOptions) {
opts.Bypass = bypass opts.Bypasser = bypasser
} }
} }

View File

@ -189,7 +189,7 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) {
return return
} }
if h.options.Bypass.Contains(host) { if h.options.Bypasser.Bypass(host) {
resp.StatusCode = http.StatusForbidden resp.StatusCode = http.StatusForbidden
log.Logf("[http] %s - %s bypass %s", log.Logf("[http] %s - %s bypass %s",

View File

@ -374,7 +374,7 @@ func (h *http2Handler) roundTrip(w http.ResponseWriter, r *http.Request) {
return return
} }
if h.options.Bypass.Contains(host) { if h.options.Bypasser.Bypass(host) {
log.Logf("[http2] %s - %s bypass %s", log.Logf("[http2] %s - %s bypass %s",
r.RemoteAddr, laddr, host) r.RemoteAddr, laddr, host)
w.WriteHeader(http.StatusForbidden) w.WriteHeader(http.StatusForbidden)

View File

@ -8,6 +8,8 @@ import (
"strings" "strings"
"sync" "sync"
"time" "time"
"github.com/go-gost/bypass"
) )
var ( var (
@ -31,7 +33,7 @@ type Node struct {
ConnectOptions []ConnectOption ConnectOptions []ConnectOption
Client *Client Client *Client
marker *failMarker marker *failMarker
Bypass *Bypass Bypasser bypass.Bypasser
} }
// ParseNode parses the node info. // ParseNode parses the node info.

2
sni.go
View File

@ -113,7 +113,7 @@ func (h *sniHandler) Handle(conn net.Conn) {
conn.RemoteAddr(), conn.LocalAddr(), host) conn.RemoteAddr(), conn.LocalAddr(), host)
return return
} }
if h.options.Bypass.Contains(host) { if h.options.Bypasser.Bypass(host) {
log.Log("[sni] %s - %s bypass %s", log.Log("[sni] %s - %s bypass %s",
conn.RemoteAddr(), conn.LocalAddr(), host) conn.RemoteAddr(), conn.LocalAddr(), host)
return return

View File

@ -900,7 +900,7 @@ func (h *socks5Handler) handleConnect(conn net.Conn, req *gosocks5.Request) {
} }
return return
} }
if h.options.Bypass.Contains(host) { if h.options.Bypasser.Bypass(host) {
log.Logf("[socks5] %s - %s : Bypass %s", log.Logf("[socks5] %s - %s : Bypass %s",
conn.RemoteAddr(), conn.LocalAddr(), host) conn.RemoteAddr(), conn.LocalAddr(), host)
rep := gosocks5.NewReply(gosocks5.NotAllowed, nil) rep := gosocks5.NewReply(gosocks5.NotAllowed, nil)
@ -1261,7 +1261,7 @@ func (h *socks5Handler) transportUDP(relay, peer net.PacketConn) (err error) {
if err != nil { if err != nil {
continue // drop silently 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) log.Log("[socks5-udp] [bypass] write to", raddr)
continue // bypass continue // bypass
} }
@ -1288,7 +1288,7 @@ func (h *socks5Handler) transportUDP(relay, peer net.PacketConn) (err error) {
if clientAddr == nil { if clientAddr == nil {
continue continue
} }
if h.options.Bypass.Contains(raddr.String()) { if h.options.Bypasser.Bypass(raddr.String()) {
log.Log("[socks5-udp] [bypass] read from", raddr) log.Log("[socks5-udp] [bypass] read from", raddr)
continue // bypass continue // bypass
} }
@ -1341,7 +1341,7 @@ func (h *socks5Handler) tunnelClientUDP(uc *net.UDPConn, cc net.Conn) (err error
clientAddr = addr clientAddr = addr
} }
raddr := dgram.Header.Addr.String() 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) log.Log("[udp-tun] [bypass] write to", raddr)
continue // bypass continue // bypass
} }
@ -1370,7 +1370,7 @@ func (h *socks5Handler) tunnelClientUDP(uc *net.UDPConn, cc net.Conn) (err error
continue continue
} }
raddr := dgram.Header.Addr.String() 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) log.Log("[udp-tun] [bypass] read from", raddr)
continue // bypass continue // bypass
} }
@ -1469,7 +1469,7 @@ func (h *socks5Handler) tunnelServerUDP(cc net.Conn, pc net.PacketConn) (err err
errc <- err errc <- err
return return
} }
if h.options.Bypass.Contains(addr.String()) { if h.options.Bypasser.Bypass(addr.String()) {
log.Log("[socks5] udp-tun bypass read from", addr) log.Log("[socks5] udp-tun bypass read from", addr)
continue // bypass continue // bypass
} }
@ -1502,7 +1502,7 @@ func (h *socks5Handler) tunnelServerUDP(cc net.Conn, pc net.PacketConn) (err err
if err != nil { if err != nil {
continue // drop silently 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) log.Log("[socks5] udp-tun bypass write to", addr)
continue // bypass continue // bypass
} }
@ -1715,7 +1715,7 @@ func (h *socks4Handler) handleConnect(conn net.Conn, req *gosocks4.Request) {
} }
return return
} }
if h.options.Bypass.Contains(addr) { if h.options.Bypasser.Bypass(addr) {
log.Log("[socks4] %s - %s : Bypass %s", log.Log("[socks4] %s - %s : Bypass %s",
conn.RemoteAddr(), conn.LocalAddr(), addr) conn.RemoteAddr(), conn.LocalAddr(), addr)
rep := gosocks4.NewReply(gosocks4.Rejected, nil) rep := gosocks4.NewReply(gosocks4.Rejected, nil)

6
ss.go
View File

@ -149,7 +149,7 @@ func (h *shadowHandler) Handle(conn net.Conn) {
return return
} }
if h.options.Bypass.Contains(host) { if h.options.Bypasser.Bypass(host) {
log.Logf("[ss] %s - %s : Bypass %s", log.Logf("[ss] %s - %s : Bypass %s",
conn.RemoteAddr(), conn.LocalAddr(), host) conn.RemoteAddr(), conn.LocalAddr(), host)
return return
@ -435,7 +435,7 @@ func (h *shadowUDPHandler) transportUDP(conn net.Conn, cc net.PacketConn) error
if err != nil { if err != nil {
return return
} }
if h.options.Bypass.Contains(addr.String()) { if h.options.Bypasser.Bypass(addr.String()) {
log.Log("[ssu] bypass", addr) log.Log("[ssu] bypass", addr)
return // bypass return // bypass
} }
@ -463,7 +463,7 @@ func (h *shadowUDPHandler) transportUDP(conn net.Conn, cc net.PacketConn) error
if Debug { if Debug {
log.Logf("[ssu] %s <<< %s length: %d", conn.RemoteAddr(), addr, n) 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) log.Log("[ssu] bypass", addr)
return // bypass return // bypass
} }

2
ssh.go
View File

@ -608,7 +608,7 @@ func (h *sshForwardHandler) directPortForwardChannel(channel ssh.Channel, raddr
return return
} }
if h.options.Bypass.Contains(raddr) { if h.options.Bypasser.Bypass(raddr) {
log.Logf("[ssh-tcp] [bypass] %s", raddr) log.Logf("[ssh-tcp] [bypass] %s", raddr)
return return
} }