Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
proxy.py — 💫 Альтернатива Ngrok FRP • ⚡ Быстрый • 🪶 Легковесный • 0️⃣ 0 зависимостей • 🔌 Подключаемый • 😈 Перехват TLS • 🔒 DNS через HTTPS • 🔥 VPN для бедных • ⏪ Обратное и ⏩ Прямое • 👮🏿 Фреймворк 'Прокси-сервер' • 🌐 Фреймворк 'Веб-сервер' • ➵ ➶ ➷ ➠ Фреймворк 'PubSub' • 👷 Фреймворк приёма и выполнения задач | Kitploit
Инструменты/GitHubGitHub/abhinavsingh/proxy.py
Веб-прокси и перехватТестирование на ПроникновениеУтилиты и фреймворкиRed Teaming
GitHubabhinavsingh/proxy.py

proxy.py

РепозиторийСайт
3.5k6291 год назадПроверено Kitploit

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →

Описание

💫 Альтернатива Ngrok FRP • ⚡ Быстрый • 🪶 Легковесный • 0️⃣ 0 зависимостей • 🔌 Подключаемый • 😈 Перехват TLS • 🔒 DNS через HTTPS • 🔥 VPN для бедных • ⏪ Обратное и ⏩ Прямое • 👮🏿 Фреймворк 'Прокси-сервер' • 🌐 Фреймворк 'Веб-сервер' • ➵ ➶ ➷ ➠ Фреймворк 'PubSub' • 👷 Фреймворк приёма и выполнения задач

Поделиться

Proxy.Py

PyPi Monthly Docker Pulls No Dependencies Gitter License

Tested With MacOS, Ubuntu, Windows, Android, Android Emulator, iOS, iOS Simulator Android, Android Emulator iOS, iOS Simulator

pypi version Python 3.x Checked with mypy

doc codecov lib

Contributions Welcome Need Help Sponsored by Jaxl Innovations Private Limited

Содержание

  • Особенности
  • Установка
    • Использование PIP
      • Стабильная версия
      • Версия для разработки
    • Использование Docker
      • Стабильная версия с Docker Hub
      • Версия для разработки с GHCR
      • Сборка контейнера локально
    • Использование HomeBrew
      • Стабильная версия
      • Версия для разработки
  • Запуск proxy.py
    • Из командной строки при установке через PIP
      • Запуск
      • Понимание логов
      • Включение DEBUG-логирования
    • Из командной строки из исходников репозитория
    • Docker-образ
      • Настройка флагов запуска
  • Примеры плагинов
    • Плагины HTTP-прокси
      • Плагин коротких ссылок
      • Плагин изменения данных POST
      • Плагин Mock API
      • Плагин перенаправления на пользовательский сервер
      • Плагин фильтрации по вышестоящему хосту
      • Плагин кэширования ответов
      • Кэширование по типу ответа
      • Плагин Man-In-The-Middle
      • Плагин пула прокси
      • Плагин фильтрации по IP клиента
      • Плагин изменения чанк-ответа
      • Плагин изменения заголовка запроса

Особенности

  • Готовая альтернатива ngrok

  • Быстрый и масштабируемый

    • Масштабируется, используя все доступные ядра системы

    • Беспоточное выполнение с использованием asyncio

    • Создан для обработки десятков тысяч соединений в секунду

      root@kitploit:~
      # 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
        =============================
      

Установка

Смотрите Deploying proxy.py in production при развёртывании production-приложений с использованием proxy.py.

Использование PIP

Стабильная версия с PIP

Установка из `PyPi````console ❯ pip install --upgrade proxy.py

root@kitploit:~
или из ветки `master` на GitHub```console
❯ pip install git+https://github.com/abhinavsingh/proxy.py.git@master

Версия для разработки с PIP```console

❯ pip install git+https://github.com/abhinavsingh/proxy.py.git@develop

root@kitploit:~
## Использование Docker

Многоплатформенные контейнеры доступны через:

- Docker Hub
  - тег `latest` указывает на последний `stable` релиз
  - `docker pull abhinavsingh/proxy.py:latest`
- GitHub container registry (GHCR)
  - тег `latest` указывает на последний `develop` релиз
  - `docker pull ghcr.io/abhinavsingh/proxy.py:latest`

Релизы контейнеров стабильной версии доступны для следующих платформ:

- `linux/386`
- `linux/amd64`
- `linux/arm/v6`
- `linux/arm/v7`
- `linux/arm64/v8`
- `linux/ppc64le`
- `linux/s390x`

### Стабильная версия из Docker Hub

Запустите последний контейнер `proxy.py`:```console
❯ docker run -it -p 8899:8899 --rm abhinavsingh/proxy.py:latest

Демон Docker автоматически загрузит образ соответствующей платформы. Для запуска контейнера под конкретную целевую платформу на серверах с поддержкой нескольких платформ:```console ❯ docker run -it -p 8899:8899 --rm --platform linux/arm64/v8 abhinavsingh/proxy.py:latest

root@kitploit:~
### Версия для разработки из GHCR

Запустите контейнер `proxy.py` из передового кода в ветке develop:```console
❯ docker run -it -p 8899:8899 --rm ghcr.io/abhinavsingh/proxy.py:latest

Сборка версии для разработки локально```console

❯ 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

root@kitploit:~
[![WARNING](https://img.shields.io/static/v1?label=MacOS&message=warning&color=red)](https://github.com/moby/vpnkit/issues/469)
`docker` образ в настоящее время не работает на `macOS` из-за несовместимости с [vpnkit](https://github.com/moby/vpnkit/issues/469).

## Использование HomeBrew

Обновлённые формулы для `HomeBrew` хранятся в ветке `develop` в каталоге `helper/homebrew`.

- `stable` формула устанавливает пакет из ветки `master`.
- `develop` формула устанавливает пакет из ветки `develop`.

### Стабильная версия с HomeBrew```console
❯ brew install https://raw.githubusercontent.com/abhinavsingh/proxy.py/develop/helper/homebrew/stable/proxy.rb

Версия для разработки с HomeBrew```console

❯ brew install https://raw.githubusercontent.com/abhinavsingh/proxy.py/develop/helper/homebrew/develop/proxy.rb

root@kitploit:~
# Запуск proxy.py

## Из командной строки при установке через PIP

Когда `proxy.py` установлен с помощью `pip`,
исполняемый файл с именем `proxy` помещается в ваш `$PATH`.

### Запуск

Просто введите `proxy` в командной строке, чтобы запустить с конфигурацией по умолчанию.```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

Понимание логов

Что стоит заметить в приведенных логах:

  • Loaded plugin

    • proxy.py загрузит proxy.http.proxy.HttpProxyPlugin по умолчанию
    • Как следует из названия, этот основной плагин добавляет возможности прокси-сервера http(s) в экземпляр proxy.py
  • Started N threadless workers

    • По умолчанию proxy.py запускает столько рабочих процессов, сколько ядер ЦП на машине
    • Используйте флаг --num-workers для настройки количества рабочих процессов
    • См. Threads vs Threadless чтобы понять, как управлять режимом выполнения
  • Started N acceptors

    • По умолчанию proxy.py запускает столько процессов-акцепторов, сколько ядер ЦП на машине
    • Используйте флаг --num-acceptors для настройки количества процессов-акцепторов

Включение DEBUG-логирования

Все приведенные выше логи — это логи уровня INFO, который является значением по умолчанию для --log-level в proxy.py.

Давайте запустим proxy.py с логированием уровня 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

root@kitploit:~
Вы можете использовать одну букву для настройки уровня логирования. Пример:
- `d = DEBUG`
- `i = INFO`
- `w = WARNING`
- `e = ERROR`
- `c = CRITICAL`

Как видно из логов выше, перед запуском:

- `proxy.py` попытался установить лимит открытых файлов `ulimit` в системе
- Используемое по умолчанию значение для `--open-file-limit` равно `1024`
- Флаг `--open-file-limit` не работает в операционных системах `Windows`

