Refactor + Re-use net.Conn for validation

This commit is contained in:
kayos@tcp.direct 2022-08-28 06:12:48 -07:00
parent 28805017f0
commit c3e3694a3e
Signed by: kayos
GPG Key ID: 4B841471B4BEE979
19 changed files with 293 additions and 308 deletions

View File

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

View File

@ -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
View File

@ -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
View File

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

View File

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

View File

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

View File

@ -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=

View File

@ -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) {

View File

@ -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
View File

@ -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
View File

@ -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=

13
internal/pools/strings.go Normal file
View File

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

6
logger/logger.go Normal file
View File

@ -0,0 +1,6 @@
package logger
type Logger interface {
Print(str string)
Printf(format string, a ...interface{})
}

View File

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

24
mystery_resolver.go Normal file
View File

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

View File

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

View File

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

View File

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

View File

@ -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 {