prox5/main.go

257 lines
5.3 KiB
Go
Raw Normal View History

2021-09-12 02:59:05 +00:00
package pxndscvm
import (
"bufio"
"bytes"
"crypto/tls"
2021-09-12 04:55:36 +00:00
"errors"
"io"
2021-09-12 02:59:05 +00:00
"io/ioutil"
"net"
"net/http"
"os"
"strconv"
2021-09-12 02:59:05 +00:00
"time"
"golang.org/x/net/proxy"
"h12.io/socks"
)
const (
grn = "\033[32m"
ylw = "\033[33m"
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.
// The first call to this function will start all background pool operations, essentially initializing the proxy pool.
// Additional calls will add more proxies to the pool to be validated.
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 {
return err
2021-09-12 02:59:05 +00:00
}
scan := bufio.NewScanner(f)
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
}
if !s.started {
go s.feed()
}
s.started = true
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 {
if s.Status == Paused {
return
}
2021-09-12 02:59:05 +00:00
select {
2021-09-13 15:12:02 +00:00
case s.Pending <- randStrChoice(s.scvm):
2021-09-12 02:59:05 +00:00
//
case <-s.quit:
s.dbgPrint("feed() paused")
return
2021-09-12 02:59:05 +00:00
default:
time.Sleep(1 * time.Second)
}
}
}
func (s *Swamp) checkHTTP(sock Proxy) (string, error) {
req, err := http.NewRequest("GET", s.GetRandomEndpoint(), bytes.NewBuffer([]byte("")))
2021-09-12 02:59:05 +00:00
if err != nil {
return "", err
}
headers := make(map[string]string)
headers["User-Agent"] = s.RandomUserAgent()
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)
}
var dialSocks = socks.Dial("socks" + sock.Proto + "://" +
sock.Endpoint + "?timeout=" + strconv.Itoa(s.GetValidationTimeout()) + "s")
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(s.GetValidationTimeout()) * time.Second,
2021-09-12 02:59:05 +00:00
},
}
} else {
//goland:noinspection GoDeprecation
client = &http.Client{
Transport: &http.Transport{
Dial: dialSocks,
DisableKeepAlives: true,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
TLSHandshakeTimeout: time.Duration(s.GetValidationTimeout()) * time.Second,
2021-09-12 02:59:05 +00:00
},
}
}
resp, err := client.Do(req)
if err != nil {
return "", err
}
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
}
func (s *Swamp) singleProxyCheck(sock Proxy) error {
if _, err := net.DialTimeout("tcp", sock.Endpoint, time.Duration(s.GetValidationTimeout())*time.Second); err != nil {
2021-09-13 08:30:49 +00:00
badProx.Check(sock)
return err
2021-09-12 02:59:05 +00:00
}
resp, err := s.checkHTTP(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
}
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("bad response from http request: " + resp)
2021-09-12 02:59:05 +00:00
}
sock.ProxiedIP = resp
2021-09-13 08:30:49 +00:00
return nil
2021-09-12 02:59:05 +00:00
}
func (s *Swamp) validate() {
var sversions = []string{"5", "4", "4a"}
2021-09-12 02:59:05 +00:00
for {
if s.Status == Paused {
return
}
sock := <-s.Pending
p := Proxy{
Endpoint: sock,
}
// ratelimited
if useProx.Check(p) {
// s.dbgPrint(blu+"useProx ratelimited: " + p.Endpoint+rst)
continue
}
// determined as bad, won't try again until it expires from that cache
if badProx.Peek(p) {
s.dbgPrint(ylw + "badProx ratelimited: " + p.Endpoint + rst)
continue
}
// try to use the proxy with all 3 SOCKS versions
var good = false
for _, sver := range sversions {
if s.Status == Paused {
return
}
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-12 02:59:05 +00:00
}
}
if !good {
s.dbgPrint(ylw + "failed to verify " + p.Endpoint + rst)
badProx.Check(p)
continue
}
p.Verified = time.Now()
switch p.Proto {
case "4":
s.Stats.v4()
s.Socks4 <- p
case "4a":
s.Stats.v4a()
s.Socks4a <- p
case "5":
s.Stats.v5()
s.Socks5 <- p
}
2021-09-12 02:59:05 +00:00
}
}
func (s *Swamp) tossUp() {
s.dbgPrint("tossUp() proxy checking loop start")
for {
if s.Status == Paused {
return
}
select {
case <-s.quit:
s.dbgPrint("tossUp() paused")
return
default:
go s.pool.Submit(s.validate)
time.Sleep(time.Duration(10) * time.Millisecond)
}
}
}
// Pause will cease all proxy pool operation. You will be able to start the proxy pool again, it will have the same Statistics, options, and ratelimits.
// Options may be changed and proxy lists may be loaded when paused.
// NOTE: There will be a few leftover validation attemps after pause, but no new jobs will be added.
func (s *Swamp) Pause() {
s.mu.Lock()
for n := 2; n > 0; n-- {
s.quit <- true
}
s.Status = Paused
}
// Resume will resume pause proxy pool operations, must be called after Pause or it will block.
func (s *Swamp) Resume() {
s.mu.Unlock()
s.Status = Running
go s.feed()
go s.tossUp()
}