Устав искать нормальный портативный инструмент для переключения между моим рабочим прокси-сервером и прямым подключением дома (который, к тому же, работал бы на Windows и Linux), я решил-таки запилить собственную тулзу для этих целей. Вооружившись Python и Qt, начал клепать код в VSCode... Что из этого вышло -- читаем под катом.


Мотивация

Основной мотивацией для создания данного инструмента стало жуткое неудобство системных настроек прокси при работе из офиса и дома. Каждый раз приходилось лезть в настройки прокси, передвигать флажок... А, кроме того, еще удалять или скрывать системные переменные HTTP_PROXY (и им подобные), чтобы консольные приложения вроде git также слушались руля... Это на Винде. А на Линуксе так вообще веселая история: не все графические системы имеют встроенные утилиты для управления настройками прокси, и моя Kali Linux как раз такая. Приходится вручную комментировать / раскомментировать экспорты переменных среды (той же HTTP_PROXY) и перелогиниваться... Морока, одним словом.

Беглый (а затем и не очень беглый) поиск в гугле / яндексе результатов не дал: предлагаются в основном плагины для браузеров, переключающие прокси только для браузера (системные настройки не изменяются). Нормальной легковесной, портативной, бесплатной, кроссплатформенной тулзы с графическим интерфейсом мне найти так и не удалось. И тогда, кряхтя и сопя от борьбы с ленью, открыл я VSCode и создал новый проект на Python...

Требования к инструменту

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

  • включение / выключение прокси-сервера одной кнопкой (с соответствующими автоматическими изменениями переменных среды)

  • настройки прокси должны быть постоянными, т.е. записываться в соответствующие системные файлы и оставаться после перезагрузки

  • возможность раздельных настроек для HTTP, HTTPS, FTP и (что бывает нужно для Unix) - RSYNC

  • импорт / экспорт настроек в / из файла

  • возможность подробного лога для отладки

Сразу скажу, что особой эстетичнойти GUI в минимальных требованиях не числилось. Главное -- простота и интуитивность. Это так, чтобы вы меня не слишком терроризировали за дизайнерские способности :)

Где хранятся системные настройки прокси

Windows

На машинах под Windows настройки прокси хранятся (как и большинство других системных настроек) в реестре. А именно, в ветке HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings (таким образом, эти настройки задаются пользователем и не являются общесистемными).

Настройки прокси в реестре Windows. Зеленым выделены основные переменные.
Настройки прокси в реестре Windows. Зеленым выделены основные переменные.

За настройки прокси отвечают две переменные в реестре:

  1. ProxyServer: адрес и порт прокси сервера, разделенные двоеточием (у моего прокси, например, адрес = 192.168.1.10, порт = 3128)

  2. ProxyOverride: разделенные запятыми адреса и маски адресов, которые должны работать по прямому соединению, минуя прокси (обычно сюда добавляется <local>, что означает localhost, т.е. не использовать прокси для локальных соединений)

Кроме того, многие приложения (в основном, консольные) берут настройки прокси не из реестра, а из специальных переменных среды:

  • HTTP_PROXY - прокси для HTTP-соединений в формате http://[[USER]:[PASSWORD]@]HOST:PORT (например, "http://user:pass@192.168.1.1:3000" или если без прокси-аутентификации: "http://192.168.1.1:3000")

  • HTTPS_PROXY - то же для HTTPS-соединений

  • FTP_PROXY - то же для FTP-соединений

  • RSYNC_PROXY - то же для RSYNC-соединений

  • NO_PROXY - адреса в обход прокси (аналог вышеуказанного ProxyOverride)

Переменные среды в Windows: определены переменные, относящиеся к настройкам прокси
Переменные среды в Windows: определены переменные, относящиеся к настройкам прокси

Linux и MacOS

В Unix'ах, как водится, все настройки хранятся в обычных файлах: пользовательские -- в директории текущего пользователя (~/...), системные -- в директории /etc.

Настройки прокси задаются такими же переменными среды для соответствующих соединений (HTTP_PROXY и т.д.) + NO_PROXY для прямых адресов + иногда может встречаться переменная ALL_PROXY, задающая настройки для всех типов соединений.

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

  • Пользователь: ~/.profile, ~/.bashrc, ~/.bash_profile, ~/.zshrc, ~/.cshrc, ~/.tcshrc, ~/.login

  • Система: /etc/environment, /etc/profile, /etc/bashrc, /etc/bash.bashrc, /etc/zsh/zshrc, /etc/csh.cshrc, /etc/csh.login

