We detected you are likely not from a Russian-speaking region. Would you like to switch to the international version of the site?

  Назад к списку статей

Создание самописного сетевого прокси в Termux с использованием libproxy

Termux предоставляет полноценную Linux‑среду на Android‑устройствах, позволяя устанавливать компиляторы, библиотеки и запускать серверные приложения непосредственно на смартфоне. В этой статье мы рассмотрим, как создать простой сетевой прокси‑сервер с использованием библиотеки libproxy, которая автоматически определяет настройки прокси в системе и упрощает работу с сетью.

Подготовка окружения в Termux

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

pkg update && pkg upgrade -y
pkg install -y git clang make autoconf automake libtool pkg-config openssl-dev libxml2-dev

Эти пакеты обеспечат компилятор clang, систему сборки make и заголовочные файлы, требуемые для сборки libproxy.

Установка libproxy

Библиотека libproxy не входит в стандартные репозитории Termux, поэтому её необходимо собрать из исходных кодов.

# Склонировать репозиторий libproxy
git clone https://github.com/libproxy/libproxy.git
cd libproxy
# Подготовить сборочную среду
./autogen.sh
./configure --prefix=$HOME/.local
make -j$(nproc)
make install

После установки библиотека будет находиться в каталоге $HOME/.local. Добавьте путь к библиотекам в переменную окружения, чтобы система могла их находить:

export PKG_CONFIG_PATH=$HOME/.local/lib/pkgconfig:$PKG_CONFIG_PATH
export LD_LIBRARY_PATH=$HOME/.local/lib:$LD_LIBRARY_PATH

Создание простого HTTP‑прокси

