Перейти к содержанию

Глава 30. Маршрутизация (Forwarding)

Действия маршрутизации определяют, куда направить запрос: напрямую к серверу, через upstream HTTP-прокси или через SOCKS-шлюз.

Аналоги BlueCoat: forward(), direct .

30.1. forward(gateway) — перенаправить на upstream

Направляет запрос через указанный upstream HTTP-прокси. Аргумент может быть:

  1. Literal адресhost:port или host (порт по умолчанию 8080)
  2. Имя группы — ссылка на Forwarding Group из конфигурации (балансировка, health check)
  3. Host alias — ссылка на Forwarding Host из конфигурации

Синтаксис:

forward(<gateway>)

where: gateway — один из: - Literal адрес: 192.168.1.100:3128, proxy.corp:8080 - Имя группы: primary-group (из Configuration → Forwarding → Groups) - Host alias: squid-primary (из Configuration → Forwarding → Hosts)

Порядок разрешения имён (registry resolution):

  1. Проверяется, есть ли группа с таким именем → выбор member по алгоритму балансировки
  2. Проверяется, есть ли хост с таким alias → возврат адреса если healthy
  3. Если не найдено → literal host:port (обратная совместимость)

Тип: Нетерминальное.

Слои и транзакции: Forward, Proxy. Применяется к HTTP/HTTPS-транзакциям.

Примеры:

; Способ 1: Literal адрес (без Forwarding конфигурации)
<Forward>
    url.host=httpbin.org forward(192.168.1.100:3128)
</Forward>

; Способ 2: Через Forwarding Group (балансировка + health check)
<Forward>
    url.host=*.corp.com forward(primary-group)
</Forward>

; Способ 3: Через Host alias
<Forward>
    url.host=api.service.com forward(squid-primary)
</Forward>

; Комбинация: internal → direct, остальное → через группу
<Forward>
    client.address=10.0.0.0/8 direct
    forward(primary-group) forward.fail_open(yes)
</Forward>

