Refactor + Re-use net.Conn for validation
This commit is contained in:
parent
28805017f0
commit
c3e3694a3e
13
conductor.go
13
conductor.go
|
@ -3,7 +3,6 @@ package prox5
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
|
@ -30,19 +29,17 @@ func (pe *ProxyEngine) Start() error {
|
|||
|
||||
/*
|
||||
Pause will cease the creation of any new proxy validation operations.
|
||||
* You will be able to start the proxy pool again with Swamp.Resume(), it will have the same Statistics, options, and ratelimits.
|
||||
* During pause you are still able to dispense proxies.
|
||||
* Options may be changed and proxy lists may be loaded when paused.
|
||||
* Pausing an already paused ProxyEngine is a nonop.
|
||||
- You will be able to start the proxy pool again with Swamp.Resume(), it will have the same Statistics, options, and ratelimits.
|
||||
- During pause you are still able to dispense proxies.
|
||||
- Options may be changed and proxy lists may be loaded when paused.
|
||||
- Pausing an already paused ProxyEngine is a nonop.
|
||||
*/
|
||||
func (pe *ProxyEngine) Pause() error {
|
||||
if !pe.IsRunning() {
|
||||
return errors.New("not running")
|
||||
}
|
||||
|
||||
buf := copABuffer.Get().(*strings.Builder)
|
||||
buf.WriteString("pausing...")
|
||||
pe.dbgPrint(buf)
|
||||
pe.dbgPrint(simpleString("pausing proxy pool"))
|
||||
|
||||
pe.quit()
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ import (
|
|||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"git.tcp.direct/kayos/prox5/internal/pools"
|
||||
)
|
||||
|
||||
func (pe *ProxyEngine) svcUp() {
|
||||
|
@ -148,7 +150,7 @@ func (pe *ProxyEngine) jobSpawner() {
|
|||
default:
|
||||
time.Sleep(25 * time.Millisecond)
|
||||
count := pe.recycling()
|
||||
buf := copABuffer.Get().(*strings.Builder)
|
||||
buf := pools.CopABuffer.Get().(*strings.Builder)
|
||||
buf.WriteString("recycled ")
|
||||
buf.WriteString(strconv.Itoa(count))
|
||||
buf.WriteString(" proxies from our map")
|
||||
|
|
139
debug.go
139
debug.go
|
@ -4,21 +4,35 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"git.tcp.direct/kayos/prox5/internal/pools"
|
||||
)
|
||||
|
||||
var (
|
||||
debugStatus *uint32
|
||||
debugHardLock = &sync.RWMutex{}
|
||||
)
|
||||
|
||||
func init() {
|
||||
debugMutex = &sync.RWMutex{}
|
||||
dd := debugDisabled
|
||||
debugStatus = &dd
|
||||
}
|
||||
|
||||
var (
|
||||
useDebugChannel = false
|
||||
debugChan chan string
|
||||
debugMutex *sync.RWMutex
|
||||
const (
|
||||
debugEnabled uint32 = iota
|
||||
debugDisabled
|
||||
)
|
||||
|
||||
type DebugPrinter interface {
|
||||
Print(str string)
|
||||
Printf(format string, items ...any)
|
||||
type SocksLogger struct {
|
||||
parent *ProxyEngine
|
||||
}
|
||||
|
||||
// Printf is used to handle socks server logging.
|
||||
func (s SocksLogger) Printf(format string, a ...interface{}) {
|
||||
buf := pools.CopABuffer.Get().(*strings.Builder)
|
||||
buf.WriteString(fmt.Sprintf(format, a...))
|
||||
s.parent.dbgPrint(buf)
|
||||
}
|
||||
|
||||
type basicPrinter struct{}
|
||||
|
@ -31,83 +45,75 @@ func (b basicPrinter) Printf(format string, items ...any) {
|
|||
println(fmt.Sprintf("prox5: "+format, items))
|
||||
}
|
||||
|
||||
// DebugChannel will return a channel which will receive debug messages once debug is enabled.
|
||||
// This will alter the flow of debug messages, they will no longer print to console, they will be pushed into this channel.
|
||||
// Make sure you pull from the channel eventually to avoid build up of blocked goroutines.
|
||||
func (pe *ProxyEngine) DebugChannel() chan string {
|
||||
debugChan = make(chan string, 1000000)
|
||||
useDebugChannel = true
|
||||
return debugChan
|
||||
}
|
||||
|
||||
// DebugEnabled returns the current state of our debug switch.
|
||||
func (pe *ProxyEngine) DebugEnabled() bool {
|
||||
return pe.swampopt.debug
|
||||
}
|
||||
|
||||
// DisableDebugChannel redirects debug messages back to the console.
|
||||
// DisableProxyChannel does not disable debug, use DisableDebug().
|
||||
func (pe *ProxyEngine) DisableDebugChannel() {
|
||||
debugMutex.Lock()
|
||||
defer debugMutex.Unlock()
|
||||
useDebugChannel = false
|
||||
debugHardLock.RLock()
|
||||
defer debugHardLock.RUnlock()
|
||||
return atomic.CompareAndSwapUint32(debugStatus, debugEnabled, debugEnabled)
|
||||
}
|
||||
|
||||
// EnableDebug enables printing of verbose messages during operation
|
||||
func (pe *ProxyEngine) EnableDebug() {
|
||||
pe.swampopt.debug = true
|
||||
atomic.StoreUint32(debugStatus, debugEnabled)
|
||||
}
|
||||
|
||||
// DisableDebug enables printing of verbose messages during operation.
|
||||
// WARNING: if you are using a DebugChannel, you must read all of the messages in the channel's cache or this will block.
|
||||
func (pe *ProxyEngine) DisableDebug() {
|
||||
pe.swampopt.debug = false
|
||||
atomic.StoreUint32(debugStatus, debugDisabled)
|
||||
}
|
||||
|
||||
func simpleString(s string) *strings.Builder {
|
||||
buf := copABuffer.Get().(*strings.Builder)
|
||||
buf := pools.CopABuffer.Get().(*strings.Builder)
|
||||
buf.WriteString(s)
|
||||
return buf
|
||||
}
|
||||
|
||||
func (pe *ProxyEngine) dbgPrint(builder *strings.Builder) {
|
||||
defer discardBuffer(builder)
|
||||
if !pe.swampopt.debug {
|
||||
defer pools.DiscardBuffer(builder)
|
||||
if !pe.DebugEnabled() {
|
||||
return
|
||||
}
|
||||
if !useDebugChannel {
|
||||
pe.Debug.Print(builder.String())
|
||||
return
|
||||
}
|
||||
select {
|
||||
case debugChan <- builder.String():
|
||||
return
|
||||
default:
|
||||
buf := copABuffer.Get().(*strings.Builder)
|
||||
buf.WriteString("overflow: ")
|
||||
buf.WriteString(builder.String())
|
||||
pe.Debug.Print(buf.String())
|
||||
discardBuffer(buf)
|
||||
}
|
||||
pe.DebugLogger.Print(builder.String())
|
||||
return
|
||||
}
|
||||
|
||||
func (pe *ProxyEngine) msgUnableToReach(socksString string) {
|
||||
buf := copABuffer.Get().(*strings.Builder)
|
||||
buf.WriteString("unable to reach [redacted] with ")
|
||||
func (pe *ProxyEngine) msgUnableToReach(socksString, target string, err error) {
|
||||
if !pe.DebugEnabled() {
|
||||
return
|
||||
}
|
||||
buf := pools.CopABuffer.Get().(*strings.Builder)
|
||||
buf.WriteString("unable to reach ")
|
||||
if pe.swampopt.redact {
|
||||
buf.WriteString("[redacted]")
|
||||
} else {
|
||||
buf.WriteString(target)
|
||||
}
|
||||
buf.WriteString(" with ")
|
||||
buf.WriteString(socksString)
|
||||
if !pe.swampopt.redact {
|
||||
buf.WriteString(": ")
|
||||
buf.WriteString(err.Error())
|
||||
}
|
||||
buf.WriteString(", cycling...")
|
||||
pe.dbgPrint(buf)
|
||||
}
|
||||
|
||||
func (pe *ProxyEngine) msgUsingProxy(socksString string) {
|
||||
buf := copABuffer.Get().(*strings.Builder)
|
||||
if !pe.DebugEnabled() {
|
||||
return
|
||||
}
|
||||
buf := pools.CopABuffer.Get().(*strings.Builder)
|
||||
buf.WriteString("MysteryDialer using socks: ")
|
||||
buf.WriteString(socksString)
|
||||
pe.dbgPrint(buf)
|
||||
}
|
||||
|
||||
func (pe *ProxyEngine) msgFailedMiddleware(socksString string) {
|
||||
buf := copABuffer.Get().(*strings.Builder)
|
||||
if !pe.DebugEnabled() {
|
||||
return
|
||||
}
|
||||
buf := pools.CopABuffer.Get().(*strings.Builder)
|
||||
buf.WriteString("failed middleware check, ")
|
||||
buf.WriteString(socksString)
|
||||
buf.WriteString(", cycling...")
|
||||
|
@ -115,14 +121,20 @@ func (pe *ProxyEngine) msgFailedMiddleware(socksString string) {
|
|||
}
|
||||
|
||||
func (pe *ProxyEngine) msgTry(socksString string) {
|
||||
buf := copABuffer.Get().(*strings.Builder)
|
||||
if !pe.DebugEnabled() {
|
||||
return
|
||||
}
|
||||
buf := pools.CopABuffer.Get().(*strings.Builder)
|
||||
buf.WriteString("try dial with: ")
|
||||
buf.WriteString(socksString)
|
||||
pe.dbgPrint(buf)
|
||||
}
|
||||
|
||||
func (pe *ProxyEngine) msgCantGetLock(socksString string, putback bool) {
|
||||
buf := copABuffer.Get().(*strings.Builder)
|
||||
if !pe.DebugEnabled() {
|
||||
return
|
||||
}
|
||||
buf := pools.CopABuffer.Get().(*strings.Builder)
|
||||
buf.WriteString("can't get lock for ")
|
||||
buf.WriteString(socksString)
|
||||
if putback {
|
||||
|
@ -132,18 +144,30 @@ func (pe *ProxyEngine) msgCantGetLock(socksString string, putback bool) {
|
|||
}
|
||||
|
||||
func (pe *ProxyEngine) msgGotLock(socksString string) {
|
||||
buf := copABuffer.Get().(*strings.Builder)
|
||||
if !pe.DebugEnabled() {
|
||||
return
|
||||
}
|
||||
buf := pools.CopABuffer.Get().(*strings.Builder)
|
||||
buf.WriteString("got lock for ")
|
||||
buf.WriteString(socksString)
|
||||
pe.dbgPrint(buf)
|
||||
}
|
||||
|
||||
func (pe *ProxyEngine) msgChecked(sock *Proxy, success bool) {
|
||||
buf := copABuffer.Get().(*strings.Builder)
|
||||
if !pe.DebugEnabled() {
|
||||
return
|
||||
}
|
||||
buf := pools.CopABuffer.Get().(*strings.Builder)
|
||||
if success {
|
||||
buf.WriteString("verified ")
|
||||
buf.WriteString(sock.Endpoint)
|
||||
buf.WriteString(" as SOCKS")
|
||||
if sock.proto != ProtoHTTP {
|
||||
buf.WriteString(" as SOCKS")
|
||||
} else {
|
||||
buf.WriteString(" as HTTP proxy")
|
||||
pe.dbgPrint(buf)
|
||||
return
|
||||
}
|
||||
buf.WriteString(getProtoStr(sock.proto))
|
||||
pe.dbgPrint(buf)
|
||||
return
|
||||
|
@ -154,7 +178,10 @@ func (pe *ProxyEngine) msgChecked(sock *Proxy, success bool) {
|
|||
}
|
||||
|
||||
func (pe *ProxyEngine) msgBadProxRate(sock *Proxy) {
|
||||
buf := copABuffer.Get().(*strings.Builder)
|
||||
if !pe.DebugEnabled() {
|
||||
return
|
||||
}
|
||||
buf := pools.CopABuffer.Get().(*strings.Builder)
|
||||
buf.WriteString("badProx ratelimited: ")
|
||||
buf.WriteString(sock.Endpoint)
|
||||
pe.dbgPrint(buf)
|
||||
|
|
67
defs.go
67
defs.go
|
@ -9,6 +9,9 @@ import (
|
|||
|
||||
"github.com/panjf2000/ants/v2"
|
||||
rl "github.com/yunginnanet/Rate5"
|
||||
|
||||
"git.tcp.direct/kayos/prox5/internal/pools"
|
||||
"git.tcp.direct/kayos/prox5/logger"
|
||||
)
|
||||
|
||||
type ProxyChannels struct {
|
||||
|
@ -24,10 +27,8 @@ type ProxyChannels struct {
|
|||
|
||||
// ProxyEngine represents a proxy pool
|
||||
type ProxyEngine struct {
|
||||
Valids ProxyChannels
|
||||
|
||||
socksServerLogger socksLogger
|
||||
Debug DebugPrinter
|
||||
Valids ProxyChannels
|
||||
DebugLogger logger.Logger
|
||||
|
||||
// stats holds the statistics for our swamp
|
||||
stats *statistics
|
||||
|
@ -41,8 +42,6 @@ type ProxyEngine struct {
|
|||
useProx *rl.Limiter
|
||||
badProx *rl.Limiter
|
||||
|
||||
socks5ServerAuth socksCreds
|
||||
|
||||
dispenseMiddleware func(*Proxy) (*Proxy, bool)
|
||||
|
||||
ctx context.Context
|
||||
|
@ -60,9 +59,10 @@ type ProxyEngine struct {
|
|||
}
|
||||
|
||||
var (
|
||||
defaultStaleTime = 1 * time.Hour
|
||||
defWorkers = 100
|
||||
defBailout = 5
|
||||
defaultStaleTime = 1 * time.Hour
|
||||
defaultWorkerCount = 50
|
||||
defaultBailout = 15
|
||||
defaultRemoveAfter = 25
|
||||
// Note: I've chosen to use https here exclusively assuring all validated proxies are SSL capable.
|
||||
defaultChecks = []string{
|
||||
"https://wtfismyip.com/text",
|
||||
|
@ -79,27 +79,22 @@ var (
|
|||
// Returns a pointer to our default options (modified and accessed later through concurrent safe getters and setters)
|
||||
func defOpt() *config {
|
||||
sm := &config{
|
||||
useProxConfig: defUseProx,
|
||||
badProxConfig: defBadProx,
|
||||
useProxConfig: defaultUseProxyRatelimiter,
|
||||
badProxConfig: defaultBadProxyRateLimiter,
|
||||
|
||||
checkEndpoints: defaultChecks,
|
||||
userAgents: defaultUserAgents,
|
||||
RWMutex: &sync.RWMutex{},
|
||||
removeafter: defaultRemoveAfter,
|
||||
recycle: true,
|
||||
debug: true,
|
||||
dialerBailout: defaultBailout,
|
||||
stale: defaultStaleTime,
|
||||
maxWorkers: defaultWorkerCount,
|
||||
redact: true,
|
||||
}
|
||||
|
||||
sm.Lock()
|
||||
defer sm.Unlock()
|
||||
|
||||
sm.removeafter = 5
|
||||
sm.recycle = true
|
||||
sm.debug = false
|
||||
sm.validationTimeout = time.Duration(12) * time.Second
|
||||
sm.serverTimeout = time.Duration(180) * time.Second
|
||||
|
||||
sm.dialerBailout = defBailout
|
||||
sm.stale = defaultStaleTime
|
||||
sm.maxWorkers = defWorkers
|
||||
|
||||
return sm
|
||||
}
|
||||
|
||||
|
@ -109,32 +104,29 @@ type config struct {
|
|||
// stale is the amount of time since verification that qualifies a proxy going stale.
|
||||
// if a stale proxy is drawn during the use of our getter functions, it will be skipped.
|
||||
stale time.Duration
|
||||
|
||||
// userAgents contains a list of userAgents to be randomly drawn from for proxied requests, this should be supplied via SetUserAgents
|
||||
userAgents []string
|
||||
|
||||
// debug when enabled will print results as they come in
|
||||
debug bool
|
||||
|
||||
// checkEndpoints includes web services that respond with (just) the WAN IP of the connection for validation purposes
|
||||
checkEndpoints []string
|
||||
|
||||
// maxWorkers determines the maximum amount of workers used for checking proxies
|
||||
maxWorkers int
|
||||
|
||||
// validationTimeout defines the timeout for proxy validation operations.
|
||||
// This will apply for both the initial quick check (dial), and the second check (HTTP GET).
|
||||
validationTimeout time.Duration
|
||||
|
||||
// serverTimeout defines the timeout for outgoing connections made with the MysteryDialer.
|
||||
serverTimeout time.Duration
|
||||
|
||||
// dialerBailout defines the amount of times a dial atttempt can fail before giving up and returning an error.
|
||||
dialerBailout int
|
||||
|
||||
// redact when enabled will redact the target string from the debug output
|
||||
redact bool
|
||||
// recycle determines whether or not we recycle proxies pack into the pending channel after we dispense them
|
||||
recycle bool
|
||||
// remove proxy from recycling after being marked bad this many times
|
||||
removeafter int
|
||||
// shuffle determines whether or not we shuffle proxies before we validate and dispense them.
|
||||
shuffle bool
|
||||
|
||||
// TODO: make getters and setters for these
|
||||
useProxConfig rl.Policy
|
||||
|
@ -147,8 +139,8 @@ type config struct {
|
|||
// After calling this you may use the various "setters" to change the options before calling ProxyEngine.Start().
|
||||
func NewProxyEngine() *ProxyEngine {
|
||||
pe := &ProxyEngine{
|
||||
stats: &statistics{birthday: time.Now()},
|
||||
Debug: basicPrinter{},
|
||||
stats: &statistics{birthday: time.Now()},
|
||||
DebugLogger: basicPrinter{},
|
||||
|
||||
swampopt: defOpt(),
|
||||
|
||||
|
@ -170,15 +162,10 @@ func NewProxyEngine() *ProxyEngine {
|
|||
pe.dispenseMiddleware = func(p *Proxy) (*Proxy, bool) {
|
||||
return p, true
|
||||
}
|
||||
|
||||
pe.ctx, pe.quit = context.WithCancel(context.Background())
|
||||
|
||||
atomic.StoreUint32(&pe.Status, uint32(StateNew))
|
||||
|
||||
pe.swampmap = newSwampMap(pe)
|
||||
|
||||
pe.socksServerLogger = socksLogger{parent: pe}
|
||||
|
||||
atomic.StoreUint32(&pe.Status, uint32(StateNew))
|
||||
atomic.StoreInt32(&pe.runningdaemons, 0)
|
||||
|
||||
pe.useProx = rl.NewCustomLimiter(pe.swampopt.useProxConfig)
|
||||
|
@ -191,7 +178,7 @@ func NewProxyEngine() *ProxyEngine {
|
|||
}))
|
||||
|
||||
if err != nil {
|
||||
buf := copABuffer.Get().(*strings.Builder)
|
||||
buf := pools.CopABuffer.Get().(*strings.Builder)
|
||||
buf.WriteString("CRITICAL: ")
|
||||
buf.WriteString(err.Error())
|
||||
pe.dbgPrint(buf)
|
||||
|
|
|
@ -6,6 +6,8 @@ import (
|
|||
"time"
|
||||
|
||||
"git.tcp.direct/kayos/common/entropy"
|
||||
|
||||
"git.tcp.direct/kayos/prox5/internal/pools"
|
||||
)
|
||||
|
||||
// Socks5Str gets a SOCKS5 proxy that we have fully verified (dialed and then retrieved our IP address from a what-is-my-ip endpoint.
|
||||
|
@ -103,7 +105,7 @@ func (pe *ProxyEngine) stillGood(sock *Proxy) bool {
|
|||
defer atomic.StoreUint32(&sock.lock, stateUnlocked)
|
||||
|
||||
if atomic.LoadInt64(&sock.timesBad) > int64(pe.GetRemoveAfter()) && pe.GetRemoveAfter() != -1 {
|
||||
buf := copABuffer.Get().(*strings.Builder)
|
||||
buf := pools.CopABuffer.Get().(*strings.Builder)
|
||||
buf.WriteString("deleting from map (too many failures): ")
|
||||
buf.WriteString(sock.Endpoint)
|
||||
pe.dbgPrint(buf)
|
||||
|
@ -113,7 +115,7 @@ func (pe *ProxyEngine) stillGood(sock *Proxy) bool {
|
|||
}
|
||||
|
||||
if pe.badProx.Peek(sock) {
|
||||
buf := copABuffer.Get().(*strings.Builder)
|
||||
buf := pools.CopABuffer.Get().(*strings.Builder)
|
||||
buf.WriteString("badProx dial ratelimited: ")
|
||||
buf.WriteString(sock.Endpoint)
|
||||
pe.dbgPrint(buf)
|
||||
|
@ -121,7 +123,7 @@ func (pe *ProxyEngine) stillGood(sock *Proxy) bool {
|
|||
}
|
||||
|
||||
if time.Since(sock.lastValidated) > pe.swampopt.stale {
|
||||
buf := copABuffer.Get().(*strings.Builder)
|
||||
buf := pools.CopABuffer.Get().(*strings.Builder)
|
||||
buf.WriteString("proxy stale: ")
|
||||
buf.WriteString(sock.Endpoint)
|
||||
pe.dbgPrint(buf)
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
module p5example
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
git.tcp.direct/kayos/prox5 v0.5.3-0.20220709184754-7ecedfdd0c63
|
||||
github.com/haxii/socks5 v1.0.0
|
||||
github.com/mattn/go-tty v0.0.4
|
||||
)
|
||||
|
||||
require (
|
||||
git.tcp.direct/kayos/common v0.7.0 // indirect
|
||||
git.tcp.direct/kayos/go-socks5 v1.0.1 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/miekg/dns v1.1.50 // indirect
|
||||
github.com/panjf2000/ants/v2 v2.5.0 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
github.com/yunginnanet/Rate5 v1.0.1 // indirect
|
||||
go4.org/intern v0.0.0-20211027215823-ae77deb06f29 // indirect
|
||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 // indirect
|
||||
golang.org/x/mod v0.4.2 // indirect
|
||||
golang.org/x/net v0.0.0-20220630215102-69896b714898 // indirect
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
h12.io/socks v1.0.3 // indirect
|
||||
inet.af/netaddr v0.0.0-20220617031823-097006376321 // indirect
|
||||
nullprogram.com/x/rng v1.1.0 // indirect
|
||||
)
|
|
@ -1,90 +0,0 @@
|
|||
git.tcp.direct/kayos/common v0.7.0 h1:KZDwoCzUiwQaYSWESr080N8wUVyLD27QYgzXgc7LiAQ=
|
||||
git.tcp.direct/kayos/common v0.7.0/go.mod h1:7tMZBVNPLFSZk+JXTA6pgXWpf/XHqYRfT7Q3OziI++Y=
|
||||
git.tcp.direct/kayos/go-socks5 v1.0.1 h1:Pe9PlSXofibIJyWkrr9rwWcgyfUxSdUcDCQ//6fAi0U=
|
||||
git.tcp.direct/kayos/go-socks5 v1.0.1/go.mod h1:I9xU/uzFAZKukMJgEgWPrfC6rDlcPQe8wXMibF3qvhE=
|
||||
git.tcp.direct/kayos/prox5 v0.5.3-0.20220709184754-7ecedfdd0c63 h1:eidAXI7o5gIf4linhOIFEtSiYQQOsqHLcMqhBrF9vgA=
|
||||
git.tcp.direct/kayos/prox5 v0.5.3-0.20220709184754-7ecedfdd0c63/go.mod h1:/44/UlcKPOXZ/jr+NdftkZvLkW0k4QokPXqAdQ2O3BQ=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
|
||||
github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364 h1:5XxdakFhqd9dnXoAZy1Mb2R/DZ6D1e+0bGC/JhucGYI=
|
||||
github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364/go.mod h1:eDJQioIyy4Yn3MVivT7rv/39gAJTrA7lgmYr8EW950c=
|
||||
github.com/haxii/socks5 v1.0.0 h1:78BIzd4lHibdRNOKdMwKCnnsgYLW9SeotqU+nMhWSSo=
|
||||
github.com/haxii/socks5 v1.0.0/go.mod h1:6O9Ba2yrLlvuSe/L1e84eZI8cPw6H+q1Ilr4hjgm4uY=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-tty v0.0.4 h1:NVikla9X8MN0SQAqCYzpGyXv0jY7MNl3HOWD2dkle7E=
|
||||
github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3pxse28=
|
||||
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
|
||||
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||
github.com/panjf2000/ants/v2 v2.5.0 h1:1rWGWSnxCsQBga+nQbA4/iY6VMeNoOIAM0ZWh9u3q2Q=
|
||||
github.com/panjf2000/ants/v2 v2.5.0/go.mod h1:cU93usDlihJZ5CfRGNDYsiBYvoilLvBF5Qp/BT2GNRE=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
|
||||
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yunginnanet/Rate5 v1.0.1 h1:OePwNrj9/A/flmhyr/gKI5RYgrW6d1oWCqrZRXUev3k=
|
||||
github.com/yunginnanet/Rate5 v1.0.1/go.mod h1:f0r66kVQZojRqUgVdLC/CKexMlF0nUDAmd01tBeF4Ms=
|
||||
go4.org/intern v0.0.0-20211027215823-ae77deb06f29 h1:UXLjNohABv4S58tHmeuIZDO6e3mHpW2Dx33gaNt03LE=
|
||||
go4.org/intern v0.0.0-20211027215823-ae77deb06f29/go.mod h1:cS2ma+47FKrLPdXFpr7CuxiTW3eyJbWew4qx0qtQWDA=
|
||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20211027215541-db492cf91b37/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E=
|
||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 h1:FyBZqvoA/jbNzuAWLQE2kG820zMAkcilx6BMjGbL/E4=
|
||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E=
|
||||
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=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220630215102-69896b714898 h1:K7wO6V1IrczY9QOQ2WkVpw4JQSwCd52UsxVEirZUfiw=
|
||||
golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 h1:BonxutuHCTL0rBDnZlKjpGIQFTjyUVTexFOdWkB6Fg0=
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
h12.io/socks v1.0.3 h1:Ka3qaQewws4j4/eDQnOdpr4wXsC//dXtWvftlIcCQUo=
|
||||
h12.io/socks v1.0.3/go.mod h1:AIhxy1jOId/XCz9BO+EIgNL2rQiPTBNnOfnVnQ+3Eck=
|
||||
inet.af/netaddr v0.0.0-20220617031823-097006376321 h1:B4dC8ySKTQXasnjDTMsoCMf1sQG4WsMej0WXaHxunmU=
|
||||
inet.af/netaddr v0.0.0-20220617031823-097006376321/go.mod h1:OIezDfdzOgFhuw4HuWapWq2e9l0H9tK4F1j+ETRtF3k=
|
||||
nullprogram.com/x/rng v1.1.0 h1:SMU7DHaQSWtKJNTpNFIFt8Wd/KSmOuSDPXrMFp/UMro=
|
||||
nullprogram.com/x/rng v1.1.0/go.mod h1:glGw6V87vyfawxCzqOABL3WfL95G65az9Z2JZCylCkg=
|
|
@ -6,9 +6,10 @@ import (
|
|||
"strconv"
|
||||
"time"
|
||||
|
||||
"git.tcp.direct/kayos/prox5"
|
||||
"github.com/haxii/socks5"
|
||||
"github.com/mattn/go-tty"
|
||||
|
||||
"git.tcp.direct/kayos/prox5"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -23,7 +24,7 @@ var socklog = socksLogger{}
|
|||
|
||||
// Printf is used to handle socks server logging.
|
||||
func (s socksLogger) Printf(format string, a ...interface{}) {
|
||||
println(fmt.Sprintf(format, a))
|
||||
println(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
func StartUpstreamProxy(listen string) {
|
||||
|
|
20
getters.go
20
getters.go
|
@ -7,6 +7,8 @@ import (
|
|||
"time"
|
||||
|
||||
"git.tcp.direct/kayos/common/entropy"
|
||||
|
||||
"git.tcp.direct/kayos/prox5/internal/pools"
|
||||
)
|
||||
|
||||
// GetProto retrieves the known protocol value of the Proxy.
|
||||
|
@ -18,14 +20,14 @@ func (sock *Proxy) GetProto() ProxyProtocol {
|
|||
func (sock *Proxy) String() string {
|
||||
tout := ""
|
||||
if sock.parent.GetServerTimeoutStr() != "-1" {
|
||||
tbuf := copABuffer.Get().(*strings.Builder)
|
||||
tbuf := pools.CopABuffer.Get().(*strings.Builder)
|
||||
tbuf.WriteString("?timeout=")
|
||||
tbuf.WriteString(sock.parent.GetServerTimeoutStr())
|
||||
tbuf.WriteString("s")
|
||||
tout = tbuf.String()
|
||||
discardBuffer(tbuf)
|
||||
pools.DiscardBuffer(tbuf)
|
||||
}
|
||||
buf := copABuffer.Get().(*strings.Builder)
|
||||
buf := pools.CopABuffer.Get().(*strings.Builder)
|
||||
buf.WriteString("socks")
|
||||
buf.WriteString(getProtoStr(sock.GetProto()))
|
||||
buf.WriteString("://")
|
||||
|
@ -34,7 +36,7 @@ func (sock *Proxy) String() string {
|
|||
buf.WriteString(tout)
|
||||
}
|
||||
out := buf.String()
|
||||
discardBuffer(buf)
|
||||
pools.DiscardBuffer(buf)
|
||||
return out
|
||||
}
|
||||
|
||||
|
@ -116,7 +118,7 @@ func (pe *ProxyEngine) GetRecyclingStatus() bool {
|
|||
}
|
||||
|
||||
// GetWorkers retrieves pond worker statistics:
|
||||
// * return MaxWorkers, RunningWorkers, IdleWorkers
|
||||
// - return MaxWorkers, RunningWorkers, IdleWorkers
|
||||
func (pe *ProxyEngine) GetWorkers() (maxWorkers, runningWorkers, idleWorkers int) {
|
||||
pe.mu.RLock()
|
||||
defer pe.mu.RUnlock()
|
||||
|
@ -124,7 +126,7 @@ func (pe *ProxyEngine) GetWorkers() (maxWorkers, runningWorkers, idleWorkers int
|
|||
}
|
||||
|
||||
// GetRemoveAfter retrieves the removeafter policy, the amount of times a recycled proxy is marked as bad until it is removed entirely.
|
||||
// * returns -1 if recycling is disabled.
|
||||
// - returns -1 if recycling is disabled.
|
||||
func (pe *ProxyEngine) GetRemoveAfter() int {
|
||||
pe.mu.RLock()
|
||||
defer pe.mu.RUnlock()
|
||||
|
@ -148,3 +150,9 @@ func (pe *ProxyEngine) GetDispenseMiddleware() func(*Proxy) (*Proxy, bool) {
|
|||
defer pe.mu.RUnlock()
|
||||
return pe.dispenseMiddleware
|
||||
}
|
||||
|
||||
func (pe *ProxyEngine) GetShuffleStatus() bool {
|
||||
pe.mu.RLock()
|
||||
defer pe.mu.RUnlock()
|
||||
return pe.swampopt.shuffle
|
||||
}
|
||||
|
|
7
go.mod
7
go.mod
|
@ -5,19 +5,22 @@ go 1.18
|
|||
require (
|
||||
git.tcp.direct/kayos/common v0.7.0
|
||||
git.tcp.direct/kayos/go-socks5 v1.0.1
|
||||
git.tcp.direct/kayos/socks v0.0.0-20220828111753-f9f7cd3e7ee7
|
||||
github.com/haxii/socks5 v1.0.0
|
||||
github.com/mattn/go-tty v0.0.4
|
||||
github.com/miekg/dns v1.1.50
|
||||
github.com/panjf2000/ants/v2 v2.5.0
|
||||
github.com/yunginnanet/Rate5 v1.0.1
|
||||
h12.io/socks v1.0.3
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985
|
||||
inet.af/netaddr v0.0.0-20220617031823-097006376321
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
go4.org/intern v0.0.0-20211027215823-ae77deb06f29 // indirect
|
||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 // indirect
|
||||
golang.org/x/mod v0.4.2 // indirect
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 // indirect
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
|
|
21
go.sum
21
go.sum
|
@ -2,18 +2,28 @@ git.tcp.direct/kayos/common v0.7.0 h1:KZDwoCzUiwQaYSWESr080N8wUVyLD27QYgzXgc7LiA
|
|||
git.tcp.direct/kayos/common v0.7.0/go.mod h1:7tMZBVNPLFSZk+JXTA6pgXWpf/XHqYRfT7Q3OziI++Y=
|
||||
git.tcp.direct/kayos/go-socks5 v1.0.1 h1:Pe9PlSXofibIJyWkrr9rwWcgyfUxSdUcDCQ//6fAi0U=
|
||||
git.tcp.direct/kayos/go-socks5 v1.0.1/go.mod h1:I9xU/uzFAZKukMJgEgWPrfC6rDlcPQe8wXMibF3qvhE=
|
||||
git.tcp.direct/kayos/socks v0.0.0-20220828111753-f9f7cd3e7ee7 h1:zuN2VWun3lu34Lz+LAt/ZbY6YJ0SqzQf2d00YQUfNao=
|
||||
git.tcp.direct/kayos/socks v0.0.0-20220828111753-f9f7cd3e7ee7/go.mod h1:KmN5oa1od8tMHmRIr9GOqWKx9MR0oGZVtAj+ARxiPwo=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
|
||||
github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364 h1:5XxdakFhqd9dnXoAZy1Mb2R/DZ6D1e+0bGC/JhucGYI=
|
||||
github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364/go.mod h1:eDJQioIyy4Yn3MVivT7rv/39gAJTrA7lgmYr8EW950c=
|
||||
github.com/haxii/socks5 v1.0.0 h1:78BIzd4lHibdRNOKdMwKCnnsgYLW9SeotqU+nMhWSSo=
|
||||
github.com/haxii/socks5 v1.0.0/go.mod h1:6O9Ba2yrLlvuSe/L1e84eZI8cPw6H+q1Ilr4hjgm4uY=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-tty v0.0.4 h1:NVikla9X8MN0SQAqCYzpGyXv0jY7MNl3HOWD2dkle7E=
|
||||
github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3pxse28=
|
||||
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
|
||||
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||
github.com/panjf2000/ants/v2 v2.5.0 h1:1rWGWSnxCsQBga+nQbA4/iY6VMeNoOIAM0ZWh9u3q2Q=
|
||||
github.com/panjf2000/ants/v2 v2.5.0/go.mod h1:cU93usDlihJZ5CfRGNDYsiBYvoilLvBF5Qp/BT2GNRE=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
|
||||
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
||||
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
|
@ -42,7 +52,10 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -66,8 +79,6 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
|
|||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
h12.io/socks v1.0.3 h1:Ka3qaQewws4j4/eDQnOdpr4wXsC//dXtWvftlIcCQUo=
|
||||
h12.io/socks v1.0.3/go.mod h1:AIhxy1jOId/XCz9BO+EIgNL2rQiPTBNnOfnVnQ+3Eck=
|
||||
inet.af/netaddr v0.0.0-20220617031823-097006376321 h1:B4dC8ySKTQXasnjDTMsoCMf1sQG4WsMej0WXaHxunmU=
|
||||
inet.af/netaddr v0.0.0-20220617031823-097006376321/go.mod h1:OIezDfdzOgFhuw4HuWapWq2e9l0H9tK4F1j+ETRtF3k=
|
||||
nullprogram.com/x/rng v1.1.0 h1:SMU7DHaQSWtKJNTpNFIFt8Wd/KSmOuSDPXrMFp/UMro=
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package pools
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var CopABuffer = &sync.Pool{New: func() interface{} { return &strings.Builder{} }}
|
||||
|
||||
func DiscardBuffer(buf *strings.Builder) {
|
||||
buf.Reset()
|
||||
CopABuffer.Put(buf)
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package logger
|
||||
|
||||
type Logger interface {
|
||||
Print(str string)
|
||||
Printf(format string, a ...interface{})
|
||||
}
|
|
@ -5,20 +5,14 @@ import (
|
|||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"h12.io/socks"
|
||||
"git.tcp.direct/kayos/socks"
|
||||
|
||||
"git.tcp.direct/kayos/prox5/internal/pools"
|
||||
)
|
||||
|
||||
var copABuffer = &sync.Pool{New: func() interface{} { return &strings.Builder{} }}
|
||||
|
||||
func discardBuffer(buf *strings.Builder) {
|
||||
buf.Reset()
|
||||
copABuffer.Put(buf)
|
||||
}
|
||||
|
||||
// DialContext is a simple stub adapter to implement a net.Dialer.
|
||||
func (pe *ProxyEngine) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return pe.MysteryDialer(ctx, network, addr)
|
||||
|
@ -40,13 +34,13 @@ func (pe *ProxyEngine) DialTimeout(network, addr string, timeout time.Duration)
|
|||
}
|
||||
|
||||
func (pe *ProxyEngine) addTimeout(socksString string) string {
|
||||
tout := copABuffer.Get().(*strings.Builder)
|
||||
tout := pools.CopABuffer.Get().(*strings.Builder)
|
||||
tout.WriteString(socksString)
|
||||
tout.WriteString("?timeout=")
|
||||
tout.WriteString(pe.GetServerTimeoutStr())
|
||||
tout.WriteRune('s')
|
||||
socksString = tout.String()
|
||||
discardBuffer(tout)
|
||||
pools.DiscardBuffer(tout)
|
||||
return socksString
|
||||
}
|
||||
|
||||
|
@ -74,12 +68,8 @@ func (pe *ProxyEngine) popSockAndLockIt(ctx context.Context) (*Proxy, error) {
|
|||
|
||||
// MysteryDialer is a dialer function that will use a different proxy for every request.
|
||||
func (pe *ProxyEngine) MysteryDialer(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
var (
|
||||
socksString string
|
||||
count int
|
||||
)
|
||||
// pull down proxies from channel until we get a proxy good enough for our spoiled asses
|
||||
|
||||
var count = 0
|
||||
for {
|
||||
max := pe.GetDialerBailout()
|
||||
if count > max {
|
||||
|
@ -99,11 +89,10 @@ func (pe *ProxyEngine) MysteryDialer(ctx context.Context, network, addr string)
|
|||
break
|
||||
}
|
||||
}
|
||||
if pe.GetServerTimeoutStr() != "-1" {
|
||||
socksString = pe.addTimeout(socksString)
|
||||
}
|
||||
socksString := sock.String()
|
||||
var ok bool
|
||||
if sock, ok = pe.dispenseMiddleware(sock); !ok {
|
||||
atomic.StoreUint32(&sock.lock, stateUnlocked)
|
||||
pe.msgFailedMiddleware(socksString)
|
||||
continue
|
||||
}
|
||||
|
@ -113,7 +102,7 @@ func (pe *ProxyEngine) MysteryDialer(ctx context.Context, network, addr string)
|
|||
conn, err := dialSocks(network, addr)
|
||||
if err != nil {
|
||||
count++
|
||||
pe.msgUnableToReach(socksString)
|
||||
pe.msgUnableToReach(socksString, addr, err)
|
||||
continue
|
||||
}
|
||||
pe.msgUsingProxy(socksString)
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package prox5
|
||||
|
||||
/*
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
|
||||
"inet.af/netaddr"
|
||||
)
|
||||
|
||||
type dnsCacheEntry []netaddr.IP
|
||||
|
||||
var dnsCache = make(map[string]dnsCacheEntry)
|
||||
|
||||
func (pe *ProxyEngine) Resolve(ctx context.Context, name string) (context.Context, net.IP, error) {
|
||||
var result net.IP
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx, nil, ctx.Err()
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
13
proxy.go
13
proxy.go
|
@ -7,14 +7,14 @@ import (
|
|||
)
|
||||
|
||||
// https://pkg.go.dev/github.com/yunginnanet/Rate5#Policy
|
||||
var defUseProx = rl.Policy{
|
||||
Window: 60,
|
||||
Burst: 2,
|
||||
var defaultUseProxyRatelimiter = rl.Policy{
|
||||
Window: 55,
|
||||
Burst: 55,
|
||||
}
|
||||
|
||||
var defBadProx = rl.Policy{
|
||||
Window: 60,
|
||||
Burst: 3,
|
||||
var defaultBadProxyRateLimiter = rl.Policy{
|
||||
Window: 55,
|
||||
Burst: 25,
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -29,6 +29,7 @@ const (
|
|||
ProtoSOCKS4
|
||||
ProtoSOCKS4a
|
||||
ProtoSOCKS5
|
||||
ProtoSOCKS5h
|
||||
ProtoHTTP
|
||||
)
|
||||
|
||||
|
|
25
setters.go
25
setters.go
|
@ -2,6 +2,8 @@ package prox5
|
|||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"git.tcp.direct/kayos/prox5/logger"
|
||||
)
|
||||
|
||||
// AddUserAgents appends to the list of useragents we randomly choose from during proxied requests
|
||||
|
@ -75,9 +77,9 @@ func (pe *ProxyEngine) DisableRecycling() {
|
|||
}
|
||||
|
||||
// SetRemoveAfter sets the removeafter policy, the amount of times a recycled proxy is marked as bad before it is removed entirely.
|
||||
// * Default is 5
|
||||
// * To disable deleting entirely, set this value to -1
|
||||
// * Only applies when recycling is enabled
|
||||
// - Default is 10
|
||||
// - To disable deleting entirely, set this value to -1
|
||||
// - Only applies when recycling is enabled
|
||||
func (pe *ProxyEngine) SetRemoveAfter(timesfailed int) {
|
||||
pe.swampopt.Lock()
|
||||
defer pe.swampopt.Unlock()
|
||||
|
@ -85,7 +87,7 @@ func (pe *ProxyEngine) SetRemoveAfter(timesfailed int) {
|
|||
}
|
||||
|
||||
// SetDialerBailout sets the amount of times the MysteryDialer will dial out and fail before it bails out.
|
||||
// * The dialer will attempt to redial a destination with a different proxy a specified amount of times before it gives up
|
||||
// - The dialer will attempt to redial a destination with a different proxy a specified amount of times before it gives up
|
||||
func (pe *ProxyEngine) SetDialerBailout(dialattempts int) {
|
||||
pe.swampopt.Lock()
|
||||
defer pe.swampopt.Unlock()
|
||||
|
@ -100,3 +102,18 @@ func (pe *ProxyEngine) SetDispenseMiddleware(f func(*Proxy) (*Proxy, bool)) {
|
|||
defer pe.mu.Unlock()
|
||||
pe.dispenseMiddleware = f
|
||||
}
|
||||
|
||||
// SetDebugLogger sets the debug logger for the ProxyEngine. See the Logger interface for implementation details.
|
||||
func (pe *ProxyEngine) SetDebugLogger(l logger.Logger) {
|
||||
debugHardLock.Lock()
|
||||
pe.mu.Lock()
|
||||
pe.DebugLogger = l
|
||||
pe.mu.Unlock()
|
||||
debugHardLock.Unlock()
|
||||
}
|
||||
|
||||
func (pe *ProxyEngine) SetShuffle(shuffle bool) {
|
||||
pe.mu.Lock()
|
||||
defer pe.mu.Unlock()
|
||||
pe.swampopt.shuffle = shuffle
|
||||
}
|
||||
|
|
|
@ -1,23 +1,13 @@
|
|||
package prox5
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.tcp.direct/kayos/go-socks5"
|
||||
|
||||
"git.tcp.direct/kayos/prox5/internal/pools"
|
||||
)
|
||||
|
||||
type socksLogger struct {
|
||||
parent *ProxyEngine
|
||||
}
|
||||
|
||||
// Printf is used to handle socks server logging.
|
||||
func (s socksLogger) Printf(format string, a ...interface{}) {
|
||||
buf := copABuffer.Get().(*strings.Builder)
|
||||
buf.WriteString(fmt.Sprintf(format, a...))
|
||||
s.parent.dbgPrint(buf)
|
||||
}
|
||||
|
||||
type socksCreds struct {
|
||||
username string
|
||||
password string
|
||||
|
@ -35,15 +25,15 @@ func (s socksCreds) Valid(username, password string) bool {
|
|||
// listen is standard Go listen string, e.g: "127.0.0.1:1080".
|
||||
// username and password are used for authenticatig to the SOCKS5 server.
|
||||
func (pe *ProxyEngine) StartSOCKS5Server(listen, username, password string) error {
|
||||
pe.socks5ServerAuth = socksCreds{username: username, password: password}
|
||||
|
||||
conf := &socks5.Config{
|
||||
Credentials: pe.socks5ServerAuth,
|
||||
Logger: pe.socksServerLogger,
|
||||
Credentials: socksCreds{username: username, password: password},
|
||||
Logger: pe.DebugLogger,
|
||||
Dial: pe.MysteryDialer,
|
||||
// Resolver: pe.MysteryResolver,
|
||||
}
|
||||
|
||||
buf := copABuffer.Get().(*strings.Builder)
|
||||
buf := pools.CopABuffer.Get().(*strings.Builder)
|
||||
buf.WriteString("listening for SOCKS5 connections on ")
|
||||
buf.WriteString(listen)
|
||||
pe.dbgPrint(buf)
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"bytes"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
|
@ -13,7 +12,10 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"h12.io/socks"
|
||||
"git.tcp.direct/kayos/socks"
|
||||
"golang.org/x/net/proxy"
|
||||
|
||||
"git.tcp.direct/kayos/prox5/internal/pools"
|
||||
)
|
||||
|
||||
func (pe *ProxyEngine) prepHTTP() (*http.Client, *http.Transport, *http.Request, error) {
|
||||
|
@ -34,7 +36,7 @@ func (pe *ProxyEngine) prepHTTP() (*http.Client, *http.Transport, *http.Request,
|
|||
var transporter = &http.Transport{
|
||||
DisableKeepAlives: true,
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //nolint:gosec
|
||||
TLSHandshakeTimeout: pe.swampopt.validationTimeout,
|
||||
TLSHandshakeTimeout: pe.GetValidationTimeout(),
|
||||
}
|
||||
|
||||
return client, transporter, req, err
|
||||
|
@ -49,13 +51,19 @@ func (sock *Proxy) good() {
|
|||
sock.lastValidated = time.Now()
|
||||
}
|
||||
|
||||
func (pe *ProxyEngine) bakeHTTP(sock *Proxy) (client *http.Client, req *http.Request, err error) {
|
||||
dialSocks := socks.Dial(fmt.Sprintf(
|
||||
"socks%s://%s/?timeout=%ss",
|
||||
getProtoStr(sock.proto),
|
||||
sock.Endpoint,
|
||||
pe.GetValidationTimeoutStr()),
|
||||
)
|
||||
func (pe *ProxyEngine) bakeHTTP(hmd *HandMeDown) (client *http.Client, req *http.Request, err error) {
|
||||
builder := pools.CopABuffer.Get().(*strings.Builder)
|
||||
builder.WriteString("socks")
|
||||
builder.WriteString(getProtoStr(hmd.sock.proto))
|
||||
builder.WriteString("://")
|
||||
builder.WriteString(hmd.sock.Endpoint)
|
||||
builder.WriteString("/?timeout=")
|
||||
builder.WriteString(pe.GetValidationTimeoutStr())
|
||||
builder.WriteString("s")
|
||||
|
||||
dialSocks := socks.DialWithConn(builder.String(), hmd.conn)
|
||||
pools.DiscardBuffer(builder)
|
||||
|
||||
var (
|
||||
purl *url.URL
|
||||
transport *http.Transport
|
||||
|
@ -65,26 +73,26 @@ func (pe *ProxyEngine) bakeHTTP(sock *Proxy) (client *http.Client, req *http.Req
|
|||
return
|
||||
}
|
||||
|
||||
if sock.proto != ProtoHTTP {
|
||||
transport.Dial = dialSocks //nolint:staticcheck
|
||||
if hmd.sock.proto != ProtoHTTP {
|
||||
transport.Dial = dialSocks
|
||||
client.Transport = transport
|
||||
return
|
||||
}
|
||||
if purl, err = url.Parse("http://" + sock.Endpoint); err != nil {
|
||||
if purl, err = url.Parse("http://" + hmd.sock.Endpoint); err != nil {
|
||||
return
|
||||
}
|
||||
transport.Proxy = http.ProxyURL(purl)
|
||||
return
|
||||
}
|
||||
|
||||
func (pe *ProxyEngine) checkHTTP(sock *Proxy) (string, error) {
|
||||
func (pe *ProxyEngine) validate(hmd *HandMeDown) (string, error) {
|
||||
var (
|
||||
client *http.Client
|
||||
req *http.Request
|
||||
err error
|
||||
)
|
||||
|
||||
client, req, err = pe.bakeHTTP(sock)
|
||||
client, req, err = pe.bakeHTTP(hmd)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -103,6 +111,22 @@ func (pe *ProxyEngine) anothaOne() {
|
|||
pe.stats.Checked++
|
||||
}
|
||||
|
||||
type HandMeDown struct {
|
||||
sock *Proxy
|
||||
conn net.Conn
|
||||
under proxy.Dialer
|
||||
}
|
||||
|
||||
func (hmd *HandMeDown) Dial(network, addr string) (c net.Conn, err error) {
|
||||
if hmd.conn.LocalAddr().Network() != network {
|
||||
return hmd.under.Dial(network, addr)
|
||||
}
|
||||
if hmd.conn.RemoteAddr().String() != addr {
|
||||
return hmd.under.Dial(network, addr)
|
||||
}
|
||||
return hmd.conn, nil
|
||||
}
|
||||
|
||||
func (pe *ProxyEngine) singleProxyCheck(sock *Proxy) error {
|
||||
defer pe.anothaOne()
|
||||
split := strings.Split(sock.Endpoint, "@")
|
||||
|
@ -110,13 +134,14 @@ func (pe *ProxyEngine) singleProxyCheck(sock *Proxy) error {
|
|||
if len(split) == 2 {
|
||||
endpoint = split[1]
|
||||
}
|
||||
if _, err := net.DialTimeout("tcp", endpoint,
|
||||
pe.swampopt.validationTimeout); err != nil {
|
||||
pe.badProx.Check(sock)
|
||||
conn, err := net.DialTimeout("tcp", endpoint, pe.GetValidationTimeout())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := pe.checkHTTP(sock)
|
||||
hmd := &HandMeDown{sock: sock, conn: conn, under: proxy.Direct}
|
||||
|
||||
resp, err := pe.validate(hmd)
|
||||
if err != nil {
|
||||
pe.badProx.Check(sock)
|
||||
return err
|
||||
|
@ -133,8 +158,9 @@ func (pe *ProxyEngine) singleProxyCheck(sock *Proxy) error {
|
|||
}
|
||||
|
||||
var protoMap = map[ProxyProtocol]string{
|
||||
ProtoSOCKS4: "4a", ProtoSOCKS4a: "4",
|
||||
ProtoSOCKS4: "4", ProtoSOCKS4a: "4a",
|
||||
ProtoSOCKS5: "5", ProtoHTTP: "http",
|
||||
ProtoSOCKS5h: "5h",
|
||||
}
|
||||
|
||||
func getProtoStr(protocol ProxyProtocol) string {
|
||||
|
|
Loading…
Reference in New Issue