- Go 100%
|
|
||
|---|---|---|
| .github | ||
| example | ||
| internal | ||
| logger | ||
| .gitignore | ||
| CHANGELOG.md | ||
| conductor.go | ||
| daemons.go | ||
| debug.go | ||
| defs.go | ||
| dispense.go | ||
| getters.go | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| list_management.go | ||
| mr_worldwide.go | ||
| mystery_dialer.go | ||
| mystery_resolver.go | ||
| parse.go | ||
| parse_test.go | ||
| proto.go | ||
| proto_test.go | ||
| prox5_test.go | ||
| proxy.go | ||
| README.md | ||
| scale_util.go | ||
| setters.go | ||
| shim.go | ||
| socks5_server.go | ||
| stats.go | ||
| validator_engine.go | ||
Prox5
SOCKS5/4/4a validating proxy pool + SOCKS5 server
import git.tcp.direct/kayos/prox5
Prox5 is a golang library for managing, validating, and utilizing a very large amount of arbitrary SOCKS proxies.
Notably it features interface compatible dialer functions that dial out from different proxies for every connection, and a SOCKS5 server that utilizes those functions.
Caution
Using prox5 to proxy connections from certain offsec tools may cause denial of service. Please spazz out responsibly.
e.g: https://youtu.be/qVRFnxjD7o8
Table of Contents
Overview
Validation Engine
- TCP Dial to the endpoint, if successful, reuse net.Conn down for step 2
- HTTPS GET request to a list of IP echo endpoints
- Store the IP address discovered during step 2
- Allocate a new
prox5.Proxytype || update an existing one, store latest info - Enqueue a pointer to this
proxy.Proxyinstance, instantiating it for further use
Auto Scaler
The validation has an optional auto scale feature that allows for the automatic tuning of validation worker count as more proxies are dispensed.
This feature is still new, but seems to work well. It can be enabled with [...].EnableAutoScaler().
Please refer to the autoscale related items within the documentation for more info.
Rate Limiting
Using Rate5, prox5 naturally reduces the frequency of proxies that fail to validate. It does this by reducing the frequency proxies are accepted into the validation pipeline the more they fail to verify or fail to successfully connect to an endpoint. This is not yet adjustable, but will be soon. See the documentation for Rate5, and the source code for this project (defs.go is a good place to start) for more info.
Accessing Validated Proxies
- Retrieve validated 4/4a/5 proxies as simple strings for generic use
- Use one of the dialer functions with any golang code that calls for a net.Dialer
- Spin up a SOCKS5 server that will then make rotating use of your validated proxies
Additional info
The Secret Sauce
What makes Prox5 special is largely the Mystery Dialer. This dialer satisfies the net.Dialer and ContextDialer interfaces. The implementation is a little bit different from your average dialer. Here's roughly what happens when you dial out with a ProxyEngine;
- Loads up a previously verified proxy
- Attempts to make connection with the dial endpoint using said proxy
- Upon failure, prox5:
- repeats this process mid-dial
- does not drop connection to the client
- Once a proxy has been successfully used to connect to the target endpoint, prox5 passes the same net.Conn onto the client
Making Yourself Invisible
Dr. Jack Griffin discovered that invisibility requires more than just disappearing. You have to make sure nothing gives you away. Prox5 closes the gaps:
TLS fingerprinting: every TLS handshake from a single binary looks identical without countermeasures. A passive observer on any network can trivially identify your traffic by the ClientHello alone, regardless of which proxy you're using. Prox5 rotates through realistic browser fingerprints (Chrome 120, Firefox 120, Safari 16, Edge 106, and others) on every connection via uTLS. Your handshakes look like a crowd.
DNS leaks: even with a proxy, every hostname you connect to is typically resolved by your real IP before the proxy is ever involved. That's a full record of everywhere you went, in plaintext, from your real address. Enable p5.EnableDNSOverProxy() to route all resolution through the validated proxy pool via TCP DNS. The real IP never touches a resolver.
p5 := prox5.NewProxyEngine()
p5.EnableDNSOverProxy()
p5.SetDNSCacheTTL(10 * time.Minute)
p5.SetDNSCacheSize(1024)
The DNS cache also does round-robin across multiple resolved IPs, and collapses concurrent cache misses for the same hostname into a single query. No thundering herd against your resolver.
Connection closing: CloseAllConns() now broadcasts to every open connection simultaneously using context cancellation instead of the old channel approach. StopSOCKS5Server() shuts down the server gracefully.
Proxy chaining: one hop means one proxy that knows both you and the target. SetChainLength(n) routes each connection through N proxies in sequence. Proxy 0 knows your real IP but not the destination. Proxy N-1 connects to the target but only knows proxy N-2. The target sees only the exit node. Two hops is a substantial improvement. Three is sufficient for most threat models.
Timing jitter: proxy rotation, TLS fingerprinting, and DNS-over-proxy all operate on content. a passive observer watching traffic rhythm can still fingerprint a tool by when connections happen, how often, and at what intervals. SetJitter(max) adds a random sleep of 0..max before each dial. The pattern becomes unpredictable. 50ms is a reasonable start.
p5 := prox5.NewProxyEngine()
p5.EnableDNSOverProxy() // no DNS from your real IP
p5.SetChainLength(2) // two hops, no single proxy has the full picture
p5.SetJitter(50 * time.Millisecond) // unpredictable timing
p5.SetDNSCacheTTL(10 * time.Minute)
"An invisible man can rule the world. Nobody will see him come, nobody will see him go." The Invisible Man (1933)
Additions by Dr. Jack Griffin.
External Integrations
Mullvad
Take a look at mullsox for an easy way to access all of the mullvad proxies reachable from any one VPN endpoint. It is trivial to feed the results of GetAndVerifySOCKS into prox5.
Here's a snippet that should just about get you there:
package main
import (
"os"
"time"
"git.tcp.direct/kayos/mullsox"
"git.tcp.direct/kayos/prox5"
)
func main() {
p5 := prox5.NewProxyEngine()
mc := mullsox.NewChecker()
if err := mc.Update(); err != nil {
println(err.Error())
return
}
incoming, _ := mc.GetAndVerifySOCKS()
var count = 0
for line := range incoming {
if p5.LoadSingleProxy(line.String()) {
count++
}
}
if count == 0 {
println("failed to load any proxies")
return
}
if err := p5.Start(); err != nil {
println(err.Error())
return
}
go func() {
if err := p5.StartSOCKS5Server("127.0.0.1:42069", "", ""); err != nil {
println(err.Error())
os.Exit(1)
}
}()
time.Sleep(time.Millisecond * 500)
println("proxies loaded and socks server started")
}
Status and Final Thoughts
This project is in development.
It "works" and has been used in "production", but still needs some love. (i gave it love babe - ibot)
Please break it and let me know what broke.
The way you choose to use this lib is yours. The API is fairly extensive for you to be able to customize runtime configuration without having to do any surgery.
Things like the amount of validation workers that are concurrently operating, timeouts, and proxy re-use policies may be tuned in real-time.
Ideas from Dr. Griffin
things that could make this faster and meaner. not done yet. left here for whoever picks it up.
notification channel instead of polling
GetAnySOCKS currently sleeps 2ms between checks waiting for a validated proxy. under high concurrency with many goroutines waiting, that polling overhead compounds. replace with a chan struct{} that add() signals when a proxy enters any valid list. waiters block on the channel instead of sleeping. proxy becomes available, everyone wakes up immediately. zero polling, zero wasted sleep.
channel-based lists instead of mutex-guarded linked lists
every pop() and add() on a proxyList takes a full write lock. under high concurrency all goroutines serialize through one mutex per protocol. replace with a buffered channel per protocol. pop() becomes a non-blocking channel receive. add() becomes a channel send. no locks at all. tournament selection still works -- receive up to 3, compare, send 2 back.
warm connection pool
every mysteryDialer call dials the proxy at request time: TCP handshake, SOCKS negotiation, then the connection to your target. a background goroutine could maintain N live connections to the top-scored proxies. when a dial comes in, grab a pre-established connection and skip straight to the target hop. dispense goes from three network roundtrips to one. needs a freshness TTL since idle SOCKS connections get killed by the proxy eventually.
fast pre-filter for validation the validation timeout is 9 seconds. a proxy that is going to fail holds a worker for the full 9 seconds. add a 500ms TCP dial before committing a worker to the full HTTP GET. cheap connections get the full treatment, timeouts get killed fast and the worker moves on. improves validation throughput significantly on dirty proxy lists.
kayos+ibot 5evr