Ниже представлен минимальный пример прокси‑сервера на C, использующего API libproxy для получения системных настроек прокси. Прокси прослушивает локальный порт 8080 и перенаправляет HTTP‑запросы согласно найденным правилам.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <proxy.h>   // libproxy header
#define LISTEN_PORT 8080
#define BUFFER_SIZE 4096
/ Функция получения URL‑прокси из libproxy /
static char get_proxy_for_url(const char url)
{
    pxProxyFactory factory = px_proxy_factory_new();
    if (!factory) return NULL;
    char **proxies = px_proxy_factory_get_proxies(factory, url);
    px_proxy_factory_free(factory);
    if (!proxies || !proxies[0]) return NULL;
    char result = strdup(proxies[0]);
    px_proxy_factory_free_proxies(proxies);
    return result;
}
int main(void)
{
    int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_fd < 0) { perror("socket"); return 1; }
    struct sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(LISTEN_PORT);
    if (bind(listen_fd, (struct sockaddr )&addr, sizeof(addr)) < 0) {
        perror("bind"); close(listen_fd); return 1;
    }
    if (listen(listen_fd, 10) < 0) { perror("listen"); close(listen_fd); return 1; }
    printf("[+] Прокси запущен на порту %d
", LISTEN_PORT);
    while (1) {
        int client_fd = accept(listen_fd, NULL, NULL);
        if (client_fd < 0) { perror("accept"); continue; }
        char buffer[BUFFER_SIZE];
        ssize_t len = recv(client_fd, buffer, BUFFER_SIZE - 1, 0);
        if (len <= 0) { close(client_fd); continue; }
        buffer[len] = '\0';
        / Извлекаем первую строку запроса, например: GET http://example.com/ HTTP/1.1 /
        char method[8], url[256];
        if (sscanf(buffer, "%7s %255s", method, url) != 2) {
            close(client_fd); continue;
        }
        char proxy = get_proxy_for_url(url);
        if (proxy) {
            printf("[i] Для %s найден прокси %s
", url, proxy);
            / Если прокси указан, просто передаём запрос клиенту без изменений –
               реальная реализация должна открыть соединение с прокси и ретранслировать /
            free(proxy);
        } else {
            printf("[i] Прокси для %s не найден, соединяемся напрямую
", url);
        }
        / Простейшее пробросное соединение к целевому хосту /
        char host[128];
        int port = 80;
        if (sscanf(url, "http://%127[^:/]:%d", host, &port) == 2) {
            / host и порт указаны явно /
        } else if (sscanf(url, "http://%127[^/]/", host) == 1) {
            / порт по умолчанию 80 /
        } else {
            close(client_fd); continue;
        }
        int remote_fd = socket(AF_INET, SOCK_STREAM, 0);
        if (remote_fd < 0) { perror("socket remote"); close(client_fd); continue; }
        struct sockaddr_in remote_addr = {0};
        remote_addr.sin_family = AF_INET;
        remote_addr.sin_port = htons(port);
        if (inet_pton(AF_INET, host, &remote_addr.sin_addr) <= 0) {
            / Попытка разрешить имя через DNS /
            struct hostent he = gethostbyname(host);
            if (!he) { perror("gethostbyname"); close(remote_fd); close(client_fd); continue; }
            memcpy(&remote_addr.sin_addr, he->h_addr, he->h_length);
        }
        if (connect(remote_fd, (struct sockaddr )&remote_addr, sizeof(remote_addr)) < 0) {
            perror("connect remote"); close(remote_fd); close(client_fd); continue;
        }
        / Перешлём исходный запрос /
        send(remote_fd, buffer, len, 0);
        / Перенаправим ответ клиенту /
        while ((len = recv(remote_fd, buffer, BUFFER_SIZE, 0)) > 0) {
            send(client_fd, buffer, len, 0);
        }
        close(remote_fd);
        close(client_fd);
    }
    close(listen_fd);
    return 0;
}

Код демонстрирует лишь базовый механизм: чтение HTTP‑запроса, получение системного прокси через libproxy и прямое соединение с целевым сервером. Для полноценного прокси‑серверного решения необходимо добавить поддержку HTTPS CONNECT, многопоточность (или асинхронный I/O) и обработку ошибок.

Сборка и запуск

Сохраните пример в файл simple_proxy.c и соберите его, указав путь к установленной библиотеке.

clang -o simple_proxy simple_proxy.c \
    -I$HOME/.local/include \
    -L$HOME/.local/lib -lproxy -lxml2 -lssl -lcrypto
# Запуск
./simple_proxy

После запуска в терминале появится сообщение [+] Прокси запущен на порту 8080. Настройте в браузере Android или в приложении curl прокси‑настройку:

curl -x http://127.0.0.1:8080 http://example.com

Отладка и улучшения

Для упрощения отладки рекомендуется использовать:

  • strace – просмотр системных вызовов.
  • tcpdump (через termux-tools) – анализ сетевого трафика.
  • Логирование в файл вместо printf для длительной работы.

Возможные улучшения:

  • Поддержка HTTPS CONNECT и TLS‑терминации.
  • Асинхронная обработка соединений с помощью libuv или epoll.
  • Кеширование DNS‑результатов и поддержка HTTP/2.

Заключение

Создание собственного сетевого прокси в Termux с использованием libproxy позволяет быстро реализовать адаптивные решения, учитывающие системные настройки прокси. Такой подход удобен для разработки мобильных тестовых стендов, отладки сетевых приложений и обучения принципам работы прокси‑серверов.

Если вам требуется профессиональная разработка, настройка инфраструктуры или консалтинг в сфере IT, обратитесь к специалистам RybinskLab. Мы предоставляем комплексные IT‑услуги в Рыбинске, помогая реализовать проекты любой сложности.

* Текст статьи подготовлен и структурирован с использованием технологий искусственного интеллекта. Проверен экспертом RybinskLab.

Поделиться знанием:

Нужна профессиональная помощь?

Меня зовут Усачёв Денис Евгеньевич. Я оказываю IT-услуги в Рыбинске и Ярославской области: настройка серверов, безопасность, автоматизация бизнеса.

Связаться со мной
Поддержать проект