А еще, конечно, переменные могут определяться в скриптах, расположенных в специальных директориях: /etc/init.d, /etc/environment.d и т.п. Простор фантазии, в двух словах!

Структура приложения

Приложение размещено на Github.

Структура приложения (писалось на Python 3.10) получилась такая:

  • ????doc/ - документация (сделана при помощи Doxygen)

  • ????resources/ - иконки и картинки

  • ©LICENSE - лицензионный файл (MIT License, т.е. полностью open-source, свободно для изменений и использования в т.ч. в коммерческих целях)

  • README.md - краткое описание

  • ????proxen.py - главный файл для запуска приложения (создает объект QApplication и запускает главный цикл с основным окном)

  • ????gui.py - все GUI формы (виджеты Qt)

  • ????qtimports.py - импорт пакетов Qt с поддержкой различных фреймворков: PyQt5, PyQt6, PySide2 и PySide6 (импортируется тот, который установлен)

  • ????sysproxy.py - классы для работы с переменными среды и настройками прокси -- "сердце" инструмента

  • ????utils.py - глобальные переменные и полезные функции

  • config.ini - файл с настройками приложения (пока там только включение лога и вывод его в консоль)

  • ????config.py - соответствующий объект настроек (используется configparser)

  • ????requirements.txt - зависимости, которые можно установить при помощи pip.

Принцип работы приложения

Работу приложения проще объяснить на визуальной схеме.

Схема работы proxen
Схема работы proxen

???? Просмотр с возможностью зума????????????????.????????

Окно приложения реализовано Qt-виджетом MainWindow. Связь между GUI и настройками прокси осуществляется при помощи 4 уровней абстракции:

  1. Уровень ❹. Обычный питоновский словарь (dict) localproxy со следующими элементами:

    {
      'enabled': b_enabled,          # статус прокси (вкл/выкл)
      'http_proxy': {                # настройки прокси для HTTP
        'host': str_host,            # адрес сервера
        'port': n_port,              # порт сервера
        'auth': b_auth,              # требуется ли аутентификация
        'uname': str_username,       # имя пользователя на прокси-сервере
        'password': str_userpass     # пароль пользователя
      },  
      'https_proxy': {               # настройки прокси для HTTPS
        # см. http_proxy
      },
      'ftp_proxy': {                 # настройки прокси для FTP
        # см. http_proxy
      },
      'rsync_proxy': {               # настройки прокси для RSYNC
        # см. http_proxy
      },
      'noproxy': str_no_proxy        # адреса (маски) без прокси через ","
    }

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

  2. Уровень ❸. Объект Proxy (sysproxy), реализующий те же параметры в виде свойств (properties). Свойства прокси (http_proxy, https_proxy и т.д.) -- объекты типа Proxyconf (инкапсулирующие параметры хоста, порта и аутентификации); свойство noproxy -- объект типа Noproxy, который позволяет преобразовывать прямые адреса в список и в строку и обратно. Синхронизация со словарем localproxy осуществляется двумя методами: asdict() сериализует объект Proxy в словарь, from_dict() -- применяет данные из словаря. При изменении каждого свойства вызываются соответствующие setter-методы, которые и передают управление на нижестроящий уровень -- объект Sysenv.

  3. Уровень ❷. Класс Sysenv определяет основные методы для работы непосредственно с переменными среды и файлами, хранящими системные настройки. Для получения значения переменной среды (например, HTTP_PROXY) используется метод get_sys_env(). Для изменения переменной и записи ее в соответствующий файл -- метод set_sys_env(). Для удаления переменной (из памяти и соответствующих файлов) -- unset_sys_env(). Каждый из этих методов уже вызывает соответствующие низкоуровневые методы.

  4. Уровень ❶. На самом нижнем уровне используются специальные методы для работы с реестром Windows (чтение, запись, создание и удаление переменных в соответствующих ветках) и файлами Linux / Mac (чтение, изменение и удаление экспортов переменных среды). Как я уже говорил, на Винде за прокси отвечает пользовательская ветка в реестре (независимо от наличия прав администратора у текущего пользователя). На Unix'ах приложение по умолчанию работает с локальным файлом пользователя (зависящем от выбранного шелла, например, у меня это ~/.zshrc) и дополнительно, если есть права суперпользователя, также синхронизирует все переменные с системным файлом (по умолчанию -- /etc/environment).

