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
.env

114
main.go
View file

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