Протоколы: - HTTP: запрос отправляется на upstream прокси с absolute URI (GET http://target/path HTTP/1.1) - HTTPS (CONNECT): прокси отправляет CONNECT target:443 на upstream, получает tunnel, затем TLS handshake через tunnel

Поведение: запрос на путь с forward(127.0.0.1:1) (недоступный gateway) возвращает 502 (трафик действительно ушёл на gateway), а путь direct возвращает 200. Это подтверждает, что forward() действительно меняет маршрут, а не игнорируется.

См. также: direct, socks_gateway, forward.fail_open, Forwarding Groups


30.2. direct(yes|no) — прямое соединение

Управляет тем, направляется ли запрос напрямую к целевому серверу, минуя upstream-прокси/SOCKS: - direct(yes) — идти напрямую: слой <Forward> для транзакции НЕ оценивается (перекрывает forward()). - direct(no)значение по умолчанию — разрешает форвардинг (используется <Forward>-политика / gateway).

Голое direct принимается как сокращение для direct(yes).

Синтаксис:

direct(yes|no)
direct          ; = direct(yes)

Тип: Нетерминальное. direct(no) не форсит прямое соединение (эквивалент дефолта) — обработка продолжается.

Слои и транзакции: <Cache>, <Proxy>. Не применяется к FTP-over-HTTP / transparent FTP.

Пример:

<Proxy>
    url.host="myhost" direct(yes)          ; напрямую, минуя forward gateway
    url.host.is_private=yes direct          ; = direct(yes)

Результат: при direct(yes)/direct запрос идёт прямо к origin (forward-gateway игнорируется); при direct(no) — через настроенный gateway.

Соответствие BlueCoat 7.3: дословно — «direct(yes): <Forward> layer policy is not evaluated; default value is no, which allows request forwarding». Слои <Cache>/<Proxy>.

См. также: forward


30.3. socks_gateway(gateway, version) — SOCKS-шлюз

Направляет запрос через SOCKS-шлюз. Поддерживает SOCKS4 и SOCKS5.

Синтаксис:

socks_gateway(<gateway>[, <version>])

where: gateway — строка с адресом шлюза (host:port); version4 или 5 (по умолчанию 5).

Тип: Нетерминальное.

Слои и транзакции: SOCKS, Forward. Применяется к HTTP/HTTPS-транзакциям.

Пример:

<Forward>
    url.domain=*.onion socks_gateway(tor-proxy:9050, 5)
    socks_gateway(socks-gw.corp:1080)      ; SOCKS5 по умолчанию

См. также: socks.authenticate, forward


30.4. socks.authenticate / .allowed_versions / .allow_bind / .allow_udp — управление SOCKS

Важно: Все действия этой группы принимаются парсером, но не применяются — SOCKS-фронтенд, который бы их выполнял, пока не реализован. Правило загрузится, но эффекта не будет.

Группа действий для управления параметрами SOCKS-прокси.

30.4.1. socks.authenticate(yes/no)

Синтаксис:

socks.authenticate(yes|no)

where: yes — требовать SOCKS-аутентификацию; no — анонимный доступ.

30.4.2. socks.allowed_versions(4|5|both)

Синтаксис:

socks.allowed_versions(4|5|both)

where: 4 — только SOCKS4; 5 — только SOCKS5; both — обе версии.

30.4.3. socks.allow_bind(yes/no)

Синтаксис:

socks.allow_bind(yes|no)

where: yes — разрешить SOCKS BIND; no — запретить.

30.4.4. socks.allow_udp(yes/no)

Синтаксис:

socks.allow_udp(yes|no)

where: yes — разрешить UDP ASSOCIATE; no — запретить.

Тип: Все четыре — нетерминальные.

Слои и транзакции: SOCKS. Применяется к SOCKS-транзакциям.

Пример:

<SOCKS>
    socks.authenticate(yes)
    socks.allowed_versions(5)
    socks.allow_bind(no)
    socks.allow_udp(no)

30.5. reflect_ip(yes/no) — отражение IP клиента

Передаёт реальный IP-адрес клиента upstream-серверу через заголовок X-Forwarded-For или другой механизм.

Синтаксис:

reflect_ip(yes|no)

where: yes — отражать IP; no — не отражать.

Тип: Нетерминальное.

Слои и транзакции: Proxy, Forward.

Пример:

<Proxy>
    reflect_ip(yes)

30.6. forward.fail_open(yes/no) — поведение при отказе upstream

Определяет поведение при недоступности upstream-прокси, указанного в forward().

Синтаксис:

forward.fail_open(yes|no)

where: yes — при ошибке upstream направить запрос напрямую к origin (direct fallback); no — при ошибке вернуть 502 Bad Gateway клиенту.

Тип: Нетерминальное. Используется совместно с forward() на одной строке.

Слои и транзакции: Forward, Proxy. Применяется к HTTP/HTTPS-транзакциям.

Поведение:

Настройка Upstream доступен Upstream недоступен
fail_open(yes) Через upstream Fallback на direct (к origin)
fail_open(no) Через upstream Ошибка 502 клиенту
Не указано Через upstream По умолчанию fail_open(no)

Примечание: Если используется Forwarding Group, значение fail_action группы (fail-open / fail-closed) определяет поведение, когда все узлы группы недоступны. CPL-действие forward.fail_open() переопределяет настройку группы для конкретного правила.

Поведение: оба пути направляются на один недоступный gateway 127.0.0.1:1, различается только fail_open: fail_open(yes)200 (переход на прямое соединение, запрос дошёл до origin), fail_open(no)502 (отказ зафиксирован). Разница 200 против 502 показывает именно работу fail_open.

Пример:

<Forward>
    ; Через upstream, при ошибке — напрямую
    forward(upstream:3128) forward.fail_open(yes)

    ; Через группу, при ошибке — ошибка клиенту
    url.host=*.secure.com forward(secure-group) forward.fail_open(no)

30.7. Конфигурация Forwarding (Hosts, Groups, SOCKS Gateways)

Forwarding использует двухуровневую модель:

  1. Инфраструктура — определяет upstream прокси серверы, их группировку и мониторинг (Configuration → Forwarding в GUI, файл forwarding.toml)
  2. Политика — определяет правила маршрутизации трафика (CPL <Forward> layer, файл policy.cpl)

30.7.1. Forwarding Hosts

Forwarding Host — описание upstream прокси-сервера с параметрами подключения и health check.

Конфигурация (/etc/rproxy/forwarding.toml):

[[hosts]]
alias = "squid-primary"          # Уникальное имя (используется в groups и CPL)
address = "192.168.1.100"        # IP-адрес или hostname
http_port = 3128                 # Порт для HTTP forward (default: 8080)
https_port = 3129                # Порт для HTTPS CONNECT (default: 8443)
weight = 1                       # Вес для балансировки (default: 1)
enabled = true                   # Включён/выключен (default: true)

[hosts.health_check]
check_type = "tcp"               # tcp | http | none (default: tcp)
interval_secs = 30               # Интервал проверки (default: 30)
timeout_secs = 5                 # Таймаут пробы (default: 5)
unhealthy_threshold = 3          # Кол-во неудач для unhealthy (default: 3)
healthy_threshold = 2            # Кол-во успехов для healthy (default: 2)
# url = "/health"                # URL для HTTP-пробы (только check_type = "http")
# expected_status = 200          # Ожидаемый статус (только check_type = "http")

API:

Метод Путь Назначение
GET /api/v1/forwarding/hosts Список хостов (с health status)
POST /api/v1/forwarding/hosts Создать хост
GET /api/v1/forwarding/hosts/:alias Получить хост
PUT /api/v1/forwarding/hosts/:alias Обновить хост
DELETE /api/v1/forwarding/hosts/:alias Удалить хост
POST /api/v1/forwarding/reload Перезагрузить конфигурацию

Health Status:

Health monitor выполняет периодические TCP/HTTP пробы ко всем enabled хостам. Статус обновляется атомарно и доступен через API:

  • up — хост отвечает на пробы
  • down — хост не отвечает (threshold превышен)
  • unknown — проба ещё не выполнялась

GUI (Configuration → Forwarding → Hosts) отображает health status в реальном времени с auto-refresh каждые 10 секунд.

30.7.2. Forwarding Groups

Forwarding Group — логическая группа хостов с балансировкой нагрузки и failover.

Конфигурация (/etc/rproxy/forwarding.toml):

[[groups]]
name = "primary-group"                    # Уникальное имя (используется в CPL)
members = ["squid-primary", "squid-backup"]  # Ссылки на alias хостов
algorithm = "round-robin"                 # Алгоритм балансировки
fail_action = "fail-open"                 # Поведение при отказе всех members

Алгоритмы балансировки:

Алгоритм Описание Время выбора
round-robin Циклический перебор healthy members ~5ns
least-connections Выбор member с наименьшим числом активных соединений ~20ns
ip-hash Consistent hash по IP клиента (один клиент → один member) ~10ns
url-hash Consistent hash по URL запроса ~10ns
none Первый healthy member ~5ns

Fail Action:

Режим Когда все узлы недоступны
fail-open Переход на прямое соединение (к origin)
fail-closed Ошибка 502 клиенту

API:

Метод Путь Назначение
GET /api/v1/forwarding/groups Список групп
POST /api/v1/forwarding/groups Создать группу
PUT /api/v1/forwarding/groups/:name Обновить группу
DELETE /api/v1/forwarding/groups/:name Удалить группу

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

<Forward>
    ; Трафик к *.corp.com — через группу primary-group (round-robin)
    url.domain=*.corp.com forward(primary-group)

    ; Остальной трафик — напрямую
    direct
</Forward>

30.7.3. SOCKS Gateways

SOCKS Gateway — конфигурация SOCKS4/SOCKS5 прокси-сервера.

Конфигурация (/etc/rproxy/forwarding.toml):

[[socks_gateways]]
name = "tor-proxy"               # Уникальное имя
address = "10.0.0.1"             # IP-адрес или hostname
port = 9050                      # Порт (default: 1080)
version = 5                      # 4 или 5 (default: 5)
enabled = true                   # Включён/выключен
# username = "user"              # SOCKS5 аутентификация (опционально)
# password = "pass"              # SOCKS5 пароль (опционально)

API:

Метод Путь Назначение
GET /api/v1/forwarding/socks-gateways Список шлюзов
POST /api/v1/forwarding/socks-gateways Создать шлюз
PUT /api/v1/forwarding/socks-gateways/:name Обновить шлюз
DELETE /api/v1/forwarding/socks-gateways/:name Удалить шлюз

30.7.4. Полный пример конфигурации

Инфраструктура (forwarding.toml):

[[hosts]]
alias = "proxy-dc1"
address = "10.0.1.10"
http_port = 3128
weight = 2
[hosts.health_check]
check_type = "http"
url = "/health"
expected_status = 200
interval_secs = 15

[[hosts]]
alias = "proxy-dc2"
address = "10.0.2.10"
http_port = 3128
weight = 1
[hosts.health_check]
check_type = "tcp"
interval_secs = 30

[[groups]]
name = "corporate-proxies"
members = ["proxy-dc1", "proxy-dc2"]
algorithm = "round-robin"
fail_action = "fail-open"

[[socks_gateways]]
name = "tor-exit"
address = "10.0.0.50"
port = 9050
version = 5

Политика (policy.cpl):

<Forward>
    ; Внутренние ресурсы — напрямую
    client.address=10.0.0.0/8 url.host.is_private=yes direct

    ; Tor — через SOCKS5
    url.domain=*.onion socks_gateway(tor-exit:9050, 5)

    ; Корпоративный трафик — через группу с балансировкой
    forward(corporate-proxies) forward.fail_open(yes)
</Forward>

<Proxy>
    allow

Как это работает:

  1. Запрос от 10.0.0.5 к intranet.corpdirect (внутренний)
  2. Запрос к hidden.onionsocks_gateway(tor-exit) → SOCKS5 через 10.0.0.50:9050
  3. Запрос к google.comforward(corporate-proxies) → registry resolve → round-robin выбирает proxy-dc1 или proxy-dc2 (с учётом health status) → HTTP forward через выбранный upstream
  4. Если оба proxy-dc1 и proxy-dc2 down → fail_open(yes) → direct к google.com