Стоит отметить еще два момента:

  • приложение реализовано с использованием многопоточности: операции работы с настройками прокси выполняются в отдельных потоках, чтобы не "замораживать" GUI

  • переключатель Enable на первой вкладке сразу применяет настройки (без нажания Apply) -- это было так задумано в рамках идеи "one-click switch"

Ручное управление переменными среды

Пока я отлаживал утилиту, я незаметно для себя реализовал еще один виджет для просмотра и управления всех переменных среды. При помощи этого инструмента я создавал, удалял и изменял произвольные переменные, следя, как программа работает с системными файлами. Позже я решил добавить эту возможность в само приложение и разместил кнопку Env variables на странице Settings.

Нажав на Env variables, попадаем в редактор переменных среды.
Нажав на Env variables, попадаем в редактор переменных среды.

Интерфейс до предела минималистичен. Я даже не буду ничего описывать, просто дам скрин :)

Эта "утилита в утилите" может применяться вместно штатных инструментов ОС.

Справочная документация

Она есть :) По кнопке Help | Open docs открывается HTML-справка в браузере.

Справочная документация: титульная страница
Справочная документация: титульная страница

Весь код подробно прокомментирован, что позволяет пользоваться Doxygen для генерации документации для разработчиков:

На этом всё! Буду рад, если кому-то инструмент окажется полезным. Также можно направлять предложения в комментариях???? или через страницу репозитория.

