2022-05-23 01:05:50 +00:00
|
|
|
package prox5
|
2021-09-14 07:28:10 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"crypto/tls"
|
|
|
|
"errors"
|
|
|
|
"io"
|
|
|
|
"net"
|
|
|
|
"net/http"
|
2022-05-23 01:20:40 +00:00
|
|
|
"net/url"
|
2021-10-23 17:25:28 +00:00
|
|
|
"strings"
|
2022-12-27 12:50:02 +00:00
|
|
|
"sync"
|
2021-09-20 05:57:42 +00:00
|
|
|
"sync/atomic"
|
2021-09-14 07:28:10 +00:00
|
|
|
"time"
|
|
|
|
|
2022-08-28 13:12:48 +00:00
|
|
|
"git.tcp.direct/kayos/socks"
|
|
|
|
"golang.org/x/net/proxy"
|
2021-09-14 07:28:10 +00:00
|
|
|
)
|
|
|
|
|
2022-12-27 12:50:02 +00:00
|
|
|
var headerPool = sync.Pool{
|
|
|
|
New: func() interface{} {
|
|
|
|
hdr := make(http.Header)
|
|
|
|
hdr["User-Agent"] = []string{""}
|
|
|
|
hdr["Accept"] = []string{"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"}
|
|
|
|
hdr["Accept-Language"] = []string{"en-US,en;q=0.5"}
|
|
|
|
hdr["Accept-Encoding"] = []string{"gzip, deflate, br"}
|
|
|
|
return hdr
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2022-10-16 10:53:04 +00:00
|
|
|
func (p5 *ProxyEngine) prepHTTP() (*http.Client, *http.Transport, *http.Request, error) {
|
2022-09-22 23:48:08 +00:00
|
|
|
req, err := http.NewRequest("GET", p5.GetRandomEndpoint(), bytes.NewBuffer([]byte("")))
|
2021-09-14 07:28:10 +00:00
|
|
|
if err != nil {
|
2021-09-24 00:15:15 +00:00
|
|
|
return nil, nil, nil, err
|
2021-09-14 07:28:10 +00:00
|
|
|
}
|
2022-12-27 12:50:02 +00:00
|
|
|
headers := headerPool.Get().(http.Header)
|
2022-12-27 13:04:15 +00:00
|
|
|
headers["User-Agent"] = []string{p5.RandomUserAgent()}
|
2022-12-27 12:50:02 +00:00
|
|
|
|
2022-06-28 02:27:52 +00:00
|
|
|
var client = &http.Client{}
|
2021-09-23 16:06:49 +00:00
|
|
|
var transporter = &http.Transport{
|
|
|
|
DisableKeepAlives: true,
|
2022-07-25 07:14:26 +00:00
|
|
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //nolint:gosec
|
2022-09-22 23:48:08 +00:00
|
|
|
TLSHandshakeTimeout: p5.GetValidationTimeout(),
|
2021-09-23 16:06:49 +00:00
|
|
|
}
|
2021-09-24 19:07:56 +00:00
|
|
|
|
2021-09-24 00:15:15 +00:00
|
|
|
return client, transporter, req, err
|
|
|
|
}
|
|
|
|
|
2021-09-24 19:07:56 +00:00
|
|
|
func (sock *Proxy) bad() {
|
2022-05-23 01:20:40 +00:00
|
|
|
atomic.AddInt64(&sock.timesBad, 1)
|
2021-09-24 19:07:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (sock *Proxy) good() {
|
2022-05-23 01:20:40 +00:00
|
|
|
atomic.AddInt64(&sock.timesValidated, 1)
|
|
|
|
sock.lastValidated = time.Now()
|
2021-09-24 19:07:56 +00:00
|
|
|
}
|
|
|
|
|
2022-12-27 12:50:02 +00:00
|
|
|
func httpEndpoint(hmd *handMeDown) (func(r *http.Request) (*url.URL, error), error) {
|
|
|
|
s := strs.Get()
|
|
|
|
defer strs.MustPut(s)
|
|
|
|
s.MustWriteString("http://")
|
|
|
|
s.MustWriteString(hmd.sock.Endpoint)
|
|
|
|
purl, err := url.Parse(s.String())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return http.ProxyURL(purl), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p5 *ProxyEngine) bakeHTTP(hmd *handMeDown) (client *http.Client, req *http.Request, err error) {
|
2022-10-16 06:45:19 +00:00
|
|
|
builder := strs.Get()
|
|
|
|
builder.MustWriteString(hmd.protoCheck.String())
|
|
|
|
builder.MustWriteString("://")
|
|
|
|
builder.MustWriteString(hmd.sock.Endpoint)
|
|
|
|
builder.MustWriteString("/?timeout=")
|
|
|
|
builder.MustWriteString(p5.GetValidationTimeoutStr())
|
|
|
|
builder.MustWriteString("s")
|
2022-08-28 13:12:48 +00:00
|
|
|
dialSocks := socks.DialWithConn(builder.String(), hmd.conn)
|
2022-10-16 06:45:19 +00:00
|
|
|
strs.MustPut(builder)
|
2022-08-28 13:12:48 +00:00
|
|
|
|
2022-12-27 12:50:02 +00:00
|
|
|
var transport *http.Transport
|
2021-09-14 07:28:10 +00:00
|
|
|
|
2022-12-27 12:50:02 +00:00
|
|
|
client, transport, req, err = p5.prepHTTP()
|
|
|
|
if err != nil {
|
|
|
|
if req != nil && req.Header != nil {
|
|
|
|
headerPool.Put(req.Header)
|
|
|
|
}
|
2022-05-23 01:20:40 +00:00
|
|
|
return
|
2021-09-23 16:06:49 +00:00
|
|
|
}
|
|
|
|
|
2022-09-22 23:24:35 +00:00
|
|
|
if hmd.protoCheck != ProtoHTTP {
|
2022-08-28 13:12:48 +00:00
|
|
|
transport.Dial = dialSocks
|
2022-05-23 01:20:40 +00:00
|
|
|
client.Transport = transport
|
|
|
|
return
|
|
|
|
}
|
2022-12-27 12:50:02 +00:00
|
|
|
|
|
|
|
proxyURL, err := httpEndpoint(hmd)
|
|
|
|
if err != nil {
|
|
|
|
if req != nil && req.Header != nil {
|
|
|
|
headerPool.Put(req.Header)
|
|
|
|
}
|
2022-05-23 01:20:40 +00:00
|
|
|
return
|
|
|
|
}
|
2022-12-27 12:58:10 +00:00
|
|
|
|
|
|
|
transport.Proxy = proxyURL
|
2022-05-23 01:20:40 +00:00
|
|
|
return
|
|
|
|
}
|
2021-09-24 00:15:15 +00:00
|
|
|
|
2022-12-27 12:58:10 +00:00
|
|
|
func (p5 *ProxyEngine) validate(hmd *handMeDown) (string, error) {
|
2022-05-23 01:20:40 +00:00
|
|
|
var (
|
|
|
|
client *http.Client
|
|
|
|
req *http.Request
|
|
|
|
err error
|
|
|
|
)
|
2021-09-14 07:28:10 +00:00
|
|
|
|
2022-09-22 23:48:08 +00:00
|
|
|
client, req, err = p5.bakeHTTP(hmd)
|
2022-05-23 01:20:40 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
2021-09-14 07:28:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := client.Do(req)
|
2022-12-27 12:50:02 +00:00
|
|
|
defer func() {
|
|
|
|
if req != nil && req.Header != nil {
|
|
|
|
headerPool.Put(req.Header)
|
|
|
|
}
|
|
|
|
}()
|
2021-09-14 07:28:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
2021-10-24 20:30:15 +00:00
|
|
|
rbody, err := io.ReadAll(resp.Body)
|
2022-06-28 02:27:52 +00:00
|
|
|
_ = resp.Body.Close()
|
2021-09-14 07:28:10 +00:00
|
|
|
return string(rbody), err
|
|
|
|
}
|
|
|
|
|
2022-10-16 10:53:04 +00:00
|
|
|
func (p5 *ProxyEngine) anothaOne() {
|
2022-12-27 12:59:23 +00:00
|
|
|
atomic.AddInt64(&p5.stats.Checked, 1)
|
2021-10-23 14:26:23 +00:00
|
|
|
}
|
|
|
|
|
2022-12-27 12:55:03 +00:00
|
|
|
type handMeDown struct {
|
2022-09-22 23:24:35 +00:00
|
|
|
sock *Proxy
|
|
|
|
protoCheck ProxyProtocol
|
|
|
|
conn net.Conn
|
|
|
|
under proxy.Dialer
|
2022-08-28 13:12:48 +00:00
|
|
|
}
|
|
|
|
|
2022-12-27 12:55:03 +00:00
|
|
|
func (hmd *handMeDown) Dial(network, addr string) (c net.Conn, err error) {
|
2022-08-28 13:12:48 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2022-10-16 10:53:04 +00:00
|
|
|
func (p5 *ProxyEngine) singleProxyCheck(sock *Proxy, protocol ProxyProtocol) error {
|
2022-09-22 23:48:08 +00:00
|
|
|
defer p5.anothaOne()
|
2021-10-23 17:25:28 +00:00
|
|
|
split := strings.Split(sock.Endpoint, "@")
|
|
|
|
endpoint := split[0]
|
|
|
|
if len(split) == 2 {
|
|
|
|
endpoint = split[1]
|
|
|
|
}
|
2022-09-22 23:48:08 +00:00
|
|
|
conn, err := net.DialTimeout("tcp", endpoint, p5.GetValidationTimeout())
|
2022-08-28 13:12:48 +00:00
|
|
|
if err != nil {
|
2021-09-14 07:28:10 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-12-27 12:55:03 +00:00
|
|
|
hmd := &handMeDown{sock: sock, conn: conn, under: proxy.Direct, protoCheck: protocol}
|
2022-08-28 13:12:48 +00:00
|
|
|
|
2022-09-22 23:48:08 +00:00
|
|
|
resp, err := p5.validate(hmd)
|
2021-09-14 07:28:10 +00:00
|
|
|
if err != nil {
|
2022-09-22 23:48:08 +00:00
|
|
|
p5.badProx.Check(sock)
|
2021-09-14 07:28:10 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if newip := net.ParseIP(resp); newip == nil {
|
2022-09-22 23:48:08 +00:00
|
|
|
p5.badProx.Check(sock)
|
2021-09-14 07:28:10 +00:00
|
|
|
return errors.New("bad response from http request: " + resp)
|
|
|
|
}
|
|
|
|
|
|
|
|
sock.ProxiedIP = resp
|
2021-10-23 14:26:23 +00:00
|
|
|
|
2021-09-14 07:28:10 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-09-20 08:49:06 +00:00
|
|
|
func (sock *Proxy) validate() {
|
2022-08-28 16:37:40 +00:00
|
|
|
if !atomic.CompareAndSwapUint32(&sock.lock, stateUnlocked, stateLocked) {
|
|
|
|
return
|
|
|
|
}
|
2022-05-23 01:20:40 +00:00
|
|
|
defer atomic.StoreUint32(&sock.lock, stateUnlocked)
|
2021-09-14 07:28:10 +00:00
|
|
|
|
2022-07-25 07:14:26 +00:00
|
|
|
pe := sock.parent
|
|
|
|
if pe.useProx.Check(sock) {
|
2022-06-26 02:51:42 +00:00
|
|
|
// s.dbgPrint("useProx ratelimited: " + sock.Endpoint )
|
2021-09-20 08:49:06 +00:00
|
|
|
return
|
|
|
|
}
|
2021-09-14 07:28:10 +00:00
|
|
|
|
2021-09-20 08:49:06 +00:00
|
|
|
// determined as bad, won't try again until it expires from that cache
|
2022-07-25 07:14:26 +00:00
|
|
|
if pe.badProx.Peek(sock) {
|
|
|
|
pe.msgBadProxRate(sock)
|
2021-09-20 08:49:06 +00:00
|
|
|
return
|
|
|
|
}
|
2021-09-14 07:28:10 +00:00
|
|
|
|
2022-05-23 01:20:40 +00:00
|
|
|
// TODO: consider giving the option for verbose logging of this stuff?
|
|
|
|
|
2022-09-22 23:24:35 +00:00
|
|
|
if sock.timesValidated == 0 || sock.protocol.Get() == ProtoNull {
|
2022-08-28 16:37:40 +00:00
|
|
|
// try to use the proxy with all 3 SOCKS versions
|
2022-09-22 23:24:35 +00:00
|
|
|
for tryProto := range protoMap {
|
2022-10-16 10:53:04 +00:00
|
|
|
if tryProto == ProtoNull {
|
|
|
|
continue
|
|
|
|
}
|
2022-08-28 16:37:40 +00:00
|
|
|
select {
|
|
|
|
case <-pe.ctx.Done():
|
|
|
|
return
|
|
|
|
default:
|
2022-09-22 23:24:35 +00:00
|
|
|
if err := pe.singleProxyCheck(sock, tryProto); err != nil {
|
2022-08-28 16:37:40 +00:00
|
|
|
// if the proxy is no good, we continue on to the next.
|
|
|
|
continue
|
|
|
|
}
|
2022-09-22 23:24:35 +00:00
|
|
|
sock.protocol.set(tryProto)
|
2022-08-28 16:37:40 +00:00
|
|
|
break
|
2022-05-23 01:20:40 +00:00
|
|
|
}
|
2022-08-28 16:37:40 +00:00
|
|
|
}
|
|
|
|
} else {
|
2022-09-22 23:24:35 +00:00
|
|
|
if err := pe.singleProxyCheck(sock, sock.GetProto()); err != nil {
|
2022-08-28 16:37:40 +00:00
|
|
|
sock.bad()
|
|
|
|
pe.badProx.Check(sock)
|
|
|
|
return
|
2021-09-14 07:28:10 +00:00
|
|
|
}
|
2021-09-20 08:49:06 +00:00
|
|
|
}
|
2021-09-14 07:28:10 +00:00
|
|
|
|
2022-09-22 23:24:35 +00:00
|
|
|
switch sock.protocol.Get() {
|
2022-05-23 01:20:40 +00:00
|
|
|
case ProtoSOCKS4, ProtoSOCKS4a, ProtoSOCKS5, ProtoHTTP:
|
2022-07-25 07:14:26 +00:00
|
|
|
pe.msgChecked(sock, true)
|
2022-05-23 01:20:40 +00:00
|
|
|
default:
|
2022-07-25 07:14:26 +00:00
|
|
|
pe.msgChecked(sock, false)
|
2021-09-24 19:07:56 +00:00
|
|
|
sock.bad()
|
2022-07-25 07:14:26 +00:00
|
|
|
pe.badProx.Check(sock)
|
2021-09-20 08:49:06 +00:00
|
|
|
return
|
|
|
|
}
|
2021-09-14 07:28:10 +00:00
|
|
|
|
2021-09-24 19:07:56 +00:00
|
|
|
sock.good()
|
2022-07-25 07:14:26 +00:00
|
|
|
pe.tally(sock)
|
2022-05-23 01:20:40 +00:00
|
|
|
}
|
|
|
|
|
2022-10-16 10:53:04 +00:00
|
|
|
func (p5 *ProxyEngine) tally(sock *Proxy) bool {
|
2022-09-28 23:44:23 +00:00
|
|
|
var target chan *Proxy
|
2022-09-22 23:24:35 +00:00
|
|
|
switch sock.protocol.Get() {
|
2022-05-23 01:20:40 +00:00
|
|
|
case ProtoSOCKS4:
|
2022-09-22 23:48:08 +00:00
|
|
|
p5.stats.v4()
|
2022-09-28 23:44:23 +00:00
|
|
|
target = p5.Valids.SOCKS4
|
2022-05-23 01:20:40 +00:00
|
|
|
case ProtoSOCKS4a:
|
2022-09-22 23:48:08 +00:00
|
|
|
p5.stats.v4a()
|
2022-09-28 23:44:23 +00:00
|
|
|
target = p5.Valids.SOCKS4a
|
2022-05-23 01:20:40 +00:00
|
|
|
case ProtoSOCKS5:
|
2022-09-22 23:48:08 +00:00
|
|
|
p5.stats.v5()
|
2022-09-28 23:44:23 +00:00
|
|
|
target = p5.Valids.SOCKS5
|
2022-05-23 01:20:40 +00:00
|
|
|
case ProtoHTTP:
|
2022-09-22 23:48:08 +00:00
|
|
|
p5.stats.http()
|
2022-09-28 23:44:23 +00:00
|
|
|
target = p5.Valids.HTTP
|
2021-09-24 00:15:15 +00:00
|
|
|
default:
|
2022-09-28 23:44:23 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
select {
|
|
|
|
case target <- sock:
|
|
|
|
return true
|
2021-09-14 07:28:10 +00:00
|
|
|
}
|
|
|
|
}
|