diff --git a/cmd/sower/main.go b/cmd/sower/main.go index d7b5881..6c8b713 100644 --- a/cmd/sower/main.go +++ b/cmd/sower/main.go @@ -18,7 +18,7 @@ import ( "github.com/cristalhq/aconfig/aconfigyaml" "github.com/miekg/dns" "github.com/pkg/errors" - "github.com/wweir/deferlog/log" + "github.com/sower-proxy/deferlog/log" "github.com/wweir/sower/router" ) diff --git a/cmd/sower/proxy.go b/cmd/sower/proxy.go index b647d8b..1d095bd 100644 --- a/cmd/sower/proxy.go +++ b/cmd/sower/proxy.go @@ -8,14 +8,14 @@ import ( "time" "github.com/pkg/errors" - "github.com/wweir/deferlog/log" - "github.com/wweir/sower/pkg/teeconn" + "github.com/sower-proxy/conns/relay" + "github.com/sower-proxy/conns/teeconn" + "github.com/sower-proxy/deferlog/log" "github.com/wweir/sower/router" "github.com/wweir/sower/transport" "github.com/wweir/sower/transport/socks5" "github.com/wweir/sower/transport/sower" "github.com/wweir/sower/transport/trojan" - "github.com/wweir/sower/util" ) func GenProxyDial(proxyType, proxyHost, proxyPassword string) router.ProxyDialFn { @@ -97,7 +97,7 @@ func ServeHTTP(ln net.Listener, r *router.Router) { defer rc.Close() teeconn.Stop().Reread() - util.Relay(teeconn, rc) + relay.Relay(teeconn, rc) log.Debug(). Str("host", req.Host). Dur("spend", time.Since(start)). @@ -134,7 +134,7 @@ func ServeHTTPS(ln net.Listener, r *router.Router) { defer rc.Close() teeconn.Stop().Reread() - util.Relay(teeconn, rc) + relay.Relay(teeconn, rc) log.Debug(). Str("host", domain). Dur("spend", time.Since(start)). diff --git a/cmd/sowerd/main.go b/cmd/sowerd/main.go index cedb2d0..1615f5a 100644 --- a/cmd/sowerd/main.go +++ b/cmd/sowerd/main.go @@ -9,12 +9,12 @@ import ( "time" "github.com/cristalhq/aconfig" - "github.com/wweir/deferlog" - "github.com/wweir/deferlog/log" - "github.com/wweir/sower/pkg/teeconn" + "github.com/sower-proxy/conns/relay" + "github.com/sower-proxy/conns/teeconn" + "github.com/sower-proxy/deferlog" + "github.com/sower-proxy/deferlog/log" "github.com/wweir/sower/transport/sower" "github.com/wweir/sower/transport/trojan" - "github.com/wweir/sower/util" "golang.org/x/crypto/acme/autocert" ) @@ -124,7 +124,7 @@ func serve443(ln net.Listener, fakeSite string, sower *sower.Sower, trojan *troj if addr, err = sower.Unwrap(teeconn); err == nil { teeconn.Stop() - dur, err = util.RelayTo(teeconn, addr.String()) + dur, err = relay.RelayTo(teeconn, addr.String()) return } @@ -133,11 +133,11 @@ func serve443(ln net.Listener, fakeSite string, sower *sower.Sower, trojan *troj if addr, err = trojan.Unwrap(teeconn); err == nil { teeconn.Stop() - dur, err = util.RelayTo(teeconn, addr.String()) + dur, err = relay.RelayTo(teeconn, addr.String()) return } // 3. fallback to fake site teeconn.Stop().Reread() - dur, err = util.RelayTo(teeconn, fakeSite) + dur, err = relay.RelayTo(teeconn, fakeSite) } diff --git a/go.mod b/go.mod index 3eaa3c1..d887721 100644 --- a/go.mod +++ b/go.mod @@ -12,8 +12,9 @@ require ( github.com/miekg/dns v1.1.43 github.com/oschwald/geoip2-golang v1.5.0 github.com/pkg/errors v0.9.1 - github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6 - github.com/wweir/deferlog v1.0.0 + github.com/sower-proxy/conns v0.0.1 + github.com/sower-proxy/deferlog v1.0.1 + github.com/sower-proxy/mem v0.0.1 golang.org/x/crypto v0.0.0-20211202192323-5770296d904e ) @@ -22,6 +23,7 @@ require ( github.com/hashicorp/hcl v1.0.0 // indirect github.com/oschwald/maxminddb-golang v1.8.0 // indirect github.com/rs/zerolog v1.26.0 // indirect + github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6 // indirect golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e // indirect golang.org/x/text v0.3.6 // indirect diff --git a/go.sum b/go.sum index 03c3300..b24b269 100644 --- a/go.sum +++ b/go.sum @@ -33,14 +33,18 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.26.0 h1:ORM4ibhEZeTeQlCojCK2kPz1ogAY4bGs4tD+SaAdGaE= github.com/rs/zerolog v1.26.0/go.mod h1:yBiM87lvSqX8h0Ww4sdzNSkVYZ8dL2xjZJG1lAuGZEo= +github.com/sower-proxy/conns v0.0.1 h1:8tKWQR+nEEH0UBfFSz4M7HAhFFf/o9rQZ/6I0yWjXE8= +github.com/sower-proxy/conns v0.0.1/go.mod h1:jpifOR3jj9HFTE3wXd6sKdd778ZaRC/zoLKkdtvXNB8= +github.com/sower-proxy/deferlog v1.0.1 h1:ZRMpB3BOt0tpGiRIPKzg4/1kQ9UGZWgVM3sA1kAmW+c= +github.com/sower-proxy/deferlog v1.0.1/go.mod h1:wd8Yxz45ZbCgzXEafgDCj7XLlcqYUoEoLyiP1NQOUMk= +github.com/sower-proxy/mem v0.0.1 h1:z5Mde14Bf+NNP4wbZwQ1noMf5XzEmWH7o05FhfSJEWA= +github.com/sower-proxy/mem v0.0.1/go.mod h1:/VJ8gxzVmxqKrjSX41Ye0I9ynnueamcjhFIZGwe0/tg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6 h1:TtyC78WMafNW8QFfv3TeP3yWNDG+uxNkk9vOrnDu6JA= github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6/go.mod h1:h8272+G2omSmi30fBXiZDMkmHuOgonplfKIKjQWzlfs= -github.com/wweir/deferlog v1.0.0 h1:rARp+N6FGQeGiN9Ufoty8y8lBchldeOCgmEmPjIV8Ss= -github.com/wweir/deferlog v1.0.0/go.mod h1:MnYQMIry5XfHBVK/qh1TPMDd/YY4izq3OxboMFXdHrg= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= diff --git a/pkg/mem/mem.go b/pkg/mem/mem.go deleted file mode 100644 index c101bd0..0000000 --- a/pkg/mem/mem.go +++ /dev/null @@ -1,139 +0,0 @@ -package mem - -import ( - "errors" - "reflect" - "sync" - "time" - - "github.com/ulule/deepcopier" -) - -// Data define the type which can speed up by mem cache -type Data interface { - Fulfill(key string) (err error) -} - -// Cache is the definition of cache, be careful of the memory usage -type Cache struct { - old *sync.Map - now *sync.Map - barrier *sync.Map - rotate <-chan time.Time - rwmutex *sync.RWMutex -} - -// DefaultCache is default cache for surge -var DefaultCache = New(time.Minute) - -// Remember is a surge, it provides a quite simple way to use cache -func Remember(dst Data, key string) error { - return DefaultCache.Remember(dst, key) -} - -// Delete is a surge, it delete a specified data in DefaultCache -func Delete(dst Data, key string) { - DefaultCache.Delete(dst, key) -} - -// New create a cache entity with a custom expiration time -func New(rotateInterval time.Duration) *Cache { - return &Cache{ - old: &sync.Map{}, - now: &sync.Map{}, - barrier: &sync.Map{}, - rotate: time.NewTicker(rotateInterval).C, - rwmutex: &sync.RWMutex{}, - } -} - -// Remember automatically save and retrieve data from a cache entity -func (c *Cache) Remember(dst Data, key string) error { - rv := reflect.ValueOf(dst) - if rv.Kind() != reflect.Ptr { - panic("invalid not pointor type: " + reflect.TypeOf(dst).Name()) - } else if rv.IsNil() { - return errors.New("invalid nil pointor") - } - - c.rwmutex.RLock() - defer c.rwmutex.RUnlock() - - // rotate logic, rwlock just protect fields in Cache, but not field content. - // So that, write lock just take a very short time, and simple read lock is - // just an atomic action, do not care the performance - select { - case <-c.rotate: - c.old = c.now - c.now = &sync.Map{} - c.barrier = &sync.Map{} - default: - } - - // First: load from cache - if val, ok := c.now.Load(key); ok { - return deepcopier.Copy(val).To(dst) - } - - // Second: load from old cache, or waitting the sigle groutine getting data - ch := make(chan struct{}) - if chVal, ok := c.barrier.LoadOrStore(key, ch); ok { - close(ch) // the ch is not used - - if val, ok := c.old.Load(key); ok { - return deepcopier.Copy(val).To(dst) - } - - // type chan: wait the sigle groutine getting data - // type error: already failed - if ch, ok = chVal.(chan struct{}); ok { - <-ch - if val, ok := c.now.Load(key); ok { - return deepcopier.Copy(val).To(dst) - } - } - - val, _ := c.barrier.Load(key) - if err, ok := val.(error); ok { - return err - } - - panic("new value lost, please report a bug") - } - - // Third: getting data from CacheType, maybe from db - err := dst.Fulfill(key) - if err != nil { - c.barrier.Store(key, err) - return err - } - - c.now.Store(key, dst) - close(ch) // broadcast, wakeup all waiting groutine - - return nil -} - -// Delete immediately specified the cached content to expire -func (c *Cache) Delete(dst Data, key string) { - c.rwmutex.Lock() - defer c.rwmutex.Unlock() - - c.old.Delete(key) - c.now.Delete(key) - c.barrier.Store(key, errors.New(key+" is deleted")) -} - -// Rotate force refresh cached data -func (c *Cache) Rotate(reset bool) { - c.rwmutex.Lock() - defer c.rwmutex.Unlock() - - if reset { - c.old = &sync.Map{} - } else { - c.old = c.now - } - c.now = &sync.Map{} - c.barrier = &sync.Map{} -} diff --git a/util/suffix_tree.go b/pkg/suffixtree/suffix_tree.go similarity index 99% rename from util/suffix_tree.go rename to pkg/suffixtree/suffix_tree.go index 3b32ff2..797ad2e 100644 --- a/util/suffix_tree.go +++ b/pkg/suffixtree/suffix_tree.go @@ -1,4 +1,4 @@ -package util +package suffixtree import ( "runtime" diff --git a/util/suffix_tree_test.go b/pkg/suffixtree/suffix_tree_test.go similarity index 72% rename from util/suffix_tree_test.go rename to pkg/suffixtree/suffix_tree_test.go index fe52ba9..be3b413 100644 --- a/util/suffix_tree_test.go +++ b/pkg/suffixtree/suffix_tree_test.go @@ -1,9 +1,9 @@ -package util_test +package suffixtree_test import ( "testing" - "github.com/wweir/sower/util" + "github.com/wweir/sower/pkg/suffixtree" ) func TestNode_Match(t *testing.T) { @@ -13,18 +13,18 @@ func TestNode_Match(t *testing.T) { } tests := []struct { name string - node *util.Node + node *suffixtree.Node tests []test }{{ "simple", - util.NewNodeFromRules("a.wweir.cc", "b.wweir.cc"), + suffixtree.NewNodeFromRules("a.wweir.cc", "b.wweir.cc"), []test{ {"a.wweir.cc", true}, {"b.wweir.cc", true}, }, }, { "parent", - util.NewNodeFromRules("wweir.cc", "a.wweir.cc"), + suffixtree.NewNodeFromRules("wweir.cc", "a.wweir.cc"), []test{ {"wweir.cc", true}, {"a.wweir.cc", true}, @@ -32,7 +32,7 @@ func TestNode_Match(t *testing.T) { }, }, { "fuzz1", - util.NewNodeFromRules("wweir.cc", "a.wweir.cc", "*.wweir.cc"), + suffixtree.NewNodeFromRules("wweir.cc", "a.wweir.cc", "*.wweir.cc"), []test{ {"wweir.cc", true}, {"a.wweir.cc", true}, @@ -41,7 +41,7 @@ func TestNode_Match(t *testing.T) { }, }, { "fuzz2", - util.NewNodeFromRules("a.*.cc", "c.wweir.*"), + suffixtree.NewNodeFromRules("a.*.cc", "c.wweir.*"), []test{ {"wweir.cc", false}, {"a.wweir.cc", true}, @@ -50,7 +50,7 @@ func TestNode_Match(t *testing.T) { }, }, { "fuzz3", - util.NewNodeFromRules("*.*.cc", "iamp.*.*"), + suffixtree.NewNodeFromRules("*.*.cc", "iamp.*.*"), []test{ {"wweir.cc", false}, {"a.wweir.cc", true}, @@ -59,7 +59,7 @@ func TestNode_Match(t *testing.T) { }, }, { "fuzz4", - util.NewNodeFromRules("**.cc", "a.**.com", "**.wweir.*"), + suffixtree.NewNodeFromRules("**.cc", "a.**.com", "**.wweir.*"), []test{ {"wweir.cc", true}, {"a.wweir.cc", true}, diff --git a/pkg/teeconn/tee_conn.go b/pkg/teeconn/tee_conn.go deleted file mode 100644 index c302949..0000000 --- a/pkg/teeconn/tee_conn.go +++ /dev/null @@ -1,56 +0,0 @@ -package teeconn - -import ( - "io" - "net" -) - -type Conn struct { - net.Conn - - buf []byte - offset int - stop bool // read - err error -} - -func New(c net.Conn) *Conn { - return &Conn{Conn: c} -} - -func (t *Conn) Reread() { - t.offset = 0 -} -func (t *Conn) Reset() { - t.buf = []byte{} - t.offset = 0 -} -func (t *Conn) Stop() *Conn { - t.stop = true - return t -} - -func (t *Conn) Read(b []byte) (n int, err error) { - length := len(t.buf) - t.offset - if length > 0 { - n = copy(b, t.buf[t.offset:]) - t.offset += n - return n, t.err - } - - n, t.err = t.Conn.Read(b) - if !t.stop { - t.buf = append(t.buf, b[:n]...) - t.offset += n - } - - return n, t.err -} - -func (t *Conn) Write(b []byte) (n int, err error) { - if t.stop { - return t.Conn.Write(b) - } - - return 0, io.ErrShortWrite -} diff --git a/router/country.go b/router/country.go index ebec241..47feecc 100644 --- a/router/country.go +++ b/router/country.go @@ -5,7 +5,7 @@ import ( "net" "time" - "github.com/wweir/deferlog/log" + "github.com/sower-proxy/deferlog/log" ) func (r *Router) localSite(domain string) bool { diff --git a/router/dns.go b/router/dns.go index 7d703eb..2794209 100644 --- a/router/dns.go +++ b/router/dns.go @@ -5,7 +5,7 @@ import ( "time" "github.com/miekg/dns" - "github.com/wweir/deferlog/log" + "github.com/sower-proxy/deferlog/log" ) func (r *Router) ServeDNS(w dns.ResponseWriter, req *dns.Msg) { diff --git a/router/ping.go b/router/ping.go index 134f5d9..395571f 100644 --- a/router/ping.go +++ b/router/ping.go @@ -5,7 +5,7 @@ import ( "sync" "time" - "github.com/wweir/deferlog/log" + "github.com/sower-proxy/deferlog/log" ) var pingClient = http.Client{ diff --git a/router/router.go b/router/router.go index 3f770ed..7f44b03 100644 --- a/router/router.go +++ b/router/router.go @@ -8,18 +8,19 @@ import ( "github.com/miekg/dns" geoip2 "github.com/oschwald/geoip2-golang" "github.com/pkg/errors" - "github.com/wweir/deferlog" - "github.com/wweir/deferlog/log" + "github.com/sower-proxy/conns/relay" + "github.com/sower-proxy/deferlog" + "github.com/sower-proxy/deferlog/log" + "github.com/sower-proxy/mem" "github.com/wweir/sower/pkg/dhcp" - "github.com/wweir/sower/pkg/mem" - "github.com/wweir/sower/util" + "github.com/wweir/sower/pkg/suffixtree" ) type ProxyDialFn func(network, host string, port uint16) (net.Conn, error) type Router struct { - blockRule *util.Node - directRule *util.Node - proxyRule *util.Node + blockRule *suffixtree.Node + directRule *suffixtree.Node + proxyRule *suffixtree.Node ProxyDial ProxyDialFn accessCache *mem.Cache @@ -57,13 +58,13 @@ func NewRouter(serveIP, fallbackDNS, mmdbFile string, proxyDial ProxyDialFn) *Ro } func (r *Router) SetBlockRules(blockList []string) { - r.blockRule = util.NewNodeFromRules(blockList...) + r.blockRule = suffixtree.NewNodeFromRules(blockList...) } func (r *Router) SetDirectRules(directList []string) { - r.directRule = util.NewNodeFromRules(directList...) + r.directRule = suffixtree.NewNodeFromRules(directList...) } func (r *Router) SetProxyRules(proxyList []string) { - r.proxyRule = util.NewNodeFromRules(proxyList...) + r.proxyRule = suffixtree.NewNodeFromRules(proxyList...) } func (r *Router) SetCountryCIDRs(directCIDRs []string) { r.country.cidrs = make([]*net.IPNet, 0, len(directCIDRs)) @@ -139,11 +140,11 @@ func (r *Router) ProxyHandle(conn net.Conn, domain string, port uint16) error { } defer rc.Close() - util.Relay(conn, rc) + relay.Relay(conn, rc) return nil } func (r *Router) DirectHandle(conn net.Conn, addr string) error { - dur, err := util.RelayTo(conn, addr) + dur, err := relay.RelayTo(conn, addr) return errors.Wrapf(err, "spend (%s)", dur) } diff --git a/transport/transport_test.go b/transport/transport_test.go index d510ab5..be3d770 100644 --- a/transport/transport_test.go +++ b/transport/transport_test.go @@ -5,8 +5,8 @@ import ( "strings" "testing" - "github.com/wweir/deferlog/log" - "github.com/wweir/sower/pkg/teeconn" + "github.com/sower-proxy/conns/teeconn" + "github.com/sower-proxy/deferlog/log" "github.com/wweir/sower/transport/sower" "github.com/wweir/sower/transport/trojan" ) diff --git a/util/relay.go b/util/relay.go deleted file mode 100644 index 3e3e5b9..0000000 --- a/util/relay.go +++ /dev/null @@ -1,50 +0,0 @@ -package util - -import ( - "io" - "net" - "sync" - "sync/atomic" - "time" - - "github.com/pkg/errors" -) - -func RelayTo(conn net.Conn, addr string) (dur time.Duration, err error) { - if _, _, err := net.SplitHostPort(addr); err != nil { - addr = net.JoinHostPort(addr, "80") - } - - start := time.Now() - rc, err := net.DialTimeout("tcp", addr, 5*time.Second) - if err != nil { - return time.Since(start), errors.WithStack(err) - } - defer rc.Close() - - Relay(conn, rc) - return time.Since(start), nil -} - -func Relay(conn1, conn2 net.Conn) { - wg := &sync.WaitGroup{} - exitFlag := new(int32) - wg.Add(2) - go redirect(conn2, conn1, wg, exitFlag) - redirect(conn1, conn2, wg, exitFlag) - wg.Wait() -} -func redirect(dst, src net.Conn, wg *sync.WaitGroup, exitFlag *int32) { - - // io.Copy(dst, io.TeeReader(src, os.Stdout)) - io.Copy(dst, src) - - if atomic.CompareAndSwapInt32(exitFlag, 0, 1) { - // wakeup blocked goroutine - now := time.Now() - src.SetDeadline(now) - dst.SetDeadline(now) - } - - wg.Done() -}