См. [флаги](#flags) для полного списка доступных параметров конфигурации.

## Из командной строки с использованием исходного кода репозитория

Если вы пытаетесь запустить `proxy.py` из исходного кода,
в исходном коде нет бинарного файла с именем `proxy`.

Чтобы запустить `proxy.py` из исходного кода, следуйте этим инструкциям:

- Клонируйте репозиторий  ```console
  ❯ git clone https://github.com/abhinavsingh/proxy.py.git
  ❯ cd proxy.py
  • Создайте виртуальное окружение Python 3 ```console ❯ python3 -m venv venv ❯ source venv/bin/activate

    root@kitploit:~
  • Установить зависимости ```console ❯ make lib-dep

    root@kitploit:~
  • Сгенерировать proxy/common/_scm_version.py

    ПРИМЕЧАНИЕ: Следующий шаг не требуется для редактируемых установок.

    Этот файл записывает обнаруженную SCM версию в файл proxy/common/_scm_version.py. ```console ❯ ./write-scm-version.sh

    root@kitploit:~
  • По желанию, запустите тесты ```console ❯ make

    root@kitploit:~
  • Запустите proxy.py ```console ❯ python -m proxy

    root@kitploit:~

См. Руководство по разработке плагинов и вкладу, если вы планируете работать с исходным кодом proxy.py.

Docker образ

Настройка флагов запуска

По умолчанию бинарный файл docker запускается с флагами IPv4 сети:

root@kitploit:~
--hostname 0.0.0.0 --port 8899

Вы можете переопределить флаг из командной строки при запуске docker-контейнера. Например, чтобы проверить версию proxy.py внутри docker-контейнера, выполните:

root@kitploit:~
❯ docker run -it \
    -p 8899:8899 \
    --rm abhinavsingh/proxy.py:latest \
    -v

Примеры плагинов

  • См. модуль plugin для полного кода.
  • Все входящие в комплект примеры плагинов также работают с трафиком https
    • Требуют дополнительные флаги и генерацию сертификатов
    • См. Перехват TLS.
  • Примеры плагинов также включены в Docker образ.
    • См. Настройка флагов запуска, чтобы попробовать плагины с Docker образом.

Плагины HTTP-прокси

ShortLinkPlugin

Добавьте поддержку коротких ссылок в ваших любимых браузерах/приложениях.

Shortlink Plugin

Запустите proxy.py как:```console ❯ proxy
--plugins proxy.plugin.ShortLinkPlugin

root@kitploit:~
Теперь вы можете ускорить повседневный просмотр, переходя на любимые сайты с помощью односимвольных доменных имён :). Это работает во всех браузерах.

По умолчанию включены следующие короткие ссылки:

| Короткая ссылка |  Целевой 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

Изменяет тело POST-запроса перед отправкой на вышестоящий сервер.

Запустите `proxy.py` как:```console
❯ proxy \
    --plugins proxy.plugin.ModifyPostDataPlugin

По умолчанию плагин заменяет содержимое тела POST на жестко заданное b'{"key": "modified"}' и применяет Content-Type: application/json.

Проверьте это с помощью `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" }

root@kitploit:~
Примечание из ответа выше:

1. Данные POST были изменены `"data": "{\"key\": \"modified\"}"`.
   Исходные данные команды `curl` были `{"key": "value"}`.
2. Наша команда `curl` не добавляла заголовок `Content-Type`,
   но наш плагин добавил один `"Content-Type": "application/json"`.
   То же самое можно проверить, посмотрев на поле `json` в выводе выше:   ```
   "json": {
    "key": "modified"
   },
  1. Наш плагин также добавил заголовок Content-Length для соответствия длине изменённого тела.

MockRestApiPlugin

Мок-ответы для REST API вашего сервера. Используйте для тестирования и разработки клиентских приложений без необходимости в реальном вышестоящем REST API сервере.

Запустите proxy.py как:```console ❯ proxy
--plugins proxy.plugin.ProposedRestApiPlugin

root@kitploit:~
Проверьте ответ мок-API, используя `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"}]}

Проверьте то же самое, изучив логи proxy.py:```console ... [redacted] ... - access_log:1210 - ::1:64792 - GET None:None/v1/users/ - None None - 0 byte

root@kitploit:~
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

Redirects all incoming `http` requests to custom web server.
By default, it redirects client requests to inbuilt web server,
also running on `8899` port.

Start `proxy.py` and enable inbuilt web server:```console
❯ proxy \
    --enable-web-server \
    --plugins proxy.plugin.RedirectToCustomServerPlugin

Проверьте с помощью `curl -v -x localhost:8899 http://google.com```` ... [redacted] ... < HTTP/1.1 404 NOT FOUND < Server: proxy.py v1.0.0 < Connection: Close <

  • Closing connection 0
root@kitploit:~
Ответ `404` выше был возвращён с веб-сервера `proxy.py`.

Убедитесь в этом, проверив логи `proxy.py`.
Наряду с журналом запросов прокси вы также должны увидеть журнал запросов http веб-сервера.```
... [redacted] ... - access_log:1241 - ::1:49525 - GET /
... [redacted] ... - access_log:1157 - ::1:49524 - GET localhost:8899/ - 404 NOT FOUND - 70 bytes

FilterByUpstreamHostPlugin

Отбрасывает трафик, проверяя вышестоящий хост. По умолчанию плагин отбрасывает трафик для facebook.com и www.facebok.com.

Запустите proxy.py как:```console ❯ proxy
--plugins proxy.plugin.FilterByUpstreamHostPlugin

root@kitploit:~
Проверьте с помощью `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

Выше 418 I'm a tea pot отправляется нашим плагином.

Проверьте то же самое, просмотрев логи 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

root@kitploit:~
### CacheResponsesPlugin

Кеширует ответы вышестоящего сервера.

Запустите `proxy.py` так:```console
❯ proxy \
    --plugins proxy.plugin.CacheResponsesPlugin

Вы также можете использовать флаг --cache-requests для включения кэширования пакетов запросов для проверки.

Проверьте, используя 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" }

  • Connection #0 to host localhost left intact
root@kitploit:~
Получить путь к файлу кэша из логов `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

Проверьте содержимое файла кэша `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" }

root@kitploit:~
### CacheByResponseType

`CacheResponsesPlugin` плагин может также автоматически кэшировать ответы по `content-type`.
Чтобы попробовать это, вы должны работать в режиме [TLS Interception](#tls-interception)
и затем передать флаг `--cache-by-content-type`.  Пример:```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

Make a few requests to the proxy server and you shall see data under ~/.proxy/cache directory.

You should see 2 folders:

  • content: Contains parsed jpg, css, js, html, pdf etc by content type
  • responses: Contains raw responses as received (of-course decrypted because of interception)

ManInTheMiddlePlugin

Modifies upstream server responses.

Start proxy.py as:```console ❯ proxy
--plugins proxy.plugin.ManInTheMiddlePlugin

root@kitploit:~
Проверьте с помощью `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

Response body Hello from man in the middle is sent by our plugin.

ProxyPoolPlugin

Forward incoming proxy requests to a set of upstream proxy servers.

Let's start 2 upstream proxies first. To simulate upstream proxies, start proxy.py on port 9000 and `9001````console ❯ proxy --port 9000

root@kitploit:~
Please provide the Markdown content to translate.```console
❯ proxy --port 9001

Теперь запустите proxy.py с ProxyPoolPlugin (на порту по умолчанию 8899), указав наши вышестоящие прокси на портах 9000 и 9001.```console ❯ proxy
--plugins proxy.plugin.ProxyPoolPlugin
--proxy-pool localhost:9000
--proxy-pool localhost:9001

root@kitploit:~
Выполните curl-запрос через прокси `8899`:

`curl -v -x localhost:8899 http://httpbin.org/get`

Проверьте, что прокси `8899` перенаправляет запросы к вышестоящим прокси, просмотрев соответствующие логи.

Если вышестоящий прокси требует учетные данные, передайте их как аргументы. Пример:

`--proxy-pool user:[email protected]:port`

### FilterByClientIpPlugin

Отклонять трафик с определенных IP-адресов. По умолчанию этот плагин блокирует трафик с `127.0.0.1` и `::1`.

Запустите `proxy.py` как:```console
❯ proxy \
    --plugins proxy.plugin.FilterByClientIpPlugin

Отправьте запрос, используя 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 <

  • Closing connection 0
root@kitploit:~
Измените плагин по своему вкусу, например, разрешите только определенные IP-адреса.

### ModifyChunkResponsePlugin

Этот плагин демонстрирует, как изменять ответы с чанкованным кодированием. Для этого плагин использует ядро `proxy.py` для разбора ответа с чанкованным кодированием. Затем мы восстанавливаем ответ, используя пользовательские жестко заданные чанки, игнорируя оригинальные чанки, полученные от вышестоящего сервера.

Запустите `proxy.py` как:```console
❯ proxy \
    --plugins proxy.plugin.ModifyChunkResponsePlugin

Проверьте, используя curl -v -x localhost:8899 http://httpbin.org/stream/5:```console ... [redacted] ... modify chunk response plugin

  • Connection #0 to host localhost left intact
  • Closing connection 0
root@kitploit:~
Настройте `ModifyChunkResponsePlugin` по своему вкусу. Например, вместо отправки жестко заданных фрагментов, парсите и модифицируйте исходные фрагменты `JSON`, полученные от вышестоящего сервера.

### ModifyRequestHeaderPlugin

Этот плагин демонстрирует, как изменять исходящие заголовки HTTPS-запросов в режиме перехвата TLS.

Запустите `proxy.py` как:```console
❯ proxy \
    --plugins proxy.plugin.ModifyRequestHeaderPlugin \
    ... [TLS interception flags] ...

Проверьте с помощью 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] ... }

root@kitploit:~
### CloudflareDnsResolverPlugin

Этот плагин использует `DNS-over-HTTPS` [API](https://developers.cloudflare.com/1.1.1.1/encrypted-dns/dns-over-https/make-api-requests/dns-json) (json), размещённый на `Cloudflare`.

`DoH` требует HTTP2-совместимый клиент. К сожалению, `proxy.py` пока этого не предоставляет, поэтому мы используем зависимость. Установите её:```console
❯ pip install "httpx[http2]"

Теперь запустите proxy.py как:```console ❯ proxy
--plugins proxy.plugin.CloudflareDnsResolverPlugin

root@kitploit:~
По умолчанию `CloudflareDnsResolverPlugin` работает в режиме `security` и обеспечивает защиту от вредоносного ПО.
Используйте `--cloudflare-dns-mode family`, чтобы также включить защиту от контента для взрослых.

### CustomDnsResolverPlugin

Этот плагин демонстрирует, как использовать пользовательскую реализацию разрешения DNS с `proxy.py`.
Этот пример плагина в настоящее время использует встроенный механизм разрешения Python.  Настройте код
по своему вкусу.  Например, запросите свой собственный DNS-сервер, реализуйте `DoH` или другие механизмы.

Запустите `proxy.py` как:```console
❯ proxy \
    --plugins proxy.plugin.CustomDnsResolverPlugin

CustomNetworkInterface

Обратный вызов HttpProxyBasePlugin.resolve_dns также можно использовать для настройки network interface, который должен использоваться в качестве source_address для соединения с вышестоящим сервером.

См. эту тему для получения дополнительной информации.

PS: Нет плагина с таким именем, но CustomDnsResolverPlugin можно легко настроить под ваши нужды.

ProgramNamePlugin

Пытается определить имя программы (приложения) для прокси-запросов, исходящих с локальной машины. Если идентифицировано, IP-адрес клиента в журналах доступа заменяется именем программы.

Запустите proxy.py как:```console ❯ proxy
--plugins proxy.plugin.ProgramNamePlugin

root@kitploit:~
Сделайте запрос с помощью `curl`:```console
❯ curl -v -x localhost:8899 https://httpbin.org/get

Вы должны видеть строки журнала, подобные этим:```console ... [redacted] ... - [I] server.access_log:419 - curl:58096 - CONNECT httpbin.org:443 - 6010 bytes - 1824.62ms

root@kitploit:~
Notice `curl` в качестве IP-клиента вместо `::1` или `127.0.0.1`.

[![WARNING](https://img.shields.io/static/v1?label=Compatibility&message=warning&color=red)](#programnameplugin) Если `ProgramNamePlugin` работает ненадёжно в вашей операционной системе, пожалуйста, помогите, отправив запрос на слияние и/или открыв задачу. Спасибо!!!

## Плагины HTTP-веб-сервера

### Маршрут веб-сервера

Демонстрирует встроенную маршрутизацию веб-сервера с использованием плагина.

Запустите `proxy.py` следующим образом:```console
❯ proxy --enable-web-server \
    --plugins proxy.plugin.WebServerPlugin

Проверьте с помощью curl -v localhost:8899/http-route-example, должен вернуть:```console HTTP route response

root@kitploit:~
## Плагины обратного прокси

Расширяет встроенный веб-сервер для добавления возможностей обратного прокси.

### Обратный прокси

Запустите `proxy.py` так:```console
❯ proxy --enable-reverse-proxy \
    --plugins proxy.plugin.ReverseProxyPlugin

С конфигурацией по умолчанию плагин ReverseProxyPlugin эквивалентен следующей конфигурации Nginx:```console location /get { proxy_pass http://httpbin.org/get; }

root@kitploit:~
Проверьте с помощью `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"
}