Комментарии (23)


  1. Nengchak
    20.01.2022 05:19

    А есть ли какой-то способ в прокси сделать обратный белый список? То есть, чтобы только определенные домены пускать через прокси?


    1. S0mbre Автор
      20.01.2022 05:21

      Это настройки самого прокси сервера. Если вы его администруете, то, конечно, настраивайте любые правила -- тем же iptables.


    1. edo1h
      20.01.2022 07:47

      если я правильно понял вопрос, можно использовать js в браузере чтобы решать использовать прокси или нет, ключевое слово для гугла — proxy.pac
      тут вот есть экстремальный вариант (заблокированные сайты будут открываться через прокси, остальные напрямую):
      https://antizapret.prostovpn.org/


      1. Nengchak
        20.01.2022 09:31

        Да, что-то типа такого, чтобы только определенные сайты ходили через прокси, а остальные через провайдера. А еще бы решить проблему не просто проксирование, но и шифрование.


        1. edo1h
          20.01.2022 09:48

          не просто проксирование, но и шифрование.

          ЕМНИП скрипт по ссылке использует https для соединения с прокси, так что будет и шифрование


      1. S0mbre Автор
        21.01.2022 01:43

        В случае корпоративного "железного" прокси это не работает, т.к. весь трафик проксируется через файрвол, и простая функция типа

        function FindProxyForURL (url, host) {
          return 'PROXY proxy.example.com:8080; DIRECT';
        }

        не работает. Также на HTTP-сервере должен находиться PAC-файл для автонастройки прокси, а у пользователя нет админки для конфигурации сервера.

        И последнее: многие клиенты все равно смотрят переменные среды, поэтому от них никуда не деться.


        1. edo1h
          21.01.2022 05:23

          В случае корпоративного "железного" прокси это не работает

          поясните, пожалуйста, что вы имели в виду.


          И последнее: многие клиенты все равно смотрят переменные среды, поэтому от них никуда не деться.

          я предположил, что человек спрашивал про решение для браузера, выше он уже подтвердил, что я угадал


  1. edo1h
    20.01.2022 06:59

    я правильно понимаю, что подразумевается перезапуск всех «заинтересованных» приложений после изменения настроек?
    КМК правильнее было использовать динамически-конфигурируемый tcp-proxy (по вкусу написать свой или взять готовый вроде nginx или haproxy), который бы принимал соединения по постоянному адресу (или адресам), и перенаправлял их на актуальный в данный момент прокси-сервер.


    1. zlo1
      20.01.2022 07:31

      3proxy может на лету подхватывать новую конфигурацию и перенаправлять на все типы прокси (включая авторизацию) - кроссплатформенный


      1. S0mbre Автор
        21.01.2022 01:48

        Ответил выше. Собственный дополнительный прокси-сервер в юзерспейсе не спасает, особенно для приложений, смотрящих на переменные среды.


  1. SnakeSolid
    20.01.2022 07:39
    +1

    В рамках предложения — можно было сделать свой локальный прокси, который прописывается в системных настройках. Галочка бы меняла не записи в реестре и переменные окружения, а настройки локального прокси. Таким образом код будет универсальным для любой системы и вы сможете изменять поведение всех приложений одной кнопкой (насколько я понимаю, при изменении переменных окружения все же нужен перезапуск).


  1. WondeRu
    20.01.2022 07:42

    Вы не пробовали собирать в бинарники? QT сама ставится через requirements или только обвязка?


    1. S0mbre Автор
      21.01.2022 01:51

      Всё ставится через requirements, ничего дополнительно устанавливать не надо. В requirements можно изменить PySide6 на сборку по своему вкусу: PySide6 / PySide2 / PyQt6 / PyQt5.

      Что касается бинарников, это можно сделать при помощи, например, pyInstaller. Но зачем, если есть Python? :)


  1. ne555
    20.01.2022 08:42
    -1

    который, к тому же, работал бы на Windows и Linux

    А разве ваш проект-переключатель работает на Windows 7? Думаю, что нет. Можно было бы это в readme, например, указать.


    1. S0mbre Автор
      21.01.2022 01:53

      Если честно, не проверял, но теоретически ограничений быть не должно. В "семерке" используются те же записи в реестре. Можете попробовать и отписаться (через тот же гитхаб).


      1. ne555
        21.01.2022 07:21
        -1

        У вас в статье написано, что проект писался на python10. А в ридми:

        proxen runs on Python 3.9+, so please make sure you have one.

        Последняя, поддерживаема версия python под windows 7 это - python 3.8. Отсюда был сделан и вывод.


        1. S0mbre Автор
          22.01.2022 15:13

          Что же, возможно. Надо просто проверить, не исключено, что запустится и на 3.8 питоне и даже 3.5. Также не уверен, что 3.9+ нельзя поставить на семёрку: есть ведь портативные сборки, например WinPython.


  1. Vest
    20.01.2022 10:54
    -1

    Мне больше нравятся плагины в браузере такие как Proxy SwitchyOmega. Они позволяют задать каждому домену свой прокси (в том числе и локальный, например, для Fiddler'а).


  1. HSerg
    20.01.2022 21:49

    Гораздо проще использовать какой-нибудь локальный proxy (например, HandyCache) и включать/выключать использование внешнего proxy уже в нём (из меню, из настроек, горячей клавишей и т.п.). Заодно и возможность использования различных proxy для различных сайтов будет.


    1. S0mbre Автор
      21.01.2022 01:53

      См. коммент выше.


      1. HSerg
        21.01.2022 02:24

        Не вижу причин, по которым может не работать. Только если натянута локальная политика и запрещено изменение переменных окружения, реестра и исполнение неподписанных файлов.


        1. S0mbre Автор
          21.01.2022 02:53
          -1

          Локальные прокси типа HandyCache не меняют переменные среды, а создают дополнительный уровень проксирования. Конечно, такие программы удобны: позволяют задавать условия для тех же внешних прокси, горячие клавиши и т.д., но это не всегда оптимальный выбор по двум причинам:

          1. Уже указанные переменные среды. Те же git, wget, curl смотрят на определение HTTP_PROXY, HTTPS_PROXY.

          2. Локальный прокси работает только когда он запущен (т.е. соответствующий процесс создает сервер, работающий в фоне). Для меня лучше было бы включить / настроить и выйти, не нагружая систему.


          1. HSerg
            21.01.2022 03:14
            +1

            1. Устанавливаете во всех программах, конфигах (далеко не все cli утилиты работают с переменными окружения) и переменных окружения (кстати, часть linux-утилит работает с http_proxy, https_proxy именно в нижнем регистре) на локальную proxy (например, 127.0.0.1:3128) и никогда более не меняете. У меня обычно именно так и настроено.

            2. Да, это обратная сторона. Но я регулярно за запросами/ответами смотрю, так что real-time UI весьма полезен. Нагрузку выше 1% CPU не видел.