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