ai/pp
1
0
Fork 0

feat: proxy rotation for 9proxy.com

This commit is contained in:
Arthur K. 2026-03-08 09:46:13 +03:00
parent 4609d34e59
commit 14b9760386
Signed by: wzray
GPG key ID: B97F30FDC4636357
3 changed files with 92 additions and 28 deletions

5
.env.example Normal file
View file

@ -0,0 +1,5 @@
PROXY_USER=user-ssid-
PROXY_PASS=123
PROXY_HOST=localhost
PROXY_PORT=8080
PORT=80

1
.gitignore vendored
View file

@ -1 +1,2 @@
/pp /pp
.env

100
main.go
View file

@ -2,6 +2,7 @@ package main
import ( import (
"bufio" "bufio"
"crypto/rand"
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"io" "io"
@ -11,9 +12,18 @@ import (
"net/url" "net/url"
"os" "os"
"strings" "strings"
"sync/atomic"
"time" "time"
) )
var (
proxyUser string
proxyPass string
proxyHost string
sessionID string
rotateCounter atomic.Int64
)
func getEnvDefault(name, def string) string { func getEnvDefault(name, def string) string {
v := os.Getenv(name) v := os.Getenv(name)
if v != "" { if v != "" {
@ -22,37 +32,85 @@ func getEnvDefault(name, def string) string {
return def return def
} }
func parseProxy() *url.URL { func generateSessionID(length int) string {
raw := strings.TrimPrefix(strings.TrimSpace(os.Getenv("PROXY")), "http://") b := make([]byte, length)
if raw == "" { if _, err := rand.Read(b); err != nil {
log.Fatal("missing PROXY (format: login:password@ip:port)") log.Fatalf("failed to generate session ID: %v", err)
}
return base64.RawURLEncoding.EncodeToString(b)[:length]
} }
creds, hostPort, ok := strings.Cut(raw, "@") func getUpstreamURL() *url.URL {
if !ok { counter := rotateCounter.Load()
log.Fatal("expected login:password@ip:port") user := fmt.Sprintf("%s%s%d", proxyUser, sessionID, counter)
return &url.URL{
Scheme: "http",
User: url.UserPassword(user, proxyPass),
Host: proxyHost,
}
} }
login, password, ok := strings.Cut(creds, ":") func parseProxyConfig() {
if !ok || strings.TrimSpace(login) == "" || strings.TrimSpace(password) == "" { proxyUser = os.Getenv("PROXY_USER")
log.Fatal("expected login:password before @") if proxyUser == "" {
log.Fatal("missing PROXY_USER")
} }
hostPort = strings.TrimSpace(hostPort) proxyPass = os.Getenv("PROXY_PASS")
if _, _, err := net.SplitHostPort(hostPort); err != nil { if proxyPass == "" {
log.Fatalf("invalid ip:port: %v", err) log.Fatal("missing PROXY_PASS")
} }
return &url.URL{Scheme: "http", User: url.UserPassword(login, password), Host: hostPort} proxyHost = os.Getenv("PROXY_HOST")
if proxyHost == "" {
log.Fatal("missing PROXY_HOST")
} }
func proxyHandler(transport *http.Transport, upstream *url.URL) http.HandlerFunc { port := os.Getenv("PROXY_PORT")
if port == "" {
log.Fatal("missing PROXY_PORT")
}
proxyHost = net.JoinHostPort(proxyHost, port)
sessionID = generateSessionID(11)
rotateCounter.Store(0)
}
func getCurrentIP() string {
upstream := getUpstreamURL()
transport := &http.Transport{Proxy: http.ProxyURL(upstream)}
client := &http.Client{Transport: transport, Timeout: 10 * time.Second}
resp, err := client.Get("https://checkip.amazonaws.com")
if err != nil {
return fmt.Sprintf("error: %v", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Sprintf("error reading: %v", err)
}
return strings.TrimSpace(string(body))
}
func proxyHandler() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/health" { switch r.URL.Path {
case "/health":
w.Write([]byte("ok")) w.Write([]byte("ok"))
return return
case "/rotate":
newCounter := rotateCounter.Add(1)
ip := getCurrentIP()
log.Printf("Rotated to counter=%d, IP=%s", newCounter, ip)
w.Write([]byte(fmt.Sprintf("%s\n", ip)))
return
} }
upstream := getUpstreamURL()
transport := &http.Transport{Proxy: http.ProxyURL(upstream)}
if r.Method == http.MethodConnect { if r.Method == http.MethodConnect {
handleTunneling(w, r, upstream) handleTunneling(w, r, upstream)
return return
@ -173,10 +231,10 @@ func copyHeader(dst, src http.Header) {
func main() { func main() {
listenAddr := ":" + getEnvDefault("PORT", "80") listenAddr := ":" + getEnvDefault("PORT", "80")
upstream := parseProxy() parseProxyConfig()
transport := &http.Transport{Proxy: http.ProxyURL(upstream)} upstream := getUpstreamURL()
ip := getCurrentIP()
log.Printf("Proxy running on %s -> http://%s@%s", listenAddr, upstream.User.Username(), upstream.Host) log.Printf("started listen=%s upstream=http://%s ip=%s", listenAddr, upstream.Host, ip)
log.Fatal(http.ListenAndServe(listenAddr, proxyHandler(transport, upstream))) log.Fatal(http.ListenAndServe(listenAddr, proxyHandler()))
} }