Перейти к содержимому
НовостиGitHubСкачать

Цепочки

Каскад ведёт трафик через несколько узлов: клиент подключается к входному узлу, входной — к выходному, выходной — к сайту. На узле с Citrus группа прокси chain описывает узлы после него в одном месте:

proxies:
- { name: entry, type: vless, server: entry.example.com, port: 443, ... }
- { name: exit-de, type: vless, server: de.example.com, port: 443, ... }
- { name: exit-nl, type: vless, server: nl.example.com, port: 443, ... }
proxy-groups:
- name: exits
type: url-test
proxies: [exit-de, exit-nl]
url: https://cp.cloudflare.com/generate_204
- name: cascade
type: chain
proxies: [entry, exits] # по порядку: первый узел, ..., выход
url: https://cp.cloudflare.com/generate_204
interval: 300
rules:
- MATCH,cascade

Цепочка строится на dialer-proxy: каждый узел после первого подключается через предыдущий. При загрузке конфига цепочка выставляет dialer-proxy прокси, из которых состоит узел:

  • прокси — самому прокси;
  • группа — её участникам и провайдерам из её use (их dialer-proxy);
  • другая цепочка — её первому узлу.

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

Связь становится частью прокси: выход цепочки всегда идёт через вход, в том числе когда его использует правило или другая группа. Каскаду нужно именно это, и на этом держится переключение между выходами: проверки здоровья группы exits выше проверяют каждый выход через вход, и группа переключается на выход, который работает через вход. Без цепочки тот же конфиг пишется руками — dialer-proxy на каждом выходе; сам dialer-proxy работает как раньше.

Конфиг не загрузится, если:

  • узел не найден или повторяется в цепочке;
  • есть цикл: группа цепочки, содержащая саму цепочку, или узел, который шёл бы через себя (группа выходов, содержащая вход);
  • у прокси или провайдера узла уже есть другой dialer-proxy (в том числе выставленный другой цепочкой, где он стоит после другого узла);
  • встроенный прокси (DIRECT, REJECT, …) или группа с include-all* стоит не первым узлом;
  • в цепочке меньше двух узлов, или у неё есть use, include-all*, filter.

Параметры цепочки: url, interval (по умолчанию 300 секунд), timeout, lazy, expected-status, disable-udp, hidden, icon.

Проверка здоровья проверяет всю цепочку одним запросом через все узлы. Если он не прошёл, она проверяет узлы с первого: проверка узла k идёт через узлы с 1 по k−1, поэтому первый не прошедший узел — тот, на котором цепочка рвётся (или связь с ним). Результат виден:

  • в GET /proxies/cascade: hops (name, position, alive: true, false или null, если неизвестно), chainAlive, а у оборванной цепочки — failedHop, failedHopPosition, chainError;
  • в GET /group/cascade/delay: ошибка с именем узла, например chain cascade: hop 2 [exit-de] failed, the hops before it are alive;
  • в метриках: citrus_chain_alive{chain} и citrus_chain_hop_alive{chain,hop,position};
  • событием chain.health в потоке событий, когда состояние меняется.

Узел проверяется запросом тестового URL с него. Узел, которому разрешено ходить только к следующему (а не в интернет), такую проверку не проходит, и если цепочка оборвалась после него, назван будет он, а не настоящий узел.

Узлы записывают и свои задержки: у узла-прокси или узла-группы история проверок есть в /proxies и citrus_proxy_alive.

  • /connections показывает соединение цепочки с chains вида ["exit-de", "exits", "cascade"]: исходящий, который его вёз, затем группы. Соединения предыдущих узлов внутренние и в списке не показываются.
  • Трафик пользователя считается один раз, на соединении пользователя, и к нему применяются лимиты пользователей; узлы его повторно не считают.
  • UDP идёт через цепочку, если его поддерживает последний узел. Протоколу, который несёт UDP внутри своего потока (VLESS, Trojan, Shadowsocks с UDP over TCP), от предыдущих узлов нужен только TCP; протоколу, который шлёт UDP-датаграммы (Shadowsocks UDP, Hysteria2, TUIC), нужен UDP на каждом предыдущем узле (например, udp: true у узла SOCKS5).