
💫 Alternativa a Ngrok FRP • ⚡ Veloce • 🪶 Leggero • 0️⃣ Dipendenza • 🔌 Pluggabile • 😈 Intercettazione TLS • 🔒 DNS-over-HTTPS • 🔥 VPN del povero • ⏪ Inversione e ⏩ Inoltro • 👮🏿 framework "Server Proxy" • 🌐 framework "Server Web" • ➵ ➶ ➷ ➠ framework "PubSub" • 👷 framework "Work" accettatore ed esecutore
Veloce e Scalabile
Scalabile sfruttando tutti i core disponibili sul sistema
Esecuzioni senza thread (threadless) usando asyncio
Progettato per gestire decine di migliaia di connessioni / sec
# On Macbook Pro M2 2022
❯ python --version
Python 3.11.8
❯ oha --version
oha 1.4.3
❯ ./benchmark/compare.sh
CONCURRENCY: 100 workers, DURATION: 1m, TIMEOUT: 1sec
=============================
Benchmarking Proxy.Py
Server (pid:75969) running
Summary:
Success rate: 100.00%
Total: 60.0006 secs
Slowest: 0.2525 secs
Fastest: 0.0002 secs
Average: 0.0019 secs
Requests/sec: 51667.3774
Total data: 56.17 MiB
Size/request: 19 B
Size/sec: 958.64 KiB
Response time histogram:
0.000 [1] |
0.025 [3073746] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.051 [10559] |
0.076 [4980] |
0.101 [2029] |
0.126 [5896] |
0.152 [2466] |
0.177 [116] |
0.202 [40] |
0.227 [52] |
0.253 [87] |
Response time distribution:
10.00% in 0.0005 secs
25.00% in 0.0007 secs
50.00% in 0.0009 secs
75.00% in 0.0014 secs
90.00% in 0.0021 secs
95.00% in 0.0035 secs
99.00% in 0.0198 secs
99.90% in 0.1262 secs
99.99% in 0.1479 secs
Details (average, fastest, slowest):
DNS+dialup: 0.0018 secs, 0.0004 secs, 0.0031 secs
DNS-lookup: 0.0000 secs, 0.0000 secs, 0.0002 secs
Status code distribution:
[200] 3099972 responses
Error distribution:
[100] aborted due to deadline
=============================
Consulta Distribuire proxy.py in produzione quando distribuisci applicazioni di livello produttivo usando proxy.py.
Installa da `PyPi````console ❯ pip install --upgrade proxy.py
o dal branch `master` di GitHub```console
❯ pip install git+https://github.com/abhinavsingh/proxy.py.git@master
❯ pip install git+https://github.com/abhinavsingh/proxy.py.git@develop
## Utilizzo di Docker
I contenitori multi-piattaforma sono disponibili tramite:
- Docker Hub
- il tag `latest` punta all'ultima release `stable`
- `docker pull abhinavsingh/proxy.py:latest`
- Registro contenitori GitHub (GHCR)
- il tag `latest` punta all'ultima release `develop`
- `docker pull ghcr.io/abhinavsingh/proxy.py:latest`
Le release dei contenitori della versione stabile sono disponibili per le seguenti piattaforme:
- `linux/386`
- `linux/amd64`
- `linux/arm/v6`
- `linux/arm/v7`
- `linux/arm64/v8`
- `linux/ppc64le`
- `linux/s390x`
### Versione stabile da Docker Hub
Esegui il contenitore più recente di `proxy.py`:```console
❯ docker run -it -p 8899:8899 --rm abhinavsingh/proxy.py:latest
Il demone Docker scaricherà automaticamente l'immagine della piattaforma corrispondente. Per eseguire un container su una piattaforma specifica su server che supportano più piattaforme:```console ❯ docker run -it -p 8899:8899 --rm --platform linux/arm64/v8 abhinavsingh/proxy.py:latest
### Versione di sviluppo da GHCR
Esegui il container `proxy.py` dal codice all'avanguardia nel branch develop:```console
❯ docker run -it -p 8899:8899 --rm ghcr.io/abhinavsingh/proxy.py:latest
❯ git clone https://github.com/abhinavsingh/proxy.py.git ❯ cd proxy.py && make container ❯ docker run -it -p 8899:8899 --rm abhinavsingh/proxy.py:latest
[](https://github.com/moby/vpnkit/issues/469)
L'immagine `docker` è attualmente non funzionante su `macOS` a causa di incompatibilità con [vpnkit](https://github.com/moby/vpnkit/issues/469).
## Utilizzo di HomeBrew
Le formule aggiornate per `HomeBrew` sono mantenute nel ramo `develop` sotto la directory `helper/homebrew`.
- Le formule `stable` installano il pacchetto dal ramo `master`.
- Le formule `develop` installano il pacchetto dal ramo `develop`.
### Versione Stabile con HomeBrew```console
❯ brew install https://raw.githubusercontent.com/abhinavsingh/proxy.py/develop/helper/homebrew/stable/proxy.rb
❯ brew install https://raw.githubusercontent.com/abhinavsingh/proxy.py/develop/helper/homebrew/develop/proxy.rb
# Avvia proxy.py
## Da riga di comando quando installato tramite PIP
Quando `proxy.py` viene installato tramite `pip`,
un eseguibile chiamato `proxy` viene inserito nel tuo `$PATH`.
### Eseguilo
Basta digitare `proxy` sulla riga di comando per avviare con la configurazione predefinita.```console
❯ proxy
...[redacted]... - Loaded plugin proxy.http.proxy.HttpProxyPlugin
...[redacted]... - Started 8 threadless workers
...[redacted]... - Started 8 acceptors
...[redacted]... - Listening on 127.0.0.1:8899
Cose da notare dai log precedenti:
Loaded plugin
proxy.py caricherà proxy.http.proxy.HttpProxyPlugin per impostazione predefinitahttp(s) all'istanza di proxy.pyStarted N threadless workers
proxy.py avvierà tanti processi worker quanti sono i core della CPU sulla macchina--num-workers per personalizzare il numero di processi workerStarted N acceptors
proxy.py avvierà tanti processi acceptor quanti sono i core della CPU sulla macchina--num-acceptors per personalizzare il numero di processi acceptorTutti i log precedenti sono log di livello INFO, il --log-level predefinito per proxy.py
Avviamo proxy.py con logging a livello DEBUG:```console
❯ proxy --log-level d
...[redacted]... - Open file descriptor soft limit set to 1024
...[redacted]... - Loaded plugin proxy.http_proxy.HttpProxyPlugin
...[redacted]... - Started 8 workers
...[redacted]... - Started server on ::1:8899
You can use single letter to customize log level. Example:
- `d = DEBUG`
- `i = INFO`
- `w = WARNING`
- `e = ERROR`
- `c = CRITICAL`
As we can see from the above logs, before starting up:
- `proxy.py` tried to set open file limit `ulimit` on the system
- Default value for `--open-file-limit` used is `1024`
- `--open-file-limit` flag is a no-op on `Windows` operating systems
See [flags](#flags) for full list of available configuration options.
## From command line using repo source
If you are trying to run `proxy.py` from source code,
there is no binary file named `proxy` in the source code.
To start `proxy.py` from source code follow these instructions:
- Clone repo ```console
❯ git clone https://github.com/abhinavsingh/proxy.py.git
❯ cd proxy.py
Crea un ambiente virtuale Python 3 ```console ❯ python3 -m venv venv ❯ source venv/bin/activate
Installa dipendenze ```console ❯ make lib-dep
Generate proxy/common/_scm_version.py
NOTA: Il passaggio seguente non è necessario per installazioni modificabili.
Questo file scrive la versione rilevata da SCM nel file proxy/common/_scm_version.py. ```console
❯ ./write-scm-version.sh
Opzionalmente, esegui i test ```console ❯ make
Esegui proxy.py ```console
❯ python -m proxy
See Plugin Developer and Contributor Guide
se hai intenzione di lavorare con il codice sorgente di proxy.py.
Per impostazione predefinita, il binario docker viene avviato con i flag di rete IPv4:
--hostname 0.0.0.0 --port 8899
Puoi sovrascrivere i flag dalla riga di comando quando avvii il container docker. Ad esempio, per controllare la versione di proxy.py all'interno del container docker, esegui:
❯ docker run -it \
-p 8899:8899 \
--rm abhinavsingh/proxy.py:latest \
-v
https
Aggiungi il supporto per i link brevi nei tuoi browser/applicazioni preferiti.
Avvia proxy.py come:```console
❯ proxy
--plugins proxy.plugin.ShortLinkPlugin
Ora puoi velocizzare la tua navigazione quotidiana visitando il tuo sito web preferito utilizzando nomi di dominio a singolo carattere :). Questo funziona su tutti i browser.
I seguenti collegamenti brevi sono abilitati per impostazione predefinita:
| Collegamento breve | URL di destinazione |
| :----------------: | :------------------: |
| a/ | `amazon.com` |
| i/ | `instagram.com` |
| l/ | `linkedin.com` |
| f/ | `facebook.com` |
| g/ | `google.com` |
| t/ | `twitter.com` |
| w/ | `web.whatsapp.com` |
| y/ | `youtube.com` |
| proxy/ | `localhost:8899` |
### ModifyPostDataPlugin
Modifica il corpo della richiesta POST prima di inviare la richiesta al server upstream.
Avvia `proxy.py` come:```console
❯ proxy \
--plugins proxy.plugin.ModifyPostDataPlugin
Di default il plugin sostituisce il contenuto del corpo della POST con il valore hard-coded b'{"key": "modified"}'
e impone Content-Type: application/json.
Verifica lo stesso usando `curl -x localhost:8899 -d '{"key": "value"}' http://httpbin.org/post````console { "args": {}, "data": "{"key": "modified"}", "files": {}, "form": {}, "headers": { "Accept": "/", "Content-Length": "19", "Content-Type": "application/json", "Host": "httpbin.org", "User-Agent": "curl/7.54.0" }, "json": { "key": "modified" }, "origin": "1.2.3.4, 5.6.7.8", "url": "https://httpbin.org/post" }
Nota seguendo dalla risposta sopra:
1. I dati POST sono stati modificati `"data": "{\"key\": \"modified\"}"`.
I dati originali del comando `curl` erano `{"key": "value"}`.
2. Il nostro comando `curl` non ha aggiunto alcun header `Content-Type`,
ma il nostro plugin ne ha aggiunto uno `"Content-Type": "application/json"`.
Lo stesso può essere verificato anche osservando il campo `json` nell'output sopra: ```
"json": {
"key": "modified"
},
Content-Length per corrispondere alla lunghezza
del corpo modificato.Risposte simulate per la tua API REST del server. Utilizza per testare e sviluppare applicazioni lato client senza la necessità di un server API REST upstream reale.
Avvia proxy.py come:```console
❯ proxy
--plugins proxy.plugin.ProposedRestApiPlugin
Verifica la risposta dell'API mock utilizzando `curl -x localhost:8899 http://api.example.com/v1/users/````console
{"count": 2, "next": null, "previous": null, "results": [{"email": "[email protected]", "groups": [], "url": "api.example.com/v1/users/1/", "username": "admin"}, {"email": "[email protected]", "groups": [], "url": "api.example.com/v1/users/2/", "username": "admin"}]}
Verifica lo stesso esaminando i log di proxy.py:```console
... [redacted] ... - access_log:1210 - ::1:64792 - GET None:None/v1/users/ - None None - 0 byte
Il log di accesso mostra `None:None` come server `ip:port`. `None` significa semplicemente che la connessione al server non è mai stata effettuata, poiché la risposta è stata restituita dal nostro plugin.
Ora modifica `ProposedRestApiPlugin` per restituire risposte mock dell'API REST come previsto dai tuoi client.
### RedirectToCustomServerPlugin
Reindirizza tutte le richieste `http` in arrivo a un server web personalizzato.
Per impostazione predefinita, reindirizza le richieste dei client al server web integrato, anch'esso in esecuzione sulla porta `8899`.
Avvia `proxy.py` e abilita il server web integrato:```console
❯ proxy \
--enable-web-server \
--plugins proxy.plugin.RedirectToCustomServerPlugin
Verifica usando `curl -v -x localhost:8899 http://google.com```` ... [redacted] ... < HTTP/1.1 404 NOT FOUND < Server: proxy.py v1.0.0 < Connection: Close <
La risposta `404` sopra è stata restituita dal server web `proxy.py`.
Verifica lo stesso controllando i log per `proxy.py`.
Insieme al log delle richieste proxy, devi anche vedere un log delle richieste del server web http.```
... [redacted] ... - access_log:1241 - ::1:49525 - GET /
... [redacted] ... - access_log:1157 - ::1:49524 - GET localhost:8899/ - 404 NOT FOUND - 70 bytes
Blocca il traffico ispezionando l'host upstream.
Per impostazione predefinita, il plugin blocca il traffico per facebook.com e www.facebok.com.
Avvia proxy.py come:```console
❯ proxy
--plugins proxy.plugin.FilterByUpstreamHostPlugin
Verifica utilizzando `curl -v -x localhost:8899 http://facebook.com`:```console
... [redacted] ...
< HTTP/1.1 418 I'm a tea pot
< Proxy-agent: proxy.py v1.0.0
* no chunk, no close, no size. Assume close to signal end
<
* Closing connection 0
Il 418 I'm a tea pot sopra è inviato dal nostro plugin. Verifica lo stesso ispezionando i log di proxy.py:```console
... [redacted] ... - handle_readables:1347 - HttpProtocolException type raised
Traceback (most recent call last):
... [redacted] ...
... [redacted] ... - access_log:1157 - ::1:49911 - GET None:None/ - None None - 0 bytes
### CacheResponsesPlugin
Memorizza nella cache le risposte del server upstream.
Avvia `proxy.py` come:```console
❯ proxy \
--plugins proxy.plugin.CacheResponsesPlugin
Puoi anche usare il flag --cache-requests per abilitare la memorizzazione nella cache dei pacchetti di richiesta a scopo di ispezione.
Verifica utilizzando curl -v -x localhost:8899 http://httpbin.org/get:```console
... [redacted] ...
< HTTP/1.1 200 OK
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Origin: *
< Content-Type: application/json
< Date: Wed, 25 Sep 2019 02:24:25 GMT
< Referrer-Policy: no-referrer-when-downgrade
< Server: nginx
< X-Content-Type-Options: nosniff
< X-Frame-Options: DENY
< X-XSS-Protection: 1; mode=block
< Content-Length: 202
< Connection: keep-alive
<
{
"args": {},
"headers": {
"Accept": "/",
"Host": "httpbin.org",
"User-Agent": "curl/7.54.0"
},
"origin": "1.2.3.4, 5.6.7.8",
"url": "https://httpbin.org/get"
}
Ottieni il percorso del file cache dai log di `proxy.py`:```console
... [redacted] ... - GET httpbin.org:80/get - 200 OK - 556 bytes
... [redacted] ... - Cached response at /var/folders/k9/x93q0_xn1ls9zy76m2mf2k_00000gn/T/httpbin.org-1569378301.407512.txt
Verifica il contenuto del file cache `cat /path/to/your/cache/httpbin.org.txt````console HTTP/1.1 200 OK Access-Control-Allow-Credentials: true Access-Control-Allow-Origin: * Content-Type: application/json Date: Wed, 25 Sep 2019 02:24:25 GMT Referrer-Policy: no-referrer-when-downgrade Server: nginx X-Content-Type-Options: nosniff X-Frame-Options: DENY X-XSS-Protection: 1; mode=block Content-Length: 202 Connection: keep-alive
{ "args": {}, "headers": { "Accept": "/", "Host": "httpbin.org", "User-Agent": "curl/7.54.0" }, "origin": "1.2.3.4, 5.6.7.8", "url": "https://httpbin.org/get" }
### CacheByResponseType
Il plugin `CacheResponsesPlugin` può anche memorizzare automaticamente nella cache le risposte in base al `content-type`.
Per provare ciò, è necessario essere in esecuzione in modalità [TLS Interception](#tls-interception)
e quindi passare il flag `--cache-by-content-type`. Esempio:```console
❯ proxy \
--plugins proxy.plugin.CacheResponsesPlugin \
--cache-by-content-type \
--ca-key-file ca-key.pem \
--ca-cert-file ca-cert.pem \
--ca-signing-key ca-signing-key.pem
Fai alcune richieste al server proxy e vedrai i dati nella directory ~/.proxy/cache.
Dovresti vedere 2 cartelle:
content: Contiene file jpg, css, js, html, pdf ecc. analizzati per tipo di contenutoresponses: Contiene le risposte grezze così come ricevute (ovviamente decriptate a causa dell'intercettazione)Modifica le risposte del server upstream.
Avvia proxy.py come:```console
❯ proxy
--plugins proxy.plugin.ManInTheMiddlePlugin
Verifica utilizzando `curl -v -x localhost:8899 http://google.com`:```console
... [redacted] ...
< HTTP/1.1 200 OK
< Content-Length: 28
<
* Connection #0 to host localhost left intact
Hello from man in the middle
Il corpo della risposta Hello from man in the middle viene inviato dal nostro plugin.
Inoltra le richieste proxy in entrata a un insieme di server proxy upstream.
Iniziamo prima con 2 proxy upstream. Per simulare proxy upstream,
avvia proxy.py sulla porta 9000 e `9001````console
❯ proxy --port 9000
Opzionale:
-c, --check <CVE> Controlla solo il numero CVE specificato
-d, --demo <filename> Modalità demo, specifica un file da testare
-v, --verbose Modalità verbose opzionale```console
❯ proxy --port 9001
Ora, avvia proxy.py con ProxyPoolPlugin (sulla porta predefinita 8899), puntando ai nostri proxy upstream sulle porte 9000 e 9001.```console
❯ proxy
--plugins proxy.plugin.ProxyPoolPlugin
--proxy-pool localhost:9000
--proxy-pool localhost:9001
Effettua una richiesta curl tramite il proxy `8899`:
`curl -v -x localhost:8899 http://httpbin.org/get`
Verifica che il proxy `8899` inoltri le richieste ai proxy upstream controllando i relativi log.
Se un proxy upstream richiede credenziali, passale come argomenti. Esempio:
`--proxy-pool user:[email protected]:port`
### FilterByClientIpPlugin
Respingi il traffico da indirizzi IP specifici. Di default questo
plugin blocca il traffico da `127.0.0.1` e `::1`.
Avvia `proxy.py` come:```console
❯ proxy \
--plugins proxy.plugin.FilterByClientIpPlugin
Invia una richiesta utilizzando curl -v -x localhost:8899 http://google.com:```console
... [redacted] ...
Proxy-Connection: Keep-Alive
< HTTP/1.1 418 I'm a tea pot < Connection: close <
Modifica il plugin a tuo piacimento, ad esempio permetti solo indirizzi IP specifici.
### ModifyChunkResponsePlugin
Questo plugin dimostra come modificare le risposte codificate a blocchi. Per farlo, utilizza il core di `proxy.py` per analizzare la risposta codificata a blocchi. Quindi ricostruiamo la risposta utilizzando blocchi personalizzati hard-coded, ignorando i blocchi originali ricevuti dal server upstream.
Avvia `proxy.py` come:```console
❯ proxy \
--plugins proxy.plugin.ModifyChunkResponsePlugin
Verifica utilizzando curl -v -x localhost:8899 http://httpbin.org/stream/5:```console
... [redacted] ...
modify
chunk
response
plugin
Modifica `ModifyChunkResponsePlugin` a tuo piacimento. Esempio, invece di inviare chunk hard-coded, analizza e modifica i chunk `JSON` originali ricevuti dal server upstream.
### ModifyRequestHeaderPlugin
Questo plugin dimostra come modificare gli header delle richieste HTTPS in uscita in modalità di intercettazione TLS.
Avvia `proxy.py` come:```console
❯ proxy \
--plugins proxy.plugin.ModifyRequestHeaderPlugin \
... [TLS interception flags] ...
Verifica usando curl -x localhost:8899 --cacert ca-cert.pem https://httpbin.org/get:```console
{
"args": {},
"headers": {
... [redacted] ...,
"X-Proxy-Py-Version": "2.4.4rc6.dev15+gf533c711"
},
... [redacted] ...
}
### CloudflareDnsResolverPlugin
Questo plugin utilizza l'`API` `DNS-over-HTTPS` ospitata da `Cloudflare` [API](https://developers.cloudflare.com/1.1.1.1/encrypted-dns/dns-over-https/make-api-requests/dns-json) (json).
`DoH` richiede un client conforme a HTTP2. Sfortunatamente `proxy.py` non lo fornisce ancora, quindi usiamo una dipendenza. Installala:
```bash
pip install <dependency-name>
``````console
❯ pip install "httpx[http2]"
Ora avvia proxy.py come:```console
❯ proxy
--plugins proxy.plugin.CloudflareDnsResolverPlugin
Per impostazione predefinita, `CloudflareDnsResolverPlugin` funziona in modalità `security` e offre protezione da malware.
Usa `--cloudflare-dns-mode family` per abilitare anche la protezione da contenuti per adulti.
### CustomDnsResolverPlugin
Questo plugin dimostra come utilizzare un'implementazione personalizzata di risoluzione DNS con `proxy.py`.
Questo plugin di esempio attualmente utilizza il meccanismo di risoluzione integrato di Python. Personalizza il codice
a tuo piacimento. Ad esempio, interroga il tuo server DNS personalizzato, implementa `DoH` o altri meccanismi.
Avvia `proxy.py` come:```console
❯ proxy \
--plugins proxy.plugin.CustomDnsResolverPlugin
Il callback HttpProxyBasePlugin.resolve_dns può anche essere utilizzato per configurare network interface che deve essere usata come source_address per la connessione al server upstream.
Vedi questo thread per maggiori dettagli.
PS: Non esiste un plugin con quel nome, ma CustomDnsResolverPlugin può essere facilmente personalizzato in base alle tue esigenze.
Tenta di risolvere il nome del programma (applicazione) per le richieste proxy provenienti dalla macchina locale. Se identificato, l'IP del client nei log di accesso viene sostituito con il nome del programma.
Avvia proxy.py come:```console
❯ proxy
--plugins proxy.plugin.ProgramNamePlugin
Fai una richiesta usando `curl`:```console
❯ curl -v -x localhost:8899 https://httpbin.org/get
Devi vedere righe di log come queste:```console ... [redacted] ... - [I] server.access_log:419 - curl:58096 - CONNECT httpbin.org:443 - 6010 bytes - 1824.62ms
Nota `curl` al posto di `::1` o `127.0.0.1` come IP client.
[](#programnameplugin) Se `ProgramNamePlugin` non funziona in modo affidabile sul tuo sistema operativo, contribuisci gentilmente inviando una pull request e/o aprendo un issue. Grazie!!!
## Plugin del Server Web HTTP
### Route del Server Web
Mostra il routing integrato del server web utilizzando il plugin.
Avvia `proxy.py` come:```console
❯ proxy --enable-web-server \
--plugins proxy.plugin.WebServerPlugin
Verifica con curl -v localhost:8899/http-route-example, dovrebbe restituire:```console
HTTP route response
## Plugin per Proxy Inverso
Estende il server web integrato per aggiungere funzionalità di proxy inverso.
### Proxy Inverso
Avvia `proxy.py` come:```console
❯ proxy --enable-reverse-proxy \
--plugins proxy.plugin.ReverseProxyPlugin
Con la configurazione predefinita, il plugin ReverseProxyPlugin è equivalente alla seguente configurazione di Nginx:```console
location /get {
proxy_pass http://httpbin.org/get;
}
Verifica utilizzando `curl -v localhost:8899/get`:```console
{
"args": {},
"headers": {
"Accept": "*/*",
"Host": "localhost",
"User-Agent": "curl/7.64.1"
},
"origin": "1.2.3.4, 5.6.7.8",
"url": "https://localhost/get"
}
Con l'esempio sopra, a volte potresti vedere:```console
Questo accade perché il nostro plugin predefinito per reverse proxy `ReverseProxyPlugin` è configurato con un server upstream `http` e uno `https`. E, per impostazione predefinita, `ReverseProxyPlugin` preserva l'header host originale. Mentre questo funziona con upstream `https`, non funziona in modo affidabile con upstream `http`. Per risolvere questo problema, utilizza il flag `--rewrite-host-header`.
Esempio:```console
❯ proxy --enable-reverse-proxy \
--plugins proxy.plugin.ReverseProxyPlugin \
--rewrite-host-header
Questo garantirà che il campo header Host sia impostato come httpbin.org e funzioni con entrambi gli upstream http e https.
NOTA: L'uso di
--rewrite-host-headero meno dipende dal tuo caso d'uso.
Quando si utilizzano più plugin, in base alla funzionalità del plugin, potrebbe essere opportuno considerare l'ordine in cui i plugin vengono passati da riga di comando.
I plugin vengono chiamati nello stesso ordine in cui vengono passati. Esempio,
supponiamo di utilizzare entrambi FilterByUpstreamHostPlugin e
RedirectToCustomServerPlugin. L'idea è di eliminare tutte le richieste http
in arrivo per facebook.com e www.facebook.com e reindirizzare le altre
richieste http al nostro server web integrato.
Quindi, in questo scenario è importante usare
FilterByUpstreamHostPlugin prima di RedirectToCustomServerPlugin.
Se abilitiamo RedirectToCustomServerPlugin prima di FilterByUpstreamHostPlugin,
anche le richieste facebook verranno reindirizzate al server web integrato,
invece di essere eliminate.
Per impostazione predefinita, proxy.py utilizza il protocollo http per la comunicazione con i client, ad es. curl, browser. Per abilitare la crittografia end-to-end utilizzando tls / https, genera prima i certificati. Fai il checkout del repository ed esegui:```console
make https-certificates
Avvia `proxy.py` come:```console
❯ proxy \
--cert-file https-cert.pem \
--key-file https-key.pem
Verifica utilizzando curl -x https://localhost:8899 --proxy-cacert https-cert.pem https://httpbin.org/get:```console
{
"args": {},
"headers": {
"Accept": "/",
"Host": "httpbin.org",
"User-Agent": "curl/7.54.0"
},
"origin": "1.2.3.4, 5.6.7.8",
"url": "https://httpbin.org/get"
}
Se vuoi evitare di passare il flag `--proxy-cacert`, considera anche la firma dei certificati SSL generati. Esempio:
Prima, genera i certificati CA:```console
make ca-certificates
Poi, firma il certificato SSL:```console make sign-https-certificates
Ora riavvia il server con il flag `--cert-file https-signed-cert.pem`. Nota che devi anche considerare attendibile il `ca-cert.pem` generato nel tuo portachiavi di sistema.
# Intercettazione TLS
Per impostazione predefinita, `proxy.py` non decritta il traffico `https` tra client e server.
Per abilitare l'intercettazione TLS, genera prima i certificati CA radice:```console
❯ make ca-certificates
Abilitiamo anche CacheResponsePlugin in modo da poter verificare la risposta decriptata dal server. Avvia proxy.py come:```console
❯ proxy
--plugins proxy.plugin.CacheResponsesPlugin
--ca-key-file ca-key.pem
--ca-cert-file ca-cert.pem
--ca-signing-key-file ca-signing-key.pem
[](https://github.com/abhinavsingh/proxy.py#user-content-flags) Fornire anche il percorso esplicito del bundle CA necessario per la validazione dei certificati peer. Vedi il parametro `--ca-file`.
Verifica l'intercettazione TLS usando `curl````console
❯ curl -v -x localhost:8899 --cacert ca-cert.pem https://httpbin.org/get
Errore: Il contenuto del chunk (135/252) non è stato fornito. Impossibile procedere con la traduzione.```console
GET /get HTTP/1.1 ... [redacted] ... < Connection: keep-alive < { "args": {}, "headers": { "Accept": "/", "Host": "httpbin.org", "User-Agent": "curl/7.54.0" }, "origin": "1.2.3.4, 5.6.7.8", "url": "https://httpbin.org/get" }
La riga `issuer` conferma che la risposta è stata intercettata.
Verifica anche il contenuto del file di risposta in cache. Ottieni il percorso del file cache dai log di `proxy.py`.
`❯ cat /path/to/your/tmp/directory/httpbin.org-1569452863.924174.txt````console
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Content-Type: application/json
Date: Wed, 25 Sep 2019 23:07:05 GMT
Referrer-Policy: no-referrer-when-downgrade
Server: nginx
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Content-Length: 202
Connection: keep-alive
{
"args": {},
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
"User-Agent": "curl/7.54.0"
},
"origin": "1.2.3.4, 5.6.7.8",
"url": "https://httpbin.org/get"
}
Ecco fatto!!! Se rimuovi i flag CA, i dati crittografati verranno trovati nel file cache invece del testo in chiaro.
Ora usa i flag CA con altri esempi di plugin per vederli funzionare con il traffico https.
Per intercettare il traffico TLS da un server che utilizza un certificato auto-firmato aggiungi il flag --insecure-tls-interception per disabilitare la convalida obbligatoria del certificato TLS.
NOTA: Questo flag disabilita il controllo del certificato per tutti i server.
Note importanti sull'intercettazione TLS con il contenitore Docker:
A partire da v2.2.0, il contenitore docker di proxy.py include anche openssl. Questo consente a proxy.py di generare certificati al volo per l'intercettazione TLS.
Per motivi di sicurezza, il contenitore docker di proxy.py non include certificati CA.
Ecco come avviare un contenitore docker di proxy.py con l'intercettazione TLS:
-v /tmp/ca-certificates:/tmp/ca-certificates monta la directory dei certificati CA nell'ambiente del container
--plugins proxy.plugin.CacheResponsesPlugin abilita CacheResponsesPlugin in modo da poter ispezionare il traffico intercettato--ca-* abilitano TLS Interception.curl. Puoi omettere il flag --cacert se il certificato CA è già trustato dal sistema. ```console
❯ curl -v issuer dagli header della risposta. ```console
cat sul dump della risposta: ```console
❯ docker exec -it $(docker ps | grep proxy.py | awk '{ print $1 }') cat /tmp/httpbin.org-ae1a927d064e4ab386ea319eb38fe251.txt
HTTP/1.1 200 OK
...[redacted]...
{
...[redacted]...,
"url": "http://httpbin.org/get"
}
grout è un sostituto diretto per ngrok e frpgrout è incluso nel pacchetto di proxy.py❯ grout NAME: grout - securely tunnel local files, folders and services to public URLs
USAGE: grout route [name]
DESCRIPTION: grout exposes local networked services behinds NATs and firewalls to the public internet over a secure tunnel. Share local folders, directories and websites, build/test webhook consumers and self-host personal services to public URLs.
EXAMPLES: Share Files and Folders: grout C:\path\to\folder # Share a folder on your system grout /path/to/folder # Share a folder on your system grout /path/to/folder --basic-auth user:pass # Add authentication for shared folder grout /path/to/photo.jpg # Share a specific file on your system
Expose HTTP, HTTPS and Websockets: grout http://localhost:9090 # Expose HTTP service running on port 9090 grout https://localhost:8080 # Expose HTTPS service running on port 8080 grout https://localhost:8080 --path /worker/ # Expose only certain paths of HTTPS service on port 8080 grout https://localhost:8080 --basic-auth u:p # Add authentication for exposed HTTPS service on port 8080
Expose TCP Services: grout tcp://:6379 # Expose Redis service running locally on port 6379 grout tcp://:22 # Expose SSH service running locally on port 22
Custom URLs: grout https://localhost:8080 abhinavsingh # Custom URL for HTTPS service running on port 8080 grout tcp://:22 abhinavsingh # Custom URL for SSH service running locally on port 22
Custom Domains: grout tcp://:5432 abhinavsingh.domain.tld # Custom URL for Postgres service running locally on port 5432
Self-hosted solutions: grout tcp://:5432 abhinavsingh.my.server # Custom URL for Postgres service running locally on port 5432
(*) Wildcard Domains: grout https://host:443 do.main --wildcard # Receive traffic on provided domain and all it's subdomains
(*) Host based routing for Wildcard Domains: grout ... --tunnel-route-url host=https://h:p # When using wildcards, optionally route traffic by incoming host header
SUPPORT: Write to us at [email protected]
Privacy policy and Terms & conditions https://jaxl.com/privacy/
Created by Jaxl™ https://jaxl.io
## Autenticazione di Grout
Grout supporta l'autenticazione per proteggere i tuoi file, cartelle e servizi da accessi non autorizzati. Usa il flag `--basic-auth` per imporre l'autenticazione. Esempio:```console
grout /path/to/folder --basic-auth user:pass
grout https://localhost:8080 --basic-auth u:p
Per impostazione predefinita, Grout consente l'accesso a tutti i percorsi sui servizi. Utilizza il flag --path per limitare l'accesso solo a determinati percorsi del tuo servizio web. Esempio:```console
grout https://localhost:8080 --path /worker/
grout https://localhost:8080 --path /webhook/ --path /callback/
## Domini Wildcard di Grout
Per impostazione predefinita, il client Grout serve il traffico in entrata su un sottodominio dedicato.
Tuttavia, alcuni servizi (ad esempio Kubernetes) potrebbero voler servire il traffico su sottodomini ad hoc.
Avviare un client Grout dedicato per ogni sottodominio ad hoc potrebbe non essere una soluzione pratica.
Per tali scenari, Grout supporta domini wildcard. Ecco come configurare il proprio
dominio wildcard per l'uso con i client Grout.
1. Scegli un dominio ad esempio `custom.example.com`
2. Il tuo servizio vuole servire traffico per `custom.example.com` e `*.custom.example.com`
3. Se prevedi di utilizzare `https://`, devi configurare un bilanciatore di carico:
- Configura un bilanciatore di carico HTTPS (LB)
- Configura il LB con un certificato generato per `custom.example.com` e `*.custom.example.com`
- Indirizza il traffico verso gli indirizzi IP pubblici del servizio Grout
4. Contatta il team Grout all'indirizzo [email protected] per aggiungere `custom.example.com` alla whitelist. Il team Grout verificherà
che tu possieda realmente il dominio e che tu abbia configurato un certificato SSL valido come descritto sopra
Avvia Grout con il flag `--wildcard`. Esempio:```console
grout https://localhost:8080 custom.example.com --wildcard
2024-08-05 18:24:59,294 - grout - Logged in as [email protected]
2024-08-05 18:25:03,159 - setup - Grouting https://*.custom.domain.com
Disponibile solo con
--wildcard
Insieme alla rotta predefinita, è possibile fornire anche rotte aggiuntive che hanno precedenza quando il campo host corrisponde. Esempio:```console
grout https://localhost:8080 custom.example.com
--wildcard
--tunnel-route-url stream.example.com=http://localhost:7001
Puoi fornire più route personalizzate ripetendo questo flag.
## Grout Client Plugin
`GroutClientBasePlugin` ti permette di instradare dinamicamente il traffico verso diversi upstream. Di seguito è riportata una semplice implementazione con una descrizione su come utilizzarlo.```python
class GroutClientPlugin(GroutClientBasePlugin):
def resolve_route(
self,
route: str,
request: HttpParser,
origin: HostPort,
server: HostPort,
) -> Tuple[Optional[str], HttpParser]:
print(request, origin, server, '->', route)
print(request.header(b'host'), request.path)
#
# Here, we send traffic to localhost:7001 irrespective
# of the original "route" value provided to the grout
# client OR any custom host:upstream mapping provided
# through the --tunnel-route-url flags (when using
# --wildcard).
#
# Optionally, you can also strip path before
# sending traffic to upstrem, like:
# request.path = b"/"
#
# To drop the request, simply return None for route
# return None, request
#
return 'http://localhost:7001', request
Vedi grout_client.py per maggiori informazioni. Per provarlo, avvia passando --plugin proxy.plugin.grout_client.GroutClientPlugin all'avvio del client grout.
❯ docker run --rm -it
--entrypoint grout
-v ~/.proxy:/root/.proxy
abhinavsingh/proxy.py:latest
http://host.docker.internal:29876
Sopra:
- Abbiamo cambiato `--entrypoint` in `grout`
- Abbiamo sostituito `localhost` con `host.docker.internal`, in modo che `grout` possa instradare il traffico verso la porta `29876` in esecuzione sulla macchina host
- *(Opzionale)* Monta la cartella `~/.proxy` della macchina host, in modo che le credenziali di `grout` possano persistere attraverso i riavvii del contenitore
## Come funziona Grout
- L'infrastruttura di `grout` ha 2 componenti: client e server
- Il client di `grout` ha 2 componenti: un client thin e un client thick
- Il client thin di `grout` fa parte del progetto open source `proxy.py` (Licenza BSD 3-Clause)
- Il client thick e i server di `grout` sono ospitati su [jaxl.io](https://jaxl.io)
e sono di proprietà di [Jaxl Innovations Private Limited](https://jaxl.com)
- Il server di `grout` ha 3 componenti: un server di registro, un server proxy inverso e un server tunnel
## `grout` auto-ospitato
- Il client thick e i server di `grout` possono anche essere ospitati sulle tue infrastrutture GCP, AWS, Cloud
- Con una versione auto-ospitata, il tuo traffico scorre attraverso la rete che controlli e di cui ti fidi
- Gli sviluppatori di `grout` su [jaxl.io](https://jaxl.io) forniscono immagini GCP, AWS, Docker per soluzioni auto-ospitate
- Invia un'email a [[email protected]](mailto:[email protected]) per iniziare.
# Proxy su tunnel SSH
**Questo è un WIP e potrebbe non funzionare come documentato**
Richiede `paramiko` per funzionare. Installa le dipendenze usando `pip install "proxy.py[tunnel]"`
## Proxy di richieste remote localmente
|
+------------+ | +----------+
| LOCAL | | | REMOTE |
| HOST | <== SSH ==== :8900 == | PROXY |
+------------+ | +----------+
:8899 proxy.py |
|
FIREWALL
(allow tcp/22)
### Cosa
Proxy delle richieste HTTP(s) effettuate su un server proxy `remote` attraverso il server `proxy.py` in esecuzione su `localhost`.
### Come
- La porta `remote` richiesta viene inoltrata sulla connessione SSH.
- `proxy.py` in esecuzione su `localhost` gestisce e risponde alle richieste proxy `remote`.
### Requisiti
1. `localhost` DEVE avere accesso SSH al server `remote`
2. Il server `remote` DEVE essere configurato per fare proxy delle richieste HTTP(s) attraverso il numero di porta inoltrato, ad es. `:8900`.
- Le porte `remote` e `localhost` POSSONO essere le stesse, ad es. `:8899`.
- `:8900` è scelto nell'arte ASCII per scopi di differenziazione.
### Provalo
Avvia `proxy.py` come:```console
❯ # On localhost
❯ proxy --enable-ssh-tunnel \
--tunnel-username username \
--tunnel-hostname ip.address.or.domain.name \
--tunnel-port 22 \
--tunnel-remote-port 8899 \
--tunnel-ssh-key /path/to/ssh/private.key \
--tunnel-ssh-key-passphrase XXXXX
...[redacted]... [I] listener.setup:97 - Listening on 127.0.0.1:8899
...[redacted]... [I] pool.setup:106 - Started 16 acceptors in threadless (local) mode
...[redacted]... [I] transport._log:1873 - Connected (version 2.0, client OpenSSH_7.6p1)
...[redacted]... [I] transport._log:1873 - Authentication (publickey) successful!
...[redacted]... [I] listener.setup:116 - SSH connection established to ip.address.or.domain.name:22...
...[redacted]... [I] listener.start_port_forward:91 - :8899 forwarding successful...
Effettua una richiesta HTTP proxy sul server remote e verifica che la risposta contenga l'indirizzo IP pubblico di localhost come origine:```console
❯ # On remote
❯ curl -x 127.0.0.1:8899 http://httpbin.org/get
{
"args": {},
"headers": {
"Accept": "/",
"Host": "httpbin.org",
"User-Agent": "curl/7.54.0"
},
"origin": "x.x.x.x, y.y.y.y",
"url": "https://httpbin.org/get"
}
Inoltre, verifica che i log di `proxy.py` su `localhost` contengano l'IP `remote` come IP del client.```console
access_log:328 - remote:52067 - GET httpbin.org:80
|
+------------+ | +----------+
| LOCAL | | | REMOTE |
| HOST | === SSH =====> | SERVER |
+------------+ | +----------+
| :8899 proxy.py
|
FIREWALL
(allow tcp/22)
Non pianificato.
Se hai un caso d'uso valido, per favore apri un issue. Sei sempre il benvenuto a inviare contributi tramite pull-request per aggiungere questa funzionalità :)
Per proxyare richieste locali in remoto, utilizza Proxy Pool Plugin.
Avvia proxy.py in modalità incorporata con la configurazione predefinita utilizzando il metodo proxy.main. Esempio:```python
import proxy
if name == 'main': proxy.main()
Personalizza i flag di avvio passandoli come kwargs:```python
import ipaddress
import proxy
if __name__ == '__main__':
proxy.main(
hostname=ipaddress.IPv6Address('::1'),
port=8899
)
Nota che:
main equivale ad avviare proxy.py dalla riga di comando.main non accetta alcun args (solo kwargs).main consumerà automaticamente qualsiasi sys.argv disponibile come args.main si bloccherà fino a quando proxy.py non si arresta.Avvia proxy.py in modalità incorporata non bloccante con configurazione predefinita utilizzando il gestore di contesto Proxy: Esempio:```python
import proxy
if name == 'main': with proxy.Proxy() as p: # Uncomment the line below and # implement your app your logic here proxy.sleep_loop()
Nota che:
1. `Proxy` è simile a `main`, tranne per il fatto che `Proxy` non blocca.
2. Internamente, `Proxy` è un context manager che avvia `proxy.py` quando viene chiamato e lo arresta una volta terminato lo scope.
3. A differenza di `main`, i flag di avvio con `Proxy` possono anche essere personalizzati usando `args` e `kwargs`. Ad esempio `Proxy(['--port', '8899'])` o passando flag come kwargs ad es. `Proxy(port=8899)`.
4. A differenza di `main`, `Proxy` non esamina `sys.argv`.
## Porta Effimera
Usa `--port=0` per associare `proxy.py` a una porta casuale allocata dal kernel.
In modalità embedded, puoi accedere a questa porta. Esempio:```python
import proxy
if __name__ == '__main__':
with proxy.Proxy(port=0) as p:
print(p.flags.port)
proxy.sleep_loop()
flags.port ti darà accesso alla porta casuale allocata dal kernel.
Gli utenti possono usare il flag --plugins più volte per caricare più plugin.
Vedi Impossibile caricare i plugin se stai riscontrando problemi.
Quando si utilizza in modalità embedded, hai alcune opzioni aggiuntive. Esempio:
bytes al metodo proxy.main o al context manager proxy.Proxy.type della classe del plugin. Questo è particolarmente utile se prevedi di definire plugin a runtime.Esempio, carica un singolo plugin usando il flag --plugins:```python
import proxy
if name == 'main': proxy.main(plugins=['proxy.plugin.CacheResponsesPlugin'])
Per semplicità, puoi anche passare la lista dei plugin come argomento keyword a `proxy.main` o al costruttore `Proxy`.
Esempio:```python
import proxy
from proxy.plugin import FilterByUpstreamHostPlugin
if __name__ == '__main__':
proxy.main(plugins=[
b'proxy.plugin.CacheResponsesPlugin',
FilterByUpstreamHostPlugin,
])
proxy.TestCasePer impostare e smantellare proxy.py per le tue classi Python unittest, usa semplicemente proxy.TestCase invece di unittest.TestCase.
Esempio:```python
import proxy
class TestProxyPyEmbedded(proxy.TestCase):
def test_my_application_with_proxy(self) -> None:
self.assertTrue(True)
Nota che:
1. `proxy.TestCase` sovrascrive il metodo `unittest.TestCase.run()` per configurare e smantellare `proxy.py`.
2. Il server `proxy.py` ascolterà su una porta disponibile casuale del sistema.
Questa porta casuale è disponibile come `self.PROXY.flags.port` nei tuoi casi di test.
3. Per impostazione predefinita, viene avviato un solo accettore e un solo lavoratore (`--num-workers 1 --num-acceptors 1`) per una configurazione e smantellamento più veloci.
4. Ancora più importante, `proxy.TestCase` garantisce anche che il server `proxy.py`
sia attivo e in esecuzione prima di procedere con l'esecuzione dei test. Per impostazione predefinita,
`proxy.TestCase` attenderà `10 secondi` per l'avvio del server `proxy.py`,
in caso di fallimento verrà sollevata un'eccezione `TimeoutError`.
## Sovrascrivere i flag di avvio
Per sovrascrivere i flag di avvio predefiniti, definisci una variabile `PROXY_PY_STARTUP_FLAGS` nella tua classe di test.
Esempio:```python
class TestProxyPyEmbedded(TestCase):
PROXY_PY_STARTUP_FLAGS = [
'--num-workers', '2',
'--num-acceptors', '1',
'--enable-web-server',
]
def test_my_application_with_proxy(self) -> None:
self.assertTrue(True)
Vedi test_embed.py per un esempio completo.
unittest.TestCaseSe per qualche motivo non puoi usare direttamente proxy.TestCase,
allora sovrascrivi semplicemente unittest.TestCase.run per configurare e smantellare proxy.py.
Esempio:```python
import unittest
import proxy
class TestProxyPyEmbedded(unittest.TestCase):
def test_my_application_with_proxy(self) -> None:
self.assertTrue(True)
def run(self, result: Optional[unittest.TestResult] = None) -> Any:
with proxy.start([
'--num-workers', '1',
'--num-acceptors', '1',
'--port', '... random port ...']):
super().run(result)
o semplicemente imposta / smonta `proxy.py` all'interno dei metodi di classe `setUpClass` e `teardownClass`.
# Utilità
## Socket TCP
### new_socket_connection
Tenta di creare una connessione IPv4, poi IPv6 e infine una connessione dual stack all'indirizzo fornito.```python
>>> conn = new_socket_connection(('httpbin.org', 80))
>>> ...[ use connection ]...
>>> conn.close()
socket_connection è un comodo decorator + context manager attorno a new_socket_connection che garantisce che conn.close sia implicito.
Come context manager:```python
with socket_connection(('httpbin.org', 80)) as conn: ... [ use connection ] ...
Come decorator:```python
>>> @socket_connection(('httpbin.org', 80))
>>> def my_api_call(conn, *args, **kwargs):
>>> ... [ use connection ] ...
build_http_request(b'GET', b'/') b'GET / HTTP/1.1\r\n\r\n'
build_http_request(b'GET', b'/', conn_close=True) b'GET / HTTP/1.1\r\nConnection: close\r\n\r\n'
import json build_http_request(b'POST', b'/form', headers={b'Content-type': b'application/json'}, body=proxy.bytes_(json.dumps({'email': '[email protected]'}))) b'POST /form HTTP/1.1\r\nContent-type: application/json\r\n\r\n{"email": "[email protected]"}'
build_http_response( status_code: int, protocol_version: bytes = HTTP_1_1, reason: Optional[bytes] = None, headers: Optional[Dict[bytes, bytes]] = None, body: Optional[bytes] = None) -> bytes
## PKI
### Utilizzo API
- `gen_private_key` ```python
gen_private_key(
key_path: str,
password: str,
bits: int = 2048,
timeout: int = 10) -> bool
gen_public_key ```python
gen_public_key(
public_key_path: str,
private_key_path: str,
private_key_password: str,
subject: str,
alt_subj_names: Optional[List[str]] = None,
extended_key_usage: Optional[str] = None,
validity_in_days: int = 365,
timeout: int = 10) -> bool
remove_passphrase ```python
remove_passphrase(
key_in_path: str,
password: str,
key_out_path: str,
timeout: int = 10) -> bool
gen_csr ```python
gen_csr(
csr_path: str,
key_path: str,
password: str,
crt_path: str,
timeout: int = 10) -> bool
sign_csr ```python
sign_csr(
csr_path: str,
crt_path: str,
ca_key_path: str,
ca_key_password: str,
ca_crt_path: str,
serial: str,
alt_subj_names: Optional[List[str]] = None,
extended_key_usage: Optional[str] = None,
validity_in_days: int = 365,
timeout: int = 10) -> bool
Vedi pki.py e test_pki.py per esempi di utilizzo.
Usa il modulo proxy.common.pki per:
proxy.py v2.4.4rc2.dev12+gdc06ea4 : PKI Utility
positional arguments: action Valid actions: remove_passphrase, gen_private_key, gen_public_key, gen_csr, sign_csr
options: -h, --help show this help message and exit --password PASSWORD Password to use for encryption. Default: proxy.py --private-key-path PRIVATE_KEY_PATH Private key path --public-key-path PUBLIC_KEY_PATH Public key path --subject SUBJECT Subject to use for public key generation. Default: /CN=localhost --csr-path CSR_PATH CSR file path. Use with gen_csr and sign_csr action. --crt-path CRT_PATH Signed certificate path. Use with sign_csr action. --hostname HOSTNAME Alternative subject names to use during CSR signing. --openssl OPENSSL Path to openssl binary. By default, we assume openssl is in your PATH
## Documentazione interna
### Leggi la documentazione
- Visita [proxypy.readthedocs.io](https://proxypy.readthedocs.io/)
- Crea localmente usando:
`make lib-doc`
### pydoc
Il codice è ben documentato. Prendi il codice sorgente ed esegui:
`pydoc3 proxy`
### pyreverse
Genera diagrammi UML della gerarchia a livello di classe per analisi approfondite:
`make lib-pyreverse`
# Esegui il Dashboard
Il Dashboard è attualmente in sviluppo e non ancora incluso nei pacchetti `pip`.
Per eseguire il dashboard, devi fare il checkout del codice sorgente.
Il Dashboard è scritto in Typescript e SCSS, quindi costruiamolo prima usando:```console
❯ make dashboard
Costruisci anche il Chrome DevTools integrato se prevedi di usarlo:```console
❯ make devtools
Ora avvia `proxy.py` con il plugin dashboard e sovrascrivendo la directory principale per il server statico:```console
❯ proxy --enable-dashboard --static-server-dir dashboard/public
...[redacted]... - Loaded plugin proxy.http.server.HttpWebServerPlugin
...[redacted]... - Loaded plugin proxy.dashboard.dashboard.ProxyDashboard
...[redacted]... - Loaded plugin proxy.dashboard.inspect_traffic.InspectTrafficPlugin
...[redacted]... - Loaded plugin proxy.http.inspector.DevtoolsProtocolPlugin
...[redacted]... - Loaded plugin proxy.http.proxy.HttpProxyPlugin
...[redacted]... - Listening on ::1:8899
...[redacted]... - Core Event enabled
Attualmente, abilitare la dashboard abiliterà anche tutti i plugin della dashboard.
Visita la dashboard:```console ❯ open http://localhost:8899/dashboard/
## Ispeziona Traffico
***Questo è un WIP e potrebbe non funzionare come documentato***
Attendi il caricamento della `Chrome Dev Console` incorporata. Al momento, i dettagli su tutto il traffico che scorre attraverso `proxy.py` vengono inviati alla scheda `Inspect Traffic`. Tuttavia, i payload ricevuti non sono ancora integrati con la console sviluppatore incorporata.
La funzionalità corrente può essere verificata aprendo la `Dev Console` della dashboard e ispezionando la connessione websocket che la dashboard ha stabilito con il server `proxy.py`.
[](https://github.com/abhinavsingh/proxy.py)
# Protocollo Chrome DevTools
Per scenari in cui si desidera l'accesso diretto all'endpoint websocket del protocollo `Chrome DevTools`, avvia `proxy.py` come:```console
❯ proxy --enable-devtools --enable-events
Ora punta la tua istanza CDT a ws://localhost:8899/devtools.
proxy.py con il flag --enable-metrics per esporre le metriche interne tramite un endpoint prometheus.prometheus.yaml per eseguire lo scraping dall'endpoint /metrics ad esempio http://localhost:8899/metrics--metrics-path--enable-metrics internamente abilita anche --enable-events e il plugin del server web.Di seguito sono elencate alcune strategie per utilizzare proxy.py nei tuoi progetti privati/di produzione/aziendali.
DEVI
evitare il forkdel repository solo per mettere il codice del tuo plugin nella directoryproxy/plugin. Il fork è un flusso di lavoro consigliato per i contributori del progetto, NON per gli utenti del progetto.
--plugin, --plugins o i kwarg plugin.proxy.py.È fortemente consigliato utilizzare proxy.py tramite requirements.txt o configurazioni simili di gestione delle dipendenze. Questo ti permetterà di sfruttare i vantaggi degli aggiornamenti regolari delle prestazioni, delle correzioni di bug, delle patch di sicurezza e di altri miglioramenti che avvengono nell'ecosistema di proxy.py. Esempio:
Usa l'opzione --pre per dipendere dall'ultima pre-release
❯ pip install proxy.py --pre
Le pre-release sono simili a dipendere dal codice del branch develop, solo che le pre-release potrebbero non puntare al HEAD. Questo potrebbe accadere perché le pre-release NON vengono rese disponibili su PyPi dopo ogni merge di una PR.
Usa TestPyPi con l'opzione --pre per dipendere dal codice del branch develop
❯ pip install -i https://test.pypi.org/simple/ proxy.py --pre
Una pre-release viene resa disponibile su TestPyPi dopo ogni merge di una PR.
Usa il codice dell'ultima release stable
Se sei interessato a distribuire container, allora costruisci semplicemente la tua immagine a partire dalle immagini container base di proxy.py.
Usa GHCR per costruire dal codice del branch develop:
FROM ghcr.io/abhinavsingh/proxy.py:latest as base
ND: Io uso GHCR latest per diversi progetti a livello di produzione
Usa DockerHub per costruire dall'ultimo codice stable:
FROM abhinavsingh/proxy.py:latest as base
ND: IMHO, la strategia basata su container è il miglior approccio e l'unica strategia che io stesso utilizzo.
Ehi, ma continui a fare modifiche che rompono nel branch develop.
Ti ascolto. E quindi, per le tue applicazioni di livello produttivo, DEVI integrare la CI/CD dell'applicazione con proxy.py. Devi assicurarti che la tua applicazione compili e superi i suoi test per ogni merge di PR nel repository upstream di proxy.py.
Se il repository della tua applicazione è pubblico, in certi scenari, gli autori delle PR potrebbero inviare PR di patch per tutti i dipendenti per mantenere la retrocompatibilità e la CI/CD verde.
L'integrazione CI/CD garantisce che la tua app continui a compilare con il codice più recente di proxy.py. A seconda di dove ospiti il tuo codice, usa la strategia elencata di seguito:
GitHub
Da definire
Google Cloud Build
Da definire
AWS
Da definire
Azure
Da definire
Altri
Da definire
Ad un certo punto, deprecheremo la segregazione del branch
mastere manterremo semplicemente un branchdevelop. Poiché i dipendenti possono mantenere la stabilità tramite integrazioni CI/CD. Attualmente, è difficile per un progetto di livello produttivo dipendere ciecamente dal branchdevelop.
Il branch master contiene l'ultimo codice stable ed è disponibile tramite il repository PyPi e i container Docker tramite i registri docker.io e ghcr.io.
I problemi segnalati per le release stable sono considerati con la massima priorità. Tuttavia, attualmente non eseguiamo backport di correzioni in release precedenti. Esempio, se hai segnalato un problema in v2.3.1, ma il branch master attuale contiene v2.4.0rc1. Quindi, la correzione arriverà in v2.4.0rc2.
Il branch develop contiene modifiche all'avanguardia
Il branch di sviluppo è mantenuto stabile (la maggior parte delle volte). Ma, se vuoi affidabilità al 100% e servire utenti in ambiente di produzione, USA SEMPRE la versione stabile.
Una pull request vX.Y.ZrcN viene creata una volta al mese che unisce develop → master. Di seguito è riportato come il codice fluisce da una pull request alla prossima release stabile.
La release di sviluppo viene distribuita da develop → test.pypi.org dopo ogni merge di pull request
La release alpha viene distribuita da develop → pypi.org prima di unire la pull request vX.Y.Z.rcN da develop → branch master. Possono esserci più release alpha prima di unire la pull request rc
La release beta viene distribuita da master → pypi.org. Le release beta vengono preparate in vista delle release rc e possono essere saltate se non necessarie
Il release candidate viene distribuito da master → pypi.org. I release candidate sono sempre disponibili prima della release stabile finale
v1.xproxy.py era solito creare nuovi thread per gestire le richieste dei client.
v2.0+proxy.py ha aggiunto il supporto per l'esecuzione threadless delle richieste dei client usando asyncio.
v2.4.0+L'esecuzione threadless è stata attivata per impostazione predefinita per Python 3.8+ su ambienti mac e linux.
L'esecuzione threadless di proxy.py è stata segnalata come sicura in questi ambienti dai nostri utenti. Se riscontri problemi, torna alla modalità threaded usando il flag --threaded.
Per windows e Python < 3.8, puoi ancora provare la modalità threadless avviando proxy.py con il flag --threadless.
Se threadless funziona per te, considera l'invio di una PR modificando il metodo _env_threadless_compliant nel file proxy/common/constants.py.
L'implementazione threadless originale utilizzava la modalità di esecuzione remote. Questo è anche rappresentato nell'architettura di alto livello come arte ASCII.
In modalità di esecuzione remote, gli acceptor delegano l'elaborazione delle connessioni client in entrata a un processo worker remoto. Per impostazione predefinita, gli acceptor delegano le connessioni in modo round-robin. Il worker che elabora la richiesta può essere o meno in esecuzione sullo stesso core CPU dell'acceptor. Questa architettura scala bene per un throughput elevato, ma comporta la creazione di due processi per core CPU.
Ad esempio, se ci sono N-CPU sulla macchina, per impostazione predefinita vengono avviati N acceptor e N processi worker. Puoi regolare il numero di processi usando i flag --num-acceptors e --num-workers. Potresti volere più worker che acceptor o viceversa a seconda del tuo caso d'uso.
In v2.4.x, è stata aggiunta la modalità di esecuzione local, principalmente per ridurre il numero di processi creati per impostazione predefinita. Questo modello è adatto per casi d'uso quotidiani di singoli utenti e per scenari di test per sviluppatori. In modalità di esecuzione local, gli acceptor delegano le connessioni client a un thread compagno, invece che a un processo remoto. La modalità di esecuzione local garantisce l'affinità della CPU, a differenza della modalità remote in cui acceptor e worker potrebbero essere in esecuzione su core CPU diversi.
--local-executor 1 è stato impostato come predefinito nella serie v2.4.x. In modalità di esecuzione local, il flag --num-workers non ha effetto, poiché non vengono avviati worker remoti.
Per utilizzare la modalità di esecuzione remote, usa il flag --local-executor 0. Quindi usa --num-workers per regolare il numero di processi worker.
proxy.py è fortemente tipizzato e utilizza annotazioni typing di Python. Esempio:```python
my_strings : List[str] = [] #############^^^^^^^^^#####
Quindi è richiesta una versione di Python che supporti le annotazioni di tipo.
Assicurati di usare `Python 3.6+`.
Verifica la versione prima di eseguire `proxy.py`:
`❯ python --version`
Tutte le annotazioni `typing` possono essere sostituite con annotazioni `comment-only`. Esempio:```python
>>> my_strings = [] # List[str]
>>> ################^^^^^^^^^^^
Permetterà a proxy.py di funzionare su Python pre-3.6, anche su 2.7.
Tuttavia, poiché tutte le versioni future di Python supporteranno le annotazioni typing,
ciò non è stato preso in considerazione.
Assicurati che i moduli dei plugin siano rilevabili aggiungendoli a PYTHONPATH. Esempio:
`PYTHONPATH=/path/to/my/app proxy --plugins my_app.proxyPlugin````console ...[redacted]... - Loaded plugin proxy.HttpProxyPlugin ...[redacted]... - Loaded plugin my_app.proxyPlugin
OPPURE, passare semplicemente il percorso completamente qualificato come parametro, ad es.
`proxy --plugins /path/to/my/app/my_app.proxyPlugin`
Ecco un rapido esempio funzionante:
- Contenuti della cartella `/tmp/plug````console
╰─ ls -1 /tmp/plug ─╯
my_plugin.py
MyPlugin personalizzata```console
╰─ cat /tmp/plug/my_plugin.py ─╯
from proxy.http.proxy import HttpProxyBasePluginclass MyPlugin(HttpProxyBasePlugin): pass
Questo è un plugin vuoto per dimostrare l'utilizzo di plugin esterni. Devi implementare i metodi necessari per far funzionare i tuoi plugin con traffico reale
- Avvia `proxy.py` con `MyPlugin````console
╰─ PYTHONPATH=/tmp/plug proxy --plugin my_plugin.MyPlugin ─╯
...[redacted]... - Loaded plugin proxy.http.proxy.HttpProxyPlugin
...[redacted]... - Loaded plugin my_plugin.MyPlugin
...[redacted]... - Listening on ::1:8899
Assicurati che proxy.py sia in ascolto sull'interfaccia di rete corretta.
Prova i seguenti flag:
--hostname ::--hostname 0.0.0.0Probabilmente è un problema di integrazione del browser con il portachiavi di sistema.
Prima verifica che l'autenticazione base funzioni usando curl
curl -v -x username:password@localhost:8899 https://httpbin.org/get
Consulta questo thread per ulteriori dettagli.
È un problema di compatibilità con vpnkit.
Vedi moby/vpnkit esaurisce le risorse di Docker e Connessione rifiutata: Il proxy non ha potuto connettersi per alcuni approfondimenti.
Un modello fluentd.conf di partenza è disponibile.
Copia questo file di configurazione come proxy.py.conf in
/etc/google-fluentd/config.d/
Aggiorna il campo path con il percorso del file di log usato con il flag --log-file.
Di default viene monitorato il percorso /tmp/proxy.log.
Ricarica google-fluentd:
sudo service google-fluentd restart
Ora i log di proxy.py possono essere consultati usando
il visualizzatore di log GCE.
ValueError: filedescriptor out of range in selectproxy.py è progettato per gestire migliaia di connessioni al secondo
senza perdite di socket.
--open-file-limit per personalizzare ulimit -n.--backlog per una maggiore concorrenza.Se nulla aiuta, apri un issue
con le richieste al secondo inviate e l'output del seguente script di debug:```console
❯ ./helper/monitor_open_files.sh
## None:None nei log di accesso
A volte potresti vedere `None:None` nei log di accesso. Semplicemente significa
che una connessione al server upstream non è mai stata stabilita, cioè
`upstream_host=None`, `upstream_port=None`.
Ci possono essere diverse ragioni per cui non c'è connessione upstream,
alcune ovvie includono:
1. Il client ha stabilito una connessione ma non ha mai completato la richiesta.
2. Un plugin ha restituito una risposta prematuramente, evitando la connessione al server upstream.
## OSError durante il wrapping del client per l'intercettazione TLS
Con `TLS Interception` attivato, potresti occasionalmente vedere le seguenti eccezioni:```console
2021-11-06 23:33:34,540 - pid:91032 [E] server.intercept:678 - OSError when wrapping client
Traceback (most recent call last):
...[redacted]...
...[redacted]...
...[redacted]...
ssl.SSLError: [SSL: TLSV1_ALERT_UNKNOWN_CA] tlsv1 alert unknown ca (_ssl.c:997)
...[redacted]... - CONNECT oauth2.googleapis.com:443 - 0 bytes - 272.08 ms
Alcuni client possono sollevare TLSV1_ALERT_UNKNOWN_CA se non riescono a verificare il certificato del server perché è firmato da una CA emittente sconosciuta. Questo è il caso quando stiamo effettuando l'intercettazione TLS. Ciò può essere dovuto a vari motivi, ad esempio certificate pinning, ecc.
Un'altra eccezione che potresti vedere è CERTIFICATE_VERIFY_FAILED:```console
2021-11-06 23:36:02,002 - pid:91033 [E] handler.handle_readables:293 - Exception while receiving from client connection <socket.socket fd=28, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8899), raddr=('127.0.0.1', 51961)> with reason SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:997)')
Traceback (most recent call last):
...[redacted]...
...[redacted]...
...[redacted]...
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:997)
...[redacted]... - CONNECT init.push.apple.com:443 - 0 bytes - 892.99 ms
In futuro, potremmo supportare la distribuzione del contenuto HTTPS originale per tali client mantenendo comunque
l'intercettazione TLS in background. Questo permetterà di mantenere i clienti soddisfatti senza
influire sulla nostra capacità di intercettare TLS. Sfortunatamente, questa funzionalità non è attualmente disponibile.
Un altro esempio con l'eccezione `SSLEOFError`:```console
2021-11-06 23:46:40,446 - pid:91034 [E] server.intercept:678 - OSError when wrapping client
Traceback (most recent call last):
...[redacted]...
...[redacted]...
...[redacted]...
ssl.SSLEOFError: EOF occurred in violation of protocol (_ssl.c:997)
...[redacted]... - CONNECT stock.adobe.io:443 - 0 bytes - 685.32 ms
+-------------+
| |
| Proxy([]) |
| |
+------+------+
|
|
+-----------v--------------+
| |
| AcceptorPool(...) |
| |
+------------+-------------+
|
+-----------------+ | +-----------------+ | | | | | | Acceptor(..) <-------------+-----------> Acceptor(..) | | | | | +---+-------------+ +---------+-------+ | | | | | +------++------++------++------++------+ | | | || || || || | | +----> || || || || <-----+ | || || || || | +------++------++------++------++------+ Threadless Worker Processes
`proxy.py` è realizzato con le prestazioni in mente. Per impostazione predefinita, `proxy.py` tenterà di utilizzare tutti i core CPU disponibili per accettare nuove connessioni client. Ciò si ottiene avviando `AcceptorPool` che ascolta sulla porta del server configurata. Quindi, `AcceptorPool` avvia i processi `Acceptor` (`--num-acceptors`) per accettare le connessioni client in arrivo. Inoltre, se `--threadless` è abilitato, viene configurato `ThreadlessPool` che avvia i processi `Threadless` (`--num-workers`) per gestire le connessioni client in arrivo.
Ogni processo `Acceptor` delega la connessione client accettata a un processo threadless tramite la classe `Work`. Attualmente, `HttpProtocolHandler` è la classe di lavoro predefinita.
`HttpProtocolHandler` assume semplicemente che i client in arrivo seguiranno le specifiche HTTP. Implementazioni specifiche di proxy HTTP e server HTTP sono scritte come plugin di `HttpProtocolHandler`.
Consulta la documentazione di `HttpProtocolHandlerPlugin` per i lifecycle hook disponibili. Usa `HttpProtocolHandlerPlugin` per aggiungere nuove funzionalità per i client http(s). Esempio, vedi `HttpWebServerPlugin`.
## Tutto è un plugin
- Abbiamo abilitato i plugin del `proxy server` usando il flag `--plugins`. Il proxy server `HttpProxyPlugin` è un plugin di `HttpProtocolHandler`. Inoltre, il proxy server consente plugin tramite la specifica `HttpProxyBasePlugin`.
- Tutti gli [esempi di plugin](#plugin-examples) del proxy server implementavano `HttpProxyBasePlugin`. Consulta la documentazione di `HttpProxyBasePlugin` per i lifecycle hook disponibili. Usa `HttpProxyBasePlugin` per modificare il comportamento del protocollo proxy http(s) tra client e server upstream. Esempio, [FilterByUpstreamHostPlugin](#filterbyupstreamhostplugin).
- Abbiamo anche abilitato il `web server` integrato usando `--enable-web-server`. Il web server `HttpWebServerPlugin` è un plugin di `HttpProtocolHandler` e implementa la specifica `HttpProtocolHandlerPlugin`.
- C'è anche un flag `--disable-http-proxy`. Disabilita il proxy server integrato. Usa questo flag con il flag `--enable-web-server` per eseguire `proxy.py` come server http(s) programmabile.
## Gestione degli stati per i tuoi plugin senza stato
Le istanze delle classi plugin vengono create per ogni richiesta. Ancora più importante, le istanze dei plugin vengono create nel contesto del core CPU dove la richiesta è stata ricevuta.
Per questo motivo, le variabili globali nei tuoi plugin potrebbero non funzionare come previsto. Il tuo codice plugin, per progettazione, deve essere **senza stato**.
Per gestire stati globali, hai un paio di opzioni: 1) Utilizza le [strutture dati sicure per multiprocessing](https://python.readthedocs.io/en/latest/library/multiprocessing.html#sharing-state-between-processes) di Python 2) Utilizza il [meccanismo di eventi](https://github.com/abhinavsingh/proxy.py/blob/develop/tutorial/eventing.ipynb) integrato di `proxy.py`
## Passaggio del contesto di elaborazione tra plugin
A volte, un plugin potrebbe dover passare un contesto aggiuntivo ad altri plugin successivi nella catena di elaborazione. Ad esempio, questo contesto aggiuntivo può anche essere scaricato come parte dei log di accesso.
Per passare il contesto di elaborazione, utilizza il metodo `on_access_log` del plugin. Vedi come il plugin [Program Name](https://github.com/abhinavsingh/proxy.py/blob/develop/proxy/plugin/program_name.py) modifica la chiave predefinita `client_ip` nel contesto e la aggiorna al nome del programma rilevato.
Di conseguenza, quando abilitiamo il [Program Name Plugin](#programnameplugin), vediamo il nome del programma client locale invece dell'indirizzo IP nei log di accesso.
## Guida allo sviluppo
### Impostazione dell'ambiente locale
I contributori devono avviare `proxy.py` dal codice sorgente per verificare e sviluppare nuove funzionalità/correzioni.
Vedi [Eseguire proxy.py dalla riga di comando usando il sorgente del repository](#from-command-line-using-repo-source) per i dettagli.
[](https://github.com/abhinavsingh/proxy.py/issues/642) Su `macOS` devi installare `Python` usando `pyenv`, poiché `Python` installato tramite `homebrew` tende a essere problematico. Vedi il thread collegato per maggiori dettagli.
### Impostazione degli hook Git
Pre-commit hook garantisce che i test siano superati.
1. `cd /path/to/proxy.py`
2. `ln -s $(PWD)/git-pre-commit .git/hooks/pre-commit`
Pre-push hook garantisce che lint e test siano superati.
1. `cd /path/to/proxy.py`
2. `ln -s $(PWD)/git-pre-push .git/hooks/pre-push`
### Invio di una Pull Request
Ogni pull request viene testata utilizzando GitHub Actions.
Vedi il [workflow GitHub](https://github.com/abhinavsingh/proxy.py/tree/develop/.github/workflows) per l'elenco dei test.
# Progetti che utilizzano Proxy.Py
Alcuni progetti popolari che utilizzano `proxy.py`
- [pip](https://github.com/pypa/pip)
- [ray-project](https://github.com/ray-project/ray)
- [aio-libs](https://github.com/aio-libs/aiohttp)
- [Selenium Base](https://github.com/seleniumbase/SeleniumBase)
- [wifipumpkin3](https://github.com/P0cL4bs/wifipumpkin3)
- [MerossIot](https://github.com/albertogeniola/MerossIot)
- [pyshorteners](https://github.com/ellisonleao/pyshorteners)
- [Slack API](https://github.com/slackapi/python-slack-events-api)
- [ibeam](https://github.com/Voyz/ibeam)
- [PyPaperBot](https://github.com/ferru97/PyPaperBot)
Per l'elenco completo vedi [used by](https://github.com/abhinavsingh/proxy.py/network/dependents?package_id=UGFja2FnZS01MjQ0MDY5Ng%3D%3D)
# Benchmark
Vedi la directory [Benchmark](https://github.com/abhinavsingh/proxy.py/tree/develop/benchmark) per come eseguire confronti di benchmark con altri server web OSS.
To run standalone benchmark for `proxy.py`, use the following command from repo root:```console
❯ ./benchmark/compare.sh
❯ proxy -h usage: -m [-h] [--tunnel-hostname TUNNEL_HOSTNAME] [--tunnel-port TUNNEL_PORT] [--tunnel-username TUNNEL_USERNAME] [--tunnel-ssh-key TUNNEL_SSH_KEY] [--tunnel-ssh-key-passphrase TUNNEL_SSH_KEY_PASSPHRASE] [--tunnel-remote-port TUNNEL_REMOTE_PORT] [--threadless] [--threaded] [--num-workers NUM_WORKERS] [--enable-events] [--inactive-conn-cleanup-timeout INACTIVE_CONN_CLEANUP_TIMEOUT] [--enable-proxy-protocol] [--enable-conn-pool] [--key-file KEY_FILE] [--cert-file CERT_FILE] [--client-recvbuf-size CLIENT_RECVBUF_SIZE] [--server-recvbuf-size SERVER_RECVBUF_SIZE] [--max-sendbuf-size MAX_SENDBUF_SIZE] [--timeout TIMEOUT] [--local-executor LOCAL_EXECUTOR] [--backlog BACKLOG] [--hostname HOSTNAME] [--hostnames HOSTNAMES [HOSTNAMES ...]] [--port PORT] [--ports PORTS [PORTS ...]] [--port-file PORT_FILE] [--unix-socket-path UNIX_SOCKET_PATH] [--num-acceptors NUM_ACCEPTORS] [--version] [--log-level LOG_LEVEL] [--log-file LOG_FILE] [--log-format LOG_FORMAT] [--open-file-limit OPEN_FILE_LIMIT] [--plugins PLUGINS [PLUGINS ...]] [--enable-dashboard] [--basic-auth BASIC_AUTH] [--enable-ssh-tunnel] [--work-klass WORK_KLASS] [--pid-file PID_FILE] [--openssl OPENSSL] [--data-dir DATA_DIR] [--ssh-listener-klass SSH_LISTENER_KLASS] [--disable-http-proxy] [--disable-headers DISABLE_HEADERS] [--ca-key-file CA_KEY_FILE] [--insecure-tls-interception] [--ca-cert-dir CA_CERT_DIR] [--ca-cert-file CA_CERT_FILE] [--ca-file CA_FILE] [--ca-signing-key-file CA_SIGNING_KEY_FILE] [--auth-plugin AUTH_PLUGIN] [--cache-requests] [--cache-by-content-type] [--cache-dir CACHE_DIR] [--proxy-pool PROXY_POOL] [--enable-web-server] [--enable-static-server] [--static-server-dir STATIC_SERVER_DIR] [--min-compression-length MIN_COMPRESSION_LENGTH] [--enable-reverse-proxy] [--rewrite-host-header] [--enable-metrics] [--metrics-path METRICS_PATH] [--pac-file PAC_FILE] [--pac-file-url-path PAC_FILE_URL_PATH] [--cloudflare-dns-mode CLOUDFLARE_DNS_MODE] [--filtered-upstream-hosts FILTERED_UPSTREAM_HOSTS] [--filtered-client-ips-mode FILTERED_CLIENT_IPS_MODE] [--filtered-client-ips FILTERED_CLIENT_IPS] [--filtered-url-regex-config FILTERED_URL_REGEX_CONFIG]
proxy.py v2.4.8.dev8+gc703edac.d20241013
options: -h, --help show this help message and exit --tunnel-hostname TUNNEL_HOSTNAME Default: None. Remote hostname or IP address to which SSH tunnel will be established. --tunnel-port TUNNEL_PORT Default: 22. SSH port of the remote host. --tunnel-username TUNNEL_USERNAME Default: None. Username to use for establishing SSH tunnel. --tunnel-ssh-key TUNNEL_SSH_KEY Default: None. Private key path in pem format --tunnel-ssh-key-passphrase TUNNEL_SSH_KEY_PASSPHRASE Default: None. Private key passphrase --tunnel-remote-port TUNNEL_REMOTE_PORT Default: 8899. Remote port which will be forwarded locally for proxy. --threadless Default: True. Enabled by default on Python 3.8+ (mac, linux). When disabled a new thread is spawned to handle each client connection. --threaded Default: False. Disabled by default on Python < 3.8 and windows. When enabled a new thread is spawned to handle each client connection. --num-workers NUM_WORKERS Defaults to number of CPU cores. --enable-events Default: False. Enables core to dispatch lifecycle events. Plugins can be used to subscribe for core events. --inactive-conn-cleanup-timeout INACTIVE_CONN_CLEANUP_TIMEOUT Time after which inactive works must be cleaned up. Increase this value if your backend services are slow to response or when proxy.py is handling a high volume. When running proxy.py on Google Cloud (GCP) you may see 'backend_connection_closed_before_data_sen t_to_client', with curl clients you may see 'Empty reply from server' error when '--inactive-conn- cleanup-timeout' value is low for your use-case. Default 1 seconds --enable-proxy-protocol Default: False. If used, will enable proxy protocol. Only version 1 is currently supported. --enable-conn-pool Default: False. (WIP) Enable upstream connection pooling. --key-file KEY_FILE Default: None. Server key file to enable end-to-end TLS encryption with clients. If used, must also pass --cert-file. --cert-file CERT_FILE Default: None. Server certificate to enable end-to-end TLS encryption with clients. If used, must also pass --key-file. --client-recvbuf-size CLIENT_RECVBUF_SIZE Default: 128 KB. Maximum amount of data received from the client in a single recv() operation. --server-recvbuf-size SERVER_RECVBUF_SIZE Default: 128 KB. Maximum amount of data received from the server in a single recv() operation. --max-sendbuf-size MAX_SENDBUF_SIZE Default: 64 KB. Maximum amount of data to flush in a single send() operation. --timeout TIMEOUT Default: 10.0. Number of seconds after which an inactive connection must be dropped. Inactivity is defined by no data sent or received by the client. --local-executor LOCAL_EXECUTOR Default: 1. Enabled by default. Use 0 to disable. When enabled acceptors will make use of local (same process) executor instead of distributing load across remote (other process) executors. Enable this option to achieve CPU affinity between acceptors and executors, instead of using underlying OS kernel scheduling algorithm. --backlog BACKLOG Default: 100. Maximum number of pending connections to proxy server. --hostname HOSTNAME Default: 127.0.0.1. Server IP address. --hostnames HOSTNAMES [HOSTNAMES ...] Default: None. Additional IP addresses to listen on. --port PORT Default: 8899. Server port. To listen on more ports, pass them using --ports flag. --ports PORTS [PORTS ...] Default: None. Additional ports to listen on. --port-file PORT_FILE Default: None. Save server port numbers. Useful when using --port=0 ephemeral mode. --unix-socket-path UNIX_SOCKET_PATH Default: None. Unix socket path to use. When provided --host and --port flags are ignored --num-acceptors NUM_ACCEPTORS Defaults to number of CPU cores. --version, -v Prints proxy.py version. --log-level LOG_LEVEL Valid options: DEBUG, INFO (default), WARNING, ERROR, CRITICAL. Both upper and lowercase values are allowed. You may also simply use the leading character e.g. --log-level d --log-file LOG_FILE Default: sys.stdout. Log file destination. --log-format LOG_FORMAT Log format for Python logger. --open-file-limit OPEN_FILE_LIMIT Default: 1024. Maximum number of files (TCP connections) that proxy.py can open concurrently. --plugins PLUGINS [PLUGINS ...] Comma separated plugins. You may use --plugins flag multiple times. --enable-dashboard Default: False. Enables proxy.py dashboard. --basic-auth BASIC_AUTH Default: No authentication. Specify colon separated user:password to enable basic authentication. --enable-ssh-tunnel Default: False. Enable SSH tunnel. --work-klass WORK_KLASS Default: proxy.http.HttpProtocolHandler. Work klass to use for work execution. --pid-file PID_FILE Default: None. Save "parent" process ID to a file. --openssl OPENSSL Default: openssl. Path to openssl binary. By default, assumption is that openssl is in your PATH. --data-dir DATA_DIR Default: ~/.proxypy. Path to proxypy data directory. --ssh-listener-klass SSH_LISTENER_KLASS Default: proxy.core.ssh.listener.SshTunnelListener. An implementation of BaseSshTunnelListener --disable-http-proxy Default: False. Whether to disable proxy.HttpProxyPlugin. --disable-headers DISABLE_HEADERS Default: None. Comma separated list of headers to remove before dispatching client request to upstream server. --ca-key-file CA_KEY_FILE Default: None. CA key to use for signing dynamically generated HTTPS certificates. If used, must also pass --ca-cert-file and --ca-signing-key-file --insecure-tls-interception Default: False. Disables certificate verification --ca-cert-dir CA_CERT_DIR Default: ~/.proxy/certificates. Directory to store dynamically generated certificates. Also see --ca-key- file, --ca-cert-file and --ca-signing-key-file --ca-cert-file CA_CERT_FILE Default: None. Signing certificate to use for signing dynamically generated HTTPS certificates. If used, must also pass --ca-key-file and --ca-signing-key-file --ca-file CA_FILE Default: /Users/abhinavsingh/Dev/proxy.py/.venv3122/li b/python3.12/site-packages/certifi/cacert.pem. Provide path to custom CA bundle for peer certificate verification --ca-signing-key-file CA_SIGNING_KEY_FILE Default: None. CA signing key to use for dynamic generation of HTTPS certificates. If used, must also pass --ca-key-file and --ca-cert-file --auth-plugin AUTH_PLUGIN Default: proxy.http.proxy.auth.AuthPlugin. Auth plugin to use instead of default basic auth plugin. --cache-requests Default: False. Whether to also write request packets in the cache file. --cache-by-content-type Default: False. Whether to extract content by type from responses. Extracted content type is written to the cache directory e.g. video.mp4. --cache-dir CACHE_DIR Default: /Users/abhinavsingh/.proxy/cache. Flag only applicable when cache plugin is used with on-disk storage. --proxy-pool PROXY_POOL List of upstream proxies to use in the pool --enable-web-server Default: False. Whether to enable proxy.HttpWebServerPlugin. --enable-static-server Default: False. Enable inbuilt static file server. Optionally, also use --static-server-dir to serve static content from custom directory. By default, static file server serves out of installed proxy.py python module folder. --static-server-dir STATIC_SERVER_DIR Default: "public" folder in directory where proxy.py is placed. This option is only applicable when static server is also enabled. See --enable-static-server. --min-compression-length MIN_COMPRESSION_LENGTH Default: 20 bytes. Sets the minimum length of a response that will be compressed (gzipped). --enable-reverse-proxy Default: False. Whether to enable reverse proxy core. --rewrite-host-header Default: False. If used, reverse proxy server will rewrite Host header field before sending to upstream. --enable-metrics Default: False. Enables metrics. --metrics-path METRICS_PATH Default: /metrics. Web server path to serve proxy.py metrics. --pac-file PAC_FILE A file (Proxy Auto Configuration) or string to serve when the server receives a direct file request. Using this option enables proxy.HttpWebServerPlugin. --pac-file-url-path PAC_FILE_URL_PATH Default: /. Web server path to serve the PAC file. --cloudflare-dns-mode CLOUDFLARE_DNS_MODE Default: security. Either "security" (for malware protection) or "family" (for malware and adult content protection) --filtered-upstream-hosts FILTERED_UPSTREAM_HOSTS Default: Blocks Facebook. Comma separated list of IPv4 and IPv6 addresses. --filtered-client-ips-mode FILTERED_CLIENT_IPS_MODE Default: blacklist. Can be either "whitelist" (restrict access to specific IPs)or "blacklist" (allow everything except specific IPs). --filtered-client-ips FILTERED_CLIENT_IPS Default: 127.0.0.1,::1. Comma separated list of IPv4 and IPv6 addresses. --filtered-url-regex-config FILTERED_URL_REGEX_CONFIG Default: No config. Comma separated list of IPv4 and IPv6 addresses.
Proxy.py not working? Report at: https://github.com/abhinavsingh/proxy.py/issues/new
ValueError: filedescriptor out of range in selectConsulta Thread vs Threadless e Modalità di esecuzione Threadless Remota vs Locale per controllare il numero di core CPU utilizzati.
Vedi Benchmark per maggiori dettagli e per come eseguire i benchmark localmente.
Leggero
~5-20 MB di RAM
~25 MBProgrammabile
--plugins proxy.plugin.ProxyPoolPlugin--enable-web-server --plugins proxy.plugin.WebServerPlugin--enable-reverse-proxy --plugins proxy.plugin.ReverseProxyPluginPuò ascoltare su più indirizzi e porte
--hostnames per fornire indirizzi aggiuntivi--ports per fornire porte aggiuntive--port per sovrascrivere la porta predefinita 8899Dashboard in tempo reale
--enable-dashboardhttp://localhost:8899/dashboardproxy.py a runtimetypescriptSicuro
proxy.pyPrivato
Man-In-The-Middle
Protocolli http supportati per richieste proxy
http(s)
http1http1.1 con pipelinehttp2websocketsSupporto per il Protocollo HAProxy
--enable-proxy-protocolSupporto per server di file statici
--enable-static-server e --static-server-dirOttimizzato per upload e download di file grandi
--client-recvbuf-size, --server-recvbuf-size, --max-sendbuf-sizeSupporto IPv4 e IPv6
--hostnameSupporto per socket Unix domain
--unix-socket-pathSupporto per autenticazione di base
--basic-authSupporto PAC (Proxy Auto-configuration)
--pac-file e --pac-file-url-pathStarted server on ::1:8899
proxy.py ascolta su IPv6 ::1, che è l'equivalente di IPv4 127.0.0.1proxy.py da un host esterno, usa --hostname :: o --hostname 0.0.0.0 oppure associa a qualsiasi altra interfaccia disponibile sulla tua macchina.proxy.py visto dai server upstream.Porta 8899
--port per personalizzare la porta TCP predefinita.Come al solito, usa semplicemente:
❯ pip install proxy.py
La release stabile viene distribuita da master → pypi.org