Chore: tidy up

This commit is contained in:
kayos@tcp.direct 2022-07-25 00:14:26 -07:00
parent 144fe6b376
commit 28805017f0
Signed by: kayos
GPG Key ID: 4B841471B4BEE979
9 changed files with 159 additions and 88 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
.idea/
*.txt
*.list
*.swp
*.save

View File

@ -90,3 +90,72 @@ func (pe *ProxyEngine) dbgPrint(builder *strings.Builder) {
discardBuffer(buf)
}
}
func (pe *ProxyEngine) msgUnableToReach(socksString string) {
buf := copABuffer.Get().(*strings.Builder)
buf.WriteString("unable to reach [redacted] with ")
buf.WriteString(socksString)
buf.WriteString(", cycling...")
pe.dbgPrint(buf)
}
func (pe *ProxyEngine) msgUsingProxy(socksString string) {
buf := 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)
buf.WriteString("failed middleware check, ")
buf.WriteString(socksString)
buf.WriteString(", cycling...")
pe.dbgPrint(buf)
}
func (pe *ProxyEngine) msgTry(socksString string) {
buf := 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)
buf.WriteString("can't get lock for ")
buf.WriteString(socksString)
if putback {
buf.WriteString(", putting back in queue")
}
pe.dbgPrint(buf)
}
func (pe *ProxyEngine) msgGotLock(socksString string) {
buf := 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 success {
buf.WriteString("verified ")
buf.WriteString(sock.Endpoint)
buf.WriteString(" as SOCKS")
buf.WriteString(getProtoStr(sock.proto))
pe.dbgPrint(buf)
return
}
buf.WriteString("failed to verify: ")
buf.WriteString(sock.Endpoint)
pe.dbgPrint(buf)
}
func (pe *ProxyEngine) msgBadProxRate(sock *Proxy) {
buf := copABuffer.Get().(*strings.Builder)
buf.WriteString("badProx ratelimited: ")
buf.WriteString(sock.Endpoint)
pe.dbgPrint(buf)
}

View File

