
💫 Ngrok FRP Alternative • ⚡ Schnell • 🪶 Leichtgewichtig • 0️⃣ Keine Abhängigkeiten • 🔌 Plugbar • 😈 TLS-Interception • 🔒 DNS-over-HTTPS • 🔥 Arme-Leute-VPN • ⏪ Reverse & ⏩ Forward • 👮🏿 „Proxy Server“-Framework • 🌐 „Web Server“-Framework • ➵ ➶ ➷ ➠ „PubSub“-Framework • 👷 „Work“-Acceptor- & Executor-Framework
Schnell und skalierbar
Hochskalieren durch Nutzung aller verfügbaren Kerne des Systems
Threadless-Ausführungen mit asyncio
Entwickelt für zehntausende Verbindungen / Sekunde
# Auf 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
=============================
Beachten Sie Bereitstellung von proxy.py in der Produktion bei der Bereitstellung von Produktionsanwendungen mit proxy.py.
Installieren von `PyPi````console ❯ pip install --upgrade proxy.py
oder vom GitHub `master` branch```console
❯ pip install git+https://github.com/abhinavsingh/proxy.py.git@master
❯ pip install git+https://github.com/abhinavsingh/proxy.py.git@develop
## Docker verwenden
Multiplattform-Container sind verfügbar über:
- Docker Hub
- `latest`-Tag verweist auf die letzte `stable`-Version
- `docker pull abhinavsingh/proxy.py:latest`
- GitHub container registry (GHCR)
- `latest`-Tag verweist auf die letzte `develop`-Version
- `docker pull ghcr.io/abhinavsingh/proxy.py:latest`
Stabile Versionen der Container-Releases sind für folgende Plattformen verfügbar:
- `linux/386`
- `linux/amd64`
- `linux/arm/v6`
- `linux/arm/v7`
- `linux/arm64/v8`
- `linux/ppc64le`
- `linux/s390x`
### Stabile Version von Docker Hub
Führen Sie den neuesten `proxy.py`-Container aus:```console
❯ docker run -it -p 8899:8899 --rm abhinavsingh/proxy.py:latest
Docker daemon wird automatisch das passende Plattform-Image abrufen. Um einen Container für eine bestimmte Zielplattform auf Servern mit Multi-Plattform-Unterstützung auszuführen:```console ❯ docker run -it -p 8899:8899 --rm --platform linux/arm64/v8 abhinavsingh/proxy.py:latest
### Entwicklungsversion von GHCR
Führen Sie den `proxy.py`-Container mit dem neuesten Code aus dem develop-Branch aus:```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)
`docker`-Image ist derzeit auf `macOS` aufgrund von Inkompatibilität mit [vpnkit](https://github.com/moby/vpnkit/issues/469) defekt.
## HomeBrew verwenden
Aktualisierte Formulae für `HomeBrew` werden im `develop`-Zweig unter dem Verzeichnis `helper/homebrew` verwaltet.
- Das `stable`-Formula installiert das Paket aus dem `master`-Zweig.
- Das `develop`-Formula installiert das Paket aus dem `develop`-Zweig.
### Stabile Version mit 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
# Start proxy.py
## Über die Kommandozeile, wenn mit PIP installiert
Wenn `proxy.py` mit `pip` installiert wird,
wird eine ausführbare Datei namens `proxy` in Ihrem `$PATH` abgelegt.
### Ausführen
Geben Sie einfach `proxy` in der Kommandozeile ein, um mit der Standardkonfiguration zu starten.```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
Dinge, die in den obigen Logs auffallen:
Loaded plugin
proxy.py lädt standardmäßig proxy.http.proxy.HttpProxyPluginproxy.py-Instance HTTP(S)-Proxy-Server-Funktionen hinzuStarted N threadless workers
proxy.py so viele Worker-Prozesse wie CPU-Kerne auf dem Rechner vorhanden sind--num-workers-Flag, um die Anzahl der Worker-Prozesse anzupassenStarted N acceptors
proxy.py so viele Akzeptor-Prozesse wie CPU-Kerne auf dem Rechner vorhanden sind--num-acceptors-Flag, um die Anzahl der Akzeptor-Prozesse anzupassenAlle obigen Logs sind Logs der Stufe INFO, der Standard---log-level für proxy.py
Starten wir proxy.py mit DEBUG-Level-Logging:```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
Sie können einen einzelnen Buchstaben verwenden, um die Protokollebene anzupassen. Beispiel:
- `d = DEBUG`
- `i = INFO`
- `w = WARNING`
- `e = ERROR`
- `c = CRITICAL`
Wie wir aus den obigen Logs ersehen können, wird vor dem Start:
- `proxy.py` versucht, das offene Dateilimit `ulimit` auf dem System zu setzen
- Der Standardwert für `--open-file-limit` ist `1024`
- Das Flag `--open-file-limit` ist auf `Windows`-Betriebssystemen ohne Wirkung
Siehe [flags](#flags) für die vollständige Liste der verfügbaren Konfigurationsoptionen.
## Von der Kommandozeile aus dem Repository-Quellcode
Wenn Sie versuchen, `proxy.py` aus dem Quellcode auszuführen,
gibt es keine ausführbare Datei namens `proxy` im Quellcode.
Um `proxy.py` aus dem Quellcode zu starten, folgen Sie diesen Anweisungen:
- Repository klonen ```console
❯ git clone https://github.com/abhinavsingh/proxy.py.git
❯ cd proxy.py
Erstelle eine Python 3 virtuelle Umgebung ```console ❯ python3 -m venv venv ❯ source venv/bin/activate
Abhängigkeiten installieren ```console ❯ make lib-dep
Generate proxy/common/_scm_version.py
HINWEIS: Der folgende Schritt ist nicht für editierbare Installationen erforderlich.
Diese Datei schreibt die vom SCM erkannte Version in die Datei proxy/common/_scm_version.py. ```console
❯ ./write-scm-version.sh
Optional: Tests ausführen ```console ❯ make
Führen Sie proxy.py aus ```console
❯ python -m proxy
Siehe Plugin-Entwickler- und Mitwirkenden-Leitfaden
wenn Sie vorhaben, mit dem Quellcode von proxy.py zu arbeiten.
Standardmäßig wird die docker-Binärdatei mit IPv4-Netzwerk-Flags gestartet:
--hostname 0.0.0.0 --port 8899
Sie können das Flag von der Kommandozeile überschreiben, wenn Sie den Docker-Container starten. Um beispielsweise die proxy.py-Version im Docker-Container zu überprüfen, führen Sie aus:
❯ docker run -it \
-p 8899:8899 \
--rm abhinavsingh/proxy.py:latest \
-v
https-Verkehr
Fügen Sie Unterstützung für Shortlinks in Ihren bevorzugten Browsern / Anwendungen hinzu.
Starten Sie proxy.py wie folgt:```console
❯ proxy
--plugins proxy.plugin.ShortLinkPlugin
Jetzt können Sie Ihr tägliches Surferlebnis beschleunigen, indem Sie Ihre Lieblingswebsite mit einstelligen Domainnamen besuchen :). Dies funktioniert in allen Browsern.
Die folgenden Kurzlinks sind standardmäßig aktiviert:
| Kurzlink | Ziel-URL |
| :------: | :------------: |
| 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
Ändert den POST-Anforderungstext, bevor die Anfrage an den Upstream-Server gesendet wird.
Starten Sie `proxy.py` wie folgt:```console
❯ proxy \
--plugins proxy.plugin.ModifyPostDataPlugin
Standardmäßig ersetzt das Plugin den POST-Textkörper durch die fest codierten b'{"key": "modified"}' und erzwingt Content-Type: application/json.
Überprüfen Sie dies mit `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" }
Note following from the response above:
1. POST-Daten wurden geändert `"data": "{\"key\": \"modified\"}"`.
Ursprüngliche `curl`-Befehlsdaten waren `{"key": "value"}`.
2. Unser `curl`-Befehl hat keinen `Content-Type`-Header hinzugefügt,
aber unser Plugin hat einen hinzugefügt `"Content-Type": "application/json"`.
Gleiches kann auch durch Betrachten des `json`-Felds in der obigen Ausgabe überprüft werden: ```
"json": {
"key": "modified"
},
Content-Length-Header hinzu, um mit der Länge des modifizierten Bodys übereinzustimmen.Mock-Antworten für Ihre Server-REST-API. Verwenden Sie dies zum Testen und Entwickeln von Client-Seiten-Anwendungen ohne die Notwendigkeit eines tatsächlichen vorgelagerten REST-API-Servers.
Starten Sie proxy.py als:```console
❯ proxy
--plugins proxy.plugin.ProposedRestApiPlugin
Überprüfen Sie die Mock-API-Antwort mit `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"}]}
Überprüfen Sie dasselbe, indem Sie die proxy.py-Logs einsehen:```console
... [redacted] ... - access_log:1210 - ::1:64792 - GET None:None/v1/users/ - None None - 0 byte
Access log shows `None:None` as server `ip:port`. `None` simply means that
the server connection was never made, since response was returned by our plugin.
Now modify `ProposedRestApiPlugin` to returns REST API mock
responses as expected by your clients.
### RedirectToCustomServerPlugin
Leitet alle eingehenden `http`-Anfragen an einen benutzerdefinierten Webserver weiter.
Standardmäßig leitet es Client-Anfragen an den integrierten Webserver weiter,
der ebenfalls auf Port `8899` läuft.
Starten Sie `proxy.py` und aktivieren Sie den integrierten Webserver:```console
❯ proxy \
--enable-web-server \
--plugins proxy.plugin.RedirectToCustomServerPlugin
Überprüfen mit `curl -v -x localhost:8899 http://google.com```` ... [redacted] ... < HTTP/1.1 404 NOT FOUND < Server: proxy.py v1.0.0 < Connection: Close <
Oben wurde die `404`-Antwort vom `proxy.py`-Webserver zurückgegeben.
Überprüfen Sie dies, indem Sie die Logs für `proxy.py` einsehen.
Neben dem Proxy-Anfrage-Log müssen Sie auch ein http-Webserver-Anfrage-Log sehen.```
... [redacted] ... - access_log:1241 - ::1:49525 - GET /
... [redacted] ... - access_log:1157 - ::1:49524 - GET localhost:8899/ - 404 NOT FOUND - 70 bytes
Verwirft Traffic, indem der Upstream-Host überprüft wird.
Standardmäßig verwirft das Plugin Traffic für facebook.com und www.facebok.com.
Starte proxy.py als:```console
❯ proxy
--plugins proxy.plugin.FilterByUpstreamHostPlugin
Überprüfen mit `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
Oben 418 I'm a tea pot wird von unserem Plugin gesendet. Überprüfen Sie dies, indem Sie die Logs für proxy.py inspizieren:```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
Zwischenspeichert Antworten des Upstream-Servers.
Starten Sie `proxy.py` wie folgt:```console
❯ proxy \
--plugins proxy.plugin.CacheResponsesPlugin
Sie können auch das Flag --cache-requests verwenden, um das Caching von Anforderungspaketen zur Überprüfung zu aktivieren.
Überprüfen Sie mit 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"
}
Pfad zur Cache-Datei aus den Protokollen von `proxy.py` abrufen:```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
Überprüfen Sie den Inhalt der Cache-Datei `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
Das `CacheResponsesPlugin`-Plugin kann Antworten auch automatisch nach `content-type` zwischenspeichern.
Dazu muss der [TLS Interception](#tls-interception) Modus aktiviert sein
und das `--cache-by-content-type`-Flag übergeben werden. Beispiel:```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
Senden Sie einige Anfragen an den Proxy-Server und Sie werden Daten unter ~/.proxy/cache Verzeichnis sehen.
Sie sollten 2 Ordner sehen:
content: Enthält analysierte jpg, css, js, html, pdf usw. nach Inhaltstypresponses: Enthält rohe Antworten wie empfangen (natürlich entschlüsselt wegen des Abfangens)Ändert die Antworten des vorgeschalteten Servers.
Starten Sie proxy.py als:```console
❯ proxy
--plugins proxy.plugin.ManInTheMiddlePlugin
Überprüfen mit `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
Der Antworttext Hello from man in the middle wird von unserem Plugin gesendet.
Leitet eingehende Proxy-Anfragen an eine Gruppe von vorgeschalteten Proxy-Servern weiter.
Lass uns zunächst 2 vorgeschaltete Proxys starten. Um vorgeschaltete Proxys zu simulieren, starte proxy.py auf Port 9000 und `9001````console
❯ proxy --port 9000
---
## 🏪 **SSH-Snake V1 – Berichtszusammenfassungen und Heatmaps**
Das Sammeln technischer Informationen von mehreren IT-Systemen erfordert eine große Anzahl von SSH-Verbindungen. Diese Grafik, erstellt mit der neuen Version v1.0.26 des SSH-Snake, ist eine automatisierte Visualisierung, die zeigt, wie das Tool einen detaillierten Bericht der Rückverbindungsaktivitäten liefert.
Die v1-Berichtsfunktion des Tools bietet:
- **Zusammenfassung jedes entdeckten Systems**: Neue Hosts, neue Benutzer, neue Ziele, Geheimnisse und nicht identifizierte Schlüssel
- **Gesamtzusammenfassung**: Gesamtzahl der entdeckten Systeme und Rückverbindungsaktivitäten
- **Heatmap**: Eine automatisierte Visualisierung sowohl der Netzwerkaktivität als auch der Ergebnisse von `find_from_hosts`
Wenn Sie nur einen Bericht benötigen, fügen Sie einfach das `-r`-Flag hinzu, um die Zusammenfassung und die Heatmap zu generieren; die tatsächlichen Rückverbindungsaktivitäten werden übersprungen. Das Generieren des Berichts nach dem Ausführen des Tools und das `-r`-Flag erzeugen derzeit dieselbe Ausgabe.
---```console
❯ proxy --port 9001
Starte nun proxy.py mit ProxyPoolPlugin (auf dem Standard-Port 8899), wobei es auf unsere Upstream-Proxies an den Ports 9000 und 9001 verweist.```console
❯ proxy
--plugins proxy.plugin.ProxyPoolPlugin
--proxy-pool localhost:9000
--proxy-pool localhost:9001
Stellen Sie eine curl-Anfrage über den `8899`-Proxy:
`curl -v -x localhost:8899 http://httpbin.org/get`
Überprüfen Sie, ob der `8899`-Proxy Anfragen an die vorgeschalteten Proxys weiterleitet,
indem Sie die jeweiligen Logs prüfen.
Wenn ein vorgeschalteter Proxy Anmeldeinformationen benötigt, übergeben Sie diese als Argumente. Beispiel:
`--proxy-pool user:[email protected]:port`
### FilterByClientIpPlugin
Lehne Datenverkehr von bestimmten IP-Adressen ab. Standardmäßig blockiert dieses
Plugin den Datenverkehr von `127.0.0.1` und `::1`.
Starten Sie `proxy.py` mit:```console
❯ proxy \
--plugins proxy.plugin.FilterByClientIpPlugin
Sende eine Anfrage mit 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 <
Passen Sie das Plugin nach Ihren Wünschen an, z.B. nur bestimmte IP-Adressen zulassen.
### ModifyChunkResponsePlugin
Dieses Plugin zeigt, wie chunk-kodierte Antworten modifiziert werden können. Dazu nutzt es den `proxy.py`-Kern, um die chunk-kodierte Antwort zu parsen. Dann rekonstruieren wir die Antwort mit benutzerdefinierten hartcodierten Chunks, wobei die ursprünglichen Chunks vom Upstream-Server ignoriert werden.
Starten Sie `proxy.py` als:```console
❯ proxy \
--plugins proxy.plugin.ModifyChunkResponsePlugin
Überprüfen mit curl -v -x localhost:8899 http://httpbin.org/stream/5:```console
... [redacted] ...
modify
chunk
response
plugin
Passen Sie `ModifyChunkResponsePlugin` nach Ihren Wünschen an. Beispiel: Anstatt hartcodierte Chunks zu senden, parsen und modifizieren Sie die ursprünglichen `JSON`-Chunks, die vom vorgelagerten Server empfangen werden.
### ModifyRequestHeaderPlugin
Dieses Plugin demonstriert, wie ausgehende HTTPS-Anfrageheader im TLS-Interception-Modus geändert werden können.
Starten Sie `proxy.py` wie folgt:```console
❯ proxy \
--plugins proxy.plugin.ModifyRequestHeaderPlugin \
... [TLS interception flags] ...
Verifizieren mit 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
Dieses Plugin verwendet den von `Cloudflare` gehosteten `DNS-over-HTTPS` [API](https://developers.cloudflare.com/1.1.1.1/encrypted-dns/dns-over-https/make-api-requests/dns-json) (json).
`DoH` erfordert einen HTTP2-konformen Client. Leider bietet `proxy.py`
das noch nicht, daher verwenden wir eine Abhängigkeit. Installieren Sie sie:```console
❯ pip install "httpx[http2]"
Jetzt starte proxy.py wie folgt:```console
❯ proxy
--plugins proxy.plugin.CloudflareDnsResolverPlugin
Standardmäßig läuft `CloudflareDnsResolverPlugin` im `security`-Modus und bietet Malware-Schutz.
Verwenden Sie `--cloudflare-dns-mode family`, um auch den Schutz vor Erwachseneninhalten zu aktivieren.
### CustomDnsResolverPlugin
Dieses Plugin demonstriert, wie eine benutzerdefinierte DNS-Auflösungsimplementierung mit `proxy.py` verwendet wird.
Dieses Beispiel-Plugin verwendet derzeit den in Python integrierten Auflösungsmechanismus. Passen Sie den Code
nach Ihren Wünschen an. Beispiel: Fragen Sie Ihren benutzerdefinierten DNS-Server ab, implementieren Sie `DoH` oder andere Mechanismen.
Starten Sie `proxy.py` mit:```console
❯ proxy \
--plugins proxy.plugin.CustomDnsResolverPlugin
HttpProxyBasePlugin.resolve_dns-Callback kann auch verwendet werden, um die Netzwerkschnittstelle zu konfigurieren, die als source_address für die Verbindung zum Upstream-Server verwendet werden muss.
Siehe diesen Thread für weitere Details.
PS: Es gibt kein Plugin mit diesem Namen, aber CustomDnsResolverPlugin kann einfach nach Ihren Bedürfnissen angepasst werden.
Versucht, den Programmnamen (application) für Proxy-Anfragen, die von der lokalen Maschine stammen, aufzulösen. Falls identifiziert, wird die Client-IP in den Zugriffsprotokollen durch den Programmnamen ersetzt.
Starten Sie proxy.py als:```console
❯ proxy
--plugins proxy.plugin.ProgramNamePlugin
Stellen Sie eine Anfrage mit `curl`:```console
❯ curl -v -x localhost:8899 https://httpbin.org/get
Sie müssen Logzeilen wie diese sehen:```console ... [redacted] ... - [I] server.access_log:419 - curl:58096 - CONNECT httpbin.org:443 - 6010 bytes - 1824.62ms
Beachten Sie `curl` anstelle von `::1` oder `127.0.0.1` als Client-IP.
[](#programnameplugin) Falls `ProgramNamePlugin` auf Ihrem Betriebssystem nicht zuverlässig funktioniert, tragen Sie bitte durch das Senden eines Pull-Requests und/oder das Eröffnen eines Issues bei. Vielen Dank!!!
## HTTP-Webserver-Plugins
### Webserver-Route
Demonstriert das integrierte Webserver-Routing mittels Plugin.
Starten Sie `proxy.py` wie folgt:```console
❯ proxy --enable-web-server \
--plugins proxy.plugin.WebServerPlugin
Überprüfen mit curl -v localhost:8899/http-route-example, sollte zurückgeben:```console
HTTP route response
## Reverse Proxy Plugins
Erweitert den integrierten Webserver um Reverse-Proxy-Funktionen.
### Reverse Proxy
Starten Sie `proxy.py` wie folgt:```console
❯ proxy --enable-reverse-proxy \
--plugins proxy.plugin.ReverseProxyPlugin
Mit der Standardkonfiguration ist das ReverseProxyPlugin-Plugin äquivalent zur folgenden Nginx-Konfiguration:```console
location /get {
proxy_pass http://httpbin.org/get;
}
Überprüfen mit `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"
}
Mit dem obigen Beispiel sehen Sie manchmal:```console
Das passiert, weil unser standardmäßiger Reverse-Proxy-Plugin `ReverseProxyPlugin` mit einem `http`- und einem `https`-Upstream-Server konfiguriert ist. Und standardmäßig bewahrt `ReverseProxyPlugin` den ursprünglichen Host-Header. Während dies mit `https`-Upstreams funktioniert, funktioniert es mit `http`-Upstreams nicht zuverlässig. Um dieses Problem zu umgehen, verwenden Sie die `--rewrite-host-header`-Flags.
Beispiel:```console
❯ proxy --enable-reverse-proxy \
--plugins proxy.plugin.ReverseProxyPlugin \
--rewrite-host-header
This will ensure that Host header field is set as httpbin.org and works with both http and
https upstreams.
HINWEIS: Ob
--rewrite-host-headerverwendet wird oder nicht, hängt von Ihrem Anwendungsfall ab.
Bei Verwendung mehrerer Plugins kann es je nach Plugin-Funktionalität sinnvoll sein, die Reihenfolge zu berücksichtigen, in der Plugins in der Befehlszeile übergeben werden.
Plugins werden in der gleichen Reihenfolge aufgerufen, in der sie übergeben werden. Beispiel:
Angenommen, wir verwenden sowohl FilterByUpstreamHostPlugin als auch
RedirectToCustomServerPlugin. Die Idee ist, alle eingehenden http-Anfragen
für facebook.com und www.facebook.com zu verwerfen und andere
http-Anfragen an unseren integrierten Webserver umzuleiten.
Daher ist es in diesem Szenario wichtig, FilterByUpstreamHostPlugin vor
RedirectToCustomServerPlugin zu verwenden.
Wenn wir RedirectToCustomServerPlugin vor FilterByUpstreamHostPlugin aktivieren,
werden auch facebook-Anfragen an den integrierten Webserver umgeleitet,
anstatt verworfen zu werden.
Standardmäßig verwendet proxy.py das http-Protokoll für die Kommunikation mit Clients wie curl, Browser. Um eine Ende-zu-Ende-Verschlüsselung mit tls / https zu ermöglichen, generieren Sie zunächst Zertifikate. Checken Sie das Repository aus und führen Sie Folgendes aus:```console
make https-certificates
Starten Sie `proxy.py` als:```console
❯ proxy \
--cert-file https-cert.pem \
--key-file https-key.pem
Überprüfen mit 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"
}
Wenn Sie vermeiden möchten, das Flag `--proxy-cacert` zu übergeben, erwägen Sie auch, generierte SSL-Zertifikate zu signieren. Beispiel:
Erstellen Sie zunächst CA-Zertifikate:```console
make ca-certificates
Dann signieren Sie das SSL-Zertifikat:```console make sign-https-certificates
Starten Sie den Server nun mit dem Flag `--cert-file https-signed-cert.pem` neu. Beachten Sie, dass Sie auch das generierte `ca-cert.pem` in Ihrem System-Keychain als vertrauenswürdig einstufen müssen.
# TLS-Interception
Standardmäßig entschlüsselt `proxy.py` keinen `https`-Traffic zwischen Client und Server.
Um die TLS-Interception zu aktivieren, generieren Sie zunächst Root-CA-Zertifikate:```console
❯ make ca-certificates
Aktivieren wir auch CacheResponsePlugin, damit wir die entschlüsselte Antwort vom Server überprüfen können. Starten Sie proxy.py wie folgt:```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) Geben Sie auch den expliziten CA-Bundle-Pfad an, der für die Validierung von Peer-Zertifikaten benötigt wird. Siehe `--ca-file` Flag.
Überprüfen Sie die TLS-Interception mit `curl````console
❯ curl -v -x localhost:8899 --cacert ca-cert.pem https://httpbin.org/get
Run go version, um die Golang-Installation zu überprüfen.Run go env, um die Golang-Umgebungseinstellungen und -Version zu überprüfen.Run the following command im Terminal.```consoleGET /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" }
Die `issuer`-Zeile bestätigt, dass die Antwort abgefangen wurde.
Überprüfen Sie auch den Inhalt der zwischengespeicherten Antwortdatei. Ermitteln Sie den Pfad zur Cache-Datei aus den `proxy.py`-Logs.
`❯ 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"
}
Voilà!!! Wenn Sie CA-Flags entfernen, werden verschlüsselte Daten in der zwischengespeicherten Datei anstelle von Klartext gefunden.
Verwenden Sie nun CA-Flags mit anderen Plugin-Beispielen, um zu sehen, wie sie mit https-Verkehr funktionieren.
Um TLS-Verkehr von einem Server mit einem selbstsignierten Zertifikat abzufangen, fügen Sie das Flag --insecure-tls-interception hinzu, um die obligatorische TLS-Zertifikatsüberprüfung zu deaktivieren.
HINWEIS: Dieses Flag deaktiviert die Zertifikatsprüfung für alle Server.
Wichtige Hinweise zur TLS-Abfangung mit Docker-Container:
Seit v2.2.0 wird im proxy.py Docker-Container auch openssl mitgeliefert. Dies ermöglicht es proxy.py, Zertifikate während der Laufzeit für die TLS-Abfangung zu generieren.
Aus Sicherheitsgründen wird im proxy.py Docker-Container kein CA-Zertifikat mitgeliefert.
So starten Sie einen proxy.py Docker-Container mit TLS-Abfangung:
-v /tmp/ca-certificates:/tmp/ca-certificates Flag mountet unser CA-Zertifikatsverzeichnis in der Container-Umgebung
--plugins proxy.plugin.CacheResponsesPlugin aktiviert CacheResponsesPlugin, damit wir abgefangenen Datenverkehr inspizieren können--ca-* Flags aktivieren TLS-Interception.curl durch. Sie können das --cacert-Flag weglassen, wenn das CA-Zertifikat bereits vom System als vertrauenswürdig eingestuft ist. ```console
❯ curl -v issuer Feld aus den Antwort-Headern. ```console
cat an: ```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 ist eine Drop-in-Alternative für ngrok und frpgrout ist innerhalb von proxy.py enthalten❯ 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
## Grout Authentifizierung
Grout unterstützt Authentifizierung, um Ihre Dateien, Ordner und Dienste vor unbefugtem Zugriff zu schützen. Verwenden Sie die Option `--basic-auth`, um die Authentifizierung zu erzwingen. Beispiel:```console
grout /path/to/folder --basic-auth user:pass
grout https://localhost:8080 --basic-auth u:p
Standardmäßig erlaubt Grout den Zugriff auf alle Pfade der Dienste. Verwenden Sie das Flag --path, um den Zugriff auf bestimmte Pfade Ihres Webdienstes zu beschränken. Beispiel:```console
grout https://localhost:8080 --path /worker/
grout https://localhost:8080 --path /webhook/ --path /callback/
## Grout Wildcard-Domains
Standardmäßig bedient der Grout-Client eingehenden Traffic auf einer dedizierten Subdomain.
Einige Dienste (z. B. Kubernetes) möchten jedoch Traffic auf Ad-hoc-Subdomains bereitstellen.
Einen dedizierten Grout-Client für jede Ad-hoc-Subdomain zu starten, ist möglicherweise keine praktikable Lösung.
Für solche Szenarien unterstützt Grout Wildcard-Domains. So konfigurieren Sie Ihre eigene
Wildcard-Domain für die Verwendung mit Grout-Clients.
1. Wählen Sie eine Domain, z. B. `custom.example.com`
2. Ihr Dienst möchte Traffic für `custom.example.com` und `*.custom.example.com` bereitstellen
3. Wenn Sie `https://` verwenden möchten, müssen Sie einen Load Balancer einrichten:
- Richten Sie einen HTTPS-Load-Balancer (LB) ein
- Konfigurieren Sie den LB mit einem Zertifikat, das für `custom.example.com` und `*.custom.example.com` ausgestellt wurde
- Leiten Sie den Traffic an die öffentlichen IP-Adressen des Grout-Dienstes weiter
4. Kontaktieren Sie das Grout-Team unter [email protected], um `custom.example.com` auf die Whitelist zu setzen. Das Grout-Team stellt sicher,
dass Ihnen die Domain wirklich gehört und Sie ein gültiges SSL-Zertifikat wie oben beschrieben konfiguriert haben
Starten Sie Grout mit der `--wildcard`-Flagge. Beispiel:```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
Nur verfügbar mit
--wildcard
Neben der Standardroute können Sie auch zusätzliche Routen angeben, die Vorrang haben, wenn das Host-Feld übereinstimmt. Beispiel:```console
grout https://localhost:8080 custom.example.com
--wildcard
--tunnel-route-url stream.example.com=http://localhost:7001
Sie können mehrere benutzerdefinierte Routen bereitstellen, indem Sie dieses Flag wiederholen.
## Grout Client Plugin
`GroutClientBasePlugin` ermöglicht es Ihnen, Datenverkehr dynamisch zu verschiedenen Upstreams zu routen. Im Folgenden finden Sie eine einfache Implementierung mit einer Beschreibung zur Verwendung.```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
Weitere Informationen finden Sie unter grout_client.py. Um dies auszuprobieren, starten Sie, indem Sie --plugin proxy.plugin.grout_client.GroutClientPlugin beim Starten des Grout-Clients übergeben.
❯ docker run --rm -it
--entrypoint grout
-v ~/.proxy:/root/.proxy
abhinavsingh/proxy.py:latest
http://host.docker.internal:29876
Oben:
- Wir haben `--entrypoint` zu `grout` geändert
- Wir haben `localhost` durch `host.docker.internal` ersetzt, damit `grout` Datenverkehr an Port `29876` weiterleiten kann, der auf dem Host-Rechner läuft
- *(Optional)* Binden Sie den Ordner `~/.proxy` des Host-Rechners ein, damit `grout`-Anmeldeinformationen über Container-Neustarts hinweg bestehen bleiben
## Wie Grout funktioniert
- Die `grout`-Infrastruktur hat 2 Komponenten: Client und Server
- Der `grout`-Client hat 2 Komponenten: einen Thin- und einen Thick-Client
- Der `grout`-Thin-Client ist Teil des Open-Source-Projekts `proxy.py` (BSD-3-Klausel-Lizenz)
- Der `grout`-Thick-Client und die Server werden auf [jaxl.io](https://jaxl.io) gehostet und unterliegen dem Urheberrecht von [Jaxl Innovations Private Limited](https://jaxl.com)
- Der `grout`-Server hat 3 Komponenten: einen Registrierungsserver, einen Reverse-Proxy-Server und einen Tunnel-Server
## Selbst gehostetes `grout`
- Der `grout`-Thick-Client und die Server können auch auf Ihrer GCP-, AWS- oder Cloud-Infrastruktur gehostet werden
- Bei einer selbst gehosteten Version fließt Ihr Datenverkehr durch das Netzwerk, das Sie kontrollieren und dem Sie vertrauen
- Die `grout`-Entwickler auf [jaxl.io](https://jaxl.io) stellen GCP-, AWS- und Docker-Images für selbst gehostete Lösungen bereit
- Bitte senden Sie eine E-Mail an [[email protected]](mailto:[email protected]), um loszulegen
# Proxy über SSH-Tunnel
**Dies ist eine laufende Arbeit und funktioniert möglicherweise nicht wie dokumentiert**
Erfordert `paramiko`, um zu funktionieren. Installieren Sie Abhängigkeiten mit `pip install "proxy.py[tunnel]"`
## Proxy-Anfragen von entfernten Rechnern lokal bearbeiten
|
+------------+ | +----------+
| LOCAL | | | REMOTE |
| HOST | <== SSH ==== :8900 == | PROXY |
+------------+ | +----------+
:8899 proxy.py |
|
FIREWALL
(allow tcp/22)
### Was
Proxy-HTTP(s)-Anfragen, die auf einem `remote`-Proxy-Server gestellt werden, über den auf `localhost` laufenden `proxy.py`-Server.
### Wie
- Der angeforderte `remote`-Port wird über die SSH-Verbindung weitergeleitet.
- Der auf `localhost` laufende `proxy.py` bearbeitet und beantwortet `remote`-Proxy-Anfragen.
### Anforderungen
1. `localhost` MUSS SSH-Zugriff auf den `remote`-Server haben
2. Der `remote`-Server MUSS so konfiguriert sein, dass er HTTP(s)-Anfragen über die weitergeleitete Portnummer z.B. `:8900` proxyt.
- Die Ports von `remote` und `localhost` KÖNNEN gleich sein, z.B. `:8899`.
- `:8900` wurde in der ASCII-Grafik zur Unterscheidung gewählt.
### Ausprobieren
Starten Sie `proxy.py` wie folgt:```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...
Stellen Sie eine HTTP-Proxy-Anfrage auf dem remote-Server und
überprüfen Sie, dass die Antwort die öffentliche IP-Adresse von localhost als Ursprung enthält:```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"
}
Also, überprüfe, dass `proxy.py`-Logs auf `localhost` die `remote`-IP als Client-IP enthalten.```console
access_log:328 - remote:52067 - GET httpbin.org:80
|
+------------+ | +----------+
| LOCAL | | | REMOTE |
| HOST | === SSH =====> | SERVER |
+------------+ | +----------+
| :8899 proxy.py
|
FIREWALL
(allow tcp/22)
Nicht geplant.
Falls Sie einen gültigen Anwendungsfall haben, eröffnen Sie bitte ein Issue. Beiträge zur Erweiterung dieser Funktionalität sind über Pull-Requests jederzeit willkommen :)
Um lokale Anfragen aus der Ferne zu proxen, verwenden Sie das Proxy-Pool-Plugin.
Starten Sie proxy.py im eingebetteten Modus mit Standardkonfiguration durch Verwendung der proxy.main-Methode. Beispiel:```python
import proxy
if name == 'main': proxy.main()
Passen Sie die Startflags an, indem Sie sie als kwargs übergeben:```python
import ipaddress
import proxy
if __name__ == '__main__':
proxy.main(
hostname=ipaddress.IPv6Address('::1'),
port=8899
)
Note that:
main ist gleichbedeutend mit dem Start von proxy.py von der Kommandozeile.main akzeptiert keine args (nur kwargs).main wird automatisch alle verfügbaren sys.argv als args verbrauchen.main blockiert, bis proxy.py heruntergefahren wird.Starten Sie proxy.py im nicht-blockierenden eingebetteten Modus mit der Standardkonfiguration
durch die Verwendung des Proxy-Kontextmanagers: Beispiel:```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()
Beachten Sie:
1. `Proxy` ist ähnlich wie `main`, außer dass `Proxy` nicht blockiert.
2. Intern ist `Proxy` ein Kontextmanager, der `proxy.py` startet, wenn er aufgerufen wird, und ihn beendet, sobald der Gültigkeitsbereich endet.
3. Im Gegensatz zu `main` können Startflags bei `Proxy` auch über `args` und `kwargs` angepasst werden, z. B. `Proxy(['--port', '8899'])` oder durch Übergabe von Flags als kwargs, z. B. `Proxy(port=8899)`.
4. Im Gegensatz zu `main` untersucht `Proxy` nicht `sys.argv`.
## Ephemeral Port
Verwenden Sie `--port=0`, um `proxy.py` an einen vom Kernel zugewiesenen zufälligen Port zu binden.
Im eingebetteten Modus können Sie auf diesen Port zugreifen. Beispiel:```python
import proxy
if __name__ == '__main__':
with proxy.Proxy(port=0) as p:
print(p.flags.port)
proxy.sleep_loop()
flags.port gibt Ihnen Zugriff auf den zufälligen Port, der vom Kernel zugewiesen wurde.
Benutzer können das --plugins-Flag mehrmals verwenden, um mehrere Plugins zu laden.
Siehe Plugins können nicht geladen werden, wenn Sie auf Probleme stoßen.
Bei Verwendung im eingebetteten Modus haben Sie einige weitere Optionen. Beispiel:
bytes an die proxy.main-Methode oder den proxy.Proxy-Kontextmanager weiter.type-Instanz der Plugin-Klasse an. Dies ist besonders nützlich, wenn Sie Plugins zur Laufzeit definieren möchten.Beispiel: Laden Sie ein einzelnes Plugin mit dem --plugins-Flag:```python
import proxy
if name == 'main': proxy.main(plugins=['proxy.plugin.CacheResponsesPlugin'])
Der Einfachheit halber können Sie die Liste der Plugins auch als Schlüsselwortargument an `proxy.main` oder den `Proxy`-Konstruktor übergeben.
Beispiel:```python
import proxy
from proxy.plugin import FilterByUpstreamHostPlugin
if __name__ == '__main__':
proxy.main(plugins=[
b'proxy.plugin.CacheResponsesPlugin',
FilterByUpstreamHostPlugin,
])
proxy.TestCaseUm proxy.py für Ihre Python-unittest-Klassen einzurichten und abzubauen, verwenden Sie einfach proxy.TestCase anstelle von unittest.TestCase.
Beispiel:```python
import proxy
class TestProxyPyEmbedded(proxy.TestCase):
def test_my_application_with_proxy(self) -> None:
self.assertTrue(True)
Beachten Sie:
1. `proxy.TestCase` überschreibt die Methode `unittest.TestCase.run()`, um `proxy.py` einzurichten und zu beenden.
2. Der `proxy.py`-Server lauscht auf einem zufällig verfügbaren Port des Systems.
Dieser zufällige Port ist innerhalb Ihrer Testfälle als `self.PROXY.flags.port` verfügbar.
3. Standardmäßig wird nur ein einzelner Acceptor und Worker gestartet (`--num-workers 1 --num-acceptors 1`) für ein schnelleres Einrichten und Beenden.
4. Am wichtigsten: `proxy.TestCase` stellt auch sicher, dass der `proxy.py`-Server
läuft, bevor mit der Ausführung der Tests fortgefahren wird. Standardmäßig
wartet `proxy.TestCase` `10 Sekunden` auf den Start des `proxy.py`-Servers,
bei Fehlschlag wird eine `TimeoutError`-Ausnahme ausgelöst.
## Überschreiben der Startflags
Um die standardmäßigen Startflags zu überschreiben, definieren Sie eine Variable `PROXY_PY_STARTUP_FLAGS` in Ihrer Testklasse.
Beispiel:```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)
See test_embed.py for full working example.
unittest.TestCaseIf for some reasons you are unable to directly use proxy.TestCase,
then simply override unittest.TestCase.run yourself to setup and tear down proxy.py.
Example:```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)
oder einfach `proxy.py` innerhalb der Klassenmethoden `setUpClass` und `teardownClass` einrichten/abbauen.
# Hilfsprogramme
## TCP-Sockets
### new_socket_connection
Versucht eine IPv4-Verbindung herzustellen, dann IPv6 und
schließlich eine Dual-Stack-Verbindung zur angegebenen Adresse.```python
>>> conn = new_socket_connection(('httpbin.org', 80))
>>> ...[ use connection ]...
>>> conn.close()
socket_connection ist ein praktischer Dekorator + Kontextmanager
um new_socket_connection, der implizit conn.close sicherstellt.
Als Kontextmanager:```python
with socket_connection(('httpbin.org', 80)) as conn: ... [ use connection ] ...
Als Dekorator:```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
### API-Nutzung
- `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
Siehe pki.py und test_pki.py für Anwendungsbeispiele.
Verwenden Sie das Modul proxy.common.pki für:
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
## Interne Dokumentation
### Dokumentation lesen
- Besuchen Sie [proxypy.readthedocs.io](https://proxypy.readthedocs.io/)
- Lokal erstellen mit:
`make lib-doc`
### pydoc
Der Code ist gut dokumentiert. Holen Sie den Quellcode und führen Sie aus:
`pydoc3 proxy`
### pyreverse
Generieren Sie Klassenhierarchie-UML-Diagramme für eine tiefergehende Analyse:
`make lib-pyreverse`
# Dashboard ausführen
Das Dashboard befindet sich derzeit in der Entwicklung und ist noch nicht in `pip`-Paketen enthalten.
Um das Dashboard auszuführen, müssen Sie den Quellcode auschecken.
Das Dashboard ist in Typescript und SCSS geschrieben, also bauen wir es zuerst mit:```console
❯ make dashboard
Erstellen Sie auch das eingebettete Chrome DevTools, wenn Sie es verwenden möchten:```console
❯ make devtools
Starten Sie nun `proxy.py` mit dem Dashboard-Plugin und durch Überschreiben des Root-Verzeichnisses für den statischen Server:```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
Derzeit werden durch Aktivieren des Dashboards auch alle Dashboard-Plugins aktiviert.
Dashboard besuchen:```console ❯ open http://localhost:8899/dashboard/
## Datenverkehr überwachen
***Dies ist ein WIP und funktioniert möglicherweise nicht wie dokumentiert***
Warten Sie, bis die eingebettete `Chrome Dev Console` geladen ist. Derzeit werden Details zu allen Datenverkehr, der durch `proxy.py` fließt, an den Tab `Inspect Traffic` gesendet. Die empfangenen Nutzlasten sind jedoch noch nicht in die eingebettete Entwicklungskonsole integriert.
Die aktuelle Funktionalität kann überprüft werden, indem Sie die `Dev Console` des Dashboards öffnen und die websocket-Verbindung untersuchen, die das Dashboard mit dem `proxy.py`-Server hergestellt hat.
[](https://github.com/abhinavsingh/proxy.py)
# Chrome DevTools Protocol
Für Szenarien, in denen Sie direkten Zugriff auf den WebSocket-Endpunkt des `Chrome DevTools`-Protokolls wünschen,
starten Sie `proxy.py` wie folgt:```console
❯ proxy --enable-devtools --enable-events
Richten Sie Ihre CDT-Instanz jetzt auf ws://localhost:8899/devtools ein.
proxy.py mit dem Flag --enable-metrics, um interne Metriken über einen Prometheus-Endpunkt bereitzustellenprometheus.yaml, um den Endpunkt /metrics zu scrapen, z. B. http://localhost:8899/metrics--metrics-path an--enable-metrics aktiviert intern auch --enable-events und das Webserver-PluginIm Folgenden sind einige Strategien für die Verwendung von proxy.py in Ihren privaten/Produktions-/Unternehmensprojekten aufgeführt.
Sie MÜSSEN
forking des Repositorysvermeiden, "nur" um Ihren Plugin-Code im Verzeichnisproxy/pluginabzulegen. Forken ist der empfohlene Workflow für Projektbeiträger, NICHT für Projektnutzer.
--plugin, --plugins oder dem Argument plugin.proxy.py verwendet.Es wird dringend empfohlen, proxy.py über requirements.txt oder ähnliche Abhängigkeitsverwaltungssetups zu verwenden. Dadurch können Sie von regelmäßigen Leistungsupdates, Fehlerbehebungen, Sicherheitspatches und anderen Verbesserungen im proxy.py-Ökosystem profitieren. Beispiel:
Verwenden Sie die Option --pre, um vom letzten pre-release abzuhängen
❯ pip install proxy.py --pre
Pre-Releases sind ähnlich wie die Abhängigkeit vom Code des develop-Zweigs, nur dass Pre-Releases möglicherweise nicht auf den HEAD zeigen. Dies kann passieren, weil Pre-Releases NICHT nach jedem PR-Merge auf PyPi verfügbar gemacht werden.
Verwenden Sie TestPyPi mit der Option --pre, um vom Code des develop-Zweigs abzuhängen
❯ pip install -i https://test.pypi.org/simple/ proxy.py --pre
Ein Pre-Release wird nach jedem PR-Merge auf TestPyPi verfügbar gemacht.
Verwenden Sie den letzten stable-Release-Code
Wenn Sie Container bereitstellen, erstellen Sie Ihr Image einfach aus den Basis-proxy.py-Container-Images.
Verwenden Sie GHCR, um vom Code des develop-Zweigs zu erstellen:
FROM ghcr.io/abhinavsingh/proxy.py:latest as base
PS: Ich verwende GHCR latest für mehrere Produktionsprojekte
Verwenden Sie DockerHub, um vom letzten stable-Release-Code zu erstellen:
FROM abhinavsingh/proxy.py:latest as base
PS: IMHO ist die containerbasierte Strategie der beste Ansatz und die einzige Strategie, die ich selbst verwende.
Hey, aber Sie machen ständig bahnbrechende Änderungen im develop-Zweig.
Ich verstehe. Und daher MÜSSEN Sie für Ihre produktionsreifen Anwendungen die CI/CD Ihrer Anwendung in proxy.py integrieren. Sie müssen sicherstellen, dass Ihre Anwendung für jeden PR-Merge in das Upstream-Repository von proxy.py gebaut wird und ihre Tests besteht.
Wenn Ihr Anwendungsrepository öffentlich ist, können PR-Autoren in bestimmten Szenarien Patch-PRs für alle Abhängigen senden, um Rückwärtsinkompatibilität und grüne CI/CD aufrechtzuerhalten.
CI/CD-Integration stellt sicher, dass Ihre App weiterhin mit dem neuesten proxy.py-Code gebaut wird. Verwenden Sie je nachdem, wo Sie Ihren Code hosten, die unten aufgeführte Strategie:
GitHub
TBD
Google Cloud Build
TBD
AWS
TBD
Azure
TBD
Andere
TBD
Irgendwann werden wir die Trennung des
master-Zweigs aufheben und einfach einendevelop-Zweig pflegen. Da Abhängige über CI/CD-Integrationen Stabilität gewährleisten können. Derzeit ist es für ein produktionsreifes Projekt schwierig, blind vomdevelop-Zweig abzuhängen.
Der master-Zweig enthält den neuesten stable-Code und ist über das PyPi-Repository und Docker-Container über die Registries docker.io und ghcr.io verfügbar.
Probleme, die für stable-Releases gemeldet werden, werden mit höchster Priorität behandelt. Derzeit portieren wir jedoch keine Fixes in ältere Releases zurück. Beispiel: Wenn Sie ein Problem in v2.3.1 gemeldet haben, der aktuelle master-Zweig aber jetzt v2.4.0rc1 enthält, wird der Fix in v2.4.0rc2 landen.
Der develop-Zweig enthält hochmoderne Änderungen
Der Entwicklungszweig wird stabil gehalten (meistens). Aber wenn Sie 100% Zuverlässigkeit wünschen und Benutzer in der Produktionsumgebung bedienen, verwenden Sie IMMER die stabile Version.
Ein Pull-Request vX.Y.ZrcN wird einmal im Monat erstellt, der develop in master zusammenführt. Nachfolgend finden Sie, wie Code von einem Pull-Request zum nächsten stabilen Release fließt.
Das Entwicklungs-Release wird nach jedem Pull-Request-Merge von develop → test.pypi.org bereitgestellt
Das Alpha-Release wird von develop → pypi.org bereitgestellt, bevor der Pull-Request vX.Y.Z.rcN von develop → master-Zweig zusammengeführt wird. Es können mehrere Alpha-Releases erstellt werden, bevor der rc-Pull-Request zusammengeführt wird
Das Beta-Release wird von master → pypi.org bereitgestellt. Beta-Releases werden in Vorbereitung auf rc-Releases erstellt und können bei Bedarf übersprungen werden
Der Release Candidate wird von master → pypi.org bereitgestellt. Release Candidates werden immer vor dem endgültigen stabilen Release verfügbar gemacht
v1.xproxy.py erzeugte neue Threads zur Bearbeitung von Client-Anfragen.
v2.0+proxy.py führte Unterstützung für threadlose Ausführung von Client-Anfragen mit asyncio ein.
v2.4.0+Die threadlose Ausführung wurde standardmäßig für Python 3.8+ auf mac- und linux-Umgebungen aktiviert.
proxy.py threadlose Ausführung wurde von unseren Benutzern als sicher auf diesen Umgebungen gemeldet. Wenn Sie Probleme haben, wechseln Sie mit dem Flag --threaded in den Thread-Modus.
Für windows und Python < 3.8 können Sie den threadlosen Modus trotzdem ausprobieren, indem Sie proxy.py mit dem Flag --threadless starten.
Wenn threadlos für Sie funktioniert, erwägen Sie, einen PR zu senden, indem Sie die Methode _env_threadless_compliant in der Datei proxy/common/constants.py bearbeiten.
Die ursprüngliche threadlose Implementierung verwendete den remote-Ausführungsmodus. Dies ist auch unter High level architecture als ASCII-Art dargestellt.
Im remote-Ausführungsmodus delegieren Akzeptoren die Verarbeitung eingehender Client-Verbindungen an einen entfernten Worker-Prozess. Standardmäßig delegieren Akzeptoren Verbindungen im Round-Robin-Verfahren. Der Worker, der die Anfrage verarbeitet, kann auf demselben CPU-Kern wie der Akzeptor laufen oder auch nicht. Diese Architektur skaliert gut für hohen Durchsatz, führt jedoch dazu, dass zwei Prozesse pro CPU-Kern gestartet werden.
Beispiel: Wenn auf dem Rechner N-CPUs vorhanden sind, werden standardmäßig N Akzeptoren und N Worker-Prozesse gestartet. Sie können die Anzahl der Prozesse mit den Flags --num-acceptors und --num-workers anpassen. Je nach Anwendungsfall benötigen Sie möglicherweise mehr Worker als Akzeptoren oder umgekehrt.
In v2.4.x wurde der local-Ausführungsmodus hinzugefügt, hauptsächlich um die Anzahl der standardmäßig gestarteten Prozesse zu reduzieren. Dieses Modell eignet sich gut für alltägliche Einzelbenutzer-Anwendungsfälle und für Entwicklertestszenarien. Im local-Ausführungsmodus delegieren Akzeptoren Client-Verbindungen an einen Begleit-Thread anstatt an einen entfernten Prozess. Der local-Ausführungsmodus gewährleistet CPU-Affinität, anders als im remote-Modus, bei dem Akzeptor und Worker auf verschiedenen CPU-Kernen laufen können.
--local-executor 1 wurde in der v2.4.x-Serie zum Standard. Im local-Ausführungsmodus hat das Flag --num-workers keine Auswirkung, da keine entfernten Worker gestartet werden.
Um den remote-Ausführungsmodus zu verwenden, verwenden Sie das Flag --local-executor 0. Verwenden Sie dann --num-workers, um die Anzahl der Worker-Prozesse anzupassen.
proxy.py ist streng typisiert und verwendet Python typing-Annotationen. Beispiel:```python
my_strings : List[str] = [] #############^^^^^^^^^#####
Daher wird eine Python-Version benötigt, die Typannotierungen versteht.
Stellen Sie sicher, dass Sie `Python 3.6+` verwenden.
Überprüfen Sie die Version vor dem Ausführen von `proxy.py`:
`❯ python --version`
Alle `typing`-Annotationen können durch `comment-only`-Annotationen ersetzt werden. Beispiel:```python
>>> my_strings = [] # List[str]
>>> ################^^^^^^^^^^^
Es wird proxy.py ermöglichen, auf Python pre-3.6, sogar auf 2.7, ausgeführt zu werden.
Da jedoch alle zukünftigen Python-Versionen typing-Annotationen unterstützen werden, wurde dies nicht berücksichtigt.
Stellen Sie sicher, dass Plugin-Module durch Hinzufügen zu PYTHONPATH auffindbar sind. Beispiel:
`PYTHONPATH=/path/to/my/app proxy --plugins my_app.proxyPlugin````console ...[redacted]... - Loaded plugin proxy.HttpProxyPlugin ...[redacted]... - Loaded plugin my_app.proxyPlugin
ODER, geben Sie einfach den vollständigen Pfad als Parameter an, z. B.
`proxy --plugins /path/to/my/app/my_app.proxyPlugin`
Hier ist ein kurzes funktionierendes Beispiel:
- Inhalt des Ordners `/tmp/plug````console
╰─ ls -1 /tmp/plug ─╯
my_plugin.py
MyPlugin Klasse```console
╰─ cat /tmp/plug/my_plugin.py ─╯
from proxy.http.proxy import HttpProxyBasePluginclass MyPlugin(HttpProxyBasePlugin): pass
Dies ist ein leeres Plugin zur Demonstration der Nutzung externer Plugins. Sie müssen die notwendigen Methoden implementieren, damit Ihre Plugins für echten Datenverkehr funktionieren
- Starten Sie `proxy.py` mit `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
Stellen Sie sicher, dass proxy.py auf dem richtigen Netzwerk-Interface horcht.
Probieren Sie die folgenden Flags:
--hostname ::--hostname 0.0.0.0Höchstwahrscheinlich handelt es sich um ein Browser-Integrationsproblem mit der System-Tastenkette.
Verifizieren Sie zuerst, dass die Basisauthentifizierung mit curl funktioniert
curl -v -x benutzername:passwort@localhost:8899 https://httpbin.org/get
Siehe diesen Thread für weitere Details.
Es handelt sich um ein Kompatibilitätsproblem mit vpnkit.
Siehe moby/vpnkit erschöpft Docker-Ressourcen und Verbindung abgelehnt: Der Proxy konnte keine Verbindung herstellen für Hintergrundinformationen.
Eine fluentd.conf Vorlage ist verfügbar.
Kopieren Sie diese Konfigurationsdatei als proxy.py.conf unter
/etc/google-fluentd/config.d/
Aktualisieren Sie das path-Feld auf den Log-Dateipfad, der mit dem --log-file-Flag verwendet wird.
Standardmäßig wird auf den Pfad /tmp/proxy.log getailt.
Laden Sie google-fluentd neu:
sudo service google-fluentd restart
Jetzt können die proxy.py-Logs mit dem
GCE-Logviewer durchsucht werden.
ValueError: filedescriptor out of range in selectproxy.py ist dafür ausgelegt, Tausende von Verbindungen pro Sekunde zu verarbeiten,
ohne Socket-Leaks.
--open-file-limit-Flag, um ulimit -n anzupassen.--backlog-Flag für höhere Parallelität anpassen.Wenn nichts hilft, öffnen Sie ein Issue
mit den gesendeten requests per second und der Ausgabe des folgenden Debug-Skripts:```console
❯ ./helper/monitor_open_files.sh
## None:None in Zugriffsprotokollen
Manchmal sieht man `None:None` in Zugriffsprotokollen. Es bedeutet einfach,
dass niemals eine Verbindung zu einem Upstream-Server hergestellt wurde, d.h.
`upstream_host=None`, `upstream_port=None`.
Es kann mehrere Gründe für das Fehlen einer Upstream-Verbindung geben,
einige offensichtliche sind:
1. Der Client hat eine Verbindung aufgebaut, aber die Anfrage nie abgeschlossen.
2. Ein Plugin hat vorzeitig eine Antwort zurückgegeben und so die Verbindung zum Upstream-Server vermieden.
## OSError beim Wrappen des Clients für TLS Interception
Bei aktiviertem `TLS Interception` können gelegentlich folgende Ausnahmen auftreten:```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
Manche Clients können TLSV1_ALERT_UNKNOWN_CA auslösen, wenn sie das Zertifikat des Servers nicht überprüfen können, da es von einer unbekannten Aussteller-CA signiert wurde. Dies ist der Fall, wenn wir TLS-Interception durchführen. Dies kann verschiedene Gründe haben, z. B. Certificate Pinning usw.
Eine weitere Ausnahme, die auftreten kann, ist 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 Zukunft könnten wir möglicherweise das Ausliefern des ursprünglichen HTTPS-Inhalts für solche Clients unterstützen, während weiterhin TLS-Abfangen im Hintergrund erfolgt. Dies hält die Clients zufrieden, ohne
unsere Fähigkeit zum TLS-Abfangen zu beeinträchtigen. Leider steht diese Funktion derzeit nicht zur Verfügung.
Ein weiteres Beispiel mit der `SSLEOFError`-Ausnahme:```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` ist leistungsorientiert gestaltet. Standardmäßig versucht `proxy.py`,
alle verfügbaren CPU-Kerne zu nutzen, um neue Verbindungen von Clients anzunehmen.
Dies wird erreicht, indem ein `AcceptorPool` gestartet wird, der auf dem konfigurierten Server-Port lauscht. Dann startet der `AcceptorPool`
`Acceptor`-Prozesse (`--num-acceptors`), um eingehende Client-Verbindungen anzunehmen.
Daneben wird, falls `--threadless` aktiviert ist, ein `ThreadlessPool` eingerichtet,
der `Threadless`-Prozesse (`--num-workers`) startet, um die eingehenden Client-Verbindungen zu bearbeiten.
Jeder `Acceptor`-Prozess delegiert die angenommene Client-Verbindung
über die `Work`-Klasse an einen threadless Prozess. Derzeit ist `HttpProtocolHandler`
die Standard-Work-Klasse.
`HttpProtocolHandler` geht einfach davon aus, dass eingehende Clients der
HTTP-Spezifikation folgen. Spezifische HTTP-Proxy- und HTTP-Server-Implementierungen
sind als Plugins von `HttpProtocolHandler` geschrieben.
Siehe Dokumentation von `HttpProtocolHandlerPlugin` für verfügbare Lebenszyklus-Hooks.
Verwenden Sie `HttpProtocolHandlerPlugin`, um neue Funktionen für http(s)-Clients hinzuzufügen. Beispiel:
Siehe `HttpWebServerPlugin`.
## Alles ist ein Plugin
Innerhalb von `proxy.py` ist alles ein Plugin.
- Wir haben `Proxy-Server`-Plugins mithilfe des `--plugins`-Flags aktiviert.
Der Proxy-Server `HttpProxyPlugin` ist ein Plugin von `HttpProtocolHandler`.
Weiterhin erlaubt der Proxy-Server Plugins durch die `HttpProxyBasePlugin`-Spezifikation.
- Alle [Plugin-Beispiele](#plugin-beispiele) des Proxy-Servers implementierten
`HttpProxyBasePlugin`. Siehe Dokumentation von `HttpProxyBasePlugin` für verfügbare
Lebenszyklus-Hooks. Verwenden Sie `HttpProxyBasePlugin`, um das Verhalten des http(s)-Proxy-Protokolls
zwischen Client und Upstream-Server zu ändern. Beispiel:
[FilterByUpstreamHostPlugin](#filterbyupstreamhostplugin).
- Wir haben auch den integrierten `Webserver` mithilfe von `--enable-web-server` aktiviert.
Der Webserver `HttpWebServerPlugin` ist ein Plugin von `HttpProtocolHandler`
und implementiert die `HttpProtocolHandlerPlugin`-Spezifikation.
- Es gibt auch ein `--disable-http-proxy`-Flag. Es deaktiviert den integrierten Proxy-Server.
Verwenden Sie dieses Flag zusammen mit dem `--enable-web-server`-Flag, um `proxy.py` als programmierbaren
http(s)-Server auszuführen.
## Zustandsverwaltung für Ihre zustandslosen Plugins
Plugin-Klasseninstanzen werden pro Anfrage erstellt. Besonders wichtig:
Plugin-Instanzen werden im Kontext des CPU-Kerns erstellt, in dem die Anfrage
empfangen wurde.
Aus diesem Grund funktionieren globale Variablen in Ihren Plugins möglicherweise nicht wie erwartet.
Ihr Plugin-Code muss von Natur aus **zustandslos (stateless)** sein.
Um globale Zustände zu verwalten, haben Sie einige Optionen:
1) Nutzen Sie Pythons [multiprocessing-sichere Datenstrukturen](https://python.readthedocs.io/en/latest/library/multiprocessing.html#sharing-state-between-processes)
2) Nutzen Sie den integrierten [Event-Mechanismus](https://github.com/abhinavsingh/proxy.py/blob/develop/tutorial/eventing.ipynb) von `proxy.py`
## Übergeben von Verarbeitungskontext zwischen Plugins
Manchmal muss ein Plugin anderen Plugins in der Verarbeitungskette zusätzlichen Kontext übergeben. Beispielsweise kann dieser zusätzliche
Kontext auch als Teil der Zugriffsprotokolle ausgegeben werden.
Um Verarbeitungskontext zu übergeben, verwenden Sie die `on_access_log`-Methode des Plugins. Siehe, wie das [Program-Name](https://github.com/abhinavsingh/proxy.py/blob/develop/proxy/plugin/program_name.py)-Plugin den Standard-`client_ip`-Schlüssel im Kontext ändert und ihn auf den erkannten Programmnamen aktualisiert.
Infolgedessen sehen wir, wenn wir das [Program Name Plugin](#programnameplugin) aktivieren, in den Zugriffsprotokollen anstelle der IP-Adresse den lokalen Client-Programmnamen.
## Entwicklungsleitfaden
### Einrichten der lokalen Umgebung
Mitwirkende müssen `proxy.py` aus dem Quellcode starten, um neue Funktionen/Korrekturen zu überprüfen und zu entwickeln.
Siehe [Ausführen von proxy.py über die Befehlszeile mit dem Quellcode des Repositorys](#von-der-befehlszeile-aus-mit-quellcode-des-repositorys) für Details.
[](https://github.com/abhinavsingh/proxy.py/issues/642) Unter `macOS`
müssen Sie `Python` mit `pyenv` installieren, da das über `homebrew` installierte `Python`
oft problematisch ist. Siehe den verlinkten Thread für weitere Details.
### Einrichten von Git-Hooks
Der Pre-Commit-Hook stellt sicher, dass Tests bestanden werden.
1. `cd /path/to/proxy.py`
2. `ln -s $(PWD)/git-pre-commit .git/hooks/pre-commit`
Der Pre-Push-Hook stellt sicher, dass Lint und Tests bestanden werden.
1. `cd /path/to/proxy.py`
2. `ln -s $(PWD)/git-pre-push .git/hooks/pre-push`
### Einen Pull Request senden
Jeder Pull Request wird mit GitHub Actions getestet.
Siehe [GitHub-Workflow](https://github.com/abhinavsingh/proxy.py/tree/develop/.github/workflows)
für die Liste der Tests.
# Projekte, die Proxy.Py verwenden
Einige beliebte Projekte, die `proxy.py` verwenden
- [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)
Für die vollständige Liste siehe [verwendet von](https://github.com/abhinavsingh/proxy.py/network/dependents?package_id=UGFja2FnZS01MjQ0MDY5Ng%3D%3D)
# Benchmarks
Siehe das [Benchmark](https://github.com/abhinavsingh/proxy.py/tree/develop/benchmark)-Verzeichnis für Informationen zur Durchführung von Benchmark-Vergleichen mit anderen OSS-Webservern.
Um einen eigenständigen Benchmark für `proxy.py` auszuführen, verwenden Sie den folgenden Befehl vom Repository-Stammverzeichnis aus:```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 selectSiehe Threads vs. Threadless und Threadless-Entfernter vs. Lokaler Ausführungsmodus um die Anzahl der genutzten CPU-Kerne zu steuern.
Siehe Benchmark für weitere Details und zur lokalen Durchführung von Benchmarks.
Leichtgewichtig
~5-20 MB RAM
~25 MBProgrammierbar
--plugins proxy.plugin.ProxyPoolPlugin--enable-web-server --plugins proxy.plugin.WebServerPlugin--enable-reverse-proxy --plugins proxy.plugin.ReverseProxyPluginKann auf mehreren Adressen und Ports lauschen
--hostnames-Flag, um zusätzliche Adressen anzugeben--ports-Flag, um zusätzliche Ports anzugeben--port-Flag verwenden, um den Standardport 8899 zu überschreibenEchtzeit-Dashboard
--enable-dashboardhttp://localhost:8899/dashboardproxy.py zur LaufzeitSicher
proxy.pyPrivat
Man-In-The-Middle
Unterstützte HTTP-Protokolle für Proxy-Anfragen
http(s)
http1http1.1 mit Pipelinehttp2websocketsUnterstützung für das HAProxy-Protokoll
--enable-proxy-protocol-FlagUnterstützung für statische Dateiserver
--enable-static-server und --static-server-dir-FlagsOptimiert für große Datei-Uploads und Downloads
--client-recvbuf-size, --server-recvbuf-size, --max-sendbuf-size-FlagsIPv4- und IPv6-Unterstützung
--hostname-FlagUnix-Domain-Socket-Unterstützung
--unix-socket-path-FlagBasisauthentifizierungsunterstützung
--basic-auth-FlagPAC (Proxy Auto-configuration) Unterstützung
--pac-file und --pac-file-url-path-FlagsStarted server on ::1:8899
proxy.py auf IPv6 ::1, was dem IPv4-Äquivalent 127.0.0.1 entsprichtproxy.py zugreifen möchten, verwenden Sie --hostname :: oder --hostname 0.0.0.0 oder binden Sie an eine andere auf Ihrem Rechner verfügbare Schnittstelle.proxy.py, die von Upstream-Servern gesehen wird.Port 8899
--port-Flag, um den standardmäßigen TCP-Port anzupassen.Wie gewohnt einfach verwenden:
❯ pip install proxy.py
Das stabile Release wird von master → pypi.org bereitgestellt