Перезапись заголовка Host

В приведённом выше примере вы иногда можете увидеть:```console

  • Empty reply from server
  • Closing connection curl: (52) Empty reply from server
root@kitploit:~
Это происходит потому, что наш плагин обратного прокси по умолчанию `ReverseProxyPlugin` настроен с upstream-серверами `http` и `https`. И по умолчанию `ReverseProxyPlugin` сохраняет исходный заголовок Host. Хотя это работает с upstream `https`, это ненадежно работает с upstream `http`. Чтобы обойти эту проблему, используйте флаг `--rewrite-host-header`.

Пример:```console
❯ proxy --enable-reverse-proxy \
    --plugins proxy.plugin.ReverseProxyPlugin \
    --rewrite-host-header

Это гарантирует, что поле заголовка Host будет установлено как httpbin.org и будет работать как с http, так и с https вышестоящими серверами.

ПРИМЕЧАНИЕ: Использовать --rewrite-host-header или нет — зависит от вашего сценария.

Порядок плагинов

При использовании нескольких плагинов, в зависимости от их функциональности, стоит учитывать порядок, в котором плагины передаются в командной строке.

Плагины вызываются в том же порядке, в котором они переданы. Например, предположим, мы используем одновременно FilterByUpstreamHostPlugin и RedirectToCustomServerPlugin. Идея состоит в том, чтобы отбрасывать все входящие http-запросы к facebook.com и www.facebook.com, а остальные http-запросы перенаправлять на наш встроенный веб-сервер.

Следовательно, в этом сценарии важно использовать FilterByUpstreamHostPlugin перед RedirectToCustomServerPlugin. Если мы включим RedirectToCustomServerPlugin до FilterByUpstreamHostPlugin, то запросы к facebook также будут перенаправляться на встроенный веб-сервер, вместо того чтобы быть отброшенными.

Сквозное шифрование

По умолчанию proxy.py использует протокол http для связи с клиентами, например curl, браузер. Для включения сквозного шифрования с помощью tls / https сначала сгенерируйте сертификаты. Склонируйте репозиторий и выполните:```console make https-certificates

root@kitploit:~
Запустите `proxy.py` как:```console
❯ proxy \
    --cert-file https-cert.pem \
    --key-file https-key.pem

Проверьте, используя 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" }

root@kitploit:~
Если вы хотите избежать передачи флага `--proxy-cacert`, рассмотрите также подписание сгенерированных SSL-сертификатов. Пример:

Сначала сгенерируйте сертификаты ЦС:```console
make ca-certificates

Затем, подпишите SSL-сертификат:```console make sign-https-certificates

root@kitploit:~
Теперь перезапустите сервер с флагом `--cert-file https-signed-cert.pem`. Обратите внимание, что вы также должны доверять созданному `ca-cert.pem` в вашей системной связке ключей.

# Перехват TLS

По умолчанию `proxy.py` не расшифровывает трафик `https` между клиентом и сервером. Чтобы включить перехват TLS, сначала сгенерируйте корневые сертификаты CA:```console
❯ make ca-certificates

Давайте также включим CacheResponsePlugin, чтобы мы могли проверить расшифрованный ответ от сервера. Запустите proxy.py как:```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

