2021-09-12 02:59:05 +00:00
|
|
|
package pxndscvm
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"bytes"
|
2021-09-12 04:55:36 +00:00
|
|
|
"context"
|
2021-09-12 02:59:05 +00:00
|
|
|
"crypto/tls"
|
2021-09-12 04:55:36 +00:00
|
|
|
"errors"
|
2021-09-13 09:37:59 +00:00
|
|
|
"io"
|
2021-09-12 02:59:05 +00:00
|
|
|
"io/ioutil"
|
|
|
|
"net"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/alitto/pond"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
|
|
"golang.org/x/net/proxy"
|
|
|
|
"h12.io/socks"
|
|
|
|
)
|
|
|
|
|
2021-09-13 09:37:59 +00:00
|
|
|
const (
|
|
|
|
grn = "\033[32m"
|
|
|
|
red = "\033[31m"
|
|
|
|
rst = "\033[0m"
|
|
|
|
)
|
2021-09-12 04:55:36 +00:00
|
|
|
|
|
|
|
// LoadProxyTXT loads proxies from a given seed file and randomly feeds them to the workers.
|
2021-09-12 02:59:05 +00:00
|
|
|
// This fucntion has no real error handling, if the file can't be opened it's gonna straight up panic.
|
|
|
|
// TODO: make it more gooder.
|
2021-09-13 09:37:59 +00:00
|
|
|
func (s *Swamp) LoadProxyTXT(seedFile string) error {
|
|
|
|
s.dbgPrint("LoadProxyTXT start")
|
|
|
|
|
2021-09-12 02:59:05 +00:00
|
|
|
f, err := os.Open(seedFile)
|
|
|
|
if err != nil {
|
2021-09-13 09:37:59 +00:00
|
|
|
return err
|
2021-09-12 02:59:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
scan := bufio.NewScanner(f)
|
2021-09-13 10:08:04 +00:00
|
|
|
|
|
|
|
if !s.started {
|
|
|
|
go s.tossUp()
|
|
|
|
}
|
|
|
|
|
2021-09-12 02:59:05 +00:00
|
|
|
for scan.Scan() {
|
2021-09-12 04:55:36 +00:00
|
|
|
s.scvm = append(s.scvm, scan.Text())
|
2021-09-12 02:59:05 +00:00
|
|
|
}
|
2021-09-13 10:08:04 +00:00
|
|
|
|
|
|
|
if !s.started {
|
|
|
|
go s.feed()
|
|
|
|
}
|
|
|
|
|
|
|
|
s.started = true
|
|
|
|
|
2021-09-13 09:37:59 +00:00
|
|
|
if err := f.Close(); err != nil {
|
|
|
|
s.dbgPrint(err.Error())
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Swamp) feed() {
|
|
|
|
s.dbgPrint("swamp feed start")
|
2021-09-12 02:59:05 +00:00
|
|
|
for {
|
|
|
|
select {
|
2021-09-12 04:55:36 +00:00
|
|
|
case s.Pending <- RandStrChoice(s.scvm):
|
2021-09-12 02:59:05 +00:00
|
|
|
//
|
|
|
|
default:
|
|
|
|
time.Sleep(1 * time.Second)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-12 04:55:36 +00:00
|
|
|
// MysteryDial will return a dialer that will use a different proxy for every request.
|
|
|
|
func (s *Swamp) MysteryDial(ctx context.Context, network, addr string) (net.Conn, error) {
|
2021-09-13 08:30:49 +00:00
|
|
|
var sock *Proxy
|
|
|
|
sock = &Proxy{Endpoint: ""}
|
2021-09-12 04:55:36 +00:00
|
|
|
// pull down proxies from channel until we get a proxy good enough for our spoiled asses
|
|
|
|
for {
|
|
|
|
if err := ctx.Err(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
2021-09-13 08:30:49 +00:00
|
|
|
candidate := s.getProxy()
|
2021-09-13 09:37:59 +00:00
|
|
|
if !s.stillGood(candidate) {
|
2021-09-12 04:55:36 +00:00
|
|
|
continue
|
|
|
|
}
|
2021-09-13 09:37:59 +00:00
|
|
|
|
|
|
|
sock = candidate
|
|
|
|
|
2021-09-13 08:30:49 +00:00
|
|
|
if sock.Endpoint != "" {
|
2021-09-12 04:55:36 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if err := ctx.Err(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-09-13 08:30:49 +00:00
|
|
|
var dialSocks = socks.Dial("socks" + sock.Proto + "://" + sock.Endpoint + "?timeout=3s")
|
2021-09-12 04:55:36 +00:00
|
|
|
|
2021-09-13 08:30:49 +00:00
|
|
|
return dialSocks(network, addr)
|
2021-09-12 02:59:05 +00:00
|
|
|
}
|
|
|
|
|
2021-09-13 08:30:49 +00:00
|
|
|
func (s *Swamp) proxyGETRequest(sock *Proxy) (string, error) {
|
2021-09-12 04:55:36 +00:00
|
|
|
s.mu.RLock()
|
|
|
|
defer s.mu.RUnlock()
|
2021-09-12 02:59:05 +00:00
|
|
|
req, err := http.NewRequest("GET", RandStrChoice(myipsites), bytes.NewBuffer([]byte("")))
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
headers := make(map[string]string)
|
|
|
|
// headers["Host"] = "wtfismyip.com"
|
2021-09-12 04:55:36 +00:00
|
|
|
headers["User-Agent"] = RandStrChoice(s.swampopt.UserAgents)
|
2021-09-12 02:59:05 +00:00
|
|
|
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"
|
|
|
|
|
|
|
|
for header, value := range headers {
|
|
|
|
req.Header.Set(header, value)
|
|
|
|
}
|
|
|
|
|
2021-09-13 08:30:49 +00:00
|
|
|
var dialSocks = socks.Dial("socks" + sock.Proto + "://" + sock.Endpoint + "?timeout=4s")
|
2021-09-12 02:59:05 +00:00
|
|
|
var client *http.Client
|
|
|
|
|
2021-09-13 08:30:49 +00:00
|
|
|
if sock.Proto == "none" {
|
2021-09-12 02:59:05 +00:00
|
|
|
//goland:noinspection GoDeprecation
|
|
|
|
client = &http.Client{
|
|
|
|
Transport: &http.Transport{
|
|
|
|
Dial: proxy.Direct.Dial,
|
|
|
|
DisableKeepAlives: true,
|
|
|
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
|
|
|
TLSHandshakeTimeout: time.Duration(4) * time.Second,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//goland:noinspection GoDeprecation
|
|
|
|
client = &http.Client{
|
|
|
|
Transport: &http.Transport{
|
|
|
|
Dial: dialSocks,
|
|
|
|
DisableKeepAlives: true,
|
|
|
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
|
|
|
TLSHandshakeTimeout: time.Duration(4) * time.Second,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := client.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
2021-09-13 09:37:59 +00:00
|
|
|
defer func(Body io.ReadCloser) {
|
|
|
|
err := Body.Close()
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}(resp.Body)
|
|
|
|
|
|
|
|
rbody, err := ioutil.ReadAll(resp.Body)
|
|
|
|
return string(rbody), err
|
2021-09-12 02:59:05 +00:00
|
|
|
}
|
|
|
|
|
2021-09-13 08:30:49 +00:00
|
|
|
func (s *Swamp) singleProxyCheck(sock *Proxy) error {
|
2021-09-12 04:55:36 +00:00
|
|
|
s.mu.RLock()
|
|
|
|
defer s.mu.RUnlock()
|
2021-09-13 08:30:49 +00:00
|
|
|
if _, err := net.DialTimeout("tcp", sock.Endpoint, 8*time.Second); err != nil {
|
|
|
|
badProx.Check(sock)
|
2021-09-13 09:37:59 +00:00
|
|
|
return err
|
2021-09-12 02:59:05 +00:00
|
|
|
}
|
2021-09-13 08:30:49 +00:00
|
|
|
resp, err := s.proxyGETRequest(sock)
|
2021-09-12 02:59:05 +00:00
|
|
|
if err != nil {
|
2021-09-13 08:30:49 +00:00
|
|
|
badProx.Check(sock)
|
|
|
|
return err
|
2021-09-12 02:59:05 +00:00
|
|
|
}
|
|
|
|
if newip := net.ParseIP(resp); newip == nil {
|
2021-09-13 08:30:49 +00:00
|
|
|
badProx.Check(sock)
|
|
|
|
return errors.New("nil response from http request")
|
2021-09-12 02:59:05 +00:00
|
|
|
}
|
2021-09-13 09:37:59 +00:00
|
|
|
|
2021-09-13 08:30:49 +00:00
|
|
|
return nil
|
2021-09-12 02:59:05 +00:00
|
|
|
}
|
|
|
|
|
2021-09-12 04:55:36 +00:00
|
|
|
func (s *Swamp) tossUp() {
|
2021-09-13 09:37:59 +00:00
|
|
|
s.dbgPrint("tossUp() proxy checking loop start")
|
|
|
|
var sversions = []string{"5", "4", "4a"}
|
2021-09-12 04:55:36 +00:00
|
|
|
s.Birthday = time.Now()
|
2021-09-12 02:59:05 +00:00
|
|
|
panicHandler := func(p interface{}) {
|
|
|
|
log.Error().Interface("panic", p).Msg("Task panicked")
|
|
|
|
}
|
|
|
|
pool := pond.New(100, 10000, pond.MinWorkers(100), pond.PanicHandler(panicHandler))
|
|
|
|
for {
|
|
|
|
pool.Submit(func() {
|
|
|
|
for {
|
2021-09-13 08:30:49 +00:00
|
|
|
sock := <-s.Pending
|
|
|
|
p := &Proxy{
|
|
|
|
Endpoint: sock,
|
|
|
|
}
|
2021-09-13 09:37:59 +00:00
|
|
|
// ratelimited
|
2021-09-13 08:30:49 +00:00
|
|
|
if useProx.Check(p) {
|
2021-09-13 09:37:59 +00:00
|
|
|
s.dbgPrint("useProx ratelimited: " + p.Endpoint)
|
2021-09-12 02:59:05 +00:00
|
|
|
continue
|
|
|
|
}
|
2021-09-13 09:37:59 +00:00
|
|
|
// determined as bad, won't try again until it expires from that cache
|
2021-09-13 08:30:49 +00:00
|
|
|
if badProx.Peek(p) {
|
2021-09-13 09:37:59 +00:00
|
|
|
s.dbgPrint("badProx ratelimited: " + p.Endpoint)
|
2021-09-12 02:59:05 +00:00
|
|
|
continue
|
|
|
|
}
|
2021-09-13 09:37:59 +00:00
|
|
|
|
|
|
|
// try to use the proxy with all 3 SOCKS versions
|
|
|
|
var good = false
|
|
|
|
for _, sver := range sversions {
|
|
|
|
p.Proto = sver
|
|
|
|
if err := s.singleProxyCheck(p); err == nil {
|
|
|
|
s.dbgPrint(grn+"verified " + p.Endpoint + " as SOCKS" + sver+rst)
|
|
|
|
good = true
|
|
|
|
break
|
2021-09-13 08:30:49 +00:00
|
|
|
}
|
2021-09-12 02:59:05 +00:00
|
|
|
}
|
2021-09-13 09:37:59 +00:00
|
|
|
if !good {
|
|
|
|
s.dbgPrint(red+"failed to verify " + p.Endpoint+rst)
|
|
|
|
badProx.Check(p)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
switch p.Proto {
|
|
|
|
case "4":
|
2021-09-13 10:08:04 +00:00
|
|
|
s.Stats.v4()
|
2021-09-13 09:37:59 +00:00
|
|
|
s.Socks4 <- p
|
|
|
|
case "4a":
|
2021-09-13 10:08:04 +00:00
|
|
|
s.Stats.v4a()
|
2021-09-13 09:37:59 +00:00
|
|
|
s.Socks4a <- p
|
|
|
|
case "5":
|
2021-09-13 10:08:04 +00:00
|
|
|
s.Stats.v5()
|
2021-09-13 09:37:59 +00:00
|
|
|
s.Socks5 <- p
|
|
|
|
}
|
2021-09-12 02:59:05 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
time.Sleep(time.Duration(10) * time.Millisecond)
|
|
|
|
}
|
|
|
|
}
|