@ -158,8 +158,8 @@ func NewProxyEngine() *ProxyEngine {
}
stats := []int64{pe.stats.Valid4, pe.stats.Valid4a, pe.stats.Valid5, pe.stats.ValidHTTP, pe.stats.Dispensed}
for _, st := range stats {
atomic.StoreInt64(&st, 0)
for i := range stats {
atomic.StoreInt64(&stats[i], 0)
}
chans := []*chan *Proxy{&pe.Valids.SOCKS5, &pe.Valids.SOCKS4, &pe.Valids.SOCKS4a, &pe.Valids.HTTP, &pe.Pending}

View File

@ -69,7 +69,7 @@ func (pe *ProxyEngine) GetHTTPTunnel() (p *Proxy, ok bool) {
// GetAnySOCKS retrieves any version SOCKS proxy as a Proxy type
// Will block if one is not available!
// StateNew/Temporary: Pass a true boolean to this to also receive HTTP proxies.
func (pe *ProxyEngine) GetAnySOCKS(AcceptHTTP bool) *Proxy {
func (pe *ProxyEngine) GetAnySOCKS(acceptHTTP bool) *Proxy {
defer pe.stats.dispense()
for {
var sock *Proxy
@ -81,8 +81,7 @@ func (pe *ProxyEngine) GetAnySOCKS(AcceptHTTP bool) *Proxy {
case sock = <-pe.Valids.SOCKS5:
break
default:
if !AcceptHTTP {
time.Sleep(500 * time.Millisecond)
if !acceptHTTP {
continue
}
if httptun, htok := pe.GetHTTPTunnel(); htok {

View File

@ -141,7 +141,8 @@ func (pe *ProxyEngine) GetDialerBailout() int {
return pe.swampopt.dialerBailout
}
// TODO: More docs
// TODO: Document middleware concept
func (pe *ProxyEngine) GetDispenseMiddleware() func(*Proxy) (*Proxy, bool) {
pe.mu.RLock()
defer pe.mu.RUnlock()

View File

@ -44,7 +44,7 @@ func checkV6(in string) (filtered string, ok bool) {
return fmt.Sprintf("%s:%s@%s", split6[0], split6[1], combo.String()), true
}
func (pe *ProxyEngine) filter(in string) (filtered string, ok bool) {
func (pe *ProxyEngine) filter(in string) (filtered string, ok bool) { //nolint:cyclop
if !strings.Contains(in, ":") {
return in, false
}
@ -86,7 +86,7 @@ func (pe *ProxyEngine) filter(in string) (filtered string, ok bool) {
}
// LoadProxyTXT loads proxies from a given seed file and feeds them to the mapBuilder to be later queued automatically for validation.
// Expects the following formats:
// Expects one of the following formats for each line:
// * 127.0.0.1:1080
// * 127.0.0.1:1080:user:pass
// * yeet.com:1080
@ -116,7 +116,14 @@ func (pe *ProxyEngine) LoadProxyTXT(seedFile string) (count int) {
return pe.LoadMultiLineString(sockstr)
}
// LoadSingleProxy loads a SOCKS proxy into our map. Uses the format: 127.0.0.1:1080 (host:port).
// LoadSingleProxy loads a SOCKS proxy into our map.
// Expects one of the following formats:
// * 127.0.0.1:1080
// * 127.0.0.1:1080:user:pass
// * yeet.com:1080
// * yeet.com:1080:user:pass
// * [fe80::2ef0:5dff:fe7f:c299]:1080
// * [fe80::2ef0:5dff:fe7f:c299]:1080:user:pass
func (pe *ProxyEngine) LoadSingleProxy(sock string) (ok bool) {
if sock, ok = pe.filter(sock); !ok {
return
@ -136,7 +143,14 @@ func (pe *ProxyEngine) loadSingleProxy(sock string) {
}
}
// LoadMultiLineString loads a multiine string object with one (host:port) SOCKS proxy per line.
// LoadMultiLineString loads a multiine string object with proxy per line.
// Expects one of the following formats for each line:
// * 127.0.0.1:1080
// * 127.0.0.1:1080:user:pass
// * yeet.com:1080
// * yeet.com:1080:user:pass
// * [fe80::2ef0:5dff:fe7f:c299]:1080
// * [fe80::2ef0:5dff:fe7f:c299]:1080:user:pass
func (pe *ProxyEngine) LoadMultiLineString(socks string) int {
var count int
scan := bufio.NewScanner(strings.NewReader(socks))

View File

@ -32,15 +32,46 @@ func (pe *ProxyEngine) Dial(network, addr string) (net.Conn, error) {
// DialTimeout is a simple stub adapter to implement a net.Dialer with a timeout.
func (pe *ProxyEngine) DialTimeout(network, addr string, timeout time.Duration) (net.Conn, error) {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(timeout))
go func() {
select {
case <-ctx.Done():
cancel()
}
go func() { // this is a goroutine that calls cancel() upon the deadline expiring to avoid context leaks
<-ctx.Done()
cancel()
}()
return pe.MysteryDialer(ctx, network, addr)
}
func (pe *ProxyEngine) addTimeout(socksString string) string {
tout := copABuffer.Get().(*strings.Builder)
tout.WriteString(socksString)
tout.WriteString("?timeout=")
tout.WriteString(pe.GetServerTimeoutStr())
tout.WriteRune('s')
socksString = tout.String()
discardBuffer(tout)
return socksString
}
func (pe *ProxyEngine) popSockAndLockIt(ctx context.Context) (*Proxy, error) {
sock := pe.GetAnySOCKS(false)
socksString := sock.String()
select {
case <-ctx.Done():
return nil, fmt.Errorf("context done: %w", ctx.Err())
default:
if atomic.CompareAndSwapUint32(&sock.lock, stateUnlocked, stateLocked) {
pe.msgGotLock(socksString)
return sock, nil
}
select {
case pe.Pending <- sock:
pe.msgCantGetLock(socksString, true)
return nil, nil
default:
pe.msgCantGetLock(socksString, false)
return nil, nil
}
}
}
// 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 (
@ -55,71 +86,37 @@ func (pe *ProxyEngine) MysteryDialer(ctx context.Context, network, addr string)
return nil, fmt.Errorf("giving up after %d tries", max)
}
if err := ctx.Err(); err != nil {
return nil, fmt.Errorf("context error: %v", err)
return nil, fmt.Errorf("context error: %w", err)
}
var sock *Proxy
popSockAndLockIt:
for {
sock = pe.GetAnySOCKS(false)
socksString = sock.String()
select {
case <-ctx.Done():
return nil, fmt.Errorf("context done: %v", ctx.Err())
default:
buf := copABuffer.Get().(*strings.Builder)
if atomic.CompareAndSwapUint32(&sock.lock, stateUnlocked, stateLocked) {
buf.WriteString("got lock for ")
buf.WriteString(socksString)
break popSockAndLockIt
}
select {
case pe.Pending <- sock:
buf.WriteString("can't get lock, putting back ")
buf.WriteString(socksString)
pe.dbgPrint(buf)
continue
default:
buf.WriteString("can't get lock, can't put back ")
buf.WriteString(socksString)
continue
}
var err error
sock, err = pe.popSockAndLockIt(ctx)
if err != nil {
return nil, err
}
if sock != nil {
break
}
}
buf := copABuffer.Get().(*strings.Builder)
buf.WriteString("try dial with: ")
buf.WriteString(sock.Endpoint)
pe.dbgPrint(buf)
if pe.GetServerTimeoutStr() != "-1" {
tout := copABuffer.Get().(*strings.Builder)
tout.WriteString("?timeout=")
tout.WriteString(pe.GetServerTimeoutStr())
tout.WriteRune('s')
socksString = pe.addTimeout(socksString)
}
var ok bool
if sock, ok = pe.dispenseMiddleware(sock); !ok {
buf := copABuffer.Get().(*strings.Builder)
buf.WriteString("failed middleware check, ")
buf.WriteString(sock.String())
buf.WriteString(", cycling...")
pe.dbgPrint(buf)
pe.msgFailedMiddleware(socksString)
continue
}
pe.msgTry(socksString)
atomic.StoreUint32(&sock.lock, stateUnlocked)
dialSocks := socks.Dial(socksString)
conn, err := dialSocks(network, addr)
if err != nil {
count++
buf := copABuffer.Get().(*strings.Builder)
buf.WriteString("unable to reach [redacted] with ")
buf.WriteString(socksString)
buf.WriteString(", cycling...")
pe.dbgPrint(buf)
pe.msgUnableToReach(socksString)
continue
}
buf = copABuffer.Get().(*strings.Builder)
buf.WriteString("MysteryDialer using socks: ")
buf.WriteString(socksString)
pe.dbgPrint(buf)
pe.msgUsingProxy(socksString)
return conn, nil
}
}

View File

@ -2,8 +2,9 @@ package prox5
import (
"fmt"
"git.tcp.direct/kayos/go-socks5"
"strings"
"git.tcp.direct/kayos/go-socks5"
)
type socksLogger struct {

View File

@ -26,14 +26,14 @@ func (pe *ProxyEngine) prepHTTP() (*http.Client, *http.Transport, *http.Request,
headers["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"
headers["Accept-Language"] = "en-US,en;q=0.5"
headers["'Accept-Encoding'"] = "gzip, deflate, br"
headers["Connection"] = "keep-alive"
// headers["Connection"] = "keep-alive"
for header, value := range headers {
req.Header.Set(header, value)
}
var client = &http.Client{}
var transporter = &http.Transport{
DisableKeepAlives: true,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //nolint:gosec
TLSHandshakeTimeout: pe.swampopt.validationTimeout,
}
@ -66,7 +66,7 @@ func (pe *ProxyEngine) bakeHTTP(sock *Proxy) (client *http.Client, req *http.Req
}
if sock.proto != ProtoHTTP {
transport.Dial = dialSocks
transport.Dial = dialSocks //nolint:staticcheck
client.Transport = transport
return
}
@ -148,18 +148,15 @@ func (sock *Proxy) validate() {
atomic.StoreUint32(&sock.lock, stateLocked)
defer atomic.StoreUint32(&sock.lock, stateUnlocked)
s := sock.parent
if s.useProx.Check(sock) {
pe := sock.parent
if pe.useProx.Check(sock) {
// s.dbgPrint("useProx ratelimited: " + sock.Endpoint )
return
}
// determined as bad, won't try again until it expires from that cache
if s.badProx.Peek(sock) {
buf := copABuffer.Get().(*strings.Builder)
buf.WriteString("badProx ratelimited: ")
buf.WriteString(sock.Endpoint)
s.dbgPrint(buf)
if pe.badProx.Peek(sock) {
pe.msgBadProxRate(sock)
return
}
@ -168,11 +165,11 @@ func (sock *Proxy) validate() {
// try to use the proxy with all 3 SOCKS versions
for proto := range protoMap {
select {
case <-s.ctx.Done():
case <-pe.ctx.Done():
return
default:
sock.proto = proto
if err := s.singleProxyCheck(sock); err != nil {
if err := pe.singleProxyCheck(sock); err != nil {
// if the proxy is no good, we continue on to the next.
continue
}
@ -182,25 +179,16 @@ func (sock *Proxy) validate() {
switch sock.proto {
case ProtoSOCKS4, ProtoSOCKS4a, ProtoSOCKS5, ProtoHTTP:
buf := copABuffer.Get().(*strings.Builder)
buf.WriteString("verified ")
buf.WriteString(sock.Endpoint)
buf.WriteString(" as SOCKS")
buf.WriteString(getProtoStr(sock.proto))
s.dbgPrint(buf)
break
pe.msgChecked(sock, true)
default:
buf := copABuffer.Get().(*strings.Builder)
buf.WriteString("failed to verify: ")
buf.WriteString(sock.Endpoint)
s.dbgPrint(buf)
pe.msgChecked(sock, false)
sock.bad()
s.badProx.Check(sock)
pe.badProx.Check(sock)
return
}
sock.good()
s.tally(sock)
pe.tally(sock)
}
func (pe *ProxyEngine) tally(sock *Proxy) {