root@kitploit:~
[![NOTE](https://img.shields.io/static/v1?label=MacOS&message=note&color=yellow)](https://github.com/abhinavsingh/proxy.py#user-content-flags) Также укажите явный путь к пакету CA, необходимый для проверки сертификатов сторон. См. флаг `--ca-file`.

Проверьте перехват TLS с помощью `curl````console
❯ curl -v -x localhost:8899 --cacert ca-cert.pem https://httpbin.org/get

pwna: curl "example.com$(pwna)"
pwnb: curl "example.com$(pwna_type b)"```console

  • issuer: C=US; ST=CA; L=SanFrancisco; O=proxy.py; OU=CA; CN=Proxy PY CA; emailAddress=[email protected]
  • SSL certificate verify ok.

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" }

root@kitploit:~
Строка `issuer` подтверждает, что ответ был перехвачен.

Также проверьте содержимое файла кэшированного ответа. Получите путь к файлу кэша из журналов `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"
}

Вуаля!!! Если удалить флаги CA, зашифрованные данные будут найдены в кэшированном файле вместо обычного текста.

Теперь используйте флаги CA с другими примерами плагинов, чтобы увидеть их работу с трафиком https.

Небезопасное перехватывание TLS

Чтобы перехватывать TLS-трафик от сервера, использующего самоподписанный сертификат, добавьте флаг --insecure-tls-interception, чтобы отключить обязательную проверку сертификата TLS.

ПРИМЕЧАНИЕ: Этот флаг отключает проверку сертификата для всех серверов.

Перехватывание TLS с Docker

Важные замечания о перехватывании TLS с контейнером Docker:

  • Начиная с v2.2.0, контейнер Docker proxy.py также включает openssl. Это позволяет proxy.py генерировать сертификаты на лету для перехватывания TLS.

  • По соображениям безопасности контейнер Docker proxy.py не включает сертификаты CA.

Вот как запустить контейнер Docker proxy.py с перехватыванием TLS:

  1. Сгенерируйте сертификаты CA на хост-компьютере ```console ❯ make ca-certificates
    root@kitploit:~
  2. Скопируйте все сгенерированные сертификаты в отдельную директорию. Позже мы смонтируем эту директорию в наш docker контейнер ```console ❯ mkdir /tmp/ca-certificates ❯ cp ca-cert.pem ca-key.pem ca-signing-key.pem /tmp/ca-certificates
    root@kitploit:~
  3. Запустите Docker-контейнер ```console ❯ docker run -it --rm
    -v /tmp/ca-certificates:/tmp/ca-certificates
    -p 8899:8899
    abhinavsingh/proxy.py:latest
    --hostname 0.0.0.0
    --plugins proxy.plugin.CacheResponsesPlugin
    --ca-key-file /tmp/ca-certificates/ca-key.pem
    --ca-cert-file /tmp/ca-certificates/ca-cert.pem
    --ca-signing-key /tmp/ca-certificates/ca-signing-key.pem
    root@kitploit:~
  • -v /tmp/ca-certificates:/tmp/ca-certificates флаг монтирует каталог с нашим сертификатом ЦС в среде контейнера
    • --plugins proxy.plugin.CacheResponsesPlugin включает CacheResponsesPlugin, чтобы мы могли проверять перехваченный трафик
    • --ca-* флаги включают перехват TLS.
  1. Из другого терминала попробуйте перехват TLS с помощью curl. Вы можете опустить флаг --cacert, если сертификат ЦС уже доверен системой. ```console ❯ curl -v
    --cacert ca-cert.pem
    -x 127.0.0.1:8899
    https://httpbin.org/get
    root@kitploit:~
  2. Проверьте поле issuer в заголовках ответа. ```console
    • Server certificate:
    • subject: CN=httpbin.org; C=NA; ST=Unavailable; L=Unavailable; O=Unavailable; OU=Unavailable
    • start date: Jun 17 09:26:57 2020 GMT
    • expire date: Jun 17 09:26:57 2022 GMT
    • subjectAltName: host "httpbin.org" matched cert's "httpbin.org"
    • issuer: CN=example.com
    • SSL certificate verify ok.
    root@kitploit:~
  3. Вернитесь в терминал Docker, скопируйте журналы пути дампа ответа. ```console ...[redacted]... [I] access_log:338 - 172.17.0.1:56498 - CONNECT httpbin.org:443 - 1031 bytes - 1216.70 ms ...[redacted]... [I] close:49 - Cached response at /tmp/httpbin.org-ae1a927d064e4ab386ea319eb38fe251.txt
    root@kitploit:~
  4. В другом терминале выполните cat ответного дампа: ```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" }
    root@kitploit:~

GROUT (Альтернатива NGROK)

  1. grout — это готовая замена для ngrok и frp
  2. grout поставляется в составе proxy.py

Использование Grout```console

❯ 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

root@kitploit:~
## Grout Authentication

Grout поддерживает аутентификацию для защиты ваших файлов, папок и сервисов от несанкционированного доступа.  Используйте флаг `--basic-auth` для принудительной аутентификации.  Пример:

```bash
grout --basic-auth user:pass
``````console
grout /path/to/folder --basic-auth user:pass
grout https://localhost:8080 --basic-auth u:p

Grout Пути

По умолчанию Grout разрешает доступ ко всем путям на сервисах. Используйте флаг --path, чтобы ограничить доступ только к определенным путям на вашем веб-сервисе. Пример:```console grout https://localhost:8080 --path /worker/ grout https://localhost:8080 --path /webhook/ --path /callback/

root@kitploit:~
## Подстановочные домены Grout

По умолчанию клиент Grout обслуживает входящий трафик на выделенном поддомене.
Однако некоторые сервисы (например, Kubernetes) могут захотеть обслуживать трафик на произвольных поддоменах.
Запуск отдельного клиента Grout для каждого произвольного поддомена может быть нецелесообразным решением.

Для таких сценариев Grout поддерживает подстановочные домены. Вот как настроить собственный
подстановочный домен для использования с клиентами Grout.

1. Выберите домен, например `custom.example.com`
2. Ваш сервис хочет обслуживать трафик для `custom.example.com` и `*.custom.example.com`
3. Если вы планируете использовать `https://`, вам необходимо настроить балансировщик нагрузки:
   - Настройте балансировщик нагрузки HTTPS (LB)
   - Настройте LB с сертификатом, сгенерированным для `custom.example.com` и `*.custom.example.com`
   - Направьте трафик на публичные IP-адреса службы Grout
4. Свяжитесь с командой Grout по адресу [email protected], чтобы внести `custom.example.com` в белый список. Команда Grout убедится,
   что вы действительно владеете доменом и настроили действующий SSL-сертификат, как описано выше

Запустите Grout с флагом `--wildcard`.  Пример:```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

Маршрутизация подстановочных доменов Grout на основе заголовка 'Host'

Доступно только с --wildcard

Наряду с маршрутом по умолчанию вы также можете указать дополнительные маршруты, которые имеют приоритет при совпадении поля host. Пример:```console grout https://localhost:8080 custom.example.com
--wildcard
--tunnel-route-url stream.example.com=http://localhost:7001

root@kitploit:~
You can provide multiple custom routes by repeating this flag.

## Grout Client Plugin

`GroutClientBasePlugin` позволяет динамически направлять трафик на различные вышестоящие серверы.  Ниже приведена простая реализация с описанием того, как ее использовать.```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

См. grout_client.py для дополнительной информации. Чтобы опробовать это, передайте --plugin proxy.plugin.grout_client.GroutClientPlugin при запуске grout-клиента.

Grout с использованием Docker```console

❯ docker run --rm -it
--entrypoint grout
-v ~/.proxy:/root/.proxy
abhinavsingh/proxy.py:latest
http://host.docker.internal:29876

root@kitploit:~
Выше:

- Мы изменили `--entrypoint` на `grout`
- Мы заменили `localhost` на `host.docker.internal`, чтобы `grout` мог направлять трафик на порт `29876`, запущенный на хост-машине
- *(Опционально)* Подключите папку `~/.proxy` хост-машины, чтобы учетные данные `grout` сохранялись между перезапусками контейнера

## Как работает Grout

- Инфраструктура `grout` состоит из 2 компонентов: клиента и сервера
- Клиент `grout` имеет 2 компонента: тонкий и толстый клиент
- Тонкий клиент `grout` является частью открытого исходного кода `proxy.py` (лицензия BSD 3-Clause)
- Толстый клиент и серверы `grout` размещаются на [jaxl.io](https://jaxl.io)
  и являются авторским правом [Jaxl Innovations Private Limited](https://jaxl.com)
- Сервер `grout` имеет 3 компонента: сервер реестра, обратный прокси-сервер и туннельный сервер

## Самостоятельно размещаемый `grout`

- Толстый клиент и серверы `grout` также могут размещаться на ваших инфраструктурах GCP, AWS, Cloud
- В самостоятельной версии ваш трафик проходит через сеть, которую вы контролируете и которой доверяете
- Разработчики `grout` на [jaxl.io](https://jaxl.io) предоставляют образы GCP, AWS, Docker для самостоятельных решений
- Пожалуйста, напишите на [[email protected]](mailto:[email protected]), чтобы начать.

# Прокси через SSH-туннель

**Это в разработке и может работать не так, как описано**

Для работы требуется `paramiko`. Установите зависимости с помощью `pip install "proxy.py[tunnel]"`

## Прокси удаленных запросов локально

                            |
    +------------+          |            +----------+
    |   LOCAL    |          |            |  REMOTE  |
    |   HOST     | <== SSH ==== :8900 == |  PROXY   |
    +------------+          |            +----------+
    :8899 proxy.py          |
                            |
                         FIREWALL
                      (allow tcp/22)

### Что

Прокси HTTP(s) запросов, сделанных на `удаленном` прокси-сервере, через сервер `proxy.py`, работающий на `localhost`.

### Как

- Запрашиваемый `удаленный` порт перенаправляется через SSH-соединение.
- `proxy.py`, работающий на `localhost`, обрабатывает и отвечает на
  запросы `удаленного` прокси.

### Требования

1. `localhost` ДОЛЖЕН иметь SSH-доступ к `удаленному` серверу
2. `удаленный` сервер ДОЛЖЕН быть настроен на прокси HTTP(s) запросов
   через перенаправленный номер порта, например `:8900`.
   - Порты `remote` и `localhost` МОГУТ быть одинаковыми, например `:8899`.
   - `:8900` выбран в ascii-схеме для различия.

### Попробуйте

Запустите `proxy.py` как:```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...

Сделайте HTTP-прокси запрос к серверу remote и убедитесь, что ответ содержит публичный IP-адрес localhost как источник:```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" }

root@kitploit:~
Также убедитесь, что логи `proxy.py` на `localhost` содержат `remote` IP в качестве IP-адреса клиента.```console
access_log:328 - remote:52067 - GET httpbin.org:80

Прокси локальных запросов удаленно

root@kitploit:~
                        |
+------------+          |     +----------+
|   LOCAL    |          |     |  REMOTE  |
|   HOST     | === SSH =====> |  SERVER  |
+------------+          |     +----------+
                        |     :8899 proxy.py
                        |
                    FIREWALL
                 (allow tcp/22)

Не запланировано.

Если у вас есть обоснованный сценарий использования, пожалуйста, откройте issue. Вы всегда можете внести свой вклад через pull-запросы для добавления этой функциональности :)

Для проксирования локальных запросов удаленно используйте Плагин Proxy Pool.

Встраивание proxy.py

Блокирующий режим

Запустите proxy.py во встроенном режиме с конфигурацией по умолчанию, используя метод proxy.main. Пример:```python import proxy

if name == 'main': proxy.main()

root@kitploit:~
Настройте флаги запуска, передавая их в качестве kwargs:```python
import ipaddress
import proxy

if __name__ == '__main__':
  proxy.main(
    hostname=ipaddress.IPv6Address('::1'),
    port=8899
  )

Обратите внимание:

  1. main эквивалентен запуску proxy.py из командной строки.
  2. main не принимает никаких args (только kwargs).
  3. main автоматически обработает любые доступные sys.argv как args.
  4. main будет блокироваться до завершения работы proxy.py.

Неблокирующий режим

Запустите proxy.py в неблокирующем встроенном режиме с конфигурацией по умолчанию используя контекстный менеджер Proxy: Пример:```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()

root@kitploit:~
Обратите внимание:

1. `Proxy` аналогичен `main`, за исключением того, что `Proxy` не блокирует выполнение.
2. Внутри `Proxy` является контекстным менеджером, который запускает `proxy.py` при вызове и завершает его работу после выхода из области видимости.
3. В отличие от `main`, флаги запуска для `Proxy` также можно настраивать с помощью `args` и `kwargs`. Например: `Proxy(['--port', '8899'])` или передавая флаги как kwargs, например: `Proxy(port=8899)`.
4. В отличие от `main`, `Proxy` не проверяет `sys.argv`.

## Эфемерный порт

Используйте `--port=0`, чтобы привязать `proxy.py` к случайному порту, выделенному ядром.

Во встроенном режиме вы можете получить доступ к этому порту. Пример:```python
import proxy

if __name__ == '__main__':
  with proxy.Proxy(port=0) as p:
    print(p.flags.port)
    proxy.sleep_loop()

flags.port предоставит вам доступ к случайному порту, выделенному ядром.

Загрузка плагинов

Пользователи могут использовать флаг --plugins несколько раз для загрузки нескольких плагинов. См. Не удается загрузить плагины, если у вас возникли проблемы.

При использовании во встроенном режиме у вас есть еще несколько опций. Пример:

  1. Укажите полное имя класса плагина в виде bytes методу proxy.main или контекстному менеджеру proxy.Proxy.
  2. Предоставьте экземпляр type класса плагина. Это особенно полезно, если вы планируете определять плагины во время выполнения.

Пример загрузки одного плагина с помощью флага --plugins:```python import proxy

if name == 'main': proxy.main(plugins=['proxy.plugin.CacheResponsesPlugin'])

root@kitploit:~
Для простоты вы также можете передать список плагинов в качестве ключевого аргумента в `proxy.main` или конструктор `Proxy`. Пример:```python
import proxy
from proxy.plugin import FilterByUpstreamHostPlugin

if __name__ == '__main__':
  proxy.main(plugins=[
    b'proxy.plugin.CacheResponsesPlugin',
    FilterByUpstreamHostPlugin,
  ])

Модульное тестирование с proxy.py

proxy.TestCase

Для настройки и очистки proxy.py в ваших классах Python unittest просто используйте proxy.TestCase вместо unittest.TestCase. Пример:```python import proxy

class TestProxyPyEmbedded(proxy.TestCase):

root@kitploit:~
def test_my_application_with_proxy(self) -> None:
    self.assertTrue(True)
root@kitploit:~
Обратите внимание:

1. `proxy.TestCase` переопределяет метод `unittest.TestCase.run()` для настройки и демонтажа `proxy.py`.
2. Сервер `proxy.py` будет прослушивать случайный доступный порт в системе.
   Этот случайный порт доступен как `self.PROXY.flags.port` в ваших тестовых примерах.
3. По умолчанию запускается только один acceptor и worker (`--num-workers 1 --num-acceptors 1`) для более быстрой настройки и демонтажа.
4. Самое главное, `proxy.TestCase` также гарантирует, что сервер `proxy.py`
   запущен и работает перед выполнением тестов. По умолчанию,
   `proxy.TestCase` будет ждать `10 секунд` для запуска сервера `proxy.py`,
   при неудаче будет вызвано исключение `TimeoutError`.

## Переопределение флагов запуска

Чтобы переопределить флаги запуска по умолчанию, определите переменную `PROXY_PY_STARTUP_FLAGS` в вашем тестовом классе.
Пример:```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)

См. test_embed.py для полного рабочего примера.

С помощью unittest.TestCase

Если по каким-то причинам вы не можете напрямую использовать proxy.TestCase, просто переопределите unittest.TestCase.run самостоятельно для настройки и завершения работы proxy.py. Пример:```python import unittest import proxy

class TestProxyPyEmbedded(unittest.TestCase):

root@kitploit:~
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)
root@kitploit:~
или просто настройка / удаление `proxy.py` внутри методов класса `setUpClass` и `teardownClass`.

# Утилиты

## TCP сокеты

### new_socket_connection

Пытается создать IPv4-соединение, затем IPv6 и, наконец, двухстековое соединение с указанным адресом.```python
>>> conn = new_socket_connection(('httpbin.org', 80))
>>> ...[ use connection ]...
>>> conn.close()

socket_connection

socket_connection — это удобный декоратор + контекстный менеджер, обёртка вокруг new_socket_connection, которая гарантирует, что conn.close выполняется неявно.

В качестве контекстного менеджера:```python

with socket_connection(('httpbin.org', 80)) as conn: ... [ use connection ] ...

root@kitploit:~
Как декоратор:```python
>>> @socket_connection(('httpbin.org', 80))
>>> def my_api_call(conn, *args, **kwargs):
>>>   ... [ use connection ] ...

HTTP-клиент

build_http_request

  • Сгенерировать HTTP GET запрос ```python

    build_http_request(b'GET', b'/') b'GET / HTTP/1.1\r\n\r\n'

    root@kitploit:~
  • Создать HTTP GET запрос с заголовками ```python

    build_http_request(b'GET', b'/', conn_close=True) b'GET / HTTP/1.1\r\nConnection: close\r\n\r\n'

    root@kitploit:~
  • Сгенерировать HTTP POST запрос с заголовками и телом ```python

    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]"}'

    root@kitploit:~

build_http_response```python

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

root@kitploit:~
## PKI

### Использование 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
    root@kitploit:~
  • remove_passphrase ```python remove_passphrase( key_in_path: str, password: str, key_out_path: str, timeout: int = 10) -> bool
    root@kitploit:~
  • gen_csr ```python gen_csr( csr_path: str, key_path: str, password: str, crt_path: str, timeout: int = 10) -> bool
    root@kitploit:~
  • 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
    root@kitploit:~

Смотрите pki.py и test_pki.py для примеров использования.

Использование CLI

Используйте модуль proxy.common.pki для:

  1. Генерация открытых и закрытых ключей
  2. Создание CSR-запросов
  3. Подпись CSR-запросов с использованием пользовательского ЦС.```console ❯ python -m proxy.common.pki -h usage: pki.py [-h] [--password PASSWORD] [--private-key-path PRIVATE_KEY_PATH] [--public-key-path PUBLIC_KEY_PATH] [--subject SUBJECT] [--csr-path CSR_PATH] [--crt-path CRT_PATH] [--hostname HOSTNAME] [--openssl OPENSSL] action

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

root@kitploit:~
## Внутренняя документация

### Read The Doc

- Посетите [proxypy.readthedocs.io](https://proxypy.readthedocs.io/)
- Соберите локально с помощью:

`make lib-doc`

### pydoc

Код хорошо документирован. Скачайте исходный код и выполните:

`pydoc3 proxy`

### pyreverse

Сгенерируйте UML-диаграммы иерархии классов для углублённого анализа:

`make lib-pyreverse`

# Запуск Dashboard

Dashboard в настоящее время находится в разработке и ещё не включен в пакеты `pip`.
Для запуска dashboard необходимо взять исходный код.

Dashboard написан на Typescript и SCSS, поэтому сначала соберём его с помощью:```console
❯ make dashboard

Также соберите встроенные Chrome DevTools, если планируете их использовать:```console ❯ make devtools

root@kitploit:~
Теперь запустите `proxy.py` с плагином панели управления и переопределением корневого каталога для статического сервера:```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

В настоящее время включение панели управления также включает все плагины панели управления.

Посетить панель управления:```console ❯ open http://localhost:8899/dashboard/

root@kitploit:~
## Инспекция трафика

***Это в разработке и может работать не так, как описано***

Дождитесь загрузки встроенной `Chrome Dev Console`. В настоящее время информация обо всем трафике, проходящем через `proxy.py`, передается на вкладку `Inspect Traffic`. Однако полученные полезные нагрузки еще не интегрированы со встроенной консолью разработчика.

Текущую функциональность можно проверить, открыв `Dev Console` панели управления и проверив websocket-соединение, которое панель установила с сервером `proxy.py`.

[![Proxy.Py Dashboard Inspect Traffic](https://assets.kitploit.com/production/public/readmes/157/1e6258665ca9259fc526ebb90892d4b322094bb1e8139d329ab2379fc76ab66d.png)](https://github.com/abhinavsingh/proxy.py)

# Протокол Chrome DevTools

Для сценариев, где требуется прямой доступ к websocket-конечной точке протокола `Chrome DevTools`, запустите `proxy.py` следующим образом:

```bash
proxy.py --enable-devtools-ws
``````console
❯ proxy --enable-devtools --enable-events

Теперь укажите вашему экземпляру CDT адрес ws://localhost:8899/devtools.

Метрики Prometheus

  1. Запустите proxy.py с флагом --enable-metrics, чтобы получить доступ к внутренним метрикам через endpoint Prometheus
  2. Настройте ваш prometheus.yaml для сбора данных с endpoint /metrics, например, http://localhost:8899/metrics
  3. Настройте путь к метрикам с помощью флага --metrics-path
  4. Обратите внимание, что --enable-metrics внутренне также включает --enable-events и плагин веб-сервера

Часто задаваемые вопросы

Развертывание proxy.py в production

Ниже перечислены несколько стратегий использования proxy.py в ваших частных/production/корпоративных проектах.

Чего не следует делать?

Вы ДОЛЖНЫ избегать форка репозитория «просто» для того, чтобы разместить код своего плагина в каталоге proxy/plugin. Форк — это рекомендуемый рабочий процесс для участников проекта, а НЕ для пользователей.

  • Вместо этого используйте один из предложенных ниже подходов.
  • Затем загружайте плагины с помощью флагов --plugin, --plugins или аргумента plugin.
  • См. приложение skeleton в качестве примера отдельного проекта, использующего proxy.py.

Через зависимости (Requirements)

Настоятельно рекомендуется использовать proxy.py через requirements.txt или аналогичные системы управления зависимостями. Это позволит вам воспользоваться преимуществами регулярных обновлений производительности, исправлений ошибок, патчей безопасности и других улучшений в экосистеме proxy.py. Пример:

  1. Используйте опцию --pre, чтобы зависеть от последнего pre-release

    root@kitploit:~
    ❯ pip install proxy.py --pre
    
  2. Используйте TestPyPi с опцией --pre, чтобы зависеть от кода ветки develop

    root@kitploit:~
    ❯ pip install -i https://test.pypi.org/simple/ proxy.py --pre
    

    Пререлиз публикуется на TestPyPi после каждого слияния PR.

  3. Используйте код последнего stable релиза

    Как обычно, просто используйте:

    root@kitploit:~
    ❯ pip install proxy.py
    

Через Docker-контейнер

Если вы занимаетесь развертыванием контейнеров, просто соберите свой образ из базовых образов контейнера proxy.py.

  1. Используйте GHCR для сборки из кода ветки develop:

    root@kitploit:~
    FROM ghcr.io/abhinavsingh/proxy.py:latest as base
    

    Примечание: я использую GHCR latest в нескольких production-проектах

  2. Используйте DockerHub для сборки из кода последнего stable релиза:

    root@kitploit:~
    FROM abhinavsingh/proxy.py:latest as base
    

Примечание: IMHO, стратегия на основе контейнеров — лучший подход и единственная стратегия, которую я использую сам.

Интегрируйте свой CI/CD с proxy.py

Эй, но вы продолжаете вносить критические изменения в ветку develop.

Я вас слышу. И поэтому для ваших приложений production-уровня вы ДОЛЖНЫ интегрировать CI/CD приложения с proxy.py. Вы должны убедиться, что ваше приложение собирается и проходит свои тесты для каждого слияния PR в вышестоящий репозиторий proxy.py.

Если ваш репозиторий приложения публичный, в определенных сценариях авторы PR могут отправлять PR с исправлениями для всех зависимых проектов, чтобы сохранить обратную совместимость и зеленый CI/CD.

Интеграция CI/CD гарантирует, что ваше приложение продолжает собираться с последним кодом proxy.py. В зависимости от того, где размещен ваш код, используйте стратегию, перечисленную ниже:

  • GitHub

    TBD

  • Google Cloud Build

    TBD

  • AWS

    TBD

  • Azure

    TBD

  • Другие

    TBD

На каком-то этапе мы откажемся от разделения ветки master и будем поддерживать только ветку develop. Поскольку зависимые проекты могут поддерживать стабильность через интеграции CI/CD. Сейчас сложно production-проекту слепо полагаться на ветку develop.

Стабильная и разрабатываемая версии

  • Ветка master содержит последний stable код и доступна через репозиторий PyPi и Docker-контейнеры через реестры docker.io и ghcr.io.

    Проблемы, сообщенные для stable релизов, рассматриваются с наивысшим приоритетом. Однако в настоящее время мы не переносим исправления в старые релизы. Например, если вы сообщили о проблеме в v2.3.1, но текущая ветка master теперь содержит v2.4.0rc1. Тогда исправление попадет в v2.4.0rc2.

  • Ветка develop содержит передовые изменения

    Ветка разработки поддерживается стабильной (в большинстве случаев). Но, если вам нужна 100% надежность и обслуживание пользователей в production-среде, ВСЕГДА используйте стабильную версию.

График релизов

Один раз в месяц создается pull request vX.Y.ZrcN, который сливает develop → master. Ниже показано, как код переходит от pull request к следующему стабильному релизу.

  1. Релиз разработки развертывается из develop → test.pypi.org после каждого слияния pull request

  2. Альфа-релиз развертывается из develop → pypi.org до слияния pull request vX.Y.Z.rcN из ветки develop → master. До слияния rc pull request может быть выпущено несколько альфа-релизов.

  3. Бета-релиз развертывается из master → pypi.org. Бета-релизы выпускаются в рамках подготовки к rc релизам и могут быть пропущены, если в них нет необходимости.

  4. Кандидат на релиз (release candidate) развертывается из master → pypi.org. Кандидаты на релиз всегда публикуются перед финальным стабильным релизом.

Потоки (Threads) vs Без потоков (Threadless)

v1.x

proxy.py раньше создавал новые потоки для обработки клиентских запросов.

v2.0+

proxy.py добавил поддержку выполнения клиентских запросов без потоков (threadless) с использованием asyncio.

v2.4.0+

Выполнение без потоков было включено по умолчанию для Python 3.8+ на mac и linux.

По сообщениям пользователей, выполнение proxy.py без потоков безопасно в этих средах. Если вы столкнулись с проблемами, вернитесь к многопоточному режиму с помощью флага --threaded.

Для windows и Python < 3.8 вы все еще можете попробовать режим без потоков, запустив proxy.py с флагом --threadless.

Если режим без потоков работает для вас, рассмотрите возможность отправки PR, отредактировав метод _env_threadless_compliant в файле proxy/common/constants.py.

Режим выполнения без потоков: удаленный (Remote) vs локальный (Local)

Оригинальная реализация без потоков использовала remote режим выполнения. Это также показано в Высокоуровневая архитектура в виде ASCII-арта.

В remote режиме выполнения акцепторы делегируют обработку входящих клиентских соединений удаленному рабочему процессу. По умолчанию акцепторы распределяют соединения по круговому принципу (round-robin). Рабочий процесс, обрабатывающий запрос, может работать на том же ядре CPU, что и акцептор, а может и нет. Такая архитектура хорошо масштабируется для высокой пропускной способности, но приводит к запуску двух процессов на каждое ядро CPU.

Например, если на машине N-CPU, по умолчанию запускается N акцепторов и N рабочих процессов. Вы можете настроить количество процессов с помощью флагов --num-acceptors и --num-workers. В зависимости от вашего сценария использования вам может понадобиться больше рабочих процессов, чем акцепторов, или наоборот.

В v2.4.x был добавлен local режим выполнения, в основном для уменьшения количества процессов, запускаемых по умолчанию. Эта модель хорошо подходит для повседневных сценариев использования одним пользователем и для тестирования разработчиками. В local режиме выполнения акцепторы делегируют клиентские соединения сопутствующему потоку, а не удаленному процессу. local режим обеспечивает привязку к CPU (CPU affinity), в отличие от remote режима, где акцептор и рабочий процесс могут работать на разных ядрах CPU.

--local-executor 1 был установлен по умолчанию в серии v2.4.x. В local режиме выполнения флаг --num-workers не действует, так как удаленные рабочие процессы не запускаются.

Чтобы использовать remote режим выполнения, используйте флаг --local-executor 0. Затем используйте --num-workers для настройки количества рабочих процессов.

SyntaxError: invalid syntax

proxy.py строго типизирован и использует аннотации типов Python typing. Пример:```python

my_strings : List[str] = [] #############^^^^^^^^^#####

root@kitploit:~
Следовательно, требуется версия Python, поддерживающая аннотации типов.
Убедитесь, что вы используете `Python 3.6+`.

Проверьте версию перед запуском `proxy.py`:

`❯ python --version`

Все аннотации `typing` могут быть заменены аннотациями `comment-only`. Пример:```python
>>> my_strings = [] # List[str]
>>> ################^^^^^^^^^^^

Это позволит proxy.py работать на Python pre-3.6, даже на 2.7. Однако, поскольку все будущие версии Python будут поддерживать аннотации typing, это не было учтено.

Невозможно загрузить плагины

Убедитесь, что модули плагинов доступны для поиска, добавив их в PYTHONPATH. Пример:

`PYTHONPATH=/path/to/my/app proxy --plugins my_app.proxyPlugin````console ...[redacted]... - Loaded plugin proxy.HttpProxyPlugin ...[redacted]... - Loaded plugin my_app.proxyPlugin

root@kitploit:~
ИЛИ, просто передайте полностью квалифицированный путь в качестве параметра, например

`proxy --plugins /path/to/my/app/my_app.proxyPlugin`

Вот краткий рабочий пример:

- Содержимое папки `/tmp/plug````console
╰─ ls -1 /tmp/plug                                                                                                                       ─╯
my_plugin.py
  • Пользовательский MyPlugin класс```console ╰─ cat /tmp/plug/my_plugin.py ─╯ from proxy.http.proxy import HttpProxyBasePlugin

class MyPlugin(HttpProxyBasePlugin): pass

root@kitploit:~
Это пустой плагин для демонстрации использования внешних плагинов. Вы должны реализовать необходимые методы, чтобы ваши плагины работали с реальным трафиком.

- Запустите `proxy.py` с `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

Unable to connect with proxy.py from remote host

Make sure proxy.py is listening on correct network interface. Try following flags:

  • For IPv6 --hostname ::
  • For IPv4 --hostname 0.0.0.0

Basic auth not working with a browser

Most likely it's a browser integration issue with system keychain.

  • First verify that basic auth is working using curl

    curl -v -x username:password@localhost:8899 https://httpbin.org/get

  • See this thread for further details.

Docker image not working on macOS

It's a compatibility issue with vpnkit.

See moby/vpnkit exhausts docker resources and Connection refused: The proxy could not connect for some background.

GCE log viewer integration for proxy.py

A starter fluentd.conf template is available.

  1. Copy this configuration file as proxy.py.conf under /etc/google-fluentd/config.d/

  2. Update path field to log file path as used with --log-file flag. By default /tmp/proxy.log path is tailed.

  3. Reload google-fluentd:

    sudo service google-fluentd restart

Now proxy.py logs can be browsed using GCE log viewer.

ValueError: filedescriptor out of range in select

proxy.py is made to handle thousands of connections per second without any socket leaks.

  1. Make use of --open-file-limit flag to customize ulimit -n.
  2. Make sure to adjust --backlog flag for higher concurrency.

If nothing helps, open an issue with requests per second sent and output of following debug script:```console ❯ ./helper/monitor_open_files.sh

root@kitploit:~
## None:None в логах доступа

Иногда вы можете увидеть `None:None` в логах доступа. Это просто означает,
что соединение с вышестоящим сервером никогда не устанавливалось, т.е.
`upstream_host=None`, `upstream_port=None`.

Может быть несколько причин отсутствия соединения с вышестоящим сервером,
несколько очевидных включают:

1. Клиент установил соединение, но так и не завершил запрос.
2. Плагин вернул ответ преждевременно, избегая соединения с вышестоящим сервером.

## OSError при обёртывании клиента для TLS Interception

При включённом `TLS Interception` вы иногда можете увидеть следующие исключения:```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

Некоторые клиенты могут вызывать TLSV1_ALERT_UNKNOWN_CA, если они не могут проверить сертификат сервера, поскольку он подписан неизвестным удостоверяющим центром. Это происходит, когда мы осуществляем перехват TLS. Причины могут быть разными, например, пиннинг сертификатов и т. д.

Другое исключение, которое вы можете увидеть, — это 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

root@kitploit:~
В будущем мы, возможно, добавим поддержку отправки исходного HTTPS-контента таким клиентам, продолжая при этом выполнять перехват TLS в фоновом режиме. Это позволит сохранить нормальную работу клиентов, не влияя на нашу способность перехватывать TLS. К сожалению, эта возможность в настоящее время недоступна.

Ещё один пример с исключением `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

Руководство для разработчиков плагинов и участников

Архитектура высокого уровня```console

root@kitploit:~
                    +-------------+
                    |             |
                    |  Proxy([])  |
                    |             |
                    +------+------+
                           |
                           |
               +-----------v--------------+
               |                          |
               |    AcceptorPool(...)     |
               |                          |
               +------------+-------------+
                            |

+-----------------+ | +-----------------+ | | | | | | Acceptor(..) <-------------+-----------> Acceptor(..) | | | | | +---+-------------+ +---------+-------+ | | | | | +------++------++------++------++------+ | | | || || || || | | +----> || || || || <-----+ | || || || || | +------++------++------++------++------+ Threadless Worker Processes

root@kitploit:~
`proxy.py` создана с прицелом на производительность. По умолчанию `proxy.py` будет стараться использовать все доступные ядра ЦП для приёма новых клиентских подключений. Это достигается запуском `AcceptorPool`, который прослушивает настроенный порт сервера. Затем `AcceptorPool` запускает процессы `Acceptor` (`--num-acceptors`) для приёма входящих клиентских подключений. Наряду с этим, если включён `--threadless`, запускается `ThreadlessPool`, который запускает процессы `Threadless` (`--num-workers`) для обработки входящих клиентских подключений.

Каждый процесс `Acceptor` делегирует принятое клиентское подключение процессу threadless через класс `Work`. В настоящее время классом работы по умолчанию является `HttpProtocolHandler`.

`HttpProtocolHandler` просто предполагает, что входящие клиенты будут следовать спецификации HTTP. Конкретные реализации HTTP-прокси и HTTP-сервера написаны как плагины для `HttpProtocolHandler`.

См. документацию `HttpProtocolHandlerPlugin` для доступных хуков жизненного цикла. Используйте `HttpProtocolHandlerPlugin` для добавления новых функций для http(s)-клиентов. Пример: см. `HttpWebServerPlugin`.

## Всё является плагином

Внутри `proxy.py` всё является плагином.

- Мы включаем плагины `proxy server` с помощью флага `--plugins`.
  Прокси-сервер `HttpProxyPlugin` является плагином `HttpProtocolHandler`.
  Кроме того, прокси-сервер позволяет подключать плагины через спецификацию `HttpProxyBasePlugin`.

- Все [примеры плагинов](#примеры-плагинов) прокси-сервера реализуют
  `HttpProxyBasePlugin`. См. документацию `HttpProxyBasePlugin` для доступных хуков жизненного цикла. Используйте `HttpProxyBasePlugin`, чтобы изменить поведение протокола http(s)-прокси
  между клиентом и вышестоящим сервером. Пример:
  [FilterByUpstreamHostPlugin](#filterbyupstreamhostplugin).

- Также мы включаем встроенный `web server` с помощью `--enable-web-server`.
  Веб-сервер `HttpWebServerPlugin` является плагином `HttpProtocolHandler`
  и реализует спецификацию `HttpProtocolHandlerPlugin`.

- Также существует флаг `--disable-http-proxy`. Он отключает встроенный прокси-сервер.
  Используйте этот флаг вместе с флагом `--enable-web-server`, чтобы запустить `proxy.py` как программируемый http(s)-сервер.

## Управление состояниями для ваших stateless-плагинов

Экземпляры классов плагинов создаются для каждого запроса. Самое важное: экземпляры плагинов создаются в контексте ядра ЦП, где был получен запрос.

По указанной причине глобальные переменные в ваших плагинах могут работать не так, как ожидается. Ваш код плагина по замыслу должен быть **stateless** (не иметь состояния).

Для управления глобальными состояниями у вас есть несколько вариантов:
1) Использовать [структуры данных, безопасные для многопроцессорной обработки](https://python.readthedocs.io/en/latest/library/multiprocessing.html#sharing-state-between-processes) из Python.
2) Использовать встроенный в `proxy.py` [механизм событий](https://github.com/abhinavsingh/proxy.py/blob/develop/tutorial/eventing.ipynb).

## Передача контекста обработки между плагинами

Иногда плагину может потребоваться передать дополнительный контекст другим плагинам, следующим за ним в цепочке обработки. Например, этот дополнительный контекст можно также выгружать в журналы доступа.

Для передачи контекста обработки используйте метод `on_access_log` плагина. См., как плагин [Program Name](https://github.com/abhinavsingh/proxy.py/blob/develop/proxy/plugin/program_name.py) изменяет ключ `client_ip` по умолчанию в контексте и обновляет его до определённого имени программы.

В результате, когда мы включаем [Program Name Plugin](#programnameplugin), в журналах доступа мы видим имя локальной клиентской программы вместо IP-адреса.

## Руководство по разработке

### Настройка локального окружения

Участники должны запускать `proxy.py` из исходного кода, чтобы проверить и разрабатывать новые функции / исправления.

См. раздел [Запуск proxy.py из командной строки с использованием исходного кода репозитория](#из-командной-строки-с-использованием-исходного-кода-репозитория) для подробностей.

[![WARNING](https://img.shields.io/static/v1?label=MacOS&message=warning&color=red)](https://github.com/abhinavsingh/proxy.py/issues/642) На `macOS` необходимо устанавливать `Python` с помощью `pyenv`, так как `Python`, установленный через `homebrew`, часто бывает проблематичным. Подробнее см. по ссылке в обсуждении.

### Настройка Git-хуков

Pre-commit hook гарантирует, что тесты проходят.

1. `cd /path/to/proxy.py`
2. `ln -s $(PWD)/git-pre-commit .git/hooks/pre-commit`

Pre-push hook гарантирует, что линтинг и тесты проходят.

1. `cd /path/to/proxy.py`
2. `ln -s $(PWD)/git-pre-push .git/hooks/pre-push`

### Отправка Pull Request

Каждый pull request тестируется с помощью GitHub Actions.

См. [GitHub workflow](https://github.com/abhinavsingh/proxy.py/tree/develop/.github/workflows) для списка тестов.

# Проекты, использующие Proxy.Py

Некоторые популярные проекты, использующие `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)

Полный список см. на [используется](https://github.com/abhinavsingh/proxy.py/network/dependents?package_id=UGFja2FnZS01MjQ0MDY5Ng%3D%3D)

# Бенчмарки

См. директорию [Benchmark](https://github.com/abhinavsingh/proxy.py/tree/develop/benchmark) для сведений о том, как запускать сравнительные бенчмарки с другими веб-серверами с открытым исходным кодом.

Чтобы запустить отдельный бенчмарк для `proxy.py`, используйте следующую команду из корня репозитория:```console
❯ ./benchmark/compare.sh

Флаги```console

❯ 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 ...]

root@kitploit:~

---

[Read more](https://github.com/abhinavsingh/proxy.py)
Скачать инструмент
  • Плагин DNS-резолвера Cloudflare
  • Плагин пользовательского DNS-резолвера
  • Пользовательский сетевой интерфейс
  • Плагин имени программы
  • Плагины HTTP-веб-сервера
    • Маршрут веб-сервера
  • Плагины обратного прокси
    • Обратный прокси
  • Порядок плагинов
  • Сквозное шифрование
  • Перехват TLS
    • Небезопасный перехват TLS
    • Перехват TLS с Docker
  • GROUT (Альтернатива NGROK)
    • Использование Grout
    • Аутентификация Grout
    • Пути Grout
    • Grout с подстановочными доменами
    • Маршрутизация на основе заголовка "Host"
    • "Динамическая" маршрутизация
    • Grout с использованием Docker
    • Как работает Grout
    • Самостоятельно размещённый Grout
  • Прокси через SSH-туннель
    • Прокси удалённых запросов локально
    • Прокси локальных запросов удалённо
  • Встраивание proxy.py
    • Блокирующий режим
    • Неблокирующий режим
    • Эфемерный порт
    • Загрузка плагинов
  • Модульное тестирование с proxy.py
    • proxy.TestCase
    • Переопределение флагов запуска
    • С unittest.TestCase
  • Утилиты
    • TCP
      • new_socket_connection
      • socket_connection
    • Http
      • build_http_request
      • build_http_response
    • Инфраструктура открытых ключей
      • API-использование
      • CLI-использование
  • Запуск панели управления
    • Инспекция трафика
  • Chrome DevTools Protocol
  • Метрики Prometheus
  • Часто задаваемые вопросы
    • Развёртывание proxy.py в production
      • Чего не следует делать?
      • Через Requirements
      • Через Docker-контейнер
      • Интеграция CI/CD с proxy.py
    • Stable vs Develop
      • График релизов
    • Threads vs Threadless
    • Threadless: удалённый и локальный режимы выполнения
    • SyntaxError: invalid syntax
    • Невозможно загрузить плагины
    • Невозможно подключиться к proxy.py с удалённого хоста
    • Базовая аутентификация не работает в браузере
    • Docker-образ не работает на MacOS
    • ValueError: filedescriptor out of range in select
    • None:None в логах доступа
    • OSError при оборачивании клиента для перехвата TLS
  • Руководство для разработчиков плагинов и контрибьюторов
    • Высокоуровневая архитектура
    • Всё является плагином
    • Управление состоянием для ваших плагинов без состояния
    • Передача контекста обработки между плагинами
    • Внутренняя документация
      • Read The Doc
      • pydoc
      • pyreverse
    • Руководство по разработке
      • Настройка локального окружения
      • Настройка Git-хуков
      • Отправка Pull Request
  • Проекты, использующие Proxy.Py
  • Бенчмарки
  • Флаги
  • Журнал изменений
    • v2.x
    • v1.x
    • v0.x
  • Смотрите Threads vs Threadless и Threadless Remote vs Local Execution Mode, чтобы управлять количеством используемых ядер CPU.

    Смотрите Benchmark для получения дополнительной информации и инструкций по запуску бенчмарков локально.

  • Легковесный

    • Использует всего ~5-20 MB RAM
      • Нет утечек памяти
      • Запустите один раз и забудьте, перезагрузки не требуются
    • Размер сжатых контейнеров составляет всего ~25 MB
    • Нет внешних зависимостей, кроме стандартной библиотеки Python
  • Программируемый

    • Настраивайте поведение прокси с помощью плагинов прокси-сервера. Пример:
      • --plugins proxy.plugin.ProxyPoolPlugin
    • Включите встроенный веб-сервер. Пример:
      • --enable-web-server --plugins proxy.plugin.WebServerPlugin
    • Включите встроенный обратный прокси-сервер. Пример:
      • --enable-reverse-proxy --plugins proxy.plugin.ReverseProxyPlugin
    • API плагинов в настоящее время находится в стадии разработки. Ожидайте критические изменения. Смотрите Deploying proxy.py in production о том, как обеспечить надёжность при изменениях кода.
  • Может слушать несколько адресов и портов

    • Используйте флаг --hostnames для указания дополнительных адресов
    • Используйте флаг --ports для указания дополнительных портов
    • Опционально используйте флаг --port для переопределения порта по умолчанию 8899
    • Способен обслуживать несколько протоколов на одном порту
  • Панель управления в реальном времени

    • Опционально включите панель управления proxy.py.
      • Используйте --enable-dashboard
      • Затем перейдите по адресу http://localhost:8899/dashboard
    • Инспектируйте, мониторьте, управляйте и настраивайте proxy.py во время выполнения
    • Поддержка Chrome DevTools Protocol
    • Расширяйте фронтенд панели управления с помощью плагинов на typescript
    • Панель управления в настоящее время находится в стадии разработки. Ожидайте критические изменения.
  • Безопасный

    • Включите сквозное шифрование между клиентами и proxy.py
    • Смотрите End-to-End Encryption
  • Приватный

    • Защита от DNS-блокировщиков трафика
    • Серфинг с защитой от вредоносного и взрослого контента
    • Смотрите DNS-over-HTTPS
  • Человек посередине

    • Может расшифровывать TLS-трафик между клиентами и вышестоящими серверами
    • Смотрите TLS Interception
  • Поддерживаемые http протоколы для прокси-запросов

    • http(s)
      • http1
      • http1.1 с пайплайном
    • http2
    • websockets
  • Поддержка HAProxy Protocol

    • Смотрите флаг --enable-proxy-protocol
  • Поддержка статического файлового сервера

    • Смотрите флаги --enable-static-server и --static-server-dir
  • Оптимизирован для загрузки и скачивания больших файлов

    • Смотрите флаги --client-recvbuf-size, --server-recvbuf-size, --max-sendbuf-size
  • Поддержка IPv4 и IPv6

    • Смотрите флаг --hostname
  • Поддержка Unix domain socket

    • Смотрите флаг --unix-socket-path
  • Поддержка базовой аутентификации

    • Смотрите флаг --basic-auth
  • Поддержка PAC (Proxy Auto-configuration)

    • Смотрите флаги --pac-file и --pac-file-url-path
  • См. High Level Architecture чтобы понять взаимосвязь между акцепторами и рабочими процессами
  • Started server on ::1:8899

    • По умолчанию proxy.py прослушивает IPv6 ::1, что эквивалентно IPv4 127.0.0.1
    • Если вы хотите получить доступ к proxy.py с внешнего хоста, используйте --hostname :: или --hostname 0.0.0.0 или привяжитесь к любому другому интерфейсу, доступному на вашей машине.
    • См. CustomNetworkInterface о том, как настроить proxy.py публичный IP, видимый вышестоящими серверами.
  • Port 8899

    • Используйте флаг --port для настройки порта TCP по умолчанию.
  • Стабильный релиз развертывается из master → pypi.org