mirror of
https://github.com/wweir/sower.git
synced 2024-04-21 12:42:15 +00:00
chore: separate packages
This commit is contained in:
+1
-1
@@ -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"
|
||||
)
|
||||
|
||||
|
||||
+5
-5
@@ -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)).
|
||||
|
||||
+7
-7
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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=
|
||||
|
||||
-139
@@ -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{}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package util
|
||||
package suffixtree
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
@@ -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},
|
||||
@@ -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
|
||||
}
|
||||
+1
-1
@@ -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 {
|
||||
|
||||
+1
-1
@@ -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) {
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/wweir/deferlog/log"
|
||||
"github.com/sower-proxy/deferlog/log"
|
||||
)
|
||||
|
||||
var pingClient = http.Client{
|
||||
|
||||
+13
-12
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
Reference in New